]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
UBUNTU: SAUCE: (noup) Update spl to 0.6.5.9-1, zfs to 0.6.5.9-2
authorTim Gardner <tim.gardner@canonical.com>
Wed, 17 Aug 2016 14:26:11 +0000 (08:26 -0600)
committerSeth Forshee <seth.forshee@canonical.com>
Mon, 29 Jan 2018 13:44:51 +0000 (07:44 -0600)
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
636 files changed:
spl/AUTHORS [new file with mode: 0644]
spl/COPYING [new file with mode: 0644]
spl/DISCLAIMER [new file with mode: 0644]
spl/META [new file with mode: 0644]
spl/Makefile.am [new file with mode: 0644]
spl/Makefile.in [new file with mode: 0644]
spl/aclocal.m4 [new file with mode: 0644]
spl/autogen.sh [new file with mode: 0755]
spl/cmd/Makefile.am [new file with mode: 0644]
spl/cmd/Makefile.in [new file with mode: 0644]
spl/cmd/splat.c [new file with mode: 0644]
spl/cmd/splat.h [new file with mode: 0644]
spl/config/Rules.am [new file with mode: 0644]
spl/config/compile [new file with mode: 0755]
spl/config/config.awk [new file with mode: 0644]
spl/config/config.guess [new file with mode: 0755]
spl/config/config.sub [new file with mode: 0755]
spl/config/deb.am [new file with mode: 0644]
spl/config/depcomp [new file with mode: 0755]
spl/config/install-sh [new file with mode: 0755]
spl/config/libtool.m4 [new file with mode: 0644]
spl/config/ltmain.sh [new file with mode: 0644]
spl/config/ltoptions.m4 [new file with mode: 0644]
spl/config/ltsugar.m4 [new file with mode: 0644]
spl/config/ltversion.m4 [new file with mode: 0644]
spl/config/lt~obsolete.m4 [new file with mode: 0644]
spl/config/missing [new file with mode: 0755]
spl/config/rpm.am [new file with mode: 0644]
spl/config/spl-build.m4 [new file with mode: 0644]
spl/config/spl-meta.m4 [new file with mode: 0644]
spl/config/tgz.am [new file with mode: 0644]
spl/configure [new file with mode: 0755]
spl/configure.ac [new file with mode: 0644]
spl/copy-builtin [new file with mode: 0755]
spl/cp [new file with mode: 0755]
spl/dkms.conf [new file with mode: 0644]
spl/include/Makefile.am [new file with mode: 0644]
spl/include/Makefile.in [new file with mode: 0644]
spl/include/fs/Makefile.am [new file with mode: 0644]
spl/include/fs/Makefile.in [new file with mode: 0644]
spl/include/fs/fs_subr.h [new file with mode: 0644]
spl/include/linux/Makefile.am [new file with mode: 0644]
spl/include/linux/Makefile.in [new file with mode: 0644]
spl/include/linux/bitops_compat.h [new file with mode: 0644]
spl/include/linux/compiler_compat.h [new file with mode: 0644]
spl/include/linux/delay_compat.h [new file with mode: 0644]
spl/include/linux/file_compat.h [new file with mode: 0644]
spl/include/linux/list_compat.h [new file with mode: 0644]
spl/include/linux/math64_compat.h [new file with mode: 0644]
spl/include/linux/mm_compat.h [new file with mode: 0644]
spl/include/linux/proc_compat.h [new file with mode: 0644]
spl/include/linux/rwsem_compat.h [new file with mode: 0644]
spl/include/linux/wait_compat.h [new file with mode: 0644]
spl/include/linux/zlib_compat.h [new file with mode: 0644]
spl/include/rpc/Makefile.am [new file with mode: 0644]
spl/include/rpc/Makefile.in [new file with mode: 0644]
spl/include/rpc/types.h [new file with mode: 0644]
spl/include/rpc/xdr.h [new file with mode: 0644]
spl/include/sharefs/Makefile.am [new file with mode: 0644]
spl/include/sharefs/Makefile.in [new file with mode: 0644]
spl/include/sharefs/share.h [new file with mode: 0644]
spl/include/spl-ctl.h [new file with mode: 0644]
spl/include/splat-ctl.h [new file with mode: 0644]
spl/include/strings.h [new file with mode: 0644]
spl/include/sys/Makefile.am [new file with mode: 0644]
spl/include/sys/Makefile.in [new file with mode: 0644]
spl/include/sys/acl.h [new file with mode: 0644]
spl/include/sys/acl_impl.h [new file with mode: 0644]
spl/include/sys/atomic.h [new file with mode: 0644]
spl/include/sys/attr.h [new file with mode: 0644]
spl/include/sys/bitmap.h [new file with mode: 0644]
spl/include/sys/bootconf.h [new file with mode: 0644]
spl/include/sys/bootprops.h [new file with mode: 0644]
spl/include/sys/buf.h [new file with mode: 0644]
spl/include/sys/byteorder.h [new file with mode: 0644]
spl/include/sys/callb.h [new file with mode: 0644]
spl/include/sys/callo.h [new file with mode: 0644]
spl/include/sys/cmn_err.h [new file with mode: 0644]
spl/include/sys/compress.h [new file with mode: 0644]
spl/include/sys/condvar.h [new file with mode: 0644]
spl/include/sys/conf.h [new file with mode: 0644]
spl/include/sys/console.h [new file with mode: 0644]
spl/include/sys/cpupart.h [new file with mode: 0644]
spl/include/sys/cpuvar.h [new file with mode: 0644]
spl/include/sys/crc32.h [new file with mode: 0644]
spl/include/sys/cred.h [new file with mode: 0644]
spl/include/sys/ctype.h [new file with mode: 0644]
spl/include/sys/ddi.h [new file with mode: 0644]
spl/include/sys/debug.h [new file with mode: 0644]
spl/include/sys/dirent.h [new file with mode: 0644]
spl/include/sys/disp.h [new file with mode: 0644]
spl/include/sys/dkio.h [new file with mode: 0644]
spl/include/sys/dklabel.h [new file with mode: 0644]
spl/include/sys/dnlc.h [new file with mode: 0644]
spl/include/sys/dumphdr.h [new file with mode: 0644]
spl/include/sys/efi_partition.h [new file with mode: 0644]
spl/include/sys/errno.h [new file with mode: 0644]
spl/include/sys/extdirent.h [new file with mode: 0644]
spl/include/sys/fcntl.h [new file with mode: 0644]
spl/include/sys/file.h [new file with mode: 0644]
spl/include/sys/fm/Makefile.am [new file with mode: 0644]
spl/include/sys/fm/Makefile.in [new file with mode: 0644]
spl/include/sys/fm/protocol.h [new file with mode: 0644]
spl/include/sys/fm/util.h [new file with mode: 0644]
spl/include/sys/fs/Makefile.am [new file with mode: 0644]
spl/include/sys/fs/Makefile.in [new file with mode: 0644]
spl/include/sys/fs/swapnode.h [new file with mode: 0644]
spl/include/sys/idmap.h [new file with mode: 0644]
spl/include/sys/int_limits.h [new file with mode: 0644]
spl/include/sys/int_types.h [new file with mode: 0644]
spl/include/sys/inttypes.h [new file with mode: 0644]
spl/include/sys/isa_defs.h [new file with mode: 0644]
spl/include/sys/kidmap.h [new file with mode: 0644]
spl/include/sys/kmem.h [new file with mode: 0644]
spl/include/sys/kmem_cache.h [new file with mode: 0644]
spl/include/sys/kobj.h [new file with mode: 0644]
spl/include/sys/kstat.h [new file with mode: 0644]
spl/include/sys/list.h [new file with mode: 0644]
spl/include/sys/mkdev.h [new file with mode: 0644]
spl/include/sys/mntent.h [new file with mode: 0644]
spl/include/sys/modctl.h [new file with mode: 0644]
spl/include/sys/mode.h [new file with mode: 0644]
spl/include/sys/mount.h [new file with mode: 0644]
spl/include/sys/mutex.h [new file with mode: 0644]
spl/include/sys/note.h [new file with mode: 0644]
spl/include/sys/open.h [new file with mode: 0644]
spl/include/sys/param.h [new file with mode: 0644]
spl/include/sys/pathname.h [new file with mode: 0644]
spl/include/sys/policy.h [new file with mode: 0644]
spl/include/sys/pool.h [new file with mode: 0644]
spl/include/sys/priv_impl.h [new file with mode: 0644]
spl/include/sys/proc.h [new file with mode: 0644]
spl/include/sys/processor.h [new file with mode: 0644]
spl/include/sys/pset.h [new file with mode: 0644]
spl/include/sys/random.h [new file with mode: 0644]
spl/include/sys/refstr.h [new file with mode: 0644]
spl/include/sys/resource.h [new file with mode: 0644]
spl/include/sys/rwlock.h [new file with mode: 0644]
spl/include/sys/sdt.h [new file with mode: 0644]
spl/include/sys/sid.h [new file with mode: 0644]
spl/include/sys/signal.h [new file with mode: 0644]
spl/include/sys/stat.h [new file with mode: 0644]
spl/include/sys/stropts.h [new file with mode: 0644]
spl/include/sys/sunddi.h [new file with mode: 0644]
spl/include/sys/sunldi.h [new file with mode: 0644]
spl/include/sys/sysdc.h [new file with mode: 0644]
spl/include/sys/sysevent.h [new file with mode: 0644]
spl/include/sys/sysevent/Makefile.am [new file with mode: 0644]
spl/include/sys/sysevent/Makefile.in [new file with mode: 0644]
spl/include/sys/sysevent/eventdefs.h [new file with mode: 0644]
spl/include/sys/sysmacros.h [new file with mode: 0644]
spl/include/sys/systeminfo.h [new file with mode: 0644]
spl/include/sys/systm.h [new file with mode: 0644]
spl/include/sys/t_lock.h [new file with mode: 0644]
spl/include/sys/taskq.h [new file with mode: 0644]
spl/include/sys/thread.h [new file with mode: 0644]
spl/include/sys/time.h [new file with mode: 0644]
spl/include/sys/timer.h [new file with mode: 0644]
spl/include/sys/tsd.h [new file with mode: 0644]
spl/include/sys/types.h [new file with mode: 0644]
spl/include/sys/types32.h [new file with mode: 0644]
spl/include/sys/u8_textprep.h [new file with mode: 0644]
spl/include/sys/uio.h [new file with mode: 0644]
spl/include/sys/unistd.h [new file with mode: 0644]
spl/include/sys/user.h [new file with mode: 0644]
spl/include/sys/va_list.h [new file with mode: 0644]
spl/include/sys/varargs.h [new file with mode: 0644]
spl/include/sys/vfs.h [new file with mode: 0644]
spl/include/sys/vfs_opreg.h [new file with mode: 0644]
spl/include/sys/vmem.h [new file with mode: 0644]
spl/include/sys/vmsystm.h [new file with mode: 0644]
spl/include/sys/vnode.h [new file with mode: 0644]
spl/include/sys/zmod.h [new file with mode: 0644]
spl/include/sys/zone.h [new file with mode: 0644]
spl/include/unistd.h [new file with mode: 0644]
spl/include/util/Makefile.am [new file with mode: 0644]
spl/include/util/Makefile.in [new file with mode: 0644]
spl/include/util/qsort.h [new file with mode: 0644]
spl/include/util/sscanf.h [new file with mode: 0644]
spl/include/vm/Makefile.am [new file with mode: 0644]
spl/include/vm/Makefile.in [new file with mode: 0644]
spl/include/vm/anon.h [new file with mode: 0644]
spl/include/vm/pvn.h [new file with mode: 0644]
spl/include/vm/seg_kmem.h [new file with mode: 0644]
spl/lib/Makefile.am [new file with mode: 0644]
spl/lib/Makefile.in [new file with mode: 0644]
spl/lib/list.c [new file with mode: 0644]
spl/lib/list.h [new file with mode: 0644]
spl/man/Makefile.am [new file with mode: 0644]
spl/man/Makefile.in [new file with mode: 0644]
spl/man/man1/Makefile.am [new file with mode: 0644]
spl/man/man1/Makefile.in [new file with mode: 0644]
spl/man/man1/splat.1 [new file with mode: 0644]
spl/man/man5/Makefile.am [new file with mode: 0644]
spl/man/man5/Makefile.in [new file with mode: 0644]
spl/man/man5/spl-module-parameters.5 [new file with mode: 0644]
spl/module/Makefile.in [new file with mode: 0644]
spl/module/spl/Makefile.in [new file with mode: 0644]
spl/module/spl/spl-atomic.c [new file with mode: 0644]
spl/module/spl/spl-condvar.c [new file with mode: 0644]
spl/module/spl/spl-cred.c [new file with mode: 0644]
spl/module/spl/spl-err.c [new file with mode: 0644]
spl/module/spl/spl-generic.c [new file with mode: 0644]
spl/module/spl/spl-kmem-cache.c [new file with mode: 0644]
spl/module/spl/spl-kmem.c [new file with mode: 0755]
spl/module/spl/spl-kobj.c [new file with mode: 0644]
spl/module/spl/spl-kstat.c [new file with mode: 0644]
spl/module/spl/spl-mutex.c [new file with mode: 0644]
spl/module/spl/spl-proc.c [new file with mode: 0644]
spl/module/spl/spl-rwlock.c [new file with mode: 0644]
spl/module/spl/spl-taskq.c [new file with mode: 0644]
spl/module/spl/spl-thread.c [new file with mode: 0644]
spl/module/spl/spl-tsd.c [new file with mode: 0644]
spl/module/spl/spl-vmem.c [new file with mode: 0644]
spl/module/spl/spl-vnode.c [new file with mode: 0644]
spl/module/spl/spl-xdr.c [new file with mode: 0644]
spl/module/spl/spl-zlib.c [new file with mode: 0644]
spl/module/splat/Makefile.in [new file with mode: 0644]
spl/module/splat/splat-atomic.c [new file with mode: 0644]
spl/module/splat/splat-condvar.c [new file with mode: 0644]
spl/module/splat/splat-cred.c [new file with mode: 0644]
spl/module/splat/splat-ctl.c [new file with mode: 0644]
spl/module/splat/splat-generic.c [new file with mode: 0644]
spl/module/splat/splat-internal.h [new file with mode: 0644]
spl/module/splat/splat-kmem.c [new file with mode: 0644]
spl/module/splat/splat-kobj.c [new file with mode: 0644]
spl/module/splat/splat-linux.c [new file with mode: 0644]
spl/module/splat/splat-list.c [new file with mode: 0644]
spl/module/splat/splat-mutex.c [new file with mode: 0644]
spl/module/splat/splat-random.c [new file with mode: 0644]
spl/module/splat/splat-rwlock.c [new file with mode: 0644]
spl/module/splat/splat-taskq.c [new file with mode: 0644]
spl/module/splat/splat-thread.c [new file with mode: 0644]
spl/module/splat/splat-time.c [new file with mode: 0644]
spl/module/splat/splat-vnode.c [new file with mode: 0644]
spl/module/splat/splat-zlib.c [new file with mode: 0644]
spl/rpm/Makefile.am [new file with mode: 0644]
spl/rpm/Makefile.in [new file with mode: 0644]
spl/rpm/generic/Makefile.am [new file with mode: 0644]
spl/rpm/generic/Makefile.in [new file with mode: 0644]
spl/rpm/generic/spl-dkms.spec.in [new file with mode: 0644]
spl/rpm/generic/spl-kmod.spec.in [new file with mode: 0644]
spl/rpm/generic/spl.spec.in [new file with mode: 0644]
spl/rpm/redhat/Makefile.am [new file with mode: 0644]
spl/rpm/redhat/Makefile.in [new file with mode: 0644]
spl/rpm/redhat/spl-dkms.spec.in [new file with mode: 0644]
spl/rpm/redhat/spl-kmod.spec.in [new file with mode: 0644]
spl/rpm/redhat/spl.spec.in [new file with mode: 0644]
spl/scripts/Makefile.am [new file with mode: 0644]
spl/scripts/Makefile.in [new file with mode: 0644]
spl/scripts/check.sh [new file with mode: 0755]
spl/scripts/dkms.mkconf [new file with mode: 0755]
spl/scripts/dkms.postbuild [new file with mode: 0755]
spl/scripts/kmodtool [new file with mode: 0644]
spl/spl.release.in [new file with mode: 0644]
spl/spl_config.h.in [new file with mode: 0644]
zfs/AUTHORS [new file with mode: 0644]
zfs/COPYRIGHT [new file with mode: 0644]
zfs/DISCLAIMER [new file with mode: 0644]
zfs/META [new file with mode: 0644]
zfs/Makefile.am [new file with mode: 0644]
zfs/Makefile.in [new file with mode: 0644]
zfs/OPENSOLARIS.LICENSE [new file with mode: 0644]
zfs/README.markdown [new file with mode: 0644]
zfs/aclocal.m4 [new file with mode: 0644]
zfs/autogen.sh [new file with mode: 0755]
zfs/config/Rules.am [new file with mode: 0644]
zfs/config/always-no-bool-compare.m4 [new file with mode: 0644]
zfs/config/always-no-unused-but-set-variable.m4 [new file with mode: 0644]
zfs/config/compile [new file with mode: 0755]
zfs/config/config.awk [new file with mode: 0644]
zfs/config/config.guess [new file with mode: 0755]
zfs/config/config.sub [new file with mode: 0755]
zfs/config/deb.am [new file with mode: 0644]
zfs/config/dkms.m4 [new file with mode: 0644]
zfs/config/install-sh [new file with mode: 0755]
zfs/config/kernel-acl.m4 [new file with mode: 0644]
zfs/config/kernel-aio-fsync.m4 [new file with mode: 0644]
zfs/config/kernel-automount.m4 [new file with mode: 0644]
zfs/config/kernel-bdev-block-device-operations.m4 [new file with mode: 0644]
zfs/config/kernel-bdev-logical-size.m4 [new file with mode: 0644]
zfs/config/kernel-bdev-physical-size.m4 [new file with mode: 0644]
zfs/config/kernel-bdi-setup-and-register.m4 [new file with mode: 0644]
zfs/config/kernel-bio-bvec-iter.m4 [new file with mode: 0644]
zfs/config/kernel-bio-end-io-t-args.m4 [new file with mode: 0644]
zfs/config/kernel-bio-failfast.m4 [new file with mode: 0644]
zfs/config/kernel-bio-op.m4 [new file with mode: 0644]
zfs/config/kernel-bio-rw-barrier.m4 [new file with mode: 0644]
zfs/config/kernel-bio-rw-discard.m4 [new file with mode: 0644]
zfs/config/kernel-blk-queue-flush.m4 [new file with mode: 0644]
zfs/config/kernel-blk-queue-max-hw-sectors.m4 [new file with mode: 0644]
zfs/config/kernel-blk-queue-max-segments.m4 [new file with mode: 0644]
zfs/config/kernel-blk-queue-unplug.m4 [new file with mode: 0644]
zfs/config/kernel-blkdev-get-by-path.m4 [new file with mode: 0644]
zfs/config/kernel-blkdev-get.m4 [new file with mode: 0644]
zfs/config/kernel-block-device-operations-release-void.m4 [new file with mode: 0644]
zfs/config/kernel-check-disk-size-change.m4 [new file with mode: 0644]
zfs/config/kernel-clear-inode.m4 [new file with mode: 0644]
zfs/config/kernel-commit-metadata.m4 [new file with mode: 0644]
zfs/config/kernel-create-nameidata.m4 [new file with mode: 0644]
zfs/config/kernel-current_bio_tail.m4 [new file with mode: 0644]
zfs/config/kernel-d-make-root.m4 [new file with mode: 0644]
zfs/config/kernel-d-obtain-alias.m4 [new file with mode: 0644]
zfs/config/kernel-d-prune-aliases.m4 [new file with mode: 0644]
zfs/config/kernel-declare-event-class.m4 [new file with mode: 0644]
zfs/config/kernel-dentry-operations.m4 [new file with mode: 0644]
zfs/config/kernel-dirty-inode.m4 [new file with mode: 0644]
zfs/config/kernel-discard-granularity.m4 [new file with mode: 0644]
zfs/config/kernel-elevator-change.m4 [new file with mode: 0644]
zfs/config/kernel-encode-fh-inode.m4 [new file with mode: 0644]
zfs/config/kernel-evict-inode.m4 [new file with mode: 0644]
zfs/config/kernel-fallocate.m4 [new file with mode: 0644]
zfs/config/kernel-file-inode.m4 [new file with mode: 0644]
zfs/config/kernel-fmode-t.m4 [new file with mode: 0644]
zfs/config/kernel-follow-down-one.m4 [new file with mode: 0644]
zfs/config/kernel-fsync.m4 [new file with mode: 0644]
zfs/config/kernel-generic_io_acct.m4 [new file with mode: 0644]
zfs/config/kernel-generic_readlink.m4 [new file with mode: 0644]
zfs/config/kernel-get-disk-ro.m4 [new file with mode: 0644]
zfs/config/kernel-get-gendisk.m4 [new file with mode: 0644]
zfs/config/kernel-get-link.m4 [new file with mode: 0644]
zfs/config/kernel-insert-inode-locked.m4 [new file with mode: 0644]
zfs/config/kernel-invalidate-bdev-args.m4 [new file with mode: 0644]
zfs/config/kernel-is_owner_or_cap.m4 [new file with mode: 0644]
zfs/config/kernel-kmap-atomic-args.m4 [new file with mode: 0644]
zfs/config/kernel-kobj-name-len.m4 [new file with mode: 0644]
zfs/config/kernel-lookup-bdev.m4 [new file with mode: 0644]
zfs/config/kernel-lookup-nameidata.m4 [new file with mode: 0644]
zfs/config/kernel-lseek-execute.m4 [new file with mode: 0644]
zfs/config/kernel-mk-request-fn.m4 [new file with mode: 0644]
zfs/config/kernel-mkdir-umode-t.m4 [new file with mode: 0644]
zfs/config/kernel-mount-nodev.m4 [new file with mode: 0644]
zfs/config/kernel-open-bdev-exclusive.m4 [new file with mode: 0644]
zfs/config/kernel-put-link.m4 [new file with mode: 0644]
zfs/config/kernel-rename.m4 [new file with mode: 0644]
zfs/config/kernel-security-inode-init.m4 [new file with mode: 0644]
zfs/config/kernel-set-nlink.m4 [new file with mode: 0644]
zfs/config/kernel-setattr-prepare.m4 [new file with mode: 0644]
zfs/config/kernel-sget-args.m4 [new file with mode: 0644]
zfs/config/kernel-show-options.m4 [new file with mode: 0644]
zfs/config/kernel-shrink.m4 [new file with mode: 0644]
zfs/config/kernel-submit_bio.m4 [new file with mode: 0644]
zfs/config/kernel-truncate-range.m4 [new file with mode: 0644]
zfs/config/kernel-truncate-setsize.m4 [new file with mode: 0644]
zfs/config/kernel-vfs-iterate.m4 [new file with mode: 0644]
zfs/config/kernel-vfs-rw-iterate.m4 [new file with mode: 0644]
zfs/config/kernel-xattr-handler.m4 [new file with mode: 0644]
zfs/config/kernel.m4 [new file with mode: 0644]
zfs/config/libtool.m4 [new file with mode: 0644]
zfs/config/ltmain.sh [new file with mode: 0644]
zfs/config/ltoptions.m4 [new file with mode: 0644]
zfs/config/ltsugar.m4 [new file with mode: 0644]
zfs/config/ltversion.m4 [new file with mode: 0644]
zfs/config/lt~obsolete.m4 [new file with mode: 0644]
zfs/config/missing [new file with mode: 0755]
zfs/config/mount-helper.m4 [new file with mode: 0644]
zfs/config/rpm.am [new file with mode: 0644]
zfs/config/tgz.am [new file with mode: 0644]
zfs/config/user-arch.m4 [new file with mode: 0644]
zfs/config/user-dracut.m4 [new file with mode: 0644]
zfs/config/user-frame-larger-than.m4 [new file with mode: 0644]
zfs/config/user-libblkid.m4 [new file with mode: 0644]
zfs/config/user-libuuid.m4 [new file with mode: 0644]
zfs/config/user-runstatedir.m4 [new file with mode: 0644]
zfs/config/user-systemd.m4 [new file with mode: 0644]
zfs/config/user-sysvinit.m4 [new file with mode: 0644]
zfs/config/user-udev.m4 [new file with mode: 0644]
zfs/config/user-zlib.m4 [new file with mode: 0644]
zfs/config/user.m4 [new file with mode: 0644]
zfs/config/zfs-build.m4 [new file with mode: 0644]
zfs/config/zfs-meta.m4 [new file with mode: 0644]
zfs/configure [new file with mode: 0755]
zfs/configure.ac [new file with mode: 0644]
zfs/cp [new file with mode: 0755]
zfs/dkms.conf [new file with mode: 0644]
zfs/include/Makefile.am [new file with mode: 0644]
zfs/include/Makefile.in [new file with mode: 0644]
zfs/include/libnvpair.h [new file with mode: 0644]
zfs/include/libuutil.h [new file with mode: 0644]
zfs/include/libuutil_common.h [new file with mode: 0644]
zfs/include/libuutil_impl.h [new file with mode: 0644]
zfs/include/libzfs.h [new file with mode: 0644]
zfs/include/libzfs_core.h [new file with mode: 0644]
zfs/include/libzfs_impl.h [new file with mode: 0644]
zfs/include/linux/Makefile.am [new file with mode: 0644]
zfs/include/linux/Makefile.in [new file with mode: 0644]
zfs/include/linux/blkdev_compat.h [new file with mode: 0644]
zfs/include/linux/dcache_compat.h [new file with mode: 0644]
zfs/include/linux/kmap_compat.h [new file with mode: 0644]
zfs/include/linux/utsname_compat.h [new file with mode: 0644]
zfs/include/linux/vfs_compat.h [new file with mode: 0644]
zfs/include/linux/xattr_compat.h [new file with mode: 0644]
zfs/include/sys/Makefile.am [new file with mode: 0644]
zfs/include/sys/Makefile.in [new file with mode: 0644]
zfs/include/sys/arc.h [new file with mode: 0644]
zfs/include/sys/arc_impl.h [new file with mode: 0644]
zfs/include/sys/avl.h [new file with mode: 0644]
zfs/include/sys/avl_impl.h [new file with mode: 0644]
zfs/include/sys/blkptr.h [new file with mode: 0644]
zfs/include/sys/bplist.h [new file with mode: 0644]
zfs/include/sys/bpobj.h [new file with mode: 0644]
zfs/include/sys/bptree.h [new file with mode: 0644]
zfs/include/sys/dbuf.h [new file with mode: 0644]
zfs/include/sys/ddt.h [new file with mode: 0644]
zfs/include/sys/dmu.h [new file with mode: 0644]
zfs/include/sys/dmu_impl.h [new file with mode: 0644]
zfs/include/sys/dmu_objset.h [new file with mode: 0644]
zfs/include/sys/dmu_send.h [new file with mode: 0644]
zfs/include/sys/dmu_traverse.h [new file with mode: 0644]
zfs/include/sys/dmu_tx.h [new file with mode: 0644]
zfs/include/sys/dmu_zfetch.h [new file with mode: 0644]
zfs/include/sys/dnode.h [new file with mode: 0644]
zfs/include/sys/dsl_bookmark.h [new file with mode: 0644]
zfs/include/sys/dsl_dataset.h [new file with mode: 0644]
zfs/include/sys/dsl_deadlist.h [new file with mode: 0644]
zfs/include/sys/dsl_deleg.h [new file with mode: 0644]
zfs/include/sys/dsl_destroy.h [new file with mode: 0644]
zfs/include/sys/dsl_dir.h [new file with mode: 0644]
zfs/include/sys/dsl_pool.h [new file with mode: 0644]
zfs/include/sys/dsl_prop.h [new file with mode: 0644]
zfs/include/sys/dsl_scan.h [new file with mode: 0644]
zfs/include/sys/dsl_synctask.h [new file with mode: 0644]
zfs/include/sys/dsl_userhold.h [new file with mode: 0644]
zfs/include/sys/efi_partition.h [new file with mode: 0644]
zfs/include/sys/fm/Makefile.am [new file with mode: 0644]
zfs/include/sys/fm/Makefile.in [new file with mode: 0644]
zfs/include/sys/fm/fs/Makefile.am [new file with mode: 0644]
zfs/include/sys/fm/fs/Makefile.in [new file with mode: 0644]
zfs/include/sys/fm/fs/zfs.h [new file with mode: 0644]
zfs/include/sys/fm/protocol.h [new file with mode: 0644]
zfs/include/sys/fm/util.h [new file with mode: 0644]
zfs/include/sys/fs/Makefile.am [new file with mode: 0644]
zfs/include/sys/fs/Makefile.in [new file with mode: 0644]
zfs/include/sys/fs/zfs.h [new file with mode: 0644]
zfs/include/sys/metaslab.h [new file with mode: 0644]
zfs/include/sys/metaslab_impl.h [new file with mode: 0644]
zfs/include/sys/mntent.h [new file with mode: 0644]
zfs/include/sys/multilist.h [new file with mode: 0644]
zfs/include/sys/nvpair.h [new file with mode: 0644]
zfs/include/sys/nvpair_impl.h [new file with mode: 0644]
zfs/include/sys/range_tree.h [new file with mode: 0644]
zfs/include/sys/refcount.h [new file with mode: 0644]
zfs/include/sys/rrwlock.h [new file with mode: 0644]
zfs/include/sys/sa.h [new file with mode: 0644]
zfs/include/sys/sa_impl.h [new file with mode: 0644]
zfs/include/sys/sdt.h [new file with mode: 0644]
zfs/include/sys/spa.h [new file with mode: 0644]
zfs/include/sys/spa_boot.h [new file with mode: 0644]
zfs/include/sys/spa_impl.h [new file with mode: 0644]
zfs/include/sys/space_map.h [new file with mode: 0644]
zfs/include/sys/space_reftree.h [new file with mode: 0644]
zfs/include/sys/trace.h [new file with mode: 0644]
zfs/include/sys/trace_acl.h [new file with mode: 0644]
zfs/include/sys/trace_arc.h [new file with mode: 0644]
zfs/include/sys/trace_dbgmsg.h [new file with mode: 0644]
zfs/include/sys/trace_dbuf.h [new file with mode: 0644]
zfs/include/sys/trace_dmu.h [new file with mode: 0644]
zfs/include/sys/trace_dnode.h [new file with mode: 0644]
zfs/include/sys/trace_multilist.h [new file with mode: 0644]
zfs/include/sys/trace_txg.h [new file with mode: 0644]
zfs/include/sys/trace_zil.h [new file with mode: 0644]
zfs/include/sys/trace_zrlock.h [new file with mode: 0644]
zfs/include/sys/txg.h [new file with mode: 0644]
zfs/include/sys/txg_impl.h [new file with mode: 0644]
zfs/include/sys/u8_textprep.h [new file with mode: 0644]
zfs/include/sys/u8_textprep_data.h [new file with mode: 0644]
zfs/include/sys/uberblock.h [new file with mode: 0644]
zfs/include/sys/uberblock_impl.h [new file with mode: 0644]
zfs/include/sys/uio_impl.h [new file with mode: 0644]
zfs/include/sys/unique.h [new file with mode: 0644]
zfs/include/sys/uuid.h [new file with mode: 0644]
zfs/include/sys/vdev.h [new file with mode: 0644]
zfs/include/sys/vdev_disk.h [new file with mode: 0644]
zfs/include/sys/vdev_file.h [new file with mode: 0644]
zfs/include/sys/vdev_impl.h [new file with mode: 0644]
zfs/include/sys/xvattr.h [new file with mode: 0644]
zfs/include/sys/zap.h [new file with mode: 0644]
zfs/include/sys/zap_impl.h [new file with mode: 0644]
zfs/include/sys/zap_leaf.h [new file with mode: 0644]
zfs/include/sys/zfeature.h [new file with mode: 0644]
zfs/include/sys/zfs_acl.h [new file with mode: 0644]
zfs/include/sys/zfs_context.h [new file with mode: 0644]
zfs/include/sys/zfs_ctldir.h [new file with mode: 0644]
zfs/include/sys/zfs_debug.h [new file with mode: 0644]
zfs/include/sys/zfs_delay.h [new file with mode: 0644]
zfs/include/sys/zfs_dir.h [new file with mode: 0644]
zfs/include/sys/zfs_fuid.h [new file with mode: 0644]
zfs/include/sys/zfs_ioctl.h [new file with mode: 0644]
zfs/include/sys/zfs_onexit.h [new file with mode: 0644]
zfs/include/sys/zfs_rlock.h [new file with mode: 0644]
zfs/include/sys/zfs_sa.h [new file with mode: 0644]
zfs/include/sys/zfs_stat.h [new file with mode: 0644]
zfs/include/sys/zfs_vfsops.h [new file with mode: 0644]
zfs/include/sys/zfs_vnops.h [new file with mode: 0644]
zfs/include/sys/zfs_znode.h [new file with mode: 0644]
zfs/include/sys/zil.h [new file with mode: 0644]
zfs/include/sys/zil_impl.h [new file with mode: 0644]
zfs/include/sys/zio.h [new file with mode: 0644]
zfs/include/sys/zio_checksum.h [new file with mode: 0644]
zfs/include/sys/zio_compress.h [new file with mode: 0644]
zfs/include/sys/zio_impl.h [new file with mode: 0644]
zfs/include/sys/zpl.h [new file with mode: 0644]
zfs/include/sys/zrlock.h [new file with mode: 0644]
zfs/include/sys/zvol.h [new file with mode: 0644]
zfs/include/zfeature_common.h [new file with mode: 0644]
zfs/include/zfs_comutil.h [new file with mode: 0644]
zfs/include/zfs_deleg.h [new file with mode: 0644]
zfs/include/zfs_fletcher.h [new file with mode: 0644]
zfs/include/zfs_namecheck.h [new file with mode: 0644]
zfs/include/zfs_prop.h [new file with mode: 0644]
zfs/include/zpios-ctl.h [new file with mode: 0644]
zfs/include/zpios-internal.h [new file with mode: 0644]
zfs/module/Makefile.in [new file with mode: 0644]
zfs/module/avl/Makefile.in [new file with mode: 0644]
zfs/module/avl/avl.c [new file with mode: 0644]
zfs/module/nvpair/Makefile.in [new file with mode: 0644]
zfs/module/nvpair/fnvpair.c [new file with mode: 0644]
zfs/module/nvpair/nvpair.c [new file with mode: 0644]
zfs/module/nvpair/nvpair_alloc_fixed.c [new file with mode: 0644]
zfs/module/nvpair/nvpair_alloc_spl.c [new file with mode: 0644]
zfs/module/unicode/Makefile.in [new file with mode: 0644]
zfs/module/unicode/u8_textprep.c [new file with mode: 0644]
zfs/module/unicode/uconv.c [new file with mode: 0644]
zfs/module/zcommon/Makefile.in [new file with mode: 0644]
zfs/module/zcommon/zfs_comutil.c [new file with mode: 0644]
zfs/module/zcommon/zfs_deleg.c [new file with mode: 0644]
zfs/module/zcommon/zfs_fletcher.c [new file with mode: 0644]
zfs/module/zcommon/zfs_namecheck.c [new file with mode: 0644]
zfs/module/zcommon/zfs_prop.c [new file with mode: 0644]
zfs/module/zcommon/zfs_uio.c [new file with mode: 0644]
zfs/module/zcommon/zpool_prop.c [new file with mode: 0644]
zfs/module/zcommon/zprop_common.c [new file with mode: 0644]
zfs/module/zfs/Makefile.in [new file with mode: 0644]
zfs/module/zfs/arc.c [new file with mode: 0644]
zfs/module/zfs/blkptr.c [new file with mode: 0644]
zfs/module/zfs/bplist.c [new file with mode: 0644]
zfs/module/zfs/bpobj.c [new file with mode: 0644]
zfs/module/zfs/bptree.c [new file with mode: 0644]
zfs/module/zfs/dbuf.c [new file with mode: 0644]
zfs/module/zfs/dbuf_stats.c [new file with mode: 0644]
zfs/module/zfs/ddt.c [new file with mode: 0644]
zfs/module/zfs/ddt_zap.c [new file with mode: 0644]
zfs/module/zfs/dmu.c [new file with mode: 0644]
zfs/module/zfs/dmu_diff.c [new file with mode: 0644]
zfs/module/zfs/dmu_object.c [new file with mode: 0644]
zfs/module/zfs/dmu_objset.c [new file with mode: 0644]
zfs/module/zfs/dmu_send.c [new file with mode: 0644]
zfs/module/zfs/dmu_traverse.c [new file with mode: 0644]
zfs/module/zfs/dmu_tx.c [new file with mode: 0644]
zfs/module/zfs/dmu_zfetch.c [new file with mode: 0644]
zfs/module/zfs/dnode.c [new file with mode: 0644]
zfs/module/zfs/dnode_sync.c [new file with mode: 0644]
zfs/module/zfs/dsl_bookmark.c [new file with mode: 0644]
zfs/module/zfs/dsl_dataset.c [new file with mode: 0644]
zfs/module/zfs/dsl_deadlist.c [new file with mode: 0644]
zfs/module/zfs/dsl_deleg.c [new file with mode: 0644]
zfs/module/zfs/dsl_destroy.c [new file with mode: 0644]
zfs/module/zfs/dsl_dir.c [new file with mode: 0644]
zfs/module/zfs/dsl_pool.c [new file with mode: 0755]
zfs/module/zfs/dsl_prop.c [new file with mode: 0644]
zfs/module/zfs/dsl_scan.c [new file with mode: 0644]
zfs/module/zfs/dsl_synctask.c [new file with mode: 0644]
zfs/module/zfs/dsl_userhold.c [new file with mode: 0644]
zfs/module/zfs/fm.c [new file with mode: 0644]
zfs/module/zfs/gzip.c [new file with mode: 0644]
zfs/module/zfs/lz4.c [new file with mode: 0644]
zfs/module/zfs/lzjb.c [new file with mode: 0644]
zfs/module/zfs/metaslab.c [new file with mode: 0644]
zfs/module/zfs/multilist.c [new file with mode: 0644]
zfs/module/zfs/range_tree.c [new file with mode: 0644]
zfs/module/zfs/refcount.c [new file with mode: 0644]
zfs/module/zfs/rrwlock.c [new file with mode: 0644]
zfs/module/zfs/sa.c [new file with mode: 0644]
zfs/module/zfs/sha256.c [new file with mode: 0644]
zfs/module/zfs/spa.c [new file with mode: 0644]
zfs/module/zfs/spa_boot.c [new file with mode: 0644]
zfs/module/zfs/spa_config.c [new file with mode: 0644]
zfs/module/zfs/spa_errlog.c [new file with mode: 0644]
zfs/module/zfs/spa_history.c [new file with mode: 0644]
zfs/module/zfs/spa_misc.c [new file with mode: 0644]
zfs/module/zfs/spa_stats.c [new file with mode: 0644]
zfs/module/zfs/space_map.c [new file with mode: 0644]
zfs/module/zfs/space_reftree.c [new file with mode: 0644]
zfs/module/zfs/trace.c [new file with mode: 0644]
zfs/module/zfs/txg.c [new file with mode: 0644]
zfs/module/zfs/uberblock.c [new file with mode: 0644]
zfs/module/zfs/unique.c [new file with mode: 0644]
zfs/module/zfs/vdev.c [new file with mode: 0644]
zfs/module/zfs/vdev_cache.c [new file with mode: 0644]
zfs/module/zfs/vdev_disk.c [new file with mode: 0644]
zfs/module/zfs/vdev_file.c [new file with mode: 0644]
zfs/module/zfs/vdev_label.c [new file with mode: 0644]
zfs/module/zfs/vdev_mirror.c [new file with mode: 0644]
zfs/module/zfs/vdev_missing.c [new file with mode: 0644]
zfs/module/zfs/vdev_queue.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz.c [new file with mode: 0644]
zfs/module/zfs/vdev_root.c [new file with mode: 0644]
zfs/module/zfs/zap.c [new file with mode: 0644]
zfs/module/zfs/zap_leaf.c [new file with mode: 0644]
zfs/module/zfs/zap_micro.c [new file with mode: 0644]
zfs/module/zfs/zfeature.c [new file with mode: 0644]
zfs/module/zfs/zfeature_common.c [new file with mode: 0644]
zfs/module/zfs/zfs_acl.c [new file with mode: 0644]
zfs/module/zfs/zfs_byteswap.c [new file with mode: 0644]
zfs/module/zfs/zfs_ctldir.c [new file with mode: 0644]
zfs/module/zfs/zfs_debug.c [new file with mode: 0644]
zfs/module/zfs/zfs_dir.c [new file with mode: 0644]
zfs/module/zfs/zfs_fm.c [new file with mode: 0644]
zfs/module/zfs/zfs_fuid.c [new file with mode: 0644]
zfs/module/zfs/zfs_ioctl.c [new file with mode: 0644]
zfs/module/zfs/zfs_log.c [new file with mode: 0644]
zfs/module/zfs/zfs_onexit.c [new file with mode: 0644]
zfs/module/zfs/zfs_replay.c [new file with mode: 0644]
zfs/module/zfs/zfs_rlock.c [new file with mode: 0644]
zfs/module/zfs/zfs_sa.c [new file with mode: 0644]
zfs/module/zfs/zfs_vfsops.c [new file with mode: 0644]
zfs/module/zfs/zfs_vnops.c [new file with mode: 0644]
zfs/module/zfs/zfs_znode.c [new file with mode: 0644]
zfs/module/zfs/zil.c [new file with mode: 0644]
zfs/module/zfs/zio.c [new file with mode: 0644]
zfs/module/zfs/zio_checksum.c [new file with mode: 0644]
zfs/module/zfs/zio_compress.c [new file with mode: 0644]
zfs/module/zfs/zio_inject.c [new file with mode: 0644]
zfs/module/zfs/zle.c [new file with mode: 0644]
zfs/module/zfs/zpl_ctldir.c [new file with mode: 0644]
zfs/module/zfs/zpl_export.c [new file with mode: 0644]
zfs/module/zfs/zpl_file.c [new file with mode: 0644]
zfs/module/zfs/zpl_inode.c [new file with mode: 0644]
zfs/module/zfs/zpl_super.c [new file with mode: 0644]
zfs/module/zfs/zpl_xattr.c [new file with mode: 0644]
zfs/module/zfs/zrlock.c [new file with mode: 0644]
zfs/module/zfs/zvol.c [new file with mode: 0644]
zfs/module/zpios/Makefile.in [new file with mode: 0644]
zfs/module/zpios/pios.c [new file with mode: 0644]
zfs/zfs.release.in [new file with mode: 0644]
zfs/zfs_config.h.in [new file with mode: 0644]

diff --git a/spl/AUTHORS b/spl/AUTHORS
new file mode 100644 (file)
index 0000000..96757e8
--- /dev/null
@@ -0,0 +1,25 @@
+Original author and maintainer.
+
+  Brian Behlendorf <behlendorf1@llnl.gov>
+
+Additionally the following individuals have all made contributions
+to the project and deserve to be acknowledged.
+
+  Alex Zhuravlev <Alex.Zhuravlev@Sun.COM>
+  Brian J. Murrell <brian@sun.com>
+  Chris Dunlap <cdunlap@llnl.gov>
+  Chris Dunlop <chris@onthe.net.au>
+  Darik Horn <dajhorn@vanadac.com>
+  Etienne Dechamps <etienne.dechamps@ovh.net>
+  Gunnar Beutner <gunnar@beutner.name>
+  Jorgen Lundman <lundman@lundman.net>
+  Lars Johannsen <laj@it.dk>
+  Li Wei <W.Li@Sun.COM>
+  Massimo Maggi <massimo@mmmm.it>
+  Ned Bass <bass6@llnl.gov>
+  Neependra Khare <neependra@kqinfotech.com>
+  Prakash Surya <surya1@llnl.gov>
+  Ricardo Correia <Ricardo.M.Correia@Sun.COM>
+  Richard Yao <ryao@cs.stonybrook.edu>
+  Steven Johnson <sjohnson@sakuraindustries.com>
+  Yuxuan Shui <yshuiv7@gmail.com>
diff --git a/spl/COPYING b/spl/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/spl/DISCLAIMER b/spl/DISCLAIMER
new file mode 100644 (file)
index 0000000..1bb04be
--- /dev/null
@@ -0,0 +1,24 @@
+This work was produced at the Lawrence Livermore National Laboratory
+(LLNL) under Contract No. DE-AC52-07NA27344 (Contract 44) between
+the U.S. Department of Energy (DOE) and Lawrence Livermore National
+Security, LLC (LLNS) for the operation of LLNL.
+
+This work was prepared as an account of work sponsored by an agency of
+the United States Government.  Neither the United States Government nor
+Lawrence Livermore National Security, LLC nor any of their employees,
+makes any warranty, express or implied, or assumes any liability or
+responsibility for the accuracy, completeness, or usefulness of any
+information, apparatus, product, or process disclosed, or represents
+that its use would not infringe privately-owned rights.
+
+Reference herein to any specific commercial products, process, or
+services by trade name, trademark, manufacturer or otherwise does
+not necessarily constitute or imply its endorsement, recommendation,
+or favoring by the United States Government or Lawrence Livermore
+National Security, LLC.  The views and opinions of authors expressed
+herein do not necessarily state or reflect those of the Untied States
+Government or Lawrence Livermore National Security, LLC, and shall
+not be used for advertising or product endorsement purposes.
+
+The precise terms and conditions for copying, distribution, and
+modification are specified in the file "COPYING".
diff --git a/spl/META b/spl/META
new file mode 100644 (file)
index 0000000..c7b69be
--- /dev/null
+++ b/spl/META
@@ -0,0 +1,8 @@
+Meta:         1
+Name:         spl
+Branch:       1.0
+Version:      0.6.5.9
+Release:      1
+Release-Tags: relext
+License:      GPL
+Author:       OpenZFS on Linux
diff --git a/spl/Makefile.am b/spl/Makefile.am
new file mode 100644 (file)
index 0000000..4977448
--- /dev/null
@@ -0,0 +1,54 @@
+
+ACLOCAL_AMFLAGS = -I config
+
+include config/rpm.am
+include config/deb.am
+include config/tgz.am
+
+SUBDIRS = include rpm
+if CONFIG_USER
+SUBDIRS += lib cmd man scripts
+endif
+if CONFIG_KERNEL
+SUBDIRS += module
+
+extradir = @prefix@/src/spl-$(VERSION)
+extra_HEADERS = spl.release.in spl_config.h.in
+
+kerneldir = @prefix@/src/spl-$(VERSION)/$(LINUX_VERSION)
+nodist_kernel_HEADERS = spl.release spl_config.h module/$(LINUX_SYMBOLS)
+endif
+
+AUTOMAKE_OPTIONS = foreign
+EXTRA_DIST  = autogen.sh META DISCLAIMER copy-builtin
+EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
+
+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 'aclocal.m4' -o -size 0 \
+               -o -name '*%' -o -name '.*.cmd' -o -name 'core' \
+               -o -name 'Makefile' -o -name '$(LINUX_SYMBOLS)' \
+               -o -name '*.order' -o -name '*.markers' \) \
+               -type f -print | xargs $(RM)
+
+dist-hook:
+       sed -i 's/Release:[[:print:]]*/Release:      $(RELEASE)/' \
+               $(distdir)/META
+
+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
diff --git a/spl/Makefile.in b/spl/Makefile.in
new file mode 100644 (file)
index 0000000..c451112
--- /dev/null
@@ -0,0 +1,1182 @@
+# 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.
+###############################################################################
+
+###############################################################################
+# Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Build targets for DEB packages.
+#
+# Long term native distro specific Debian style packaging should be added.
+# In the short term RPM packages are built and converted to DEB packages
+# using alien.  If someone familiar with Debian style packaging were to
+# update the build system to correctly build Debian style packages I would
+# happily take it.  Until then we will have to make due with alien.
+#
+###############################################################################
+
+###############################################################################
+# Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Build targets for TGZ packages.
+#
+# Long term native distro specific Slackware style packaging should be added.
+# In the short term RPM packages are built and converted to TGZ packages
+# using alien.  If someone familiar with Slackware style packaging were to
+# update the build system to correctly build Slackware style packages I would
+# happily take it.  Until then we will have to make due with alien.
+#
+###############################################################################
+
+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 = lib cmd man scripts
+@CONFIG_KERNEL_TRUE@am__append_2 = module
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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 = spl_config.h
+CONFIG_CLEAN_FILES = module/Makefile module/spl/Makefile \
+       module/splat/Makefile spl.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 = spl.release.in spl_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)spl_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 lib cmd man scripts module
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config/deb.am \
+       $(srcdir)/config/rpm.am $(srcdir)/config/tgz.am \
+       $(srcdir)/spl.release.in $(srcdir)/spl_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/spl/Makefile.in \
+       $(top_srcdir)/module/splat/Makefile.in AUTHORS COPYING \
+       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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+ACLOCAL_AMFLAGS = -I config
+SUBDIRS = include rpm $(am__append_1) $(am__append_2)
+@CONFIG_KERNEL_TRUE@extradir = @prefix@/src/spl-$(VERSION)
+@CONFIG_KERNEL_TRUE@extra_HEADERS = spl.release.in spl_config.h.in
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/$(LINUX_VERSION)
+@CONFIG_KERNEL_TRUE@nodist_kernel_HEADERS = spl.release spl_config.h module/$(LINUX_SYMBOLS)
+AUTOMAKE_OPTIONS = foreign
+EXTRA_DIST = autogen.sh META DISCLAIMER copy-builtin config/config.awk \
+       config/rpm.am config/deb.am config/tgz.am
+all: spl_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):
+
+spl_config.h: stamp-h1
+       @test -f $@ || rm -f stamp-h1
+       @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/spl_config.h.in $(top_builddir)/config.status
+       @rm -f stamp-h1
+       cd $(top_builddir) && $(SHELL) ./config.status spl_config.h
+$(srcdir)/spl_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+       ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+       rm -f stamp-h1
+       touch $@
+
+distclean-hdr:
+       -rm -f spl_config.h stamp-h1
+module/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/Makefile.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+module/spl/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/spl/Makefile.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+module/splat/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/splat/Makefile.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+spl.release: $(top_builddir)/config.status $(srcdir)/spl.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) spl_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@     fakeroot $(ALIEN) --bump=0 --scripts --to-deb $$pkg1; \
+@CONFIG_USER_TRUE@     $(RM) $$pkg1
+
+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@     fakeroot $(ALIEN) --scripts --to-tgz $$pkg1; \
+@CONFIG_USER_TRUE@     $(RM) $$pkg1
+
+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 'aclocal.m4' -o -size 0 \
+               -o -name '*%' -o -name '.*.cmd' -o -name 'core' \
+               -o -name 'Makefile' -o -name '$(LINUX_SYMBOLS)' \
+               -o -name '*.order' -o -name '*.markers' \) \
+               -type f -print | xargs $(RM)
+
+dist-hook:
+       sed -i 's/Release:[[:print:]]*/Release:      $(RELEASE)/' \
+               $(distdir)/META
+
+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/spl/aclocal.m4 b/spl/aclocal.m4
new file mode 100644 (file)
index 0000000..77267d9
--- /dev/null
@@ -0,0 +1,1195 @@
+# 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]))])
+
+# 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/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/spl-build.m4])
+m4_include([config/spl-meta.m4])
diff --git a/spl/autogen.sh b/spl/autogen.sh
new file mode 100755 (executable)
index 0000000..427394a
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+autoreconf -fiv
+rm -Rf autom4te.cache
diff --git a/spl/cmd/Makefile.am b/spl/cmd/Makefile.am
new file mode 100644 (file)
index 0000000..01afdcf
--- /dev/null
@@ -0,0 +1,11 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/lib
+
+sbin_PROGRAMS = splat
+
+splat_SOURCES = splat.c
+splat_LDFLAGS = $(top_builddir)/lib/libcommon.la
+
+EXTRA_DIST = splat.h
diff --git a/spl/cmd/Makefile.in b/spl/cmd/Makefile.in
new file mode 100644 (file)
index 0000000..681f095
--- /dev/null
@@ -0,0 +1,703 @@
+# 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-2010 Lawrence Livermore National Security, LLC.
+# Copyright (C) 2007 The Regents of the University of California.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Common rules for user space components.
+###############################################################################
+
+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@
+sbin_PROGRAMS = splat$(EXEEXT)
+subdir = cmd
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)"
+PROGRAMS = $(sbin_PROGRAMS)
+am_splat_OBJECTS = splat.$(OBJEXT)
+splat_OBJECTS = $(am_splat_OBJECTS)
+splat_LDADD = $(LDADD)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+splat_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(splat_LDFLAGS) $(LDFLAGS) -o $@
+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 = 
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(splat_SOURCES)
+DIST_SOURCES = $(splat_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)
+# 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 $(top_srcdir)/config/Rules.am \
+       $(top_srcdir)/config/depcomp
+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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+DEFAULT_INCLUDES = -include ${top_builddir}/spl_config.h \
+       -I$(top_srcdir)/lib
+AM_LIBTOOLFLAGS = --silent
+AM_CPPFLAGS = -D__USE_LARGEFILE64
+AM_CFLAGS = -Wall -Wshadow -Wstrict-prototypes -fno-strict-aliasing \
+       ${DEBUG_CFLAGS}
+splat_SOURCES = splat.c
+splat_LDFLAGS = $(top_builddir)/lib/libcommon.la
+EXTRA_DIST = splat.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/Rules.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 cmd/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu cmd/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_srcdir)/config/Rules.am $(am__empty):
+
+$(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-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+       fi; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p \
+        || test -f $$p1 \
+         ; then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' \
+           -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       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; \
+           else { print "f", $$3 "/" $$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_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+           } \
+       ; done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' \
+       `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+       @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+
+splat$(EXEEXT): $(splat_OBJECTS) $(splat_DEPENDENCIES) $(EXTRA_splat_DEPENDENCIES) 
+       @rm -f splat$(EXEEXT)
+       $(AM_V_CCLD)$(splat_LINK) $(splat_OBJECTS) $(splat_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splat.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+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 $(PROGRAMS)
+installdirs:
+       for dir in "$(DESTDIR)$(sbindir)"; 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 clean-sbinPROGRAMS \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+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-sbinPROGRAMS
+
+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 -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-sbinPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+       clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
+       distclean distclean-compile 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-sbinPROGRAMS install-strip \
+       installcheck installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS
+
+.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/spl/cmd/splat.c b/spl/cmd/splat.c
new file mode 100644 (file)
index 0000000..9296239
--- /dev/null
@@ -0,0 +1,836 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) User Space Interface.
+\*****************************************************************************/
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "splat.h"
+
+#undef ioctl
+
+static const char shortOpts[] = "hvlat:xc";
+static const struct option longOpts[] = {
+       { "help",            no_argument,       0, 'h' },
+       { "verbose",         no_argument,       0, 'v' },
+       { "list",            no_argument,       0, 'l' },
+       { "all",             no_argument,       0, 'a' },
+       { "test",            required_argument, 0, 't' },
+       { "exit",            no_argument,       0, 'x' },
+       { "nocolor",         no_argument,       0, 'c' },
+       { 0,                 0,                 0, 0   }
+};
+
+#define VERSION_SIZE   64
+
+static List subsystems;                                /* Subsystem/tests */
+static int splatctl_fd;                                /* Control file descriptor */
+static char splat_version[VERSION_SIZE];       /* Kernel version string */
+static char *splat_buffer = NULL;              /* Scratch space area */
+static int splat_buffer_size = 0;              /* Scratch space size */
+
+
+static void test_list(List, int);
+static int dev_clear(void);
+static void subsystem_fini(subsystem_t *);
+static void test_fini(test_t *);
+
+
+static int usage(void) {
+       fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n");
+       fprintf(stderr,
+       "  --help      -h               This help\n"
+       "  --verbose   -v               Increase verbosity\n"
+       "  --list      -l               List all tests in all subsystems\n"
+       "  --all       -a               Run all tests in all subsystems\n"
+       "  --test      -t <sub:test>    Run 'test' in subsystem 'sub'\n"
+       "  --exit      -x               Exit on first test error\n"
+       "  --nocolor   -c               Do not colorize output\n");
+       fprintf(stderr, "\n"
+       "Examples:\n"
+       "  splat -t kmem:all     # Runs all kmem tests\n"
+       "  splat -t taskq:0x201  # Run taskq test 0x201\n");
+
+       return 0;
+}
+
+static subsystem_t *subsystem_init(splat_user_t *desc)
+{
+       subsystem_t *sub;
+
+       sub = (subsystem_t *)malloc(sizeof(*sub));
+       if (sub == NULL)
+               return NULL;
+
+       memcpy(&sub->sub_desc, desc, sizeof(*desc));
+
+       sub->sub_tests = list_create((ListDelF)test_fini);
+       if (sub->sub_tests == NULL) {
+               free(sub);
+               return NULL;
+       }
+
+       return sub;
+}
+
+static void subsystem_fini(subsystem_t *sub)
+{
+       assert(sub != NULL);
+       free(sub);
+}
+
+static int subsystem_setup(void)
+{
+       splat_cfg_t *cfg;
+       int i, rc, size, cfg_size;
+       subsystem_t *sub;
+       splat_user_t *desc;
+
+       /* Aquire the number of registered subsystems */
+       cfg_size = sizeof(*cfg);
+       cfg = (splat_cfg_t *)malloc(cfg_size);
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, cfg_size);
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+        cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_COUNT;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n",
+                       (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       size = cfg->cfg_rc1;
+       free(cfg);
+
+       /* Based on the newly acquired number of subsystems allocate
+        * memory to get the descriptive information for them all. */
+       cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t);
+       cfg = (splat_cfg_t *)malloc(cfg_size);
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, cfg_size);
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+       cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_LIST;
+       cfg->cfg_data.splat_subsystems.size = size;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       /* Add the new subsystems in to the global list */
+       size = cfg->cfg_rc1;
+       for (i = 0; i < size; i++) {
+               desc = &(cfg->cfg_data.splat_subsystems.descs[i]);
+
+               sub = subsystem_init(desc);
+               if (sub == NULL) {
+                       fprintf(stderr, "Error initializing subsystem: %s\n",
+                               desc->name);
+                       free(cfg);
+                       return -ENOMEM;
+               }
+
+               list_append(subsystems, sub);
+       }
+
+       free(cfg);
+       return 0;
+}
+
+static void subsystem_list(List l, int indent)
+{
+       ListIterator i;
+       subsystem_t *sub;
+
+       fprintf(stdout,
+               "------------------------------ "
+               "Available SPLAT Tests "
+               "------------------------------\n");
+
+       i = list_iterator_create(l);
+
+       while ((sub = list_next(i))) {
+               fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n",
+                       indent, "",
+                       4, sub->sub_desc.id,
+                       SPLAT_NAME_SIZE + 7, sub->sub_desc.name,
+                       sub->sub_desc.desc);
+               test_list(sub->sub_tests, indent + 7);
+       }
+
+       list_iterator_destroy(i);
+}
+
+static test_t *test_init(subsystem_t *sub, splat_user_t *desc)
+{
+       test_t *test;
+
+       test = (test_t *)malloc(sizeof(*test));
+       if (test == NULL)
+               return NULL;
+
+       test->test_sub = sub;
+       memcpy(&test->test_desc, desc, sizeof(*desc));
+
+       return test;
+}
+
+static void test_fini(test_t *test)
+{
+       assert(test != NULL);
+       free(test);
+}
+
+static int test_setup(subsystem_t *sub)
+{
+       splat_cfg_t *cfg;
+       int i, rc, size;
+       test_t *test;
+       splat_user_t *desc;
+
+       /* Aquire the number of registered tests for the give subsystem */
+       cfg = (splat_cfg_t *)malloc(sizeof(*cfg));
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, sizeof(*cfg));
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+        cfg->cfg_cmd   = SPLAT_CFG_TEST_COUNT;
+       cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       size = cfg->cfg_rc1;
+       free(cfg);
+
+       /* Based on the newly aquired number of tests allocate enough
+        * memory to get the descriptive information for them all. */
+       cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t));
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, sizeof(*cfg) + size * sizeof(splat_user_t));
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+       cfg->cfg_cmd   = SPLAT_CFG_TEST_LIST;
+       cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
+       cfg->cfg_data.splat_tests.size = size;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       /* Add the new tests in to the relevant subsystems */
+       size = cfg->cfg_rc1;
+       for (i = 0; i < size; i++) {
+               desc = &(cfg->cfg_data.splat_tests.descs[i]);
+
+               test = test_init(sub, desc);
+               if (test == NULL) {
+                       fprintf(stderr, "Error initializing test: %s\n",
+                               desc->name);
+                       free(cfg);
+                       return -ENOMEM;
+               }
+
+               list_append(sub->sub_tests, test);
+       }
+
+       free(cfg);
+       return 0;
+}
+
+static test_t *test_copy(test_t *test)
+{
+       return test_init(test->test_sub, &test->test_desc);
+}
+
+static void test_list(List l, int indent)
+{
+       ListIterator i;
+       test_t *test;
+
+       i = list_iterator_create(l);
+
+       while ((test = list_next(i)))
+               fprintf(stdout, "%*s0x%0*x %-*s %s\n",
+                       indent, "", 04, test->test_desc.id,
+                       SPLAT_NAME_SIZE, test->test_desc.name,
+                       test->test_desc.desc);
+
+       list_iterator_destroy(i);
+}
+
+static test_t *test_find(char *sub_str, char *test_str)
+{
+       ListIterator si, ti;
+       subsystem_t *sub;
+       test_t *test;
+       __u32 sub_num, test_num;
+
+       /*
+        * No error checking here because it may not be a number, it's
+        * perfectly OK for it to be a string.  Since we're just using
+        * it for comparison purposes this is all very safe.
+        */
+       sub_num = strtoul(sub_str, NULL, 0);
+       test_num = strtoul(test_str, NULL, 0);
+
+        si = list_iterator_create(subsystems);
+
+        while ((sub = list_next(si))) {
+
+               if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) &&
+                   sub->sub_desc.id != sub_num)
+                       continue;
+
+               ti = list_iterator_create(sub->sub_tests);
+
+               while ((test = list_next(ti))) {
+
+                       if (!strncmp(test->test_desc.name, test_str,
+                           SPLAT_NAME_SIZE) || test->test_desc.id==test_num) {
+                               list_iterator_destroy(ti);
+                               list_iterator_destroy(si);
+                               return test;
+                       }
+               }
+
+               list_iterator_destroy(ti);
+        }
+
+        list_iterator_destroy(si);
+
+       return NULL;
+}
+
+static int test_add(cmd_args_t *args, test_t *test)
+{
+       test_t *tmp;
+
+       tmp = test_copy(test);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       list_append(args->args_tests, tmp);
+       return 0;
+}
+
+static int test_add_all(cmd_args_t *args)
+{
+       ListIterator si, ti;
+       subsystem_t *sub;
+       test_t *test;
+       int rc;
+
+        si = list_iterator_create(subsystems);
+
+        while ((sub = list_next(si))) {
+               ti = list_iterator_create(sub->sub_tests);
+
+               while ((test = list_next(ti))) {
+                       if ((rc = test_add(args, test))) {
+                               list_iterator_destroy(ti);
+                               list_iterator_destroy(si);
+                               return rc;
+                       }
+               }
+
+               list_iterator_destroy(ti);
+        }
+
+        list_iterator_destroy(si);
+
+       return 0;
+}
+
+static int test_run(cmd_args_t *args, test_t *test)
+{
+       subsystem_t *sub = test->test_sub;
+       splat_cmd_t *cmd;
+       int rc, cmd_size;
+
+       dev_clear();
+
+       cmd_size = sizeof(*cmd);
+       cmd = (splat_cmd_t *)malloc(cmd_size);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       memset(cmd, 0, cmd_size);
+       cmd->cmd_magic = SPLAT_CMD_MAGIC;
+        cmd->cmd_subsystem = sub->sub_desc.id;
+       cmd->cmd_test = test->test_desc.id;
+       cmd->cmd_data_size = 0; /* Unused feature */
+
+       fprintf(stdout, "%*s:%-*s ",
+               SPLAT_NAME_SIZE, sub->sub_desc.name,
+               SPLAT_NAME_SIZE, test->test_desc.name);
+       fflush(stdout);
+       rc = ioctl(splatctl_fd, SPLAT_CMD, cmd);
+       if (args->args_do_color) {
+               fprintf(stdout, "%s  %s\n", rc ?
+                       COLOR_RED "Fail" COLOR_RESET :
+                       COLOR_GREEN "Pass" COLOR_RESET,
+                       rc ? strerror(errno) : "");
+       } else {
+               fprintf(stdout, "%s  %s\n", rc ?
+                       "Fail" : "Pass",
+                       rc ? strerror(errno) : "");
+       }
+       fflush(stdout);
+       free(cmd);
+
+       if ((args->args_verbose == 1 && rc) ||
+           (args->args_verbose >= 2)) {
+               if ((rc = read(splatctl_fd, splat_buffer,
+                              splat_buffer_size - 1)) < 0) {
+                       fprintf(stdout, "Error reading results: %d\n", rc);
+               } else {
+                       fprintf(stdout, "\n%s\n", splat_buffer);
+                       fflush(stdout);
+               }
+       }
+
+       return rc;
+}
+
+static int tests_run(cmd_args_t *args)
+{
+        ListIterator i;
+       test_t *test;
+       int rc;
+
+       fprintf(stdout,
+               "------------------------------ "
+               "Running SPLAT Tests "
+               "------------------------------\n");
+
+       i = list_iterator_create(args->args_tests);
+
+       while ((test = list_next(i))) {
+               rc = test_run(args, test);
+               if (rc && args->args_exit_on_error) {
+                       list_iterator_destroy(i);
+                       return rc;
+               }
+       }
+
+       list_iterator_destroy(i);
+       return 0;
+}
+
+static int args_parse_test(cmd_args_t *args, char *str)
+{
+        ListIterator si, ti;
+       subsystem_t *s;
+       test_t *t;
+       char *sub_str, *test_str;
+       int sub_num, test_num;
+       int sub_all = 0, test_all = 0;
+       int rc, flag = 0;
+
+       test_str = strchr(str, ':');
+       if (test_str == NULL) {
+               fprintf(stderr, "Test must be of the "
+                       "form <subsystem:test>\n");
+               return -EINVAL;
+       }
+
+       sub_str = str;
+       test_str[0] = '\0';
+       test_str = test_str + 1;
+
+       sub_num = strtol(sub_str, NULL, 0);
+       test_num = strtol(test_str, NULL, 0);
+
+       if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1))
+               sub_all = 1;
+
+       if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
+               test_all = 1;
+
+       si = list_iterator_create(subsystems);
+
+       if (sub_all) {
+               if (test_all) {
+                       /* Add all tests from all subsystems */
+                       while ((s = list_next(si))) {
+                               ti = list_iterator_create(s->sub_tests);
+                               while ((t = list_next(ti))) {
+                                       if ((rc = test_add(args, t))) {
+                                               list_iterator_destroy(ti);
+                                               goto error_run;
+                                       }
+                               }
+                               list_iterator_destroy(ti);
+                       }
+               } else {
+                       /* Add a specific test from all subsystems */
+                       while ((s = list_next(si))) {
+                               if ((t=test_find(s->sub_desc.name,test_str))) {
+                                       if ((rc = test_add(args, t)))
+                                               goto error_run;
+
+                                       flag = 1;
+                               }
+                       }
+
+                       if (!flag)
+                               fprintf(stderr, "No tests '%s:%s' could be "
+                                       "found\n", sub_str, test_str);
+               }
+       } else {
+               if (test_all) {
+                       /* Add all tests from a specific subsystem */
+                       while ((s = list_next(si))) {
+                               if (strncasecmp(sub_str, s->sub_desc.name,
+                                   strlen(sub_str)))
+                                       continue;
+
+                               ti = list_iterator_create(s->sub_tests);
+                               while ((t = list_next(ti))) {
+                                       if ((rc = test_add(args, t))) {
+                                               list_iterator_destroy(ti);
+                                               goto error_run;
+                                       }
+                               }
+                               list_iterator_destroy(ti);
+                       }
+               } else {
+                       /* Add a specific test from a specific subsystem */
+                       if ((t = test_find(sub_str, test_str))) {
+                               if ((rc = test_add(args, t)))
+                                       goto error_run;
+                       } else {
+                               fprintf(stderr, "Test '%s:%s' could not be "
+                                       "found\n", sub_str, test_str);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       list_iterator_destroy(si);
+
+       return 0;
+
+error_run:
+       list_iterator_destroy(si);
+
+       fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
+               sub_str, test_str, rc);
+
+       return rc;
+}
+
+static void args_fini(cmd_args_t *args)
+{
+       assert(args != NULL);
+
+       if (args->args_tests != NULL)
+               list_destroy(args->args_tests);
+
+       free(args);
+}
+
+static cmd_args_t *
+args_init(int argc, char **argv)
+{
+       cmd_args_t *args;
+       int c, rc;
+
+       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));
+       args->args_verbose = 0;
+       args->args_do_list = 0;
+       args->args_do_all  = 0;
+       args->args_do_color = 1;
+       args->args_exit_on_error = 0;
+       args->args_tests = list_create((ListDelF)test_fini);
+       if (args->args_tests == NULL) {
+               args_fini(args);
+               return NULL;
+       }
+
+       while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){
+               switch (c) {
+               case 'v':  args->args_verbose++;                        break;
+               case 'l':  args->args_do_list = 1;                      break;
+               case 'a':  args->args_do_all = 1;                       break;
+               case 'c':  args->args_do_color = 0;                     break;
+               case 'x':  args->args_exit_on_error = 1;                break;
+               case 't':
+                       if (args->args_do_all) {
+                               fprintf(stderr, "Option -t <subsystem:test> is "
+                                       "useless when used with -a\n");
+                               args_fini(args);
+                               return NULL;
+                       }
+
+                       rc = args_parse_test(args, argv[optind - 1]);
+                       if (rc) {
+                               args_fini(args);
+                               return NULL;
+                       }
+                       break;
+               case 'h':
+               case '?':
+                       usage();
+                       args_fini(args);
+                       return NULL;
+               default:
+                       fprintf(stderr, "Unknown option '%s'\n",
+                               argv[optind - 1]);
+                       break;
+               }
+       }
+
+       return args;
+}
+
+static int
+dev_clear(void)
+{
+       splat_cfg_t cfg;
+       int rc;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.cfg_magic = SPLAT_CFG_MAGIC;
+        cfg.cfg_cmd   = SPLAT_CFG_BUFFER_CLEAR;
+       cfg.cfg_arg1  = 0;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
+       if (rc)
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
+
+       lseek(splatctl_fd, 0, SEEK_SET);
+
+       return rc;
+}
+
+static int
+dev_size(int size)
+{
+       splat_cfg_t cfg;
+       int rc;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.cfg_magic = SPLAT_CFG_MAGIC;
+        cfg.cfg_cmd   = SPLAT_CFG_BUFFER_SIZE;
+       cfg.cfg_arg1  = size;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
+               return rc;
+       }
+
+       return cfg.cfg_rc1;
+}
+
+static void
+dev_fini(void)
+{
+       if (splat_buffer)
+               free(splat_buffer);
+
+       if (splatctl_fd != -1) {
+               if (close(splatctl_fd) == -1) {
+                       fprintf(stderr, "Unable to close %s: %d\n",
+                               SPLAT_DEV, errno);
+               }
+       }
+}
+
+static int
+dev_init(void)
+{
+       ListIterator i;
+       subsystem_t *sub;
+       int rc;
+
+       splatctl_fd = open(SPLAT_DEV, O_RDONLY);
+       if (splatctl_fd == -1) {
+               fprintf(stderr, "Unable to open %s: %d\n"
+                       "Is the splat module loaded?\n", SPLAT_DEV, errno);
+               rc = errno;
+               goto error;
+       }
+
+       /* Determine kernel module version string */
+       memset(splat_version, 0, VERSION_SIZE);
+       if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
+               goto error;
+
+       if ((rc = dev_clear()))
+               goto error;
+
+       if ((rc = dev_size(0)) < 0)
+               goto error;
+
+       splat_buffer_size = rc;
+       splat_buffer = (char *)malloc(splat_buffer_size);
+       if (splat_buffer == NULL) {
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       memset(splat_buffer, 0, splat_buffer_size);
+
+       /* Determine available subsystems */
+       if ((rc = subsystem_setup()) != 0)
+               goto error;
+
+       /* Determine available tests for all subsystems */
+       i = list_iterator_create(subsystems);
+
+       while ((sub = list_next(i))) {
+               if ((rc = test_setup(sub)) != 0) {
+                       list_iterator_destroy(i);
+                       goto error;
+               }
+       }
+
+       list_iterator_destroy(i);
+       return 0;
+
+error:
+       if (splatctl_fd != -1) {
+               if (close(splatctl_fd) == -1) {
+                       fprintf(stderr, "Unable to close %s: %d\n",
+                               SPLAT_DEV, errno);
+               }
+       }
+
+       return rc;
+}
+
+int
+init(void)
+{
+       int rc = 0;
+
+       /* Allocate the subsystem list */
+       subsystems = list_create((ListDelF)subsystem_fini);
+       if (subsystems == NULL)
+               rc = ENOMEM;
+
+       return rc;
+}
+
+void
+fini(void)
+{
+       list_destroy(subsystems);
+}
+
+
+int
+main(int argc, char **argv)
+{
+       cmd_args_t *args = NULL;
+       int rc = 0;
+
+       /* General init */
+       if ((rc = init()))
+               return rc;
+
+       /* Device specific init */
+       if ((rc = dev_init()))
+               goto out;
+
+       /* Argument init and parsing */
+       if ((args = args_init(argc, argv)) == NULL) {
+               rc = -1;
+               goto out;
+       }
+
+       /* Generic kernel version string */
+       if (args->args_verbose)
+               fprintf(stdout, "%s", splat_version);
+
+       /* Print the available test list and exit */
+       if (args->args_do_list) {
+               subsystem_list(subsystems, 0);
+               goto out;
+       }
+
+       /* Add all available test to the list of tests to run */
+       if (args->args_do_all) {
+               if ((rc = test_add_all(args)))
+                       goto out;
+       }
+
+       /* Run all the requested tests */
+       if ((rc = tests_run(args)))
+               goto out;
+
+out:
+       if (args != NULL)
+               args_fini(args);
+
+       dev_fini();
+       fini();
+       return rc;
+}
diff --git a/spl/cmd/splat.h b/spl/cmd/splat.h
new file mode 100644 (file)
index 0000000..5b838af
--- /dev/null
@@ -0,0 +1,70 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPLAT_H
+#define _SPLAT_H
+
+#include "list.h"
+#include "../include/splat-ctl.h"
+
+#define DEV_NAME                       "/dev/splatctl"
+#define COLOR_BLACK                    "\033[0;30m"
+#define COLOR_DK_GRAY                  "\033[1;30m"
+#define COLOR_BLUE                     "\033[0;34m"
+#define COLOR_LT_BLUE                  "\033[1;34m"
+#define COLOR_GREEN                    "\033[0;32m"
+#define COLOR_LT_GREEN                 "\033[1;32m"
+#define COLOR_CYAN                     "\033[0;36m"
+#define COLOR_LT_CYAN                  "\033[1;36m"
+#define COLOR_RED                      "\033[0;31m"
+#define COLOR_LT_RED                   "\033[1;31m"
+#define COLOR_PURPLE                   "\033[0;35m"
+#define COLOR_LT_PURPLE                        "\033[1;35m"
+#define COLOR_BROWN                    "\033[0;33m"
+#define COLOR_YELLOW                   "\033[1;33m"
+#define COLOR_LT_GRAY                  "\033[0;37m"
+#define COLOR_WHITE                    "\033[1;37m"
+#define COLOR_RESET                    "\033[0m"
+
+typedef struct subsystem {
+       splat_user_t sub_desc;          /* Subsystem description */
+       List sub_tests;                 /* Assocated subsystem tests list */
+} subsystem_t;
+
+typedef struct test {
+       splat_user_t test_desc;         /* Test description */
+       subsystem_t *test_sub;          /* Parent subsystem */
+} test_t;
+
+typedef struct cmd_args {
+       int args_verbose;               /* Verbose flag */
+       int args_do_list;               /* Display all tests flag */
+       int args_do_all;                /* Run all tests flag */
+       int args_do_color;              /* Colorize output */
+       int args_exit_on_error;         /* Exit on first error flag */
+       List args_tests;                /* Requested subsystems/tests */
+} cmd_args_t;
+
+#endif /* _SPLAT_H */
+
diff --git a/spl/config/Rules.am b/spl/config/Rules.am
new file mode 100644 (file)
index 0000000..7c5d328
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+# Copyright (C) 2007 The Regents of the University of California.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Common rules for user space components.
+###############################################################################
+
+DEFAULT_INCLUDES = -include ${top_builddir}/spl_config.h
+
+AM_LIBTOOLFLAGS = --silent
+AM_CPPFLAGS = -D__USE_LARGEFILE64
+AM_CFLAGS  = -Wall -Wshadow -Wstrict-prototypes -fno-strict-aliasing
+AM_CFLAGS += ${DEBUG_CFLAGS}
diff --git a/spl/config/compile b/spl/config/compile
new file mode 100755 (executable)
index 0000000..a85b723
--- /dev/null
@@ -0,0 +1,347 @@
+#! /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/spl/config/config.awk b/spl/config/config.awk
new file mode 100644 (file)
index 0000000..cc4b7cc
--- /dev/null
@@ -0,0 +1,15 @@
+# Remove default preprocessor define's from config.h
+#   PACKAGE
+#   PACKAGE_BUGREPORT
+#   PACKAGE_NAME
+#   PACKAGE_STRING
+#   PACKAGE_TARNAME
+#   PACKAGE_VERSION
+#   STDC_HEADERS
+#   VERSION
+
+BEGIN { RS = "" ; FS = "\n" }     \
+       !/.#define PACKAGE./ &&   \
+       !/.#define VERSION./ &&   \
+       !/.#define STDC_HEADERS./ \
+       { print $0"\n" }
diff --git a/spl/config/config.guess b/spl/config/config.guess
new file mode 100755 (executable)
index 0000000..2e9ad7f
--- /dev/null
@@ -0,0 +1,1462 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-10-02'
+
+# 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
+#
+# 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-2016 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) and ABI.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               os=netbsdelf
+               ;;
+           arm*|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 ;;
+    *:LibertyBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${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 "[:upper:]" "[:lower:]"``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 ;;
+    k1om: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; }
+       ;;
+    mips64el:Linux:*:*)
+       echo ${UNAME_MACHINE}-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 ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+       echo ${UNAME_MACHINE}-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 configure 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 ;;
+    SX-ACE:SUPER-UX:*:*)
+       echo sxace-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 ;;
+    amd64:Isilon\ OneFS:*:*)
+       echo x86_64-unknown-onefs
+       exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary 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/spl/config/config.sub b/spl/config/config.sub
new file mode 100755 (executable)
index 0000000..dd2ca93
--- /dev/null
@@ -0,0 +1,1825 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-11-04'
+
+# 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
+
+# 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 or 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-2016 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* | cloudabi*-eabi* | \
+  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 \
+       | pru \
+       | 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-* \
+       | pru-* \
+       | 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
+               ;;
+       e500v[12])
+               basic_machine=powerpc-unknown
+               os=$os"spe"
+               ;;
+       e500v[12]-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=$os"spe"
+               ;;
+       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)
+               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)
+               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* | -libertybsd* \
+             | -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* \
+             | -midipix* | -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* \
+             | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
+       # 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*)
+               ;;
+       -ios)
+               ;;
+       -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/spl/config/deb.am b/spl/config/deb.am
new file mode 100644 (file)
index 0000000..a2bad02
--- /dev/null
@@ -0,0 +1,51 @@
+###############################################################################
+# Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Build targets for DEB packages.
+#
+# Long term native distro specific Debian style packaging should be added.
+# In the short term RPM packages are built and converted to DEB packages
+# using alien.  If someone familiar with Debian style packaging were to
+# update the build system to correctly build Debian style packages I would
+# happily take it.  Until then we will have to make due with alien.
+#
+###############################################################################
+
+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
+if CONFIG_KERNEL
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --bump=0 --scripts --to-deb $$pkg1; \
+       $(RM) $$pkg1
+endif
+
+deb-utils: deb-local rpm-utils
+if CONFIG_USER
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=$${name}-$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --bump=0 --scripts --to-deb $$pkg1; \
+       $(RM) $$pkg1
+endif
+
+deb: deb-kmod deb-utils
diff --git a/spl/config/depcomp b/spl/config/depcomp
new file mode 100755 (executable)
index 0000000..fc98710
--- /dev/null
@@ -0,0 +1,791 @@
+#! /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/spl/config/install-sh b/spl/config/install-sh
new file mode 100755 (executable)
index 0000000..59990a1
--- /dev/null
@@ -0,0 +1,508 @@
+#!/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:
diff --git a/spl/config/libtool.m4 b/spl/config/libtool.m4
new file mode 100644 (file)
index 0000000..ee80844
--- /dev/null
@@ -0,0 +1,8387 @@
+# 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/spl/config/ltmain.sh b/spl/config/ltmain.sh
new file mode 100644 (file)
index 0000000..a736cf9
--- /dev/null
@@ -0,0 +1,11156 @@
+#! /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-2"
+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'
+
+
+# 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 Debian-2.4.6-2
+       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/spl/config/ltoptions.m4 b/spl/config/ltoptions.m4
new file mode 100644 (file)
index 0000000..94b0829
--- /dev/null
@@ -0,0 +1,437 @@
+# 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/spl/config/ltsugar.m4 b/spl/config/ltsugar.m4
new file mode 100644 (file)
index 0000000..48bc934
--- /dev/null
@@ -0,0 +1,124 @@
+# 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/spl/config/ltversion.m4 b/spl/config/ltversion.m4
new file mode 100644 (file)
index 0000000..fa04b52
--- /dev/null
@@ -0,0 +1,23 @@
+# 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/spl/config/lt~obsolete.m4 b/spl/config/lt~obsolete.m4
new file mode 100644 (file)
index 0000000..c6b26f8
--- /dev/null
@@ -0,0 +1,99 @@
+# 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/spl/config/missing b/spl/config/missing
new file mode 100755 (executable)
index 0000000..f62bbae
--- /dev/null
@@ -0,0 +1,215 @@
+#! /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/spl/config/rpm.am b/spl/config/rpm.am
new file mode 100644 (file)
index 0000000..51a20b3
--- /dev/null
@@ -0,0 +1,87 @@
+###############################################################################
+# 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.
+###############################################################################
+
+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)
diff --git a/spl/config/spl-build.m4 b/spl/config/spl-build.m4
new file mode 100644 (file)
index 0000000..5a2f1de
--- /dev/null
@@ -0,0 +1,1599 @@
+###############################################################################
+# Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+# Copyright (C) 2007 The Regents of the University of California.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# SPL_AC_CONFIG_KERNEL: Default SPL kernel configuration.
+###############################################################################
+
+AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
+       SPL_AC_KERNEL
+
+       if test "${LINUX_OBJ}" != "${LINUX}"; then
+               KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
+       fi
+       AC_SUBST(KERNELMAKE_PARAMS)
+
+       KERNELCPPFLAGS="$KERNELCPPFLAGS -Wstrict-prototypes"
+       AC_SUBST(KERNELCPPFLAGS)
+
+       SPL_AC_DEBUG
+       SPL_AC_DEBUG_KMEM
+       SPL_AC_DEBUG_KMEM_TRACKING
+       SPL_AC_TEST_MODULE
+       SPL_AC_ATOMIC_SPINLOCK
+       SPL_AC_SHRINKER_CALLBACK
+       SPL_AC_CTL_NAME
+       SPL_AC_CONFIG_TRIM_UNUSED_KSYMS
+       SPL_AC_PDE_DATA
+       SPL_AC_SET_FS_PWD_WITH_CONST
+       SPL_AC_2ARGS_VFS_UNLINK
+       SPL_AC_4ARGS_VFS_RENAME
+       SPL_AC_2ARGS_VFS_FSYNC
+       SPL_AC_INODE_TRUNCATE_RANGE
+       SPL_AC_FS_STRUCT_SPINLOCK
+       SPL_AC_KUIDGID_T
+       SPL_AC_PUT_TASK_STRUCT
+       SPL_AC_KERNEL_FALLOCATE
+       SPL_AC_CONFIG_ZLIB_INFLATE
+       SPL_AC_CONFIG_ZLIB_DEFLATE
+       SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
+       SPL_AC_SHRINK_CONTROL_STRUCT
+       SPL_AC_RWSEM_SPINLOCK_IS_RAW
+       SPL_AC_RWSEM_ACTIVITY
+       SPL_AC_RWSEM_ATOMIC_LONG_COUNT
+       SPL_AC_SCHED_RT_HEADER
+       SPL_AC_2ARGS_VFS_GETATTR
+       SPL_AC_USLEEP_RANGE
+       SPL_AC_KMEM_CACHE_ALLOCFLAGS
+       SPL_AC_WAIT_ON_BIT
+       SPL_AC_INODE_LOCK
+       SPL_AC_MUTEX_OWNER
+       SPL_AC_GROUP_INFO_GID
+])
+
+AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
+       modpost=$LINUX/scripts/Makefile.modpost
+       AC_MSG_CHECKING([kernel file name for module symbols])
+       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
+                       AC_MSG_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.])
+               fi
+       else
+               LINUX_SYMBOLS=NONE
+       fi
+       AC_MSG_RESULT($LINUX_SYMBOLS)
+       AC_SUBST(LINUX_SYMBOLS)
+])
+
+AC_DEFUN([SPL_AC_KERNEL], [
+       AC_ARG_WITH([linux],
+               AS_HELP_STRING([--with-linux=PATH],
+               [Path to kernel source]),
+               [kernelsrc="$withval"])
+
+       AC_ARG_WITH([linux-obj],
+               AS_HELP_STRING([--with-linux-obj=PATH],
+               [Path to kernel build objects]),
+               [kernelbuild="$withval"])
+
+       AC_MSG_CHECKING([kernel source directory])
+       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
+
+       AC_MSG_RESULT([$kernelsrc])
+       if test ! -d "$kernelsrc"; then
+               AC_MSG_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.])
+       fi
+
+       AC_MSG_CHECKING([kernel build directory])
+       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
+       AC_MSG_RESULT([$kernelbuild])
+
+       AC_MSG_CHECKING([kernel source version])
+       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
+                       AC_MSG_RESULT([Not found])
+                       AC_MSG_ERROR([*** Cannot determine kernel version.])
+               fi
+       else
+               AC_MSG_RESULT([Not found])
+               if test "x$enable_linux_builtin" != xyes; then
+                       AC_MSG_ERROR([*** Cannot find UTS_RELEASE definition.])
+               else
+                       AC_MSG_ERROR([
+       *** Cannot find UTS_RELEASE definition.
+       *** Please run 'make prepare' inside the kernel source tree.])
+               fi
+       fi
+
+       AC_MSG_RESULT([$kernsrcver])
+
+       LINUX=${kernelsrc}
+       LINUX_OBJ=${kernelbuild}
+       LINUX_VERSION=${kernsrcver}
+
+       AC_SUBST(LINUX)
+       AC_SUBST(LINUX_OBJ)
+       AC_SUBST(LINUX_VERSION)
+
+       SPL_AC_MODULE_SYMVERS
+])
+
+dnl #
+dnl # Default SPL user configuration
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_USER], [])
+
+dnl #
+dnl # Check for rpm+rpmbuild to build RPM packages.  If these tools
+dnl # are missing, it is non-fatal, but you will not be able to build
+dnl # RPM packages and will be warned if you try too.
+dnl #
+dnl # By default, the generic spec file will be used because it requires
+dnl # minimal dependencies.  Distribution specific spec files can be
+dnl # placed under the 'rpm/<distribution>' directory and enabled using
+dnl # the --with-spec=<distribution> configure option.
+dnl #
+AC_DEFUN([SPL_AC_RPM], [
+       RPM=rpm
+       RPMBUILD=rpmbuild
+
+       AC_MSG_CHECKING([whether $RPM is available])
+       AS_IF([tmp=$($RPM --version 2>/dev/null)], [
+               RPM_VERSION=$(echo $tmp | $AWK '/RPM/ { print $[3] }')
+               HAVE_RPM=yes
+               AC_MSG_RESULT([$HAVE_RPM ($RPM_VERSION)])
+       ],[
+               HAVE_RPM=no
+               AC_MSG_RESULT([$HAVE_RPM])
+       ])
+
+       AC_MSG_CHECKING([whether $RPMBUILD is available])
+       AS_IF([tmp=$($RPMBUILD --version 2>/dev/null)], [
+               RPMBUILD_VERSION=$(echo $tmp | $AWK '/RPM/ { print $[3] }')
+               HAVE_RPMBUILD=yes
+               AC_MSG_RESULT([$HAVE_RPMBUILD ($RPMBUILD_VERSION)])
+       ],[
+               HAVE_RPMBUILD=no
+               AC_MSG_RESULT([$HAVE_RPMBUILD])
+       ])
+
+       RPM_DEFINE_COMMON='--define "$(DEBUG_SPL) 1" --define "$(DEBUG_KMEM) 1" --define "$(DEBUG_KMEM_TRACKING) 1"'
+       RPM_DEFINE_UTIL=
+       RPM_DEFINE_KMOD='--define "kernels $(LINUX_VERSION)"'
+       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"
+       AC_ARG_WITH([spec],
+               AS_HELP_STRING([--with-spec=SPEC],
+               [Spec files 'generic|redhat']),
+               [RPM_SPEC_DIR="rpm/$withval"])
+
+       AC_MSG_CHECKING([whether spec files are available])
+       AC_MSG_RESULT([yes ($RPM_SPEC_DIR/*.spec.in)])
+
+       AC_SUBST(HAVE_RPM)
+       AC_SUBST(RPM)
+       AC_SUBST(RPM_VERSION)
+
+       AC_SUBST(HAVE_RPMBUILD)
+       AC_SUBST(RPMBUILD)
+       AC_SUBST(RPMBUILD_VERSION)
+
+       AC_SUBST(RPM_SPEC_DIR)
+       AC_SUBST(RPM_DEFINE_UTIL)
+       AC_SUBST(RPM_DEFINE_KMOD)
+       AC_SUBST(RPM_DEFINE_DKMS)
+       AC_SUBST(RPM_DEFINE_COMMON)
+       AC_SUBST(SRPM_DEFINE_UTIL)
+       AC_SUBST(SRPM_DEFINE_KMOD)
+       AC_SUBST(SRPM_DEFINE_DKMS)
+       AC_SUBST(SRPM_DEFINE_COMMON)
+])
+
+dnl #
+dnl # Check for dpkg+dpkg-buildpackage to build DEB packages.  If these
+dnl # tools are missing it is non-fatal but you will not be able to build
+dnl # DEB packages and will be warned if you try too.
+dnl #
+AC_DEFUN([SPL_AC_DPKG], [
+       DPKG=dpkg
+       DPKGBUILD=dpkg-buildpackage
+
+       AC_MSG_CHECKING([whether $DPKG is available])
+       AS_IF([tmp=$($DPKG --version 2>/dev/null)], [
+               DPKG_VERSION=$(echo $tmp | $AWK '/Debian/ { print $[7] }')
+               HAVE_DPKG=yes
+               AC_MSG_RESULT([$HAVE_DPKG ($DPKG_VERSION)])
+       ],[
+               HAVE_DPKG=no
+               AC_MSG_RESULT([$HAVE_DPKG])
+       ])
+
+       AC_MSG_CHECKING([whether $DPKGBUILD is available])
+       AS_IF([tmp=$($DPKGBUILD --version 2>/dev/null)], [
+               DPKGBUILD_VERSION=$(echo $tmp | \
+                   $AWK '/Debian/ { print $[4] }' | cut -f-4 -d'.')
+               HAVE_DPKGBUILD=yes
+               AC_MSG_RESULT([$HAVE_DPKGBUILD ($DPKGBUILD_VERSION)])
+       ],[
+               HAVE_DPKGBUILD=no
+               AC_MSG_RESULT([$HAVE_DPKGBUILD])
+       ])
+
+       AC_SUBST(HAVE_DPKG)
+       AC_SUBST(DPKG)
+       AC_SUBST(DPKG_VERSION)
+
+       AC_SUBST(HAVE_DPKGBUILD)
+       AC_SUBST(DPKGBUILD)
+       AC_SUBST(DPKGBUILD_VERSION)
+])
+
+dnl #
+dnl # Until native packaging for various different packing systems
+dnl # can be added the least we can do is attempt to use alien to
+dnl # convert the RPM packages to the needed package type.  This is
+dnl # a hack but so far it has worked reasonable well.
+dnl #
+AC_DEFUN([SPL_AC_ALIEN], [
+       ALIEN=alien
+
+       AC_MSG_CHECKING([whether $ALIEN is available])
+       AS_IF([tmp=$($ALIEN --version 2>/dev/null)], [
+               ALIEN_VERSION=$(echo $tmp | $AWK '{ print $[3] }')
+               HAVE_ALIEN=yes
+               AC_MSG_RESULT([$HAVE_ALIEN ($ALIEN_VERSION)])
+       ],[
+               HAVE_ALIEN=no
+               AC_MSG_RESULT([$HAVE_ALIEN])
+       ])
+
+       AC_SUBST(HAVE_ALIEN)
+       AC_SUBST(ALIEN)
+       AC_SUBST(ALIEN_VERSION)
+])
+
+dnl #
+dnl # Using the VENDOR tag from config.guess set the default
+dnl # package type for 'make pkg': (rpm | deb | tgz)
+dnl #
+AC_DEFUN([SPL_AC_DEFAULT_PACKAGE], [
+       AC_MSG_CHECKING([linux distribution])
+       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
+       AC_MSG_RESULT([$VENDOR])
+       AC_SUBST(VENDOR)
+
+       AC_MSG_CHECKING([default package type])
+       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
+
+       AC_MSG_RESULT([$DEFAULT_PACKAGE])
+       AC_SUBST(DEFAULT_PACKAGE)
+])
+
+dnl #
+dnl # Default SPL user configuration
+dnl #
+AC_DEFUN([SPL_AC_PACKAGE], [
+       SPL_AC_DEFAULT_PACKAGE
+       SPL_AC_RPM
+       SPL_AC_DPKG
+       SPL_AC_ALIEN
+])
+
+AC_DEFUN([SPL_AC_LICENSE], [
+       AC_MSG_CHECKING([spl author])
+       AC_MSG_RESULT([$SPL_META_AUTHOR])
+
+       AC_MSG_CHECKING([spl license])
+       AC_MSG_RESULT([$SPL_META_LICENSE])
+])
+
+AC_DEFUN([SPL_AC_CONFIG], [
+       SPL_CONFIG=all
+       AC_ARG_WITH([config],
+               AS_HELP_STRING([--with-config=CONFIG],
+               [Config file 'kernel|user|all|srpm']),
+               [SPL_CONFIG="$withval"])
+       AC_ARG_ENABLE([linux-builtin],
+               [AC_HELP_STRING([--enable-linux-builtin],
+               [Configure for builtin in-tree kernel modules @<:@default=no@:>@])],
+               [],
+               [enable_linux_builtin=no])
+
+       AC_MSG_CHECKING([spl config])
+       AC_MSG_RESULT([$SPL_CONFIG]);
+       AC_SUBST(SPL_CONFIG)
+
+       case "$SPL_CONFIG" in
+               kernel) SPL_AC_CONFIG_KERNEL ;;
+               user)   SPL_AC_CONFIG_USER   ;;
+               all)    SPL_AC_CONFIG_KERNEL
+                       SPL_AC_CONFIG_USER   ;;
+               srpm)                        ;;
+               *)
+               AC_MSG_RESULT([Error!])
+               AC_MSG_ERROR([Bad value "$SPL_CONFIG" for --with-config,
+                            user kernel|user|all|srpm]) ;;
+       esac
+
+       AM_CONDITIONAL([CONFIG_USER],
+                      [test "$SPL_CONFIG" = user -o "$SPL_CONFIG" = all])
+       AM_CONDITIONAL([CONFIG_KERNEL],
+                      [test "$SPL_CONFIG" = kernel -o "$SPL_CONFIG" = all] &&
+                      [test "x$enable_linux_builtin" != xyes ])
+])
+
+dnl #
+dnl # Enable if the SPL should be compiled with internal debugging enabled.
+dnl # By default this support is disabled.
+dnl #
+AC_DEFUN([SPL_AC_DEBUG], [
+       AC_MSG_CHECKING([whether debugging is enabled])
+       AC_ARG_ENABLE([debug],
+               [AS_HELP_STRING([--enable-debug],
+               [Enable generic debug support @<:@default=no@:>@])],
+               [],
+               [enable_debug=no])
+
+       AS_IF([test "x$enable_debug" = xyes],
+       [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG -Werror"
+               DEBUG_CFLAGS="-DDEBUG -Werror"
+               DEBUG_SPL="_with_debug"
+       ], [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DNDEBUG"
+               DEBUG_CFLAGS="-DNDEBUG"
+               DEBUG_SPL="_without_debug"
+       ])
+
+       AC_SUBST(DEBUG_CFLAGS)
+       AC_SUBST(DEBUG_SPL)
+       AC_MSG_RESULT([$enable_debug])
+])
+
+dnl #
+dnl # Enabled by default it provides a minimal level of memory tracking.
+dnl # A total count of bytes allocated is kept for each alloc and free.
+dnl # Then at module unload time a report to the console will be printed
+dnl # if memory was leaked.
+dnl #
+AC_DEFUN([SPL_AC_DEBUG_KMEM], [
+       AC_ARG_ENABLE([debug-kmem],
+               [AS_HELP_STRING([--enable-debug-kmem],
+               [Enable basic kmem accounting @<:@default=no@:>@])],
+               [],
+               [enable_debug_kmem=no])
+
+       AS_IF([test "x$enable_debug_kmem" = xyes],
+       [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_KMEM"
+               DEBUG_KMEM="_with_debug_kmem"
+               AC_DEFINE([DEBUG_KMEM], [1],
+               [Define to 1 to enable basic kmem accounting])
+       ], [
+               DEBUG_KMEM="_without_debug_kmem"
+       ])
+
+       AC_SUBST(DEBUG_KMEM)
+       AC_MSG_CHECKING([whether basic kmem accounting is enabled])
+       AC_MSG_RESULT([$enable_debug_kmem])
+])
+
+dnl #
+dnl # Disabled by default it provides detailed memory tracking.  This
+dnl # feature also requires --enable-debug-kmem to be set.  When enabled
+dnl # not only will total bytes be tracked but also the location of every
+dnl # alloc and free.  When the SPL module is unloaded a list of all leaked
+dnl # addresses and where they were allocated will be dumped to the console.
+dnl # Enabling this feature has a significant impact on performance but it
+dnl # makes finding memory leaks pretty straight forward.
+dnl #
+AC_DEFUN([SPL_AC_DEBUG_KMEM_TRACKING], [
+       AC_ARG_ENABLE([debug-kmem-tracking],
+               [AS_HELP_STRING([--enable-debug-kmem-tracking],
+               [Enable detailed kmem tracking  @<:@default=no@:>@])],
+               [],
+               [enable_debug_kmem_tracking=no])
+
+       AS_IF([test "x$enable_debug_kmem_tracking" = xyes],
+       [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_KMEM_TRACKING"
+               DEBUG_KMEM_TRACKING="_with_debug_kmem_tracking"
+               AC_DEFINE([DEBUG_KMEM_TRACKING], [1],
+               [Define to 1 to enable detailed kmem tracking])
+       ], [
+               DEBUG_KMEM_TRACKING="_without_debug_kmem_tracking"
+       ])
+
+       AC_SUBST(DEBUG_KMEM_TRACKING)
+       AC_MSG_CHECKING([whether detailed kmem tracking is enabled])
+       AC_MSG_RESULT([$enable_debug_kmem_tracking])
+])
+
+dnl #
+dnl # SPL_LINUX_CONFTEST
+dnl #
+AC_DEFUN([SPL_LINUX_CONFTEST], [
+cat confdefs.h - <<_ACEOF >conftest.c
+$1
+_ACEOF
+])
+
+dnl #
+dnl # SPL_LANG_PROGRAM(C)([PROLOGUE], [BODY])
+dnl #
+m4_define([SPL_LANG_PROGRAM], [
+$1
+int
+main (void)
+{
+dnl Do *not* indent the following line: there may be CPP directives.
+dnl Don't move the `;' right after for the same reason.
+$2
+  ;
+  return 0;
+}
+])
+
+dnl #
+dnl # SPL_LINUX_COMPILE_IFELSE / like AC_COMPILE_IFELSE
+dnl #
+AC_DEFUN([SPL_LINUX_COMPILE_IFELSE], [
+       m4_ifvaln([$1], [SPL_LINUX_CONFTEST([$1])])
+       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
+       AS_IF(
+               [AC_TRY_COMMAND(cp conftest.c build && make [$2] -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag) >/dev/null && AC_TRY_COMMAND([$3])],
+               [$4],
+               [_AC_MSG_LOG_CONFTEST m4_ifvaln([$5],[$5])]
+       )
+       rm -Rf build
+])
+
+dnl #
+dnl # SPL_LINUX_TRY_COMPILE like AC_TRY_COMPILE
+dnl #
+AC_DEFUN([SPL_LINUX_TRY_COMPILE],
+       [SPL_LINUX_COMPILE_IFELSE(
+       [AC_LANG_SOURCE([SPL_LANG_PROGRAM([[$1]], [[$2]])])],
+       [modules],
+       [test -s build/conftest.o],
+       [$3], [$4])
+])
+
+dnl #
+dnl # SPL_CHECK_SYMBOL_EXPORT
+dnl # check symbol exported or not
+dnl #
+AC_DEFUN([SPL_CHECK_SYMBOL_EXPORT], [
+       grep -q -E '[[[:space:]]]$1[[[:space:]]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in $2; do
+                       grep -q -E "EXPORT_SYMBOL.*($1)" \
+                               "$LINUX_OBJ/$file" 2>/dev/null
+                       rc=$?
+                       if test $rc -eq 0; then
+                               export=1
+                               break;
+                       fi
+               done
+               if test $export -eq 0; then :
+                       $4
+               else :
+                       $3
+               fi
+       else :
+               $3
+       fi
+])
+
+dnl #
+dnl # SPL_LINUX_TRY_COMPILE_SYMBOL
+dnl # like SPL_LINUX_TRY_COMPILE, except SPL_CHECK_SYMBOL_EXPORT
+dnl # is called if not compiling for builtin
+dnl #
+AC_DEFUN([SPL_LINUX_TRY_COMPILE_SYMBOL], [
+       SPL_LINUX_TRY_COMPILE([$1], [$2], [rc=0], [rc=1])
+       if test $rc -ne 0; then :
+               $6
+       else
+               if test "x$enable_linux_builtin" != xyes; then
+                       SPL_CHECK_SYMBOL_EXPORT([$3], [$4], [rc=0], [rc=1])
+               fi
+               if test $rc -ne 0; then :
+                       $6
+               else :
+                       $5
+               fi
+       fi
+])
+
+dnl #
+dnl # SPL_CHECK_SYMBOL_HEADER
+dnl # check if a symbol prototype is defined in listed headers.
+dnl #
+AC_DEFUN([SPL_CHECK_SYMBOL_HEADER], [
+       AC_MSG_CHECKING([whether symbol $1 exists in header])
+       header=0
+       for file in $3; do
+               grep -q "$2" "$LINUX/$file" 2>/dev/null
+               rc=$?
+               if test $rc -eq 0; then
+                       header=1
+                       break;
+               fi
+       done
+       if test $header -eq 0; then
+               AC_MSG_RESULT([no])
+               $5
+       else
+               AC_MSG_RESULT([yes])
+               $4
+       fi
+])
+
+dnl #
+dnl # SPL_CHECK_HEADER
+dnl # check whether header exists and define HAVE_$2_HEADER
+dnl #
+AC_DEFUN([SPL_CHECK_HEADER],
+       [AC_MSG_CHECKING([whether header $1 exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <$1>
+       ],[
+               return 0;
+       ],[
+               AC_DEFINE(HAVE_$2_HEADER, 1, [$1 exists])
+               AC_MSG_RESULT(yes)
+               $3
+       ],[
+               AC_MSG_RESULT(no)
+               $4
+       ])
+])
+
+dnl #
+dnl # Basic toolchain sanity check.  Verify that kernel modules can
+dnl # be built and which symbols can be used.
+dnl #
+AC_DEFUN([SPL_AC_TEST_MODULE],
+       [AC_MSG_CHECKING([whether modules can be built])
+       SPL_LINUX_TRY_COMPILE([],[],[
+               AC_MSG_RESULT([yes])
+       ],[
+               AC_MSG_RESULT([no])
+               if test "x$enable_linux_builtin" != xyes; then
+                       AC_MSG_ERROR([*** Unable to build an empty module.])
+               else
+                       AC_MSG_ERROR([
+       *** Unable to build an empty module.
+       *** Please run 'make scripts' inside the kernel source tree.])
+               fi
+       ])
+
+       AS_IF([test "x$cross_compiling" != xyes], [
+               AC_RUN_IFELSE([
+                       AC_LANG_PROGRAM([
+                               #include "$LINUX/include/linux/license.h"
+                       ], [
+                               return !license_is_gpl_compatible(
+                                   "$SPL_META_LICENSE");
+                       ])
+               ], [
+                       AC_DEFINE([SPL_IS_GPL_COMPATIBLE], [1],
+                           [Define to 1 if GPL-only symbols can be used])
+               ], [
+               ])
+       ])
+])
+
+dnl #
+dnl # Use the atomic implemenation based on global spinlocks.  This
+dnl # should only be needed by 32-bit kernels which do not provide
+dnl # the atomic64_* API.  It may be optionally enabled as a fallback
+dnl # if problems are observed with the direct mapping to the native
+dnl # Linux atomic operations.  You may not disable atomic spinlocks
+dnl # if you kernel does not an atomic64_* API.
+dnl #
+AC_DEFUN([SPL_AC_ATOMIC_SPINLOCK], [
+       AC_ARG_ENABLE([atomic-spinlocks],
+               [AS_HELP_STRING([--enable-atomic-spinlocks],
+               [Atomic types use spinlocks @<:@default=check@:>@])],
+               [],
+               [enable_atomic_spinlocks=check])
+
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               atomic64_t *ptr __attribute__ ((unused));
+       ],[
+               have_atomic64_t=yes
+               AC_DEFINE(HAVE_ATOMIC64_T, 1,
+                       [kernel defines atomic64_t])
+       ],[
+               have_atomic64_t=no
+       ])
+
+       AS_IF([test "x$enable_atomic_spinlocks" = xcheck], [
+               AS_IF([test "x$have_atomic64_t" = xyes], [
+                       enable_atomic_spinlocks=no
+               ],[
+                       enable_atomic_spinlocks=yes
+               ])
+       ])
+
+       AS_IF([test "x$enable_atomic_spinlocks" = xyes], [
+               AC_DEFINE([ATOMIC_SPINLOCK], [1],
+                       [Atomic types use spinlocks])
+       ],[
+               AS_IF([test "x$have_atomic64_t" = xno], [
+                       AC_MSG_FAILURE(
+                       [--disable-atomic-spinlocks given but required atomic64 support is unavailable])
+               ])
+       ])
+
+       AC_MSG_CHECKING([whether atomic types use spinlocks])
+       AC_MSG_RESULT([$enable_atomic_spinlocks])
+
+       AC_MSG_CHECKING([whether kernel defines atomic64_t])
+       AC_MSG_RESULT([$have_atomic64_t])
+])
+
+AC_DEFUN([SPL_AC_SHRINKER_CALLBACK],[
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       dnl #
+       dnl # 2.6.23 to 2.6.34 API change
+       dnl # ->shrink(int nr_to_scan, gfp_t gfp_mask)
+       dnl #
+       AC_MSG_CHECKING([whether old 2-argument shrinker exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/mm.h>
+
+               int shrinker_cb(int nr_to_scan, gfp_t gfp_mask);
+       ],[
+               struct shrinker cache_shrinker = {
+                       .shrink = shrinker_cb,
+                       .seeks = DEFAULT_SEEKS,
+               };
+               register_shrinker(&cache_shrinker);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_2ARGS_OLD_SHRINKER_CALLBACK, 1,
+                       [old shrinker callback wants 2 args])
+       ],[
+               AC_MSG_RESULT(no)
+               dnl #
+               dnl # 2.6.35 - 2.6.39 API change
+               dnl # ->shrink(struct shrinker *,
+               dnl #          int nr_to_scan, gfp_t gfp_mask)
+               dnl #
+               AC_MSG_CHECKING([whether old 3-argument shrinker exists])
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/mm.h>
+
+                       int shrinker_cb(struct shrinker *, int nr_to_scan,
+                                       gfp_t gfp_mask);
+               ],[
+                       struct shrinker cache_shrinker = {
+                               .shrink = shrinker_cb,
+                               .seeks = DEFAULT_SEEKS,
+                       };
+                       register_shrinker(&cache_shrinker);
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_3ARGS_SHRINKER_CALLBACK, 1,
+                               [old shrinker callback wants 3 args])
+               ],[
+                       AC_MSG_RESULT(no)
+                       dnl #
+                       dnl # 3.0 - 3.11 API change
+                       dnl # ->shrink(struct shrinker *,
+                       dnl #          struct shrink_control *sc)
+                       dnl #
+                       AC_MSG_CHECKING(
+                               [whether new 2-argument shrinker exists])
+                       SPL_LINUX_TRY_COMPILE([
+                               #include <linux/mm.h>
+
+                               int shrinker_cb(struct shrinker *,
+                                               struct shrink_control *sc);
+                       ],[
+                               struct shrinker cache_shrinker = {
+                                       .shrink = shrinker_cb,
+                                       .seeks = DEFAULT_SEEKS,
+                               };
+                               register_shrinker(&cache_shrinker);
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_2ARGS_NEW_SHRINKER_CALLBACK, 1,
+                                       [new shrinker callback wants 2 args])
+                       ],[
+                               AC_MSG_RESULT(no)
+                               dnl #
+                               dnl # 3.12 API change,
+                               dnl # ->shrink() is logically split in to
+                               dnl # ->count_objects() and ->scan_objects()
+                               dnl #
+                               AC_MSG_CHECKING(
+                                   [whether ->count_objects callback exists])
+                               SPL_LINUX_TRY_COMPILE([
+                                       #include <linux/mm.h>
+
+                                       unsigned long shrinker_cb(
+                                               struct shrinker *,
+                                               struct shrink_control *sc);
+                               ],[
+                                       struct shrinker cache_shrinker = {
+                                               .count_objects = shrinker_cb,
+                                               .scan_objects = shrinker_cb,
+                                               .seeks = DEFAULT_SEEKS,
+                                       };
+                                       register_shrinker(&cache_shrinker);
+                               ],[
+                                       AC_MSG_RESULT(yes)
+                                       AC_DEFINE(HAVE_SPLIT_SHRINKER_CALLBACK,
+                                               1, [->count_objects exists])
+                               ],[
+                                       AC_MSG_ERROR(error)
+                               ])
+                       ])
+               ])
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 2.6.33 API change,
+dnl # Removed .ctl_name from struct ctl_table.
+dnl #
+AC_DEFUN([SPL_AC_CTL_NAME], [
+       AC_MSG_CHECKING([whether struct ctl_table has ctl_name])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/sysctl.h>
+       ],[
+               struct ctl_table ctl __attribute__ ((unused));
+               ctl.ctl_name = 0;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CTL_NAME, 1, [struct ctl_table has ctl_name])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.10 API change,
+dnl # PDE is replaced by PDE_DATA
+dnl #
+AC_DEFUN([SPL_AC_PDE_DATA], [
+       AC_MSG_CHECKING([whether PDE_DATA() is available])
+       SPL_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/proc_fs.h>
+       ], [
+               PDE_DATA(NULL);
+       ], [PDE_DATA], [], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_PDE_DATA, 1, [yes])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.9 API change
+dnl # set_fs_pwd takes const struct path *
+dnl #
+AC_DEFUN([SPL_AC_SET_FS_PWD_WITH_CONST],
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       [AC_MSG_CHECKING([whether set_fs_pwd() requires const struct path *])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/spinlock.h>
+               #include <linux/fs_struct.h>
+               #include <linux/path.h>
+               void (*const set_fs_pwd_func)
+                       (struct fs_struct *, const struct path *)
+                       = set_fs_pwd;
+       ],[
+               return 0;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SET_FS_PWD_WITH_CONST, 1,
+                       [set_fs_pwd() needs const path *])
+       ],[
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/spinlock.h>
+                       #include <linux/fs_struct.h>
+                       #include <linux/path.h>
+                       void (*const set_fs_pwd_func)
+                               (struct fs_struct *, struct path *)
+                               = set_fs_pwd;
+               ],[
+                       return 0;
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       AC_MSG_ERROR(unknown)
+               ])
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 3.13 API change
+dnl # vfs_unlink() updated to take a third delegated_inode argument.
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_VFS_UNLINK],
+       [AC_MSG_CHECKING([whether vfs_unlink() wants 2 args])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               vfs_unlink((struct inode *) NULL, (struct dentry *) NULL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_2ARGS_VFS_UNLINK, 1,
+                         [vfs_unlink() wants 2 args])
+       ],[
+               AC_MSG_RESULT(no)
+               dnl #
+               dnl # Linux 3.13 API change
+               dnl # Added delegated inode
+               dnl #
+               AC_MSG_CHECKING([whether vfs_unlink() wants 3 args])
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/fs.h>
+               ],[
+                       vfs_unlink((struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode **) NULL);
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_3ARGS_VFS_UNLINK, 1,
+                                 [vfs_unlink() wants 3 args])
+               ],[
+                       AC_MSG_ERROR(no)
+               ])
+
+       ])
+])
+
+dnl #
+dnl # 3.13 and 3.15 API changes
+dnl # Added delegated inode and flags argument.
+dnl #
+AC_DEFUN([SPL_AC_4ARGS_VFS_RENAME],
+       [AC_MSG_CHECKING([whether vfs_rename() wants 4 args])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               vfs_rename((struct inode *) NULL, (struct dentry *) NULL,
+                       (struct inode *) NULL, (struct dentry *) NULL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_4ARGS_VFS_RENAME, 1,
+                         [vfs_rename() wants 4 args])
+       ],[
+               AC_MSG_RESULT(no)
+               dnl #
+               dnl # Linux 3.13 API change
+               dnl # Added delegated inode
+               dnl #
+               AC_MSG_CHECKING([whether vfs_rename() wants 5 args])
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/fs.h>
+               ],[
+                       vfs_rename((struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode **) NULL);
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_5ARGS_VFS_RENAME, 1,
+                                 [vfs_rename() wants 5 args])
+               ],[
+                       AC_MSG_RESULT(no)
+                       dnl #
+                       dnl # Linux 3.15 API change
+                       dnl # Added flags
+                       dnl #
+                       AC_MSG_CHECKING([whether vfs_rename() wants 6 args])
+                       SPL_LINUX_TRY_COMPILE([
+                               #include <linux/fs.h>
+                       ],[
+                               vfs_rename((struct inode *) NULL,
+                                       (struct dentry *) NULL,
+                                       (struct inode *) NULL,
+                                       (struct dentry *) NULL,
+                                       (struct inode **) NULL,
+                                       (unsigned int) 0);
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_6ARGS_VFS_RENAME, 1,
+                                         [vfs_rename() wants 6 args])
+                       ],[
+                               AC_MSG_ERROR(no)
+                       ])
+               ])
+       ])
+])
+
+dnl #
+dnl # 2.6.36 API change,
+dnl # The 'struct fs_struct->lock' was changed from a rwlock_t to
+dnl # a spinlock_t to improve the fastpath performance.
+dnl #
+AC_DEFUN([SPL_AC_FS_STRUCT_SPINLOCK], [
+       AC_MSG_CHECKING([whether struct fs_struct uses spinlock_t])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/sched.h>
+               #include <linux/fs_struct.h>
+       ],[
+               static struct fs_struct fs;
+               spin_lock_init(&fs.lock);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FS_STRUCT_SPINLOCK, 1,
+                         [struct fs_struct uses spinlock_t])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # User namespaces, use kuid_t in place of uid_t
+dnl # where available. Not strictly a user namespaces thing
+dnl # but it should prevent surprises
+dnl #
+AC_DEFUN([SPL_AC_KUIDGID_T], [
+       AC_MSG_CHECKING([whether kuid_t/kgid_t is available])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/uidgid.h>
+       ], [
+               kuid_t userid = KUIDT_INIT(0);
+               kgid_t groupid = KGIDT_INIT(0);
+       ],[
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/uidgid.h>
+               ], [
+                       kuid_t userid = 0;
+                       kgid_t groupid = 0;
+               ],[
+                       AC_MSG_RESULT(yes; optional)
+               ],[
+                       AC_MSG_RESULT(yes; mandatory)
+                       AC_DEFINE(HAVE_KUIDGID_T, 1, [kuid_t/kgid_t in use])
+               ])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.39 API change,
+dnl # __put_task_struct() was exported by the mainline kernel.
+dnl #
+AC_DEFUN([SPL_AC_PUT_TASK_STRUCT],
+       [AC_MSG_CHECKING([whether __put_task_struct() is available])
+       SPL_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/sched.h>
+       ], [
+               __put_task_struct(NULL);
+       ], [__put_task_struct], [], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_PUT_TASK_STRUCT, 1,
+                         [__put_task_struct() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.35 API change,
+dnl # Unused 'struct dentry *' removed from vfs_fsync() prototype.
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_VFS_FSYNC], [
+       AC_MSG_CHECKING([whether vfs_fsync() wants 2 args])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               vfs_fsync(NULL, 0);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_2ARGS_VFS_FSYNC, 1, [vfs_fsync() wants 2 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.5 API change,
+dnl # inode_operations.truncate_range removed
+dnl #
+AC_DEFUN([SPL_AC_INODE_TRUNCATE_RANGE], [
+       AC_MSG_CHECKING([whether truncate_range() inode operation is available])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct inode_operations ops;
+               ops.truncate_range = NULL;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INODE_TRUNCATE_RANGE, 1,
+                       [truncate_range() inode operation is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_FILE_FALLOCATE], [
+       AC_MSG_CHECKING([whether fops->fallocate() exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+               struct file_operations fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # Linux 2.6.x - 2.6.37 API
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_INODE_FALLOCATE], [
+       AC_MSG_CHECKING([whether iops->fallocate() exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               long (*fallocate) (struct inode *, int, loff_t, loff_t) = NULL;
+               struct inode_operations fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INODE_FALLOCATE, 1, [fops->fallocate() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # PaX Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([SPL_AC_PAX_KERNEL_FILE_FALLOCATE], [
+       AC_MSG_CHECKING([whether fops->fallocate() exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+               struct file_operations_no_const fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # The fallocate callback was moved from the inode_operations
+dnl # structure to the file_operations structure.
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_FALLOCATE], [
+       SPL_AC_KERNEL_FILE_FALLOCATE
+       SPL_AC_KERNEL_INODE_FALLOCATE
+       SPL_AC_PAX_KERNEL_FILE_FALLOCATE
+])
+
+dnl #
+dnl # zlib inflate compat,
+dnl # Verify the kernel has CONFIG_ZLIB_INFLATE support enabled.
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_ZLIB_INFLATE], [
+       AC_MSG_CHECKING([whether CONFIG_ZLIB_INFLATE is defined])
+       SPL_LINUX_TRY_COMPILE([
+               #if !defined(CONFIG_ZLIB_INFLATE) && \
+                   !defined(CONFIG_ZLIB_INFLATE_MODULE)
+               #error CONFIG_ZLIB_INFLATE not defined
+               #endif
+       ],[ ],[
+               AC_MSG_RESULT([yes])
+       ],[
+               AC_MSG_RESULT([no])
+               AC_MSG_ERROR([
+       *** This kernel does not include the required zlib inflate support.
+       *** Rebuild the kernel with CONFIG_ZLIB_INFLATE=y|m set.])
+       ])
+])
+
+dnl #
+dnl # zlib deflate compat,
+dnl # Verify the kernel has CONFIG_ZLIB_DEFLATE support enabled.
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_ZLIB_DEFLATE], [
+       AC_MSG_CHECKING([whether CONFIG_ZLIB_DEFLATE is defined])
+       SPL_LINUX_TRY_COMPILE([
+               #if !defined(CONFIG_ZLIB_DEFLATE) && \
+                   !defined(CONFIG_ZLIB_DEFLATE_MODULE)
+               #error CONFIG_ZLIB_DEFLATE not defined
+               #endif
+       ],[ ],[
+               AC_MSG_RESULT([yes])
+       ],[
+               AC_MSG_RESULT([no])
+               AC_MSG_ERROR([
+       *** This kernel does not include the required zlib deflate support.
+       *** Rebuild the kernel with CONFIG_ZLIB_DEFLATE=y|m set.])
+       ])
+])
+
+dnl #
+dnl # config trim unused symbols,
+dnl # Verify the kernel has CONFIG_TRIM_UNUSED_KSYMS DISABLED.
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_TRIM_UNUSED_KSYMS], [
+       AC_MSG_CHECKING([whether CONFIG_TRIM_UNUSED_KSYM is disabled])
+       SPL_LINUX_TRY_COMPILE([
+               #if defined(CONFIG_TRIM_UNUSED_KSYMS)
+               #error CONFIG_TRIM_UNUSED_KSYMS not defined
+               #endif
+       ],[ ],[
+               AC_MSG_RESULT([yes])
+       ],[
+               AC_MSG_RESULT([no])
+               AC_MSG_ERROR([
+       *** This kernel has unused symbols trimming enabled, please disable.
+       *** Rebuild the kernel with CONFIG_TRIM_UNUSED_KSYMS=n set.])
+       ])
+])
+
+dnl #
+dnl # 2.6.39 API compat,
+dnl # The function zlib_deflate_workspacesize() now take 2 arguments.
+dnl # This was done to avoid always having to allocate the maximum size
+dnl # workspace (268K).  The caller can now specific the windowBits and
+dnl # memLevel compression parameters to get a smaller workspace.
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE],
+       [AC_MSG_CHECKING([whether zlib_deflate_workspacesize() wants 2 args])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/zlib.h>
+       ],[
+               return zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE, 1,
+                         [zlib_deflate_workspacesize() wants 2 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.39 API change,
+dnl # Shrinker adjust to use common shrink_control structure.
+dnl #
+AC_DEFUN([SPL_AC_SHRINK_CONTROL_STRUCT], [
+       AC_MSG_CHECKING([whether struct shrink_control exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/mm.h>
+       ],[
+               struct shrink_control sc __attribute__ ((unused));
+
+               sc.nr_to_scan = 0;
+               sc.gfp_mask = GFP_KERNEL;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SHRINK_CONTROL_STRUCT, 1,
+                       [struct shrink_control exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.1 API Change
+dnl #
+dnl # The rw_semaphore.wait_lock member was changed from spinlock_t to
+dnl # raw_spinlock_t at commit ddb6c9b58a19edcfac93ac670b066c836ff729f1.
+dnl #
+AC_DEFUN([SPL_AC_RWSEM_SPINLOCK_IS_RAW], [
+       AC_MSG_CHECKING([whether struct rw_semaphore member wait_lock is raw])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/rwsem.h>
+       ],[
+               struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+               raw_spinlock_t dummy_lock __attribute__ ((unused));
+               dummy_semaphore.wait_lock = dummy_lock;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(RWSEM_SPINLOCK_IS_RAW, 1,
+               [struct rw_semaphore member wait_lock is raw_spinlock_t])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 3.16 API Change
+dnl #
+dnl # rwsem-spinlock "->activity" changed to "->count"
+dnl #
+AC_DEFUN([SPL_AC_RWSEM_ACTIVITY], [
+       AC_MSG_CHECKING([whether struct rw_semaphore has member activity])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/rwsem.h>
+       ],[
+               struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+               dummy_semaphore.activity = 0;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_RWSEM_ACTIVITY, 1,
+               [struct rw_semaphore has member activity])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 4.8 API Change
+dnl #
+dnl # rwsem "->count" changed to atomic_long_t type
+dnl #
+AC_DEFUN([SPL_AC_RWSEM_ATOMIC_LONG_COUNT], [
+       AC_MSG_CHECKING(
+       [whether struct rw_semaphore has atomic_long_t member count])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/rwsem.h>
+       ],[
+               DECLARE_RWSEM(dummy_semaphore);
+               (void) atomic_long_read(&dummy_semaphore.count);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_RWSEM_ATOMIC_LONG_COUNT, 1,
+               [struct rw_semaphore has atomic_long_t member count])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 3.9 API change,
+dnl # Moved things from linux/sched.h to linux/sched/rt.h
+dnl #
+AC_DEFUN([SPL_AC_SCHED_RT_HEADER],
+       [AC_MSG_CHECKING([whether header linux/sched/rt.h exists])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/sched.h>
+               #include <linux/sched/rt.h>
+       ],[
+               return 0;
+       ],[
+               AC_DEFINE(HAVE_SCHED_RT_HEADER, 1, [linux/sched/rt.h exists])
+               AC_MSG_RESULT(yes)
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.9 API change,
+dnl # vfs_getattr() uses 2 args
+dnl # It takes struct path * instead of struct vfsmount * and struct dentry *
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_VFS_GETATTR], [
+       AC_MSG_CHECKING([whether vfs_getattr() wants])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               vfs_getattr((struct path *) NULL,
+                       (struct kstat *)NULL);
+       ],[
+               AC_MSG_RESULT(2 args)
+               AC_DEFINE(HAVE_2ARGS_VFS_GETATTR, 1,
+                         [vfs_getattr wants 2 args])
+       ],[
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/fs.h>
+               ],[
+                       vfs_getattr((struct vfsmount *)NULL,
+                               (struct dentry *)NULL,
+                               (struct kstat *)NULL);
+               ],[
+                       AC_MSG_RESULT(3 args)
+               ],[
+                       AC_MSG_ERROR(unknown)
+               ])
+       ])
+])
+
+dnl #
+dnl # 2.6.36 API compatibility.
+dnl # Added usleep_range timer.
+dnl # usleep_range is a finer precision implementation of msleep
+dnl # designed to be a drop-in replacement for udelay where a precise
+dnl # sleep / busy-wait is unnecessary.
+dnl #
+AC_DEFUN([SPL_AC_USLEEP_RANGE], [
+       AC_MSG_CHECKING([whether usleep_range() is available])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/delay.h>
+       ],[
+               usleep_range(0, 0);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_USLEEP_RANGE, 1,
+                         [usleep_range is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.35 API change,
+dnl # The cachep->gfpflags member was renamed cachep->allocflags.  These are
+dnl # private allocation flags which are applied when allocating a new slab
+dnl # in kmem_getpages().  Unfortunately there is no public API for setting
+dnl # non-default flags.
+dnl #
+AC_DEFUN([SPL_AC_KMEM_CACHE_ALLOCFLAGS], [
+       AC_MSG_CHECKING([whether struct kmem_cache has allocflags])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/slab.h>
+       ],[
+               struct kmem_cache cachep __attribute__ ((unused));
+               cachep.allocflags = GFP_KERNEL;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_KMEM_CACHE_ALLOCFLAGS, 1,
+                       [struct kmem_cache has allocflags])
+       ],[
+               AC_MSG_RESULT(no)
+
+               AC_MSG_CHECKING([whether struct kmem_cache has gfpflags])
+               SPL_LINUX_TRY_COMPILE([
+                       #include <linux/slab.h>
+               ],[
+                       struct kmem_cache cachep __attribute__ ((unused));
+                       cachep.gfpflags = GFP_KERNEL;
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_KMEM_CACHE_GFPFLAGS, 1,
+                               [struct kmem_cache has gfpflags])
+               ],[
+                       AC_MSG_RESULT(no)
+               ])
+       ])
+])
+
+dnl #
+dnl # 3.17 API change,
+dnl # wait_on_bit() no longer requires an action argument. The former
+dnl # "wait_on_bit" interface required an 'action' function to be provided
+dnl # which does the actual waiting. There were over 20 such functions in the
+dnl # kernel, many of them identical, though most cases can be satisfied by one
+dnl # of just two functions: one which uses io_schedule() and one which just
+dnl # uses schedule().  This API change was made to consolidate all of those
+dnl # redundant wait functions.
+dnl #
+AC_DEFUN([SPL_AC_WAIT_ON_BIT], [
+       AC_MSG_CHECKING([whether wait_on_bit() takes an action])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/wait.h>
+       ],[
+               int (*action)(void *) = NULL;
+               wait_on_bit(NULL, 0, action, 0);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_WAIT_ON_BIT_ACTION, 1, [yes])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 4.7 API change
+dnl # i_mutex is changed to i_rwsem. Instead of directly using
+dnl # i_mutex/i_rwsem, we should use inode_lock() and inode_lock_shared()
+dnl # We test inode_lock_shared because inode_lock is introduced earlier.
+dnl #
+AC_DEFUN([SPL_AC_INODE_LOCK], [
+       AC_MSG_CHECKING([whether inode_lock_shared() exists])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct inode *inode = NULL;
+               inode_lock_shared(inode);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INODE_LOCK_SHARED, 1, [yes])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # Check whether mutex has owner with task_struct type.
+dnl #
+dnl # Note that before Linux 3.0, mutex owner is of type thread_info.
+dnl #
+dnl # Note that in Linux 3.18, the condition for owner is changed from
+dnl # defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) to
+dnl # defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
+dnl #
+AC_DEFUN([SPL_AC_MUTEX_OWNER], [
+       AC_MSG_CHECKING([whether mutex has owner])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/mutex.h>
+               #include <linux/spinlock.h>
+       ],[
+               DEFINE_MUTEX(m);
+               struct task_struct *t __attribute__ ((unused));
+               t = m.owner;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_MUTEX_OWNER, 1, [yes])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 4.9 API change
+dnl # group_info changed from 2d array via >blocks to 1d array via ->gid
+dnl #
+AC_DEFUN([SPL_AC_GROUP_INFO_GID], [
+       AC_MSG_CHECKING([whether group_info->gid exists])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/cred.h>
+       ],[
+               struct group_info *gi = groups_alloc(1);
+               gi->gid[0] = KGIDT_INIT(0);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GROUP_INFO_GID, 1, [group_info->gid exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/spl/config/spl-meta.m4 b/spl/config/spl-meta.m4
new file mode 100644 (file)
index 0000000..0561fbb
--- /dev/null
@@ -0,0 +1,162 @@
+dnl #
+dnl # DESCRIPTION:
+dnl # Read meta data from the META file.  When building from a git repository
+dnl # the SPL_META_RELEASE field will be overwritten if there is an annotated
+dnl # tag matching the form SPL_META_NAME-SPL_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$
+dnl #
+dnl #    In other words:
+dnl #    - KEY is separated from VALUE by a colon and one or more spaces/tabs.
+dnl #    - KEY and VALUE are case sensitive.
+dnl #    - Leading spaces are ignored.
+dnl #    - First match wins for duplicate keys.
+dnl #
+dnl #    A line can be commented out by preceding it with a '#' (or technically
+dnl #    any non-space character since that will prevent the regex from
+dnl #    matching).
+dnl #
+dnl # WARNING:
+dnl #   Placing a colon followed by a space or tab (ie, ":[ \t]+") within the
+dnl #   VALUE will prematurely terminate the string since that sequence is
+dnl #   used as the awk field separator.
+dnl #
+dnl # KEYS:
+dnl #   The following META keys are recognized:
+dnl #     Name, Version, Release, Date, Author, LT_Current, LT_Revision, LT_Age
+dnl #
+dnl # Written by Chris Dunlap <cdunlap@llnl.gov>.
+dnl # Modified by Brian Behlendorf <behlendorf1@llnl.gov>.
+dnl #
+AC_DEFUN([SPL_AC_META], [
+       AC_PROG_AWK
+       AC_MSG_CHECKING([metadata])
+
+       META="$srcdir/META"
+       _spl_ac_meta_type="none"
+       if test -f "$META"; then
+               _spl_ac_meta_type="META file"
+
+               SPL_META_NAME=_SPL_AC_META_GETVAL([(Name|Project|Package)]);
+               if test -n "$SPL_META_NAME"; then
+                       AC_DEFINE_UNQUOTED([SPL_META_NAME], ["$SPL_META_NAME"],
+                               [Define the project name.]
+                       )
+                       AC_SUBST([SPL_META_NAME])
+               fi
+
+               SPL_META_VERSION=_SPL_AC_META_GETVAL([Version]);
+               if test -n "$SPL_META_VERSION"; then
+                       AC_DEFINE_UNQUOTED([SPL_META_VERSION], ["$SPL_META_VERSION"],
+                               [Define the project version.]
+                       )
+                       AC_SUBST([SPL_META_VERSION])
+               fi
+
+               SPL_META_RELEASE=_SPL_AC_META_GETVAL([Release]);
+               if test ! -f ".nogitrelease" && git rev-parse --git-dir > /dev/null 2>&1; then
+                       _match="${SPL_META_NAME}-${SPL_META_VERSION}"
+                       _alias=$(git describe --match=${_match} 2>/dev/null)
+                       _release=$(echo ${_alias}|cut -f3- -d'-'|sed 's/-/_/g')
+                       if test -n "${_release}"; then
+                               SPL_META_RELEASE=${_release}
+                               _spl_ac_meta_type="git describe"
+                       fi
+               fi
+
+               if test -n "$SPL_META_RELEASE"; then
+                       AC_DEFINE_UNQUOTED([SPL_META_RELEASE], ["$SPL_META_RELEASE"],
+                               [Define the project release.]
+                       )
+                       AC_SUBST([SPL_META_RELEASE])
+
+                       RELEASE="$SPL_META_RELEASE"
+                       AC_SUBST([RELEASE])
+               fi
+
+               SPL_META_LICENSE=_SPL_AC_META_GETVAL([License]);
+               if test -n "$SPL_META_LICENSE"; then
+                       AC_DEFINE_UNQUOTED([SPL_META_LICENSE], ["$SPL_META_LICENSE"],
+                               [Define the project license.]
+                       )
+                       AC_SUBST([SPL_META_LICENSE])
+               fi
+
+               if test -n "$SPL_META_NAME" -a -n "$SPL_META_VERSION"; then
+                               SPL_META_ALIAS="$SPL_META_NAME-$SPL_META_VERSION"
+                               test -n "$SPL_META_RELEASE" && 
+                                       SPL_META_ALIAS="$SPL_META_ALIAS-$SPL_META_RELEASE"
+                               AC_DEFINE_UNQUOTED([SPL_META_ALIAS],
+                                       ["$SPL_META_ALIAS"],
+                                       [Define the project alias string.] 
+                               )
+                               AC_SUBST([SPL_META_ALIAS])
+               fi
+
+               SPL_META_DATA=_SPL_AC_META_GETVAL([Date]);
+               if test -n "$SPL_META_DATA"; then
+                       AC_DEFINE_UNQUOTED([SPL_META_DATA], ["$SPL_META_DATA"],
+                               [Define the project release date.] 
+                       )
+                       AC_SUBST([SPL_META_DATA])
+               fi
+
+               SPL_META_AUTHOR=_SPL_AC_META_GETVAL([Author]);
+               if test -n "$SPL_META_AUTHOR"; then
+                       AC_DEFINE_UNQUOTED([SPL_META_AUTHOR], ["$SPL_META_AUTHOR"],
+                               [Define the project author.]
+                       )
+                       AC_SUBST([SPL_META_AUTHOR])
+               fi
+
+               m4_pattern_allow([^LT_(CURRENT|REVISION|AGE)$])
+               SPL_META_LT_CURRENT=_SPL_AC_META_GETVAL([LT_Current]);
+               SPL_META_LT_REVISION=_SPL_AC_META_GETVAL([LT_Revision]);
+               SPL_META_LT_AGE=_SPL_AC_META_GETVAL([LT_Age]);
+               if test -n "$SPL_META_LT_CURRENT" \
+                                -o -n "$SPL_META_LT_REVISION" \
+                                -o -n "$SPL_META_LT_AGE"; then
+                       test -n "$SPL_META_LT_CURRENT" || SPL_META_LT_CURRENT="0"
+                       test -n "$SPL_META_LT_REVISION" || SPL_META_LT_REVISION="0"
+                       test -n "$SPL_META_LT_AGE" || SPL_META_LT_AGE="0"
+                       AC_DEFINE_UNQUOTED([SPL_META_LT_CURRENT],
+                               ["$SPL_META_LT_CURRENT"],
+                               [Define the libtool library 'current'
+                                version information.]
+                       )
+                       AC_DEFINE_UNQUOTED([SPL_META_LT_REVISION],
+                               ["$SPL_META_LT_REVISION"],
+                               [Define the libtool library 'revision'
+                                version information.]
+                       )
+                       AC_DEFINE_UNQUOTED([SPL_META_LT_AGE], ["$SPL_META_LT_AGE"],
+                               [Define the libtool library 'age' 
+                                version information.]
+                       )
+                       AC_SUBST([SPL_META_LT_CURRENT])
+                       AC_SUBST([SPL_META_LT_REVISION])
+                       AC_SUBST([SPL_META_LT_AGE])
+               fi
+       fi
+
+       AC_MSG_RESULT([$_spl_ac_meta_type])
+       ]
+)
+
+dnl # _SPL_AC_META_GETVAL (KEY_NAME_OR_REGEX)
+dnl #
+dnl # Returns the META VALUE associated with the given KEY_NAME_OR_REGEX expr.
+dnl #
+dnl # Despite their resemblance to line noise,
+dnl #   the "@<:@" and "@:>@" constructs are quadrigraphs for "[" and "]".
+dnl #   <www.gnu.org/software/autoconf/manual/autoconf.html#Quadrigraphs>
+dnl #
+dnl # The "$[]1" and "$[]2" constructs prevent M4 parameter expansion
+dnl #   so a literal $1 and $2 will be passed to the resulting awk script,
+dnl #   whereas the "$1" will undergo M4 parameter expansion for the META key.
+dnl #
+AC_DEFUN([_SPL_AC_META_GETVAL],
+       [`$AWK -F ':@<:@ \t@:>@+' '$[]1 ~ /^ *$1$/ { print $[]2; exit }' $META`]dnl
+)
diff --git a/spl/config/tgz.am b/spl/config/tgz.am
new file mode 100644 (file)
index 0000000..765be43
--- /dev/null
@@ -0,0 +1,44 @@
+###############################################################################
+# Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Build targets for TGZ packages.
+#
+# Long term native distro specific Slackware style packaging should be added.
+# In the short term RPM packages are built and converted to TGZ packages
+# using alien.  If someone familiar with Slackware style packaging were to
+# update the build system to correctly build Slackware style packages I would
+# happily take it.  Until then we will have to make due with alien.
+#
+###############################################################################
+
+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
+if CONFIG_KERNEL
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --scripts --to-tgz $$pkg1; \
+       $(RM) $$pkg1
+endif
+
+tgz-utils: tgz-local rpm-utils
+if CONFIG_USER
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=$${name}-$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --scripts --to-tgz $$pkg1; \
+       $(RM) $$pkg1
+endif
+
+tgz: tgz-kmod tgz-utils
diff --git a/spl/configure b/spl/configure
new file mode 100755 (executable)
index 0000000..5e323ae
--- /dev/null
@@ -0,0 +1,20644 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for spl 0.6.5.9.
+#
+#
+# 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='spl'
+PACKAGE_TARNAME='spl'
+PACKAGE_VERSION='0.6.5.9'
+PACKAGE_STRING='spl 0.6.5.9'
+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
+CONFIG_KERNEL_FALSE
+CONFIG_KERNEL_TRUE
+CONFIG_USER_FALSE
+CONFIG_USER_TRUE
+DEBUG_KMEM_TRACKING
+DEBUG_KMEM
+DEBUG_SPL
+DEBUG_CFLAGS
+KERNELCPPFLAGS
+KERNELMAKE_PARAMS
+LINUX_SYMBOLS
+LINUX_VERSION
+LINUX_OBJ
+LINUX
+SPL_CONFIG
+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
+DEFAULT_PACKAGE
+VENDOR
+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
+SPL_META_LT_AGE
+SPL_META_LT_REVISION
+SPL_META_LT_CURRENT
+SPL_META_AUTHOR
+SPL_META_DATA
+SPL_META_ALIAS
+SPL_META_LICENSE
+RELEASE
+SPL_META_RELEASE
+SPL_META_VERSION
+SPL_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_linux
+with_linux_obj
+enable_debug
+enable_debug_kmem
+enable_debug_kmem_tracking
+enable_atomic_spinlocks
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+LT_SYS_LIBRARY_PATH
+CPP'
+
+
+# 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 spl 0.6.5.9 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/spl]
+  --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 spl 0.6.5.9:";;
+   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-debug          Enable generic debug support [default=no]
+  --enable-debug-kmem     Enable basic kmem accounting [default=no]
+  --enable-debug-kmem-tracking
+                          Enable detailed kmem tracking [default=no]
+  --enable-atomic-spinlocks
+                          Atomic types use spinlocks [default=check]
+
+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-linux=PATH       Path to kernel source
+  --with-linux-obj=PATH   Path to kernel build objects
+
+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
+
+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
+spl configure 0.6.5.9
+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
+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 spl $as_me 0.6.5.9, 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"
+       _spl_ac_meta_type="none"
+       if test -f "$META"; then
+               _spl_ac_meta_type="META file"
+
+               SPL_META_NAME=`$AWK -F ':[ \t]+' '$1 ~ /^ *(Name|Project|Package)$/ { print $2; exit }' $META`;
+               if test -n "$SPL_META_NAME"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_NAME "$SPL_META_NAME"
+_ACEOF
+
+
+               fi
+
+               SPL_META_VERSION=`$AWK -F ':[ \t]+' '$1 ~ /^ *Version$/ { print $2; exit }' $META`;
+               if test -n "$SPL_META_VERSION"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_VERSION "$SPL_META_VERSION"
+_ACEOF
+
+
+               fi
+
+               SPL_META_RELEASE=`$AWK -F ':[ \t]+' '$1 ~ /^ *Release$/ { print $2; exit }' $META`;
+               if test ! -f ".nogitrelease" && git rev-parse --git-dir > /dev/null 2>&1; then
+                       _match="${SPL_META_NAME}-${SPL_META_VERSION}"
+                       _alias=$(git describe --match=${_match} 2>/dev/null)
+                       _release=$(echo ${_alias}|cut -f3- -d'-'|sed 's/-/_/g')
+                       if test -n "${_release}"; then
+                               SPL_META_RELEASE=${_release}
+                               _spl_ac_meta_type="git describe"
+                       fi
+               fi
+
+               if test -n "$SPL_META_RELEASE"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_RELEASE "$SPL_META_RELEASE"
+_ACEOF
+
+
+
+                       RELEASE="$SPL_META_RELEASE"
+
+               fi
+
+               SPL_META_LICENSE=`$AWK -F ':[ \t]+' '$1 ~ /^ *License$/ { print $2; exit }' $META`;
+               if test -n "$SPL_META_LICENSE"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_LICENSE "$SPL_META_LICENSE"
+_ACEOF
+
+
+               fi
+
+               if test -n "$SPL_META_NAME" -a -n "$SPL_META_VERSION"; then
+                               SPL_META_ALIAS="$SPL_META_NAME-$SPL_META_VERSION"
+                               test -n "$SPL_META_RELEASE" &&
+                                       SPL_META_ALIAS="$SPL_META_ALIAS-$SPL_META_RELEASE"
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_ALIAS "$SPL_META_ALIAS"
+_ACEOF
+
+
+               fi
+
+               SPL_META_DATA=`$AWK -F ':[ \t]+' '$1 ~ /^ *Date$/ { print $2; exit }' $META`;
+               if test -n "$SPL_META_DATA"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_DATA "$SPL_META_DATA"
+_ACEOF
+
+
+               fi
+
+               SPL_META_AUTHOR=`$AWK -F ':[ \t]+' '$1 ~ /^ *Author$/ { print $2; exit }' $META`;
+               if test -n "$SPL_META_AUTHOR"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_AUTHOR "$SPL_META_AUTHOR"
+_ACEOF
+
+
+               fi
+
+
+               SPL_META_LT_CURRENT=`$AWK -F ':[ \t]+' '$1 ~ /^ *LT_Current$/ { print $2; exit }' $META`;
+               SPL_META_LT_REVISION=`$AWK -F ':[ \t]+' '$1 ~ /^ *LT_Revision$/ { print $2; exit }' $META`;
+               SPL_META_LT_AGE=`$AWK -F ':[ \t]+' '$1 ~ /^ *LT_Age$/ { print $2; exit }' $META`;
+               if test -n "$SPL_META_LT_CURRENT" \
+                                -o -n "$SPL_META_LT_REVISION" \
+                                -o -n "$SPL_META_LT_AGE"; then
+                       test -n "$SPL_META_LT_CURRENT" || SPL_META_LT_CURRENT="0"
+                       test -n "$SPL_META_LT_REVISION" || SPL_META_LT_REVISION="0"
+                       test -n "$SPL_META_LT_AGE" || SPL_META_LT_AGE="0"
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_LT_CURRENT "$SPL_META_LT_CURRENT"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_LT_REVISION "$SPL_META_LT_REVISION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SPL_META_LT_AGE "$SPL_META_LT_AGE"
+_ACEOF
+
+
+
+
+               fi
+       fi
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_spl_ac_meta_type" >&5
+$as_echo "$_spl_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='spl'
+ VERSION='0.6.5.9'
+
+
+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 spl_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:
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl author" >&5
+$as_echo_n "checking spl author... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SPL_META_AUTHOR" >&5
+$as_echo "$SPL_META_AUTHOR" >&6; }
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl license" >&5
+$as_echo_n "checking spl license... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SPL_META_LICENSE" >&5
+$as_echo "$SPL_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; }
+
+
+
+       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_SPL) 1" --define "$(DEBUG_KMEM) 1" --define "$(DEBUG_KMEM_TRACKING) 1"'
+       RPM_DEFINE_UTIL=
+       RPM_DEFINE_KMOD='--define "kernels $(LINUX_VERSION)"'
+       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
+
+
+
+
+
+
+
+       SPL_CONFIG=all
+
+# Check whether --with-config was given.
+if test "${with_config+set}" = set; then :
+  withval=$with_config; SPL_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 spl config" >&5
+$as_echo_n "checking spl config... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SPL_CONFIG" >&5
+$as_echo "$SPL_CONFIG" >&6; };
+
+
+       case "$SPL_CONFIG" in
+               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; }
+
+
+
+
+       if test "${LINUX_OBJ}" != "${LINUX}"; then
+               KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
+       fi
+
+
+       KERNELCPPFLAGS="$KERNELCPPFLAGS -Wstrict-prototypes"
+
+
+
+       { $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"
+               DEBUG_CFLAGS="-DDEBUG -Werror"
+               DEBUG_SPL="_with_debug"
+
+else
+
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DNDEBUG"
+               DEBUG_CFLAGS="-DNDEBUG"
+               DEBUG_SPL="_without_debug"
+
+fi
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug" >&5
+$as_echo "$enable_debug" >&6; }
+
+
+       # Check whether --enable-debug-kmem was given.
+if test "${enable_debug_kmem+set}" = set; then :
+  enableval=$enable_debug_kmem;
+else
+  enable_debug_kmem=no
+fi
+
+
+       if test "x$enable_debug_kmem" = xyes; then :
+
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_KMEM"
+               DEBUG_KMEM="_with_debug_kmem"
+
+$as_echo "#define DEBUG_KMEM 1" >>confdefs.h
+
+
+else
+
+               DEBUG_KMEM="_without_debug_kmem"
+
+fi
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether basic kmem accounting is enabled" >&5
+$as_echo_n "checking whether basic kmem accounting is enabled... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug_kmem" >&5
+$as_echo "$enable_debug_kmem" >&6; }
+
+
+       # Check whether --enable-debug-kmem-tracking was given.
+if test "${enable_debug_kmem_tracking+set}" = set; then :
+  enableval=$enable_debug_kmem_tracking;
+else
+  enable_debug_kmem_tracking=no
+fi
+
+
+       if test "x$enable_debug_kmem_tracking" = xyes; then :
+
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_KMEM_TRACKING"
+               DEBUG_KMEM_TRACKING="_with_debug_kmem_tracking"
+
+$as_echo "#define DEBUG_KMEM_TRACKING 1" >>confdefs.h
+
+
+else
+
+               DEBUG_KMEM_TRACKING="_without_debug_kmem_tracking"
+
+fi
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether detailed kmem tracking is enabled" >&5
+$as_echo_n "checking whether detailed kmem tracking is enabled... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug_kmem_tracking" >&5
+$as_echo "$enable_debug_kmem_tracking" >&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
+
+
+       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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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(
+                                   "$SPL_META_LICENSE");
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+
+$as_echo "#define SPL_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
+
+
+       # Check whether --enable-atomic-spinlocks was given.
+if test "${enable_atomic_spinlocks+set}" = set; then :
+  enableval=$enable_atomic_spinlocks;
+else
+  enable_atomic_spinlocks=check
+fi
+
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               atomic64_t *ptr __attribute__ ((unused));
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 :
+
+               have_atomic64_t=yes
+
+$as_echo "#define HAVE_ATOMIC64_T 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+               have_atomic64_t=no
+
+
+
+fi
+       rm -Rf build
+
+
+
+       if test "x$enable_atomic_spinlocks" = xcheck; then :
+
+               if test "x$have_atomic64_t" = xyes; then :
+
+                       enable_atomic_spinlocks=no
+
+else
+
+                       enable_atomic_spinlocks=yes
+
+fi
+
+fi
+
+       if test "x$enable_atomic_spinlocks" = xyes; then :
+
+
+$as_echo "#define ATOMIC_SPINLOCK 1" >>confdefs.h
+
+
+else
+
+               if test "x$have_atomic64_t" = xno; 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 $? "--disable-atomic-spinlocks given but required atomic64 support is unavailable
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+
+fi
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether atomic types use spinlocks" >&5
+$as_echo_n "checking whether atomic types use spinlocks... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_atomic_spinlocks" >&5
+$as_echo "$enable_atomic_spinlocks" >&6; }
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel defines atomic64_t" >&5
+$as_echo_n "checking whether kernel defines atomic64_t... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_atomic64_t" >&5
+$as_echo "$have_atomic64_t" >&6; }
+
+
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether old 2-argument shrinker exists" >&5
+$as_echo_n "checking whether old 2-argument shrinker exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/mm.h>
+
+               int shrinker_cb(int nr_to_scan, gfp_t gfp_mask);
+
+int
+main (void)
+{
+
+               struct shrinker cache_shrinker = {
+                       .shrink = shrinker_cb,
+                       .seeks = DEFAULT_SEEKS,
+               };
+               register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_OLD_SHRINKER_CALLBACK 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 old 3-argument shrinker exists" >&5
+$as_echo_n "checking whether old 3-argument shrinker exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/mm.h>
+
+                       int shrinker_cb(struct shrinker *, int nr_to_scan,
+                                       gfp_t gfp_mask);
+
+int
+main (void)
+{
+
+                       struct shrinker cache_shrinker = {
+                               .shrink = shrinker_cb,
+                               .seeks = DEFAULT_SEEKS,
+                       };
+                       register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_3ARGS_SHRINKER_CALLBACK 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 new 2-argument shrinker exists" >&5
+$as_echo_n "checking whether new 2-argument shrinker exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                               #include <linux/mm.h>
+
+                               int shrinker_cb(struct shrinker *,
+                                               struct shrink_control *sc);
+
+int
+main (void)
+{
+
+                               struct shrinker cache_shrinker = {
+                                       .shrink = shrinker_cb,
+                                       .seeks = DEFAULT_SEEKS,
+                               };
+                               register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_NEW_SHRINKER_CALLBACK 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 ->count_objects callback exists" >&5
+$as_echo_n "checking whether ->count_objects callback exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                                       #include <linux/mm.h>
+
+                                       unsigned long shrinker_cb(
+                                               struct shrinker *,
+                                               struct shrink_control *sc);
+
+int
+main (void)
+{
+
+                                       struct shrinker cache_shrinker = {
+                                               .count_objects = shrinker_cb,
+                                               .scan_objects = shrinker_cb,
+                                               .seeks = DEFAULT_SEEKS,
+                                       };
+                                       register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_SPLIT_SHRINKER_CALLBACK 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                                       as_fn_error $? "error" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+       EXTRA_KCFLAGS="$tmp_flags"
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct ctl_table has ctl_name" >&5
+$as_echo_n "checking whether struct ctl_table has ctl_name... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sysctl.h>
+
+int
+main (void)
+{
+
+               struct ctl_table ctl __attribute__ ((unused));
+               ctl.ctl_name = 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_CTL_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 CONFIG_TRIM_UNUSED_KSYM is disabled" >&5
+$as_echo_n "checking whether CONFIG_TRIM_UNUSED_KSYM is disabled... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #if defined(CONFIG_TRIM_UNUSED_KSYMS)
+               #error CONFIG_TRIM_UNUSED_KSYMS not defined
+               #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; }
+               as_fn_error $? "
+       *** This kernel has unused symbols trimming enabled, please disable.
+       *** Rebuild the kernel with CONFIG_TRIM_UNUSED_KSYMS=n set." "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether PDE_DATA() is available" >&5
+$as_echo_n "checking whether PDE_DATA() is available... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/proc_fs.h>
+
+int
+main (void)
+{
+
+               PDE_DATA(NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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:]]PDE_DATA[[:space:]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in ; do
+                       grep -q -E "EXPORT_SYMBOL.*(PDE_DATA)" \
+                               "$LINUX_OBJ/$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_PDE_DATA 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether set_fs_pwd() requires const struct path *" >&5
+$as_echo_n "checking whether set_fs_pwd() requires const struct path *... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/spinlock.h>
+               #include <linux/fs_struct.h>
+               #include <linux/path.h>
+               void (*const set_fs_pwd_func)
+                       (struct fs_struct *, const struct path *)
+                       = set_fs_pwd;
+
+int
+main (void)
+{
+
+               return 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_FS_PWD_WITH_CONST 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/spinlock.h>
+                       #include <linux/fs_struct.h>
+                       #include <linux/path.h>
+                       void (*const set_fs_pwd_func)
+                               (struct fs_struct *, struct path *)
+                               = set_fs_pwd;
+
+int
+main (void)
+{
+
+                       return 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_fn_error $? "unknown" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+       EXTRA_KCFLAGS="$tmp_flags"
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_unlink() wants 2 args" >&5
+$as_echo_n "checking whether vfs_unlink() wants 2 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_unlink((struct inode *) NULL, (struct dentry *) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_VFS_UNLINK 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 vfs_unlink() wants 3 args" >&5
+$as_echo_n "checking whether vfs_unlink() wants 3 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       vfs_unlink((struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode **) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_3ARGS_VFS_UNLINK 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                       as_fn_error $? "no" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_rename() wants 4 args" >&5
+$as_echo_n "checking whether vfs_rename() wants 4 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_rename((struct inode *) NULL, (struct dentry *) NULL,
+                       (struct inode *) NULL, (struct dentry *) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_4ARGS_VFS_RENAME 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 vfs_rename() wants 5 args" >&5
+$as_echo_n "checking whether vfs_rename() wants 5 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       vfs_rename((struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode **) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_5ARGS_VFS_RENAME 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 vfs_rename() wants 6 args" >&5
+$as_echo_n "checking whether vfs_rename() wants 6 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                               vfs_rename((struct inode *) NULL,
+                                       (struct dentry *) NULL,
+                                       (struct inode *) NULL,
+                                       (struct dentry *) NULL,
+                                       (struct inode **) NULL,
+                                       (unsigned int) 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_VFS_RENAME 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                               as_fn_error $? "no" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_fsync() wants 2 args" >&5
+$as_echo_n "checking whether vfs_fsync() wants 2 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_fsync(NULL, 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_VFS_FSYNC 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 truncate_range() inode operation is available" >&5
+$as_echo_n "checking whether truncate_range() inode operation is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               struct inode_operations ops;
+               ops.truncate_range = NULL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 struct fs_struct uses spinlock_t" >&5
+$as_echo_n "checking whether struct fs_struct uses spinlock_t... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sched.h>
+               #include <linux/fs_struct.h>
+
+int
+main (void)
+{
+
+               static struct fs_struct fs;
+               spin_lock_init(&fs.lock);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_FS_STRUCT_SPINLOCK 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 kuid_t/kgid_t is available" >&5
+$as_echo_n "checking whether kuid_t/kgid_t is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/uidgid.h>
+
+int
+main (void)
+{
+
+               kuid_t userid = KUIDT_INIT(0);
+               kgid_t groupid = KGIDT_INIT(0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 :
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/uidgid.h>
+
+int
+main (void)
+{
+
+                       kuid_t userid = 0;
+                       kgid_t groupid = 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; optional" >&5
+$as_echo "yes; optional" >&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; mandatory" >&5
+$as_echo "yes; mandatory" >&6; }
+
+$as_echo "#define HAVE_KUIDGID_T 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 __put_task_struct() is available" >&5
+$as_echo_n "checking whether __put_task_struct() is available... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sched.h>
+
+int
+main (void)
+{
+
+               __put_task_struct(NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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:]]__put_task_struct[[:space:]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in ; do
+                       grep -q -E "EXPORT_SYMBOL.*(__put_task_struct)" \
+                               "$LINUX_OBJ/$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_PUT_TASK_STRUCT 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+
+
+       { $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>
+
+int
+main (void)
+{
+
+               long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+               struct file_operations fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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>
+
+int
+main (void)
+{
+
+               long (*fallocate) (struct inode *, int, loff_t, loff_t) = NULL;
+               struct inode_operations fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 fops->fallocate() exists" >&5
+$as_echo_n "checking whether fops->fallocate() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+               struct file_operations_no_const fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 CONFIG_ZLIB_INFLATE is defined" >&5
+$as_echo_n "checking whether CONFIG_ZLIB_INFLATE is defined... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #if !defined(CONFIG_ZLIB_INFLATE) && \
+                   !defined(CONFIG_ZLIB_INFLATE_MODULE)
+               #error CONFIG_ZLIB_INFLATE not defined
+               #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; }
+               as_fn_error $? "
+       *** This kernel does not include the required zlib inflate support.
+       *** Rebuild the kernel with CONFIG_ZLIB_INFLATE=y|m set." "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CONFIG_ZLIB_DEFLATE is defined" >&5
+$as_echo_n "checking whether CONFIG_ZLIB_DEFLATE is defined... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #if !defined(CONFIG_ZLIB_DEFLATE) && \
+                   !defined(CONFIG_ZLIB_DEFLATE_MODULE)
+               #error CONFIG_ZLIB_DEFLATE not defined
+               #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; }
+               as_fn_error $? "
+       *** This kernel does not include the required zlib deflate support.
+       *** Rebuild the kernel with CONFIG_ZLIB_DEFLATE=y|m set." "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether zlib_deflate_workspacesize() wants 2 args" >&5
+$as_echo_n "checking whether zlib_deflate_workspacesize() wants 2 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/zlib.h>
+
+int
+main (void)
+{
+
+               return zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE 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 struct shrink_control exists" >&5
+$as_echo_n "checking whether struct shrink_control exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/mm.h>
+
+int
+main (void)
+{
+
+               struct shrink_control sc __attribute__ ((unused));
+
+               sc.nr_to_scan = 0;
+               sc.gfp_mask = GFP_KERNEL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_CONTROL_STRUCT 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 struct rw_semaphore member wait_lock is raw" >&5
+$as_echo_n "checking whether struct rw_semaphore member wait_lock is raw... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/rwsem.h>
+
+int
+main (void)
+{
+
+               struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+               raw_spinlock_t dummy_lock __attribute__ ((unused));
+               dummy_semaphore.wait_lock = dummy_lock;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 RWSEM_SPINLOCK_IS_RAW 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 struct rw_semaphore has member activity" >&5
+$as_echo_n "checking whether struct rw_semaphore has member activity... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/rwsem.h>
+
+int
+main (void)
+{
+
+               struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+               dummy_semaphore.activity = 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_RWSEM_ACTIVITY 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 struct rw_semaphore has atomic_long_t member count" >&5
+$as_echo_n "checking whether struct rw_semaphore has atomic_long_t member count... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/rwsem.h>
+
+int
+main (void)
+{
+
+               DECLARE_RWSEM(dummy_semaphore);
+               (void) atomic_long_read(&dummy_semaphore.count);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_RWSEM_ATOMIC_LONG_COUNT 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 header linux/sched/rt.h exists" >&5
+$as_echo_n "checking whether header linux/sched/rt.h exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sched.h>
+               #include <linux/sched/rt.h>
+
+int
+main (void)
+{
+
+               return 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_SCHED_RT_HEADER 1" >>confdefs.h
+
+               { $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; }
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_getattr() wants" >&5
+$as_echo_n "checking whether vfs_getattr() wants... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_getattr((struct path *) NULL,
+                       (struct kstat *)NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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: 2 args" >&5
+$as_echo "2 args" >&6; }
+
+$as_echo "#define HAVE_2ARGS_VFS_GETATTR 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       vfs_getattr((struct vfsmount *)NULL,
+                               (struct dentry *)NULL,
+                               (struct kstat *)NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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: 3 args" >&5
+$as_echo "3 args" >&6; }
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                       as_fn_error $? "unknown" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether usleep_range() is available" >&5
+$as_echo_n "checking whether usleep_range() is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/delay.h>
+
+int
+main (void)
+{
+
+               usleep_range(0, 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_USLEEP_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 struct kmem_cache has allocflags" >&5
+$as_echo_n "checking whether struct kmem_cache has allocflags... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/slab.h>
+
+int
+main (void)
+{
+
+               struct kmem_cache cachep __attribute__ ((unused));
+               cachep.allocflags = GFP_KERNEL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_KMEM_CACHE_ALLOCFLAGS 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 struct kmem_cache has gfpflags" >&5
+$as_echo_n "checking whether struct kmem_cache has gfpflags... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/slab.h>
+
+int
+main (void)
+{
+
+                       struct kmem_cache cachep __attribute__ ((unused));
+                       cachep.gfpflags = GFP_KERNEL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_KMEM_CACHE_GFPFLAGS 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
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wait_on_bit() takes an action" >&5
+$as_echo_n "checking whether wait_on_bit() takes an action... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/wait.h>
+
+int
+main (void)
+{
+
+               int (*action)(void *) = NULL;
+               wait_on_bit(NULL, 0, action, 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_WAIT_ON_BIT_ACTION 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 inode_lock_shared() exists" >&5
+$as_echo_n "checking whether inode_lock_shared() exists... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               struct inode *inode = NULL;
+               inode_lock_shared(inode);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_LOCK_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; }
+
+
+
+fi
+       rm -Rf build
+
+
+       EXTRA_KCFLAGS="$tmp_flags"
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mutex has owner" >&5
+$as_echo_n "checking whether mutex has owner... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/mutex.h>
+               #include <linux/spinlock.h>
+
+int
+main (void)
+{
+
+               DEFINE_MUTEX(m);
+               struct task_struct *t __attribute__ ((unused));
+               t = m.owner;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_MUTEX_OWNER 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 group_info->gid exists" >&5
+$as_echo_n "checking whether group_info->gid exists... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/cred.h>
+
+int
+main (void)
+{
+
+               struct group_info *gi = groups_alloc(1);
+               gi->gid[0] = KGIDT_INIT(0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_GROUP_INFO_GID 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"
+
+ ;;
+               user)      ;;
+               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; }
+
+
+
+
+       if test "${LINUX_OBJ}" != "${LINUX}"; then
+               KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
+       fi
+
+
+       KERNELCPPFLAGS="$KERNELCPPFLAGS -Wstrict-prototypes"
+
+
+
+       { $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"
+               DEBUG_CFLAGS="-DDEBUG -Werror"
+               DEBUG_SPL="_with_debug"
+
+else
+
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DNDEBUG"
+               DEBUG_CFLAGS="-DNDEBUG"
+               DEBUG_SPL="_without_debug"
+
+fi
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug" >&5
+$as_echo "$enable_debug" >&6; }
+
+
+       # Check whether --enable-debug-kmem was given.
+if test "${enable_debug_kmem+set}" = set; then :
+  enableval=$enable_debug_kmem;
+else
+  enable_debug_kmem=no
+fi
+
+
+       if test "x$enable_debug_kmem" = xyes; then :
+
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_KMEM"
+               DEBUG_KMEM="_with_debug_kmem"
+
+$as_echo "#define DEBUG_KMEM 1" >>confdefs.h
+
+
+else
+
+               DEBUG_KMEM="_without_debug_kmem"
+
+fi
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether basic kmem accounting is enabled" >&5
+$as_echo_n "checking whether basic kmem accounting is enabled... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug_kmem" >&5
+$as_echo "$enable_debug_kmem" >&6; }
+
+
+       # Check whether --enable-debug-kmem-tracking was given.
+if test "${enable_debug_kmem_tracking+set}" = set; then :
+  enableval=$enable_debug_kmem_tracking;
+else
+  enable_debug_kmem_tracking=no
+fi
+
+
+       if test "x$enable_debug_kmem_tracking" = xyes; then :
+
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_KMEM_TRACKING"
+               DEBUG_KMEM_TRACKING="_with_debug_kmem_tracking"
+
+$as_echo "#define DEBUG_KMEM_TRACKING 1" >>confdefs.h
+
+
+else
+
+               DEBUG_KMEM_TRACKING="_without_debug_kmem_tracking"
+
+fi
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether detailed kmem tracking is enabled" >&5
+$as_echo_n "checking whether detailed kmem tracking is enabled... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug_kmem_tracking" >&5
+$as_echo "$enable_debug_kmem_tracking" >&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
+
+
+       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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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(
+                                   "$SPL_META_LICENSE");
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+
+$as_echo "#define SPL_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
+
+
+       # Check whether --enable-atomic-spinlocks was given.
+if test "${enable_atomic_spinlocks+set}" = set; then :
+  enableval=$enable_atomic_spinlocks;
+else
+  enable_atomic_spinlocks=check
+fi
+
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               atomic64_t *ptr __attribute__ ((unused));
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 :
+
+               have_atomic64_t=yes
+
+$as_echo "#define HAVE_ATOMIC64_T 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+               have_atomic64_t=no
+
+
+
+fi
+       rm -Rf build
+
+
+
+       if test "x$enable_atomic_spinlocks" = xcheck; then :
+
+               if test "x$have_atomic64_t" = xyes; then :
+
+                       enable_atomic_spinlocks=no
+
+else
+
+                       enable_atomic_spinlocks=yes
+
+fi
+
+fi
+
+       if test "x$enable_atomic_spinlocks" = xyes; then :
+
+
+$as_echo "#define ATOMIC_SPINLOCK 1" >>confdefs.h
+
+
+else
+
+               if test "x$have_atomic64_t" = xno; 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 $? "--disable-atomic-spinlocks given but required atomic64 support is unavailable
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+
+fi
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether atomic types use spinlocks" >&5
+$as_echo_n "checking whether atomic types use spinlocks... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_atomic_spinlocks" >&5
+$as_echo "$enable_atomic_spinlocks" >&6; }
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel defines atomic64_t" >&5
+$as_echo_n "checking whether kernel defines atomic64_t... " >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_atomic64_t" >&5
+$as_echo "$have_atomic64_t" >&6; }
+
+
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether old 2-argument shrinker exists" >&5
+$as_echo_n "checking whether old 2-argument shrinker exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/mm.h>
+
+               int shrinker_cb(int nr_to_scan, gfp_t gfp_mask);
+
+int
+main (void)
+{
+
+               struct shrinker cache_shrinker = {
+                       .shrink = shrinker_cb,
+                       .seeks = DEFAULT_SEEKS,
+               };
+               register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_OLD_SHRINKER_CALLBACK 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 old 3-argument shrinker exists" >&5
+$as_echo_n "checking whether old 3-argument shrinker exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/mm.h>
+
+                       int shrinker_cb(struct shrinker *, int nr_to_scan,
+                                       gfp_t gfp_mask);
+
+int
+main (void)
+{
+
+                       struct shrinker cache_shrinker = {
+                               .shrink = shrinker_cb,
+                               .seeks = DEFAULT_SEEKS,
+                       };
+                       register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_3ARGS_SHRINKER_CALLBACK 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 new 2-argument shrinker exists" >&5
+$as_echo_n "checking whether new 2-argument shrinker exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                               #include <linux/mm.h>
+
+                               int shrinker_cb(struct shrinker *,
+                                               struct shrink_control *sc);
+
+int
+main (void)
+{
+
+                               struct shrinker cache_shrinker = {
+                                       .shrink = shrinker_cb,
+                                       .seeks = DEFAULT_SEEKS,
+                               };
+                               register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_NEW_SHRINKER_CALLBACK 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 ->count_objects callback exists" >&5
+$as_echo_n "checking whether ->count_objects callback exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                                       #include <linux/mm.h>
+
+                                       unsigned long shrinker_cb(
+                                               struct shrinker *,
+                                               struct shrink_control *sc);
+
+int
+main (void)
+{
+
+                                       struct shrinker cache_shrinker = {
+                                               .count_objects = shrinker_cb,
+                                               .scan_objects = shrinker_cb,
+                                               .seeks = DEFAULT_SEEKS,
+                                       };
+                                       register_shrinker(&cache_shrinker);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_SPLIT_SHRINKER_CALLBACK 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                                       as_fn_error $? "error" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+       EXTRA_KCFLAGS="$tmp_flags"
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct ctl_table has ctl_name" >&5
+$as_echo_n "checking whether struct ctl_table has ctl_name... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sysctl.h>
+
+int
+main (void)
+{
+
+               struct ctl_table ctl __attribute__ ((unused));
+               ctl.ctl_name = 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_CTL_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 CONFIG_TRIM_UNUSED_KSYM is disabled" >&5
+$as_echo_n "checking whether CONFIG_TRIM_UNUSED_KSYM is disabled... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #if defined(CONFIG_TRIM_UNUSED_KSYMS)
+               #error CONFIG_TRIM_UNUSED_KSYMS not defined
+               #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; }
+               as_fn_error $? "
+       *** This kernel has unused symbols trimming enabled, please disable.
+       *** Rebuild the kernel with CONFIG_TRIM_UNUSED_KSYMS=n set." "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether PDE_DATA() is available" >&5
+$as_echo_n "checking whether PDE_DATA() is available... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/proc_fs.h>
+
+int
+main (void)
+{
+
+               PDE_DATA(NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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:]]PDE_DATA[[:space:]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in ; do
+                       grep -q -E "EXPORT_SYMBOL.*(PDE_DATA)" \
+                               "$LINUX_OBJ/$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_PDE_DATA 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether set_fs_pwd() requires const struct path *" >&5
+$as_echo_n "checking whether set_fs_pwd() requires const struct path *... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/spinlock.h>
+               #include <linux/fs_struct.h>
+               #include <linux/path.h>
+               void (*const set_fs_pwd_func)
+                       (struct fs_struct *, const struct path *)
+                       = set_fs_pwd;
+
+int
+main (void)
+{
+
+               return 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_FS_PWD_WITH_CONST 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/spinlock.h>
+                       #include <linux/fs_struct.h>
+                       #include <linux/path.h>
+                       void (*const set_fs_pwd_func)
+                               (struct fs_struct *, struct path *)
+                               = set_fs_pwd;
+
+int
+main (void)
+{
+
+                       return 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_fn_error $? "unknown" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+       EXTRA_KCFLAGS="$tmp_flags"
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_unlink() wants 2 args" >&5
+$as_echo_n "checking whether vfs_unlink() wants 2 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_unlink((struct inode *) NULL, (struct dentry *) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_VFS_UNLINK 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 vfs_unlink() wants 3 args" >&5
+$as_echo_n "checking whether vfs_unlink() wants 3 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       vfs_unlink((struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode **) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_3ARGS_VFS_UNLINK 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                       as_fn_error $? "no" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_rename() wants 4 args" >&5
+$as_echo_n "checking whether vfs_rename() wants 4 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_rename((struct inode *) NULL, (struct dentry *) NULL,
+                       (struct inode *) NULL, (struct dentry *) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_4ARGS_VFS_RENAME 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 vfs_rename() wants 5 args" >&5
+$as_echo_n "checking whether vfs_rename() wants 5 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       vfs_rename((struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode *) NULL,
+                               (struct dentry *) NULL,
+                               (struct inode **) NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_5ARGS_VFS_RENAME 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 vfs_rename() wants 6 args" >&5
+$as_echo_n "checking whether vfs_rename() wants 6 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                               vfs_rename((struct inode *) NULL,
+                                       (struct dentry *) NULL,
+                                       (struct inode *) NULL,
+                                       (struct dentry *) NULL,
+                                       (struct inode **) NULL,
+                                       (unsigned int) 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_VFS_RENAME 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                               as_fn_error $? "no" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_fsync() wants 2 args" >&5
+$as_echo_n "checking whether vfs_fsync() wants 2 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_fsync(NULL, 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_VFS_FSYNC 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 truncate_range() inode operation is available" >&5
+$as_echo_n "checking whether truncate_range() inode operation is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               struct inode_operations ops;
+               ops.truncate_range = NULL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 struct fs_struct uses spinlock_t" >&5
+$as_echo_n "checking whether struct fs_struct uses spinlock_t... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sched.h>
+               #include <linux/fs_struct.h>
+
+int
+main (void)
+{
+
+               static struct fs_struct fs;
+               spin_lock_init(&fs.lock);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_FS_STRUCT_SPINLOCK 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 kuid_t/kgid_t is available" >&5
+$as_echo_n "checking whether kuid_t/kgid_t is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/uidgid.h>
+
+int
+main (void)
+{
+
+               kuid_t userid = KUIDT_INIT(0);
+               kgid_t groupid = KGIDT_INIT(0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 :
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/uidgid.h>
+
+int
+main (void)
+{
+
+                       kuid_t userid = 0;
+                       kgid_t groupid = 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; optional" >&5
+$as_echo "yes; optional" >&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; mandatory" >&5
+$as_echo "yes; mandatory" >&6; }
+
+$as_echo "#define HAVE_KUIDGID_T 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 __put_task_struct() is available" >&5
+$as_echo_n "checking whether __put_task_struct() is available... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sched.h>
+
+int
+main (void)
+{
+
+               __put_task_struct(NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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:]]__put_task_struct[[:space:]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in ; do
+                       grep -q -E "EXPORT_SYMBOL.*(__put_task_struct)" \
+                               "$LINUX_OBJ/$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_PUT_TASK_STRUCT 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+
+
+       { $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>
+
+int
+main (void)
+{
+
+               long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+               struct file_operations fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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>
+
+int
+main (void)
+{
+
+               long (*fallocate) (struct inode *, int, loff_t, loff_t) = NULL;
+               struct inode_operations fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 fops->fallocate() exists" >&5
+$as_echo_n "checking whether fops->fallocate() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+               struct file_operations_no_const fops __attribute__ ((unused)) = {
+                       .fallocate = fallocate,
+               };
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 CONFIG_ZLIB_INFLATE is defined" >&5
+$as_echo_n "checking whether CONFIG_ZLIB_INFLATE is defined... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #if !defined(CONFIG_ZLIB_INFLATE) && \
+                   !defined(CONFIG_ZLIB_INFLATE_MODULE)
+               #error CONFIG_ZLIB_INFLATE not defined
+               #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; }
+               as_fn_error $? "
+       *** This kernel does not include the required zlib inflate support.
+       *** Rebuild the kernel with CONFIG_ZLIB_INFLATE=y|m set." "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CONFIG_ZLIB_DEFLATE is defined" >&5
+$as_echo_n "checking whether CONFIG_ZLIB_DEFLATE is defined... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #if !defined(CONFIG_ZLIB_DEFLATE) && \
+                   !defined(CONFIG_ZLIB_DEFLATE_MODULE)
+               #error CONFIG_ZLIB_DEFLATE not defined
+               #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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; }
+               as_fn_error $? "
+       *** This kernel does not include the required zlib deflate support.
+       *** Rebuild the kernel with CONFIG_ZLIB_DEFLATE=y|m set." "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether zlib_deflate_workspacesize() wants 2 args" >&5
+$as_echo_n "checking whether zlib_deflate_workspacesize() wants 2 args... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/zlib.h>
+
+int
+main (void)
+{
+
+               return zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE 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 struct shrink_control exists" >&5
+$as_echo_n "checking whether struct shrink_control exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/mm.h>
+
+int
+main (void)
+{
+
+               struct shrink_control sc __attribute__ ((unused));
+
+               sc.nr_to_scan = 0;
+               sc.gfp_mask = GFP_KERNEL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_CONTROL_STRUCT 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 struct rw_semaphore member wait_lock is raw" >&5
+$as_echo_n "checking whether struct rw_semaphore member wait_lock is raw... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/rwsem.h>
+
+int
+main (void)
+{
+
+               struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+               raw_spinlock_t dummy_lock __attribute__ ((unused));
+               dummy_semaphore.wait_lock = dummy_lock;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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 RWSEM_SPINLOCK_IS_RAW 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 struct rw_semaphore has member activity" >&5
+$as_echo_n "checking whether struct rw_semaphore has member activity... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/rwsem.h>
+
+int
+main (void)
+{
+
+               struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+               dummy_semaphore.activity = 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_RWSEM_ACTIVITY 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 struct rw_semaphore has atomic_long_t member count" >&5
+$as_echo_n "checking whether struct rw_semaphore has atomic_long_t member count... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/rwsem.h>
+
+int
+main (void)
+{
+
+               DECLARE_RWSEM(dummy_semaphore);
+               (void) atomic_long_read(&dummy_semaphore.count);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_RWSEM_ATOMIC_LONG_COUNT 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 header linux/sched/rt.h exists" >&5
+$as_echo_n "checking whether header linux/sched/rt.h exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/sched.h>
+               #include <linux/sched/rt.h>
+
+int
+main (void)
+{
+
+               return 0;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_SCHED_RT_HEADER 1" >>confdefs.h
+
+               { $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; }
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vfs_getattr() wants" >&5
+$as_echo_n "checking whether vfs_getattr() wants... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               vfs_getattr((struct path *) NULL,
+                       (struct kstat *)NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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: 2 args" >&5
+$as_echo "2 args" >&6; }
+
+$as_echo "#define HAVE_2ARGS_VFS_GETATTR 1" >>confdefs.h
+
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       vfs_getattr((struct vfsmount *)NULL,
+                               (struct dentry *)NULL,
+                               (struct kstat *)NULL);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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: 3 args" >&5
+$as_echo "3 args" >&6; }
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+                       as_fn_error $? "unknown" "$LINENO" 5
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether usleep_range() is available" >&5
+$as_echo_n "checking whether usleep_range() is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/delay.h>
+
+int
+main (void)
+{
+
+               usleep_range(0, 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_USLEEP_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 struct kmem_cache has allocflags" >&5
+$as_echo_n "checking whether struct kmem_cache has allocflags... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/slab.h>
+
+int
+main (void)
+{
+
+               struct kmem_cache cachep __attribute__ ((unused));
+               cachep.allocflags = GFP_KERNEL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_KMEM_CACHE_ALLOCFLAGS 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 struct kmem_cache has gfpflags" >&5
+$as_echo_n "checking whether struct kmem_cache has gfpflags... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/slab.h>
+
+int
+main (void)
+{
+
+                       struct kmem_cache cachep __attribute__ ((unused));
+                       cachep.gfpflags = GFP_KERNEL;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_KMEM_CACHE_GFPFLAGS 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
+
+
+
+
+
+fi
+       rm -Rf build
+
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wait_on_bit() takes an action" >&5
+$as_echo_n "checking whether wait_on_bit() takes an action... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/wait.h>
+
+int
+main (void)
+{
+
+               int (*action)(void *) = NULL;
+               wait_on_bit(NULL, 0, action, 0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_WAIT_ON_BIT_ACTION 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 inode_lock_shared() exists" >&5
+$as_echo_n "checking whether inode_lock_shared() exists... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               struct inode *inode = NULL;
+               inode_lock_shared(inode);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_LOCK_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; }
+
+
+
+fi
+       rm -Rf build
+
+
+       EXTRA_KCFLAGS="$tmp_flags"
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mutex has owner" >&5
+$as_echo_n "checking whether mutex has owner... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/mutex.h>
+               #include <linux/spinlock.h>
+
+int
+main (void)
+{
+
+               DEFINE_MUTEX(m);
+               struct task_struct *t __attribute__ ((unused));
+               t = m.owner;
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_MUTEX_OWNER 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 group_info->gid exists" >&5
+$as_echo_n "checking whether group_info->gid exists... " >&6; }
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-Werror"
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/cred.h>
+
+int
+main (void)
+{
+
+               struct group_info *gi = groups_alloc(1);
+               gi->gid[0] = KGIDT_INIT(0);
+
+  ;
+  return 0;
+}
+
+_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 build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $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_GROUP_INFO_GID 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"
+
+
+                          ;;
+               srpm)                        ;;
+               *)
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Error!" >&5
+$as_echo "Error!" >&6; }
+               as_fn_error $? "Bad value \"$SPL_CONFIG\" for --with-config,
+                            user kernel|user|all|srpm" "$LINENO" 5 ;;
+       esac
+
+        if test "$SPL_CONFIG" = user -o "$SPL_CONFIG" = all; then
+  CONFIG_USER_TRUE=
+  CONFIG_USER_FALSE='#'
+else
+  CONFIG_USER_TRUE='#'
+  CONFIG_USER_FALSE=
+fi
+
+        if test "$SPL_CONFIG" = kernel -o "$SPL_CONFIG" = all &&
+                      test "x$enable_linux_builtin" != xyes ; then
+  CONFIG_KERNEL_TRUE=
+  CONFIG_KERNEL_FALSE='#'
+else
+  CONFIG_KERNEL_TRUE='#'
+  CONFIG_KERNEL_FALSE=
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile man/Makefile man/man1/Makefile man/man5/Makefile lib/Makefile cmd/Makefile module/Makefile module/spl/Makefile module/splat/Makefile include/Makefile include/fs/Makefile include/linux/Makefile include/rpc/Makefile include/sharefs/Makefile include/sys/Makefile include/sys/fm/Makefile include/sys/fs/Makefile include/sys/sysevent/Makefile include/util/Makefile include/vm/Makefile scripts/Makefile rpm/Makefile rpm/redhat/Makefile rpm/redhat/spl.spec rpm/redhat/spl-kmod.spec rpm/redhat/spl-dkms.spec rpm/generic/Makefile rpm/generic/spl.spec rpm/generic/spl-kmod.spec rpm/generic/spl-dkms.spec spl.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 "${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 spl $as_me 0.6.5.9, 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="\\
+spl config.status 0.6.5.9
+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
+    "spl_config.h") CONFIG_HEADERS="$CONFIG_HEADERS spl_config.h" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES 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" ;;
+    "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+    "cmd/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/Makefile" ;;
+    "module/Makefile") CONFIG_FILES="$CONFIG_FILES module/Makefile" ;;
+    "module/spl/Makefile") CONFIG_FILES="$CONFIG_FILES module/spl/Makefile" ;;
+    "module/splat/Makefile") CONFIG_FILES="$CONFIG_FILES module/splat/Makefile" ;;
+    "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
+    "include/fs/Makefile") CONFIG_FILES="$CONFIG_FILES include/fs/Makefile" ;;
+    "include/linux/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/Makefile" ;;
+    "include/rpc/Makefile") CONFIG_FILES="$CONFIG_FILES include/rpc/Makefile" ;;
+    "include/sharefs/Makefile") CONFIG_FILES="$CONFIG_FILES include/sharefs/Makefile" ;;
+    "include/sys/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/Makefile" ;;
+    "include/sys/fm/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/fm/Makefile" ;;
+    "include/sys/fs/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/fs/Makefile" ;;
+    "include/sys/sysevent/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/sysevent/Makefile" ;;
+    "include/util/Makefile") CONFIG_FILES="$CONFIG_FILES include/util/Makefile" ;;
+    "include/vm/Makefile") CONFIG_FILES="$CONFIG_FILES include/vm/Makefile" ;;
+    "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
+    "rpm/Makefile") CONFIG_FILES="$CONFIG_FILES rpm/Makefile" ;;
+    "rpm/redhat/Makefile") CONFIG_FILES="$CONFIG_FILES rpm/redhat/Makefile" ;;
+    "rpm/redhat/spl.spec") CONFIG_FILES="$CONFIG_FILES rpm/redhat/spl.spec" ;;
+    "rpm/redhat/spl-kmod.spec") CONFIG_FILES="$CONFIG_FILES rpm/redhat/spl-kmod.spec" ;;
+    "rpm/redhat/spl-dkms.spec") CONFIG_FILES="$CONFIG_FILES rpm/redhat/spl-dkms.spec" ;;
+    "rpm/generic/Makefile") CONFIG_FILES="$CONFIG_FILES rpm/generic/Makefile" ;;
+    "rpm/generic/spl.spec") CONFIG_FILES="$CONFIG_FILES rpm/generic/spl.spec" ;;
+    "rpm/generic/spl-kmod.spec") CONFIG_FILES="$CONFIG_FILES rpm/generic/spl-kmod.spec" ;;
+    "rpm/generic/spl-dkms.spec") CONFIG_FILES="$CONFIG_FILES rpm/generic/spl-dkms.spec" ;;
+    "spl.release") CONFIG_FILES="$CONFIG_FILES spl.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
+    "spl_config.h":H)
+       (mv spl_config.h spl_config.h.tmp &&
+       awk -f ${ac_srcdir}/config/config.awk spl_config.h.tmp >spl_config.h &&
+       rm spl_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
+
diff --git a/spl/configure.ac b/spl/configure.ac
new file mode 100644 (file)
index 0000000..efeb243
--- /dev/null
@@ -0,0 +1,84 @@
+###############################################################################
+# SPL AutoConf Configuration
+###############################################################################
+# Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+# Copyright (C) 2007 The Regents of the University of California.
+# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+# UCRL-CODE-235197
+#
+# This file is part of the SPL, Solaris Porting Layer.
+# For details, see <http://zfsonlinux.org/>.
+#
+# The SPL 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.
+#
+# The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+###############################################################################
+
+AC_INIT(m4_esyscmd(grep Name META | cut -d ':' -f 2 | tr -d ' \n'),
+       m4_esyscmd(grep Version META | cut -d ':' -f 2 | tr -d ' \n'))
+AC_LANG(C)
+SPL_AC_META
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_MACRO_DIR([config])
+AC_CANONICAL_SYSTEM
+AM_MAINTAINER_MODE
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AM_INIT_AUTOMAKE
+AC_CONFIG_HEADERS([spl_config.h], [
+       (mv spl_config.h spl_config.h.tmp &&
+       awk -f ${ac_srcdir}/config/config.awk spl_config.h.tmp >spl_config.h &&
+       rm spl_config.h.tmp) || exit 1])
+
+AC_PROG_INSTALL
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+SPL_AC_LICENSE
+SPL_AC_PACKAGE
+SPL_AC_CONFIG
+
+AC_CONFIG_FILES([
+       Makefile
+       man/Makefile
+       man/man1/Makefile
+       man/man5/Makefile
+       lib/Makefile
+       cmd/Makefile
+       module/Makefile
+       module/spl/Makefile
+       module/splat/Makefile
+       include/Makefile
+       include/fs/Makefile
+       include/linux/Makefile
+       include/rpc/Makefile
+       include/sharefs/Makefile
+       include/sys/Makefile
+       include/sys/fm/Makefile
+       include/sys/fs/Makefile
+       include/sys/sysevent/Makefile
+       include/util/Makefile
+       include/vm/Makefile
+       scripts/Makefile
+       rpm/Makefile
+       rpm/redhat/Makefile
+       rpm/redhat/spl.spec
+       rpm/redhat/spl-kmod.spec
+       rpm/redhat/spl-dkms.spec
+       rpm/generic/Makefile
+       rpm/generic/spl.spec
+       rpm/generic/spl-kmod.spec
+       rpm/generic/spl-dkms.spec
+       spl.release
+])
+
+AC_OUTPUT
diff --git a/spl/copy-builtin b/spl/copy-builtin
new file mode 100755 (executable)
index 0000000..34c482b
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+set -e
+
+usage()
+{
+       echo "usage: $0 <kernel source tree>" >&2
+       exit 1
+}
+
+[ "$#" -eq 1 ] || usage
+KERNEL_DIR="$(readlink --canonicalize-existing "$1")"
+
+MODULES=()
+for MODULE_DIR in module/*
+do
+       [ -d "$MODULE_DIR" ] || continue
+       MODULES+=("${MODULE_DIR##*/}")
+done
+
+if ! [ -e 'spl_config.h' ]
+then
+       echo >&2
+       echo "    $0: you did not run configure, or you're not in the SPL source directory." >&2
+       echo "    $0: run configure with --with-linux=$KERNEL_DIR and --enable-linux-builtin." >&2
+       echo >&2
+       exit 1
+fi
+
+make clean || true
+
+rm -rf "$KERNEL_DIR/include/spl" "$KERNEL_DIR/spl"
+cp --recursive include "$KERNEL_DIR/include/spl"
+cp --recursive module "$KERNEL_DIR/spl"
+cp spl_config.h "$KERNEL_DIR/"
+cp spl.release.in "$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/spl/$MODULE/Makefile"
+       sed -i.bak '/obj =/d' "$KERNEL_DIR/spl/$MODULE/Makefile"
+       sed -i.bak '/src =/d' "$KERNEL_DIR/spl/$MODULE/Makefile"
+done
+
+cat > "$KERNEL_DIR/spl/Kconfig" <<"EOF"
+config SPL
+       tristate "Solaris Porting Layer (SPL)"
+       help
+         This is the SPL library from the ZFS On Linux project.
+
+         See http://zfsonlinux.org/
+
+         To compile this library as a module, choose M here.
+
+         If unsure, say N.
+EOF
+
+{
+       cat <<-"EOF"
+       SPL_MODULE_CFLAGS  = -I$(srctree)/include/spl
+       SPL_MODULE_CFLAGS += -include $(srctree)/spl_config.h
+       export SPL_MODULE_CFLAGS
+
+       obj-$(CONFIG_SPL) :=
+       EOF
+
+       for MODULE in "${MODULES[@]}"
+       do
+               echo 'obj-$(CONFIG_SPL) += ' "$MODULE/"
+       done
+} > "$KERNEL_DIR/spl/Kbuild"
+
+add_after()
+{
+       local FILE="$1"
+       local MARKER="$2"
+       local NEW="$3"
+       local LINE
+
+       while IFS='' read -r LINE
+       do
+               echo "$LINE"
+
+               if [ -n "$MARKER" -a "$LINE" = "$MARKER" ]
+               then
+                       echo "$NEW"
+                       MARKER=''
+                       if IFS='' read -r LINE
+                       then
+                               [ "$LINE" != "$NEW" ] && echo "$LINE"
+                       fi
+               fi
+       done < "$FILE" > "$FILE.new"
+
+       mv "$FILE.new" "$FILE"
+}
+
+add_after "$KERNEL_DIR/Kconfig" 'source "arch/$SRCARCH/Kconfig"' 'source "spl/Kconfig"'
+# We must take care to build SPL before ZFS, otherwise the symbols required
+# to link ZFS will not be available.
+sed -i 's~mm/ fs/~mm/ spl/ fs/~' "$KERNEL_DIR/Makefile"
+
+echo >&2
+echo "    $0: done." >&2
+echo "    $0: now you can build the kernel with SPL support." >&2
+echo "    $0: make sure you enable SPL support (CONFIG_SPL) before building." >&2
+echo >&2
+
diff --git a/spl/cp b/spl/cp
new file mode 100755 (executable)
index 0000000..46ff2c9
--- /dev/null
+++ b/spl/cp
@@ -0,0 +1,2 @@
+#!/bin/sh
+cp "$@"
diff --git a/spl/dkms.conf b/spl/dkms.conf
new file mode 100644 (file)
index 0000000..80058f2
--- /dev/null
@@ -0,0 +1,36 @@
+AUTOINSTALL="yes"
+PACKAGE_NAME="spl"
+PACKAGE_VERSION="0.6.5.9"
+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
+                       # This is a kpkg exception for Proxmox 2.0
+                      echo ${kernel_source_dir}
+                     fi
+                     ;;
+                   (*)
+                     echo ${kernel_source_dir}
+                     ;;
+                 esac)
+  --with-linux-obj=${kernel_source_dir}
+"
+POST_BUILD="cp
+  ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/spl_config.h
+  ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/module/Module.symvers
+  ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/${kernelver}/${arch}/
+"
+[ -d "${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build" ] && POST_INSTALL=${POST_BUILD}
+REMAKE_INITRD="no"
+MAKE[0]="make"
+BUILT_MODULE_NAME[0]="spl"
+BUILT_MODULE_LOCATION[0]="module/spl/"
+DEST_MODULE_LOCATION[0]="/extra/spl/spl"
+BUILT_MODULE_NAME[1]="splat"
+BUILT_MODULE_LOCATION[1]="module/splat/"
+DEST_MODULE_LOCATION[1]="/extra/splat/splat"
diff --git a/spl/include/Makefile.am b/spl/include/Makefile.am
new file mode 100644 (file)
index 0000000..3200222
--- /dev/null
@@ -0,0 +1,18 @@
+SUBDIRS = fs linux rpc sharefs sys util vm
+
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/splat-ctl.h \
+       $(top_srcdir)/include/spl-ctl.h \
+       $(top_srcdir)/include/strings.h \
+       $(top_srcdir)/include/unistd.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/Makefile.in b/spl/include/Makefile.in
new file mode 100644 (file)
index 0000000..9cabebd
--- /dev/null
@@ -0,0 +1,743 @@
+# 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/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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/splat-ctl.h \
+       $(top_srcdir)/include/spl-ctl.h \
+       $(top_srcdir)/include/strings.h $(top_srcdir)/include/unistd.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)"
+HEADERS = $(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 \
+       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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+SUBDIRS = fs linux rpc sharefs sys util vm
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/splat-ctl.h \
+       $(top_srcdir)/include/spl-ctl.h \
+       $(top_srcdir)/include/strings.h \
+       $(top_srcdir)/include/unistd.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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)
+
+# 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)"; 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-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
+
+.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-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
+
+.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/spl/include/fs/Makefile.am b/spl/include/fs/Makefile.am
new file mode 100644 (file)
index 0000000..e0da4b3
--- /dev/null
@@ -0,0 +1,13 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/fs/fs_subr.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/fs
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/fs/Makefile.in b/spl/include/fs/Makefile.in
new file mode 100644 (file)
index 0000000..12c9050
--- /dev/null
@@ -0,0 +1,621 @@
+# 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/fs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/fs/fs_subr.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/fs/fs_subr.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/fs
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/fs/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu include/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/fs/fs_subr.h b/spl/include/fs/fs_subr.h
new file mode 100644 (file)
index 0000000..33ccc68
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_FS_FS_SUBR_H
+#define _SPL_FS_FS_SUBR_H
+
+#endif /* SPL_FS_FS_SUBR_H */
diff --git a/spl/include/linux/Makefile.am b/spl/include/linux/Makefile.am
new file mode 100644 (file)
index 0000000..712e94e
--- /dev/null
@@ -0,0 +1,23 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/linux/bitops_compat.h \
+       $(top_srcdir)/include/linux/compiler_compat.h \
+       $(top_srcdir)/include/linux/delay_compat.h \
+       $(top_srcdir)/include/linux/file_compat.h \
+       $(top_srcdir)/include/linux/list_compat.h \
+       $(top_srcdir)/include/linux/math64_compat.h \
+       $(top_srcdir)/include/linux/mm_compat.h \
+       $(top_srcdir)/include/linux/proc_compat.h \
+       $(top_srcdir)/include/linux/rwsem_compat.h \
+       $(top_srcdir)/include/linux/wait_compat.h \
+       $(top_srcdir)/include/linux/zlib_compat.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/linux
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/linux/Makefile.in b/spl/include/linux/Makefile.in
new file mode 100644 (file)
index 0000000..603dda8
--- /dev/null
@@ -0,0 +1,641 @@
+# 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/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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/bitops_compat.h \
+       $(top_srcdir)/include/linux/compiler_compat.h \
+       $(top_srcdir)/include/linux/delay_compat.h \
+       $(top_srcdir)/include/linux/file_compat.h \
+       $(top_srcdir)/include/linux/list_compat.h \
+       $(top_srcdir)/include/linux/math64_compat.h \
+       $(top_srcdir)/include/linux/mm_compat.h \
+       $(top_srcdir)/include/linux/proc_compat.h \
+       $(top_srcdir)/include/linux/rwsem_compat.h \
+       $(top_srcdir)/include/linux/wait_compat.h \
+       $(top_srcdir)/include/linux/zlib_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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/linux/bitops_compat.h \
+       $(top_srcdir)/include/linux/compiler_compat.h \
+       $(top_srcdir)/include/linux/delay_compat.h \
+       $(top_srcdir)/include/linux/file_compat.h \
+       $(top_srcdir)/include/linux/list_compat.h \
+       $(top_srcdir)/include/linux/math64_compat.h \
+       $(top_srcdir)/include/linux/mm_compat.h \
+       $(top_srcdir)/include/linux/proc_compat.h \
+       $(top_srcdir)/include/linux/rwsem_compat.h \
+       $(top_srcdir)/include/linux/wait_compat.h \
+       $(top_srcdir)/include/linux/zlib_compat.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/linux
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/linux/bitops_compat.h b/spl/include/linux/bitops_compat.h
new file mode 100644 (file)
index 0000000..0a3ac16
--- /dev/null
@@ -0,0 +1,31 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_BITOPS_COMPAT_H
+#define _SPL_BITOPS_COMPAT_H
+
+#include <linux/bitops.h>
+
+#endif /* _SPL_BITOPS_COMPAT_H */
+
diff --git a/spl/include/linux/compiler_compat.h b/spl/include/linux/compiler_compat.h
new file mode 100644 (file)
index 0000000..8dbbeee
--- /dev/null
@@ -0,0 +1,47 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_COMPILER_COMPAT_H
+#define _SPL_COMPILER_COMPAT_H
+
+#include <linux/compiler.h>
+
+#ifndef ACCESS_ONCE
+/*
+ * Prevent the compiler from merging or refetching accesses.  The compiler
+ * is also forbidden from reordering successive instances of ACCESS_ONCE(),
+ * but only when the compiler is aware of some particular ordering.  One way
+ * to make the compiler aware of ordering is to put the two invocations of
+ * ACCESS_ONCE() in different C statements.
+ *
+ * This macro does absolutely -nothing- to prevent the CPU from reordering,
+ * merging, or refetching absolutely anything at any time.  Its main intended
+ * use is to mediate communication between process-level code and irq/NMI
+ * handlers, all running on the same CPU.
+ */
+/* Taken from 2.6.33.2 */
+# define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#endif
+
+#endif /* _SPL_COMPILER_COMPAT_H */
diff --git a/spl/include/linux/delay_compat.h b/spl/include/linux/delay_compat.h
new file mode 100644 (file)
index 0000000..fc9ff66
--- /dev/null
@@ -0,0 +1,47 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2013 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DELAY_COMPAT_H
+#define _SPL_DELAY_COMPAT_H
+
+#include <linux/delay.h>
+#include <linux/time.h>
+
+/* usleep_range() introduced in 2.6.36 */
+#ifndef HAVE_USLEEP_RANGE
+
+static inline void
+usleep_range(unsigned long min, unsigned long max)
+{
+       unsigned int min_ms = min / USEC_PER_MSEC;
+
+       if (min >= MAX_UDELAY_MS)
+               msleep(min_ms);
+       else
+               udelay(min);
+}
+
+#endif /* HAVE_USLEEP_RANGE */
+
+#endif /* _SPL_DELAY_COMPAT_H */
diff --git a/spl/include/linux/file_compat.h b/spl/include/linux/file_compat.h
new file mode 100644 (file)
index 0000000..9165145
--- /dev/null
@@ -0,0 +1,100 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_FILE_COMPAT_H
+#define _SPL_FILE_COMPAT_H
+
+#include <linux/fs.h>
+#ifdef HAVE_FDTABLE_HEADER
+#include <linux/fdtable.h>
+#endif
+
+static inline struct file *
+spl_filp_open(const char *name, int flags, int mode, int *err)
+{
+        struct file *filp = NULL;
+        int rc;
+
+        filp = filp_open(name, flags, mode);
+        if (IS_ERR(filp)) {
+                rc = PTR_ERR(filp);
+                if (err)
+                        *err = rc;
+                filp = NULL;
+        }
+        return filp;
+}
+
+#define spl_filp_close(f)              filp_close(f, NULL)
+#define spl_filp_poff(f)               (&(f)->f_pos)
+#define spl_filp_write(fp, b, s, p)    (fp)->f_op->write((fp), (b), (s), p)
+
+static inline int
+spl_filp_fallocate(struct file *fp, int mode, loff_t offset, loff_t len)
+{
+       int error = -EOPNOTSUPP;
+
+#ifdef HAVE_FILE_FALLOCATE
+       if (fp->f_op->fallocate)
+               error = fp->f_op->fallocate(fp, mode, offset, len);
+#else
+#ifdef HAVE_INODE_FALLOCATE
+       if (fp->f_dentry && fp->f_dentry->d_inode &&
+           fp->f_dentry->d_inode->i_op->fallocate)
+               error = fp->f_dentry->d_inode->i_op->fallocate(
+                   fp->f_dentry->d_inode, mode, offset, len);
+#endif /* HAVE_INODE_FALLOCATE */
+#endif /*HAVE_FILE_FALLOCATE */
+
+       return (error);
+}
+
+#ifdef HAVE_2ARGS_VFS_FSYNC
+#define        spl_filp_fsync(fp, sync)        vfs_fsync(fp, sync)
+#else
+#define        spl_filp_fsync(fp, sync)        vfs_fsync(fp, (fp)->f_dentry, sync)
+#endif /* HAVE_2ARGS_VFS_FSYNC */
+
+#ifdef HAVE_INODE_LOCK_SHARED
+#define        spl_inode_lock(ip)              inode_lock(ip)
+#define        spl_inode_unlock(ip)            inode_unlock(ip)
+#define        spl_inode_lock_shared(ip)       inode_lock_shared(ip)
+#define        spl_inode_unlock_shared(ip)     inode_unlock_shared(ip)
+#define        spl_inode_trylock(ip)           inode_trylock(ip)
+#define        spl_inode_trylock_shared(ip)    inode_trylock_shared(ip)
+#define        spl_inode_is_locked(ip)         inode_is_locked(ip)
+#define        spl_inode_lock_nested(ip, s)    inode_lock_nested(ip, s)
+#else
+#define        spl_inode_lock(ip)              mutex_lock(&(ip)->i_mutex)
+#define        spl_inode_unlock(ip)            mutex_unlock(&(ip)->i_mutex)
+#define        spl_inode_lock_shared(ip)       mutex_lock(&(ip)->i_mutex)
+#define        spl_inode_unlock_shared(ip)     mutex_unlock(&(ip)->i_mutex)
+#define        spl_inode_trylock(ip)           mutex_trylock(&(ip)->i_mutex)
+#define        spl_inode_trylock_shared(ip)    mutex_trylock(&(ip)->i_mutex)
+#define        spl_inode_is_locked(ip)         mutex_is_locked(&(ip)->i_mutex)
+#define        spl_inode_lock_nested(ip, s)    mutex_lock_nested(&(ip)->i_mutex, s)
+#endif
+
+#endif /* SPL_FILE_COMPAT_H */
+
diff --git a/spl/include/linux/list_compat.h b/spl/include/linux/list_compat.h
new file mode 100644 (file)
index 0000000..d1e0d9d
--- /dev/null
@@ -0,0 +1,51 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_LIST_COMPAT_H
+#define _SPL_LIST_COMPAT_H
+
+#include <linux/list.h>
+
+#ifndef list_for_each_entry_safe_reverse
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos:        the type * to use as a loop cursor.
+ * @n:          another type * to use as temporary storage
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)          \
+        for (pos = list_entry((head)->prev, typeof(*pos), member),      \
+                n = list_entry(pos->member.prev, typeof(*pos), member); \
+             &pos->member != (head);                                    \
+             pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif /* list_for_each_entry_safe_reverse */
+
+#endif /* SPL_LIST_COMPAT_H */
+
diff --git a/spl/include/linux/math64_compat.h b/spl/include/linux/math64_compat.h
new file mode 100644 (file)
index 0000000..2c911a6
--- /dev/null
@@ -0,0 +1,32 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MATH64_COMPAT_H
+#define _SPL_MATH64_COMPAT_H
+
+#ifndef abs64
+#define abs64(x)       ({ uint64_t t = (x) >> 63; ((x) ^ t) - t; })
+#endif
+
+#endif /* _SPL_MATH64_COMPAT_H */
diff --git a/spl/include/linux/mm_compat.h b/spl/include/linux/mm_compat.h
new file mode 100644 (file)
index 0000000..7ae940a
--- /dev/null
@@ -0,0 +1,209 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MM_COMPAT_H
+#define _SPL_MM_COMPAT_H
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+
+#if !defined(HAVE_SHRINK_CONTROL_STRUCT)
+struct shrink_control {
+       gfp_t gfp_mask;
+       unsigned long nr_to_scan;
+};
+#endif /* HAVE_SHRINK_CONTROL_STRUCT */
+
+/*
+ * Due to frequent changes in the shrinker API the following
+ * compatibility wrappers should be used.  They are as follows:
+ *
+ * SPL_SHRINKER_DECLARE is used to declare the shrinker which is
+ * passed to spl_register_shrinker()/spl_unregister_shrinker().  Use
+ * shrinker_name to set the shrinker variable name, shrinker_callback
+ * to set the callback function, and seek_cost to define the cost of
+ * reclaiming an object.
+ *
+ *   SPL_SHRINKER_DECLARE(shrinker_name, shrinker_callback, seek_cost);
+ *
+ * SPL_SHRINKER_CALLBACK_FWD_DECLARE is used when a forward declaration
+ * of the shrinker callback function is required.  Only the callback
+ * function needs to be passed.
+ *
+ *   SPL_SHRINKER_CALLBACK_FWD_DECLARE(shrinker_callback);
+ *
+ * SPL_SHRINKER_CALLBACK_WRAPPER is used to declare the callback function
+ * which is registered with the shrinker.  This function will call your
+ * custom shrinker which must use the following prototype.  Notice the
+ * leading __'s, these must be appended to the callback_function name.
+ *
+ *   int  __shrinker_callback(struct shrinker *, struct shrink_control *)
+ *   SPL_SHRINKER_CALLBACK_WRAPPER(shrinker_callback);a
+ *
+ *
+ * Example:
+ *
+ * SPL_SHRINKER_CALLBACK_FWD_DECLARE(my_shrinker_fn);
+ * SPL_SHRINKER_DECLARE(my_shrinker, my_shrinker_fn, 1);
+ *
+ * static int
+ * __my_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
+ * {
+ *     if (sc->nr_to_scan) {
+ *             ...scan objects in the cache and reclaim them...
+ *     }
+ *
+ *     ...calculate number of objects in the cache...
+ *
+ *     return (number of objects in the cache);
+ * }
+ * SPL_SHRINKER_CALLBACK_WRAPPER(my_shrinker_fn);
+ */
+
+#define        spl_register_shrinker(x)        register_shrinker(x)
+#define        spl_unregister_shrinker(x)      unregister_shrinker(x)
+
+/*
+ * Linux 2.6.23 - 2.6.34 Shrinker API Compatibility.
+ */
+#if defined(HAVE_2ARGS_OLD_SHRINKER_CALLBACK)
+#define        SPL_SHRINKER_DECLARE(s, x, y)                                   \
+static struct shrinker s = {                                           \
+       .shrink = x,                                                    \
+       .seeks = y                                                      \
+}
+
+#define        SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn)                           \
+static int fn(int nr_to_scan, unsigned int gfp_mask)
+
+#define        SPL_SHRINKER_CALLBACK_WRAPPER(fn)                               \
+static int                                                             \
+fn(int nr_to_scan, unsigned int gfp_mask)                              \
+{                                                                      \
+       struct shrink_control sc;                                       \
+                                                                       \
+       sc.nr_to_scan = nr_to_scan;                                     \
+       sc.gfp_mask = gfp_mask;                                         \
+                                                                       \
+       return (__ ## fn(NULL, &sc));                                   \
+}
+
+/*
+ * Linux 2.6.35 to 2.6.39 Shrinker API Compatibility.
+ */
+#elif defined(HAVE_3ARGS_SHRINKER_CALLBACK)
+#define        SPL_SHRINKER_DECLARE(s, x, y)                                   \
+static struct shrinker s = {                                           \
+       .shrink = x,                                                    \
+       .seeks = y                                                      \
+}
+
+#define        SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn)                           \
+static int fn(struct shrinker *, int, unsigned int)
+
+#define        SPL_SHRINKER_CALLBACK_WRAPPER(fn)                               \
+static int                                                             \
+fn(struct shrinker *shrink, int nr_to_scan, unsigned int gfp_mask)     \
+{                                                                      \
+       struct shrink_control sc;                                       \
+                                                                       \
+       sc.nr_to_scan = nr_to_scan;                                     \
+       sc.gfp_mask = gfp_mask;                                         \
+                                                                       \
+       return (__ ## fn(shrink, &sc));                                 \
+}
+
+/*
+ * Linux 3.0 to 3.11 Shrinker API Compatibility.
+ */
+#elif defined(HAVE_2ARGS_NEW_SHRINKER_CALLBACK)
+#define        SPL_SHRINKER_DECLARE(s, x, y)                                   \
+static struct shrinker s = {                                           \
+       .shrink = x,                                                    \
+       .seeks = y                                                      \
+}
+
+#define        SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn)                           \
+static int fn(struct shrinker *, struct shrink_control *)
+
+#define        SPL_SHRINKER_CALLBACK_WRAPPER(fn)                               \
+static int                                                             \
+fn(struct shrinker *shrink, struct shrink_control *sc)                 \
+{                                                                      \
+       return (__ ## fn(shrink, sc));                                  \
+}
+
+/*
+ * Linux 3.12 and later Shrinker API Compatibility.
+ */
+#elif defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+#define        SPL_SHRINKER_DECLARE(s, x, y)                                   \
+static struct shrinker s = {                                           \
+       .count_objects = x ## _count_objects,                           \
+       .scan_objects = x ## _scan_objects,                             \
+       .seeks = y                                                      \
+}
+
+#define        SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn)                           \
+static unsigned long fn ## _count_objects(struct shrinker *,           \
+    struct shrink_control *);                                          \
+static unsigned long fn ## _scan_objects(struct shrinker *,            \
+    struct shrink_control *)
+
+#define        SPL_SHRINKER_CALLBACK_WRAPPER(fn)                               \
+static unsigned long                                                   \
+fn ## _count_objects(struct shrinker *shrink, struct shrink_control *sc)\
+{                                                                      \
+       int __ret__;                                                    \
+                                                                       \
+       sc->nr_to_scan = 0;                                             \
+       __ret__ = __ ## fn(NULL, sc);                                   \
+                                                                       \
+       /* Errors may not be returned and must be converted to zeros */ \
+       return ((__ret__ < 0) ? 0 : __ret__);                           \
+}                                                                      \
+                                                                       \
+static unsigned long                                                   \
+fn ## _scan_objects(struct shrinker *shrink, struct shrink_control *sc)        \
+{                                                                      \
+       int __ret__;                                                    \
+                                                                       \
+       __ret__ = __ ## fn(NULL, sc);                                   \
+       return ((__ret__ < 0) ? SHRINK_STOP : __ret__);                 \
+}
+#else
+/*
+ * Linux 2.x to 2.6.22, or a newer shrinker API has been introduced.
+ */
+#error "Unknown shrinker callback"
+#endif
+
+#if defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+typedef unsigned long  spl_shrinker_t;
+#else
+typedef int            spl_shrinker_t;
+#define        SHRINK_STOP     (-1)
+#endif
+
+#endif /* SPL_MM_COMPAT_H */
diff --git a/spl/include/linux/proc_compat.h b/spl/include/linux/proc_compat.h
new file mode 100644 (file)
index 0000000..2c57f39
--- /dev/null
@@ -0,0 +1,35 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_PROC_COMPAT_H
+#define _SPL_PROC_COMPAT_H
+
+#include <linux/proc_fs.h>
+
+extern struct proc_dir_entry *proc_spl_kstat;
+
+int spl_proc_init(void);
+void spl_proc_fini(void);
+
+#endif /* SPL_PROC_COMPAT_H */
diff --git a/spl/include/linux/rwsem_compat.h b/spl/include/linux/rwsem_compat.h
new file mode 100644 (file)
index 0000000..c874885
--- /dev/null
@@ -0,0 +1,62 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_RWSEM_COMPAT_H
+#define _SPL_RWSEM_COMPAT_H
+
+#include <linux/rwsem.h>
+
+#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
+#define        SPL_RWSEM_SINGLE_READER_VALUE   (1)
+#define        SPL_RWSEM_SINGLE_WRITER_VALUE   (-1)
+#else
+#define        SPL_RWSEM_SINGLE_READER_VALUE   (RWSEM_ACTIVE_READ_BIAS)
+#define        SPL_RWSEM_SINGLE_WRITER_VALUE   (RWSEM_ACTIVE_WRITE_BIAS)
+#endif
+
+/* Linux 3.16 changed activity to count for rwsem-spinlock */
+#if defined(HAVE_RWSEM_ACTIVITY)
+#define        RWSEM_COUNT(sem)        sem->activity
+/* Linux 4.8 changed count to an atomic_long_t for !rwsem-spinlock */
+#elif defined(HAVE_RWSEM_ATOMIC_LONG_COUNT)
+#define        RWSEM_COUNT(sem)        atomic_long_read(&(sem)->count)
+#else
+#define        RWSEM_COUNT(sem)        sem->count
+#endif
+
+int rwsem_tryupgrade(struct rw_semaphore *rwsem);
+
+#if defined(RWSEM_SPINLOCK_IS_RAW)
+#define spl_rwsem_lock_irqsave(lk, fl)       raw_spin_lock_irqsave(lk, fl)
+#define spl_rwsem_unlock_irqrestore(lk, fl)  raw_spin_unlock_irqrestore(lk, fl)
+#define spl_rwsem_trylock_irqsave(lk, fl)    raw_spin_trylock_irqsave(lk, fl)
+#else
+#define spl_rwsem_lock_irqsave(lk, fl)       spin_lock_irqsave(lk, fl)
+#define spl_rwsem_unlock_irqrestore(lk, fl)  spin_unlock_irqrestore(lk, fl)
+#define spl_rwsem_trylock_irqsave(lk, fl)    spin_trylock_irqsave(lk, fl)
+#endif /* RWSEM_SPINLOCK_IS_RAW */
+
+#define spl_rwsem_is_locked(rwsem)           rwsem_is_locked(rwsem)
+
+#endif /* _SPL_RWSEM_COMPAT_H */
diff --git a/spl/include/linux/wait_compat.h b/spl/include/linux/wait_compat.h
new file mode 100644 (file)
index 0000000..d8cd09b
--- /dev/null
@@ -0,0 +1,46 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_WAIT_COMPAT_H
+#define _SPL_WAIT_COMPAT_H
+
+#include <linux/sched.h>
+
+#ifndef HAVE_WAIT_ON_BIT_ACTION
+#  define spl_wait_on_bit(word, bit, mode) wait_on_bit(word, bit, mode)
+#else
+
+static inline int
+spl_bit_wait(void *word)
+{
+        schedule();
+        return 0;
+}
+
+#define spl_wait_on_bit(word, bit, mode)                       \
+       wait_on_bit(word, bit, spl_bit_wait, mode)
+
+#endif /* HAVE_WAIT_ON_BIT_ACTION */
+
+#endif /* SPL_WAIT_COMPAT_H */
diff --git a/spl/include/linux/zlib_compat.h b/spl/include/linux/zlib_compat.h
new file mode 100644 (file)
index 0000000..ba853c3
--- /dev/null
@@ -0,0 +1,37 @@
+/*****************************************************************************\
+ *  Copyright (C) 2011 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ZLIB_COMPAT_H
+#define _SPL_ZLIB_COMPAT_H
+
+#include <linux/zlib.h>
+
+#ifdef HAVE_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
+#define spl_zlib_deflate_workspacesize(wb, ml) \
+       zlib_deflate_workspacesize(wb, ml)
+#else
+#define spl_zlib_deflate_workspacesize(wb, ml) \
+       zlib_deflate_workspacesize()
+#endif /* HAVE_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE */
+
+#endif /* SPL_ZLIB_COMPAT_H */
diff --git a/spl/include/rpc/Makefile.am b/spl/include/rpc/Makefile.am
new file mode 100644 (file)
index 0000000..cfc8246
--- /dev/null
@@ -0,0 +1,14 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/rpc/types.h \
+       $(top_srcdir)/include/rpc/xdr.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/rpc
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/rpc/Makefile.in b/spl/include/rpc/Makefile.in
new file mode 100644 (file)
index 0000000..c1c162e
--- /dev/null
@@ -0,0 +1,623 @@
+# 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/rpc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/rpc/types.h \
+       $(top_srcdir)/include/rpc/xdr.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/rpc/types.h \
+       $(top_srcdir)/include/rpc/xdr.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/rpc
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/rpc/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu include/rpc/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/rpc/types.h b/spl/include/rpc/types.h
new file mode 100644 (file)
index 0000000..b57b4bd
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_RPC_TYPES_H
+#define _SPL_RPC_TYPES_H
+
+typedef int bool_t;
+
+#endif /* SPL_RPC_TYPES_H */
diff --git a/spl/include/rpc/xdr.h b/spl/include/rpc/xdr.h
new file mode 100644 (file)
index 0000000..d0f06b5
--- /dev/null
@@ -0,0 +1,155 @@
+/*****************************************************************************\
+ *  Copyright (c) 2008 Sun Microsystems, Inc.
+ *  Written by Ricardo Correia <Ricardo.M.Correia@Sun.COM>
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_RPC_XDR_H
+#define _SPL_RPC_XDR_H
+
+#include <sys/types.h>
+#include <rpc/types.h>
+
+/*
+ * XDR enums and types.
+ */
+enum xdr_op {
+       XDR_ENCODE,
+       XDR_DECODE
+};
+
+struct xdr_ops;
+
+typedef struct {
+       struct xdr_ops *x_ops;      /* Also used to let caller know if
+                                      xdrmem_create() succeeds (sigh..) */
+       caddr_t         x_addr;     /* Current buffer addr */
+       caddr_t         x_addr_end; /* End of the buffer */
+       enum xdr_op     x_op;       /* Stream direction */
+} XDR;
+
+typedef bool_t (*xdrproc_t)(XDR *xdrs, void *ptr);
+
+struct xdr_ops {
+       bool_t (*xdr_control)(XDR *, int, void *);
+
+       bool_t (*xdr_char)(XDR *, char *);
+       bool_t (*xdr_u_short)(XDR *, unsigned short *);
+       bool_t (*xdr_u_int)(XDR *, unsigned *);
+       bool_t (*xdr_u_longlong_t)(XDR *, u_longlong_t *);
+
+       bool_t (*xdr_opaque)(XDR *, caddr_t, const uint_t);
+       bool_t (*xdr_string)(XDR *, char **, const uint_t);
+       bool_t (*xdr_array)(XDR *, caddr_t *, uint_t *, const uint_t,
+                           const uint_t, const xdrproc_t);
+};
+
+/*
+ * XDR control operator.
+ */
+#define XDR_GET_BYTES_AVAIL 1
+
+struct xdr_bytesrec {
+       bool_t xc_is_last_record;
+       size_t xc_num_avail;
+};
+
+/*
+ * XDR functions.
+ */
+void xdrmem_create(XDR *xdrs, const caddr_t addr, const uint_t size,
+    const enum xdr_op op);
+#define xdr_destroy(xdrs) ((void) 0) /* Currently not needed. If needed later,
+                                        we'll add it to struct xdr_ops */
+
+#define xdr_control(xdrs, req, info) (xdrs)->x_ops->xdr_control((xdrs),        \
+                                         (req), (info))
+
+/*
+ * For precaution, the following are defined as static inlines instead of macros
+ * to get some amount of type safety.
+ *
+ * Also, macros wouldn't work in the case where typecasting is done, because it
+ * must be possible to reference the functions' addresses by these names.
+ */
+static inline bool_t xdr_char(XDR *xdrs, char *cp)
+{
+       return xdrs->x_ops->xdr_char(xdrs, cp);
+}
+
+static inline bool_t xdr_u_short(XDR *xdrs, unsigned short *usp)
+{
+       return xdrs->x_ops->xdr_u_short(xdrs, usp);
+}
+
+static inline bool_t xdr_short(XDR *xdrs, short *sp)
+{
+       BUILD_BUG_ON(sizeof(short) != 2);
+       return xdrs->x_ops->xdr_u_short(xdrs, (unsigned short *) sp);
+}
+
+static inline bool_t xdr_u_int(XDR *xdrs, unsigned *up)
+{
+       return xdrs->x_ops->xdr_u_int(xdrs, up);
+}
+
+static inline bool_t xdr_int(XDR *xdrs, int *ip)
+{
+       BUILD_BUG_ON(sizeof(int) != 4);
+       return xdrs->x_ops->xdr_u_int(xdrs, (unsigned *) ip);
+}
+
+static inline bool_t xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
+{
+       return xdrs->x_ops->xdr_u_longlong_t(xdrs, ullp);
+}
+
+static inline bool_t xdr_longlong_t(XDR *xdrs, longlong_t *llp)
+{
+       BUILD_BUG_ON(sizeof(longlong_t) != 8);
+       return xdrs->x_ops->xdr_u_longlong_t(xdrs, (u_longlong_t *) llp);
+}
+
+/*
+ * Fixed-length opaque data.
+ */
+static inline bool_t xdr_opaque(XDR *xdrs, caddr_t cp, const uint_t cnt)
+{
+       return xdrs->x_ops->xdr_opaque(xdrs, cp, cnt);
+}
+
+/*
+ * Variable-length string.
+ * The *sp buffer must have (maxsize + 1) bytes.
+ */
+static inline bool_t xdr_string(XDR *xdrs, char **sp, const uint_t maxsize)
+{
+       return xdrs->x_ops->xdr_string(xdrs, sp, maxsize);
+}
+
+/*
+ * Variable-length arrays.
+ */
+static inline bool_t xdr_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep,
+    const uint_t maxsize, const uint_t elsize, const xdrproc_t elproc)
+{
+       return xdrs->x_ops->xdr_array(xdrs, arrp, sizep, maxsize, elsize,
+           elproc);
+}
+
+#endif /* SPL_RPC_XDR_H */
diff --git a/spl/include/sharefs/Makefile.am b/spl/include/sharefs/Makefile.am
new file mode 100644 (file)
index 0000000..10e7093
--- /dev/null
@@ -0,0 +1,13 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/sharefs/share.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/sharefs
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/sharefs/Makefile.in b/spl/include/sharefs/Makefile.in
new file mode 100644 (file)
index 0000000..96273fc
--- /dev/null
@@ -0,0 +1,621 @@
+# 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/sharefs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/sharefs/share.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/sharefs/share.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/sharefs
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/sharefs/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu include/sharefs/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/sharefs/share.h b/spl/include/sharefs/share.h
new file mode 100644 (file)
index 0000000..fc248a2
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SHARE_H
+#define _SPL_SHARE_H
+
+#endif /* SPL_SHARE_H */
diff --git a/spl/include/spl-ctl.h b/spl/include/spl-ctl.h
new file mode 100644 (file)
index 0000000..bb24490
--- /dev/null
@@ -0,0 +1,45 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _DEBUG_CTL_H
+#define _DEBUG_CTL_H
+
+/*
+ * Contains shared definitions which both the user space
+ * and kernel space portions of splat must agree on.
+ */
+typedef struct spl_debug_header {
+        int ph_len;
+        int ph_flags;
+        int ph_subsys;
+        int ph_mask;
+        int ph_cpu_id;
+        int ph_sec;
+        long ph_usec;
+        int ph_stack;
+        int ph_pid;
+        int ph_line_num;
+} spl_debug_header_t;
+
+#endif /* _DEBUG_CTL_H */
diff --git a/spl/include/splat-ctl.h b/spl/include/splat-ctl.h
new file mode 100644 (file)
index 0000000..15fd01b
--- /dev/null
@@ -0,0 +1,109 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPLAT_CTL_H
+#define _SPLAT_CTL_H
+
+#include <linux/types.h>
+
+/*
+ * Contains shared definitions for both user space and kernel space.  To
+ * ensure 32-bit/64-bit interoperability over ioctl()'s only types with
+ * fixed sizes can be used.
+ */
+#define SPLAT_NAME                     "splatctl"
+#define SPLAT_DEV                      "/dev/splatctl"
+
+#define SPLAT_NAME_SIZE                        20
+#define SPLAT_DESC_SIZE                        60
+
+typedef struct splat_user {
+       char name[SPLAT_NAME_SIZE];     /* Short name */
+       char desc[SPLAT_DESC_SIZE];     /* Short description */
+       __u32 id;                       /* Unique numeric id */
+} splat_user_t;
+
+#define        SPLAT_CFG_MAGIC                 0x15263748U
+typedef struct splat_cfg {
+       __u32 cfg_magic;                /* Unique magic */
+       __u32 cfg_cmd;                  /* Configure command */
+       __s32 cfg_arg1;                 /* Configure command arg 1 */
+       __s32 cfg_rc1;                  /* Configure response 1 */
+       union {
+               struct {
+                       __u32 size;
+                       splat_user_t descs[0];
+               } splat_subsystems;
+               struct {
+                       __u32 size;
+                       splat_user_t descs[0];
+               } splat_tests;
+       } cfg_data;
+} splat_cfg_t;
+
+#define        SPLAT_CMD_MAGIC                 0x9daebfc0U
+typedef struct splat_cmd {
+       __u32 cmd_magic;                /* Unique magic */
+       __u32 cmd_subsystem;            /* Target subsystem */
+       __u32 cmd_test;                 /* Subsystem test */
+       __u32 cmd_data_size;            /* Opaque data size */
+       char cmd_data_str[0];           /* Opaque data region */
+} splat_cmd_t;
+
+/* Valid ioctls */
+#define SPLAT_CFG                      _IOWR('f', 101, splat_cfg_t)
+#define SPLAT_CMD                      _IOWR('f', 102, splat_cmd_t)
+
+/* Valid configuration commands */
+#define SPLAT_CFG_BUFFER_CLEAR         0x001   /* Clear text buffer */
+#define SPLAT_CFG_BUFFER_SIZE          0x002   /* Resize text buffer */
+#define SPLAT_CFG_SUBSYSTEM_COUNT      0x101   /* Number of subsystem */
+#define SPLAT_CFG_SUBSYSTEM_LIST       0x102   /* List of N subsystems */
+#define SPLAT_CFG_TEST_COUNT           0x201   /* Number of tests */
+#define SPLAT_CFG_TEST_LIST            0x202   /* List of N tests */
+
+/*
+ * Valid subsystem and test commands are defined in each subsystem as
+ * SPLAT_SUBSYSTEM_*.  We do need to be careful to avoid collisions, the
+ * currently defined subsystems are as follows:
+ */
+#define SPLAT_SUBSYSTEM_KMEM           0x0100
+#define SPLAT_SUBSYSTEM_TASKQ          0x0200
+#define SPLAT_SUBSYSTEM_KRNG           0x0300
+#define SPLAT_SUBSYSTEM_MUTEX          0x0400
+#define SPLAT_SUBSYSTEM_CONDVAR                0x0500
+#define SPLAT_SUBSYSTEM_THREAD         0x0600
+#define SPLAT_SUBSYSTEM_RWLOCK         0x0700
+#define SPLAT_SUBSYSTEM_TIME           0x0800
+#define SPLAT_SUBSYSTEM_VNODE          0x0900
+#define SPLAT_SUBSYSTEM_KOBJ           0x0a00
+#define SPLAT_SUBSYSTEM_ATOMIC         0x0b00
+#define SPLAT_SUBSYSTEM_LIST           0x0c00
+#define SPLAT_SUBSYSTEM_GENERIC                0x0d00
+#define SPLAT_SUBSYSTEM_CRED           0x0e00
+#define SPLAT_SUBSYSTEM_ZLIB           0x0f00
+#define SPLAT_SUBSYSTEM_LINUX          0x1000
+#define SPLAT_SUBSYSTEM_UNKNOWN                0xff00
+
+#endif /* _SPLAT_CTL_H */
diff --git a/spl/include/strings.h b/spl/include/strings.h
new file mode 100644 (file)
index 0000000..dc0f314
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_STRINGS_H
+#define _SPL_STRINGS_H
+
+#endif /* SPL_STRINGS_H */
diff --git a/spl/include/sys/Makefile.am b/spl/include/sys/Makefile.am
new file mode 100644 (file)
index 0000000..73c4a84
--- /dev/null
@@ -0,0 +1,113 @@
+SUBDIRS = fm fs sysevent
+
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/sys/acl.h \
+       $(top_srcdir)/include/sys/acl_impl.h \
+       $(top_srcdir)/include/sys/atomic.h \
+       $(top_srcdir)/include/sys/attr.h \
+       $(top_srcdir)/include/sys/bitmap.h \
+       $(top_srcdir)/include/sys/bootconf.h \
+       $(top_srcdir)/include/sys/bootprops.h \
+       $(top_srcdir)/include/sys/buf.h \
+       $(top_srcdir)/include/sys/byteorder.h \
+       $(top_srcdir)/include/sys/callb.h \
+       $(top_srcdir)/include/sys/callo.h \
+       $(top_srcdir)/include/sys/cmn_err.h \
+       $(top_srcdir)/include/sys/compress.h \
+       $(top_srcdir)/include/sys/condvar.h \
+       $(top_srcdir)/include/sys/conf.h \
+       $(top_srcdir)/include/sys/console.h \
+       $(top_srcdir)/include/sys/cpupart.h \
+       $(top_srcdir)/include/sys/cpuvar.h \
+       $(top_srcdir)/include/sys/crc32.h \
+       $(top_srcdir)/include/sys/cred.h \
+       $(top_srcdir)/include/sys/ctype.h \
+       $(top_srcdir)/include/sys/ddi.h \
+       $(top_srcdir)/include/sys/debug.h \
+       $(top_srcdir)/include/sys/dirent.h \
+       $(top_srcdir)/include/sys/disp.h \
+       $(top_srcdir)/include/sys/dkio.h \
+       $(top_srcdir)/include/sys/dklabel.h \
+       $(top_srcdir)/include/sys/dnlc.h \
+       $(top_srcdir)/include/sys/dumphdr.h \
+       $(top_srcdir)/include/sys/efi_partition.h \
+       $(top_srcdir)/include/sys/errno.h \
+       $(top_srcdir)/include/sys/extdirent.h \
+       $(top_srcdir)/include/sys/fcntl.h \
+       $(top_srcdir)/include/sys/file.h \
+       $(top_srcdir)/include/sys/idmap.h \
+       $(top_srcdir)/include/sys/int_limits.h \
+       $(top_srcdir)/include/sys/int_types.h \
+       $(top_srcdir)/include/sys/inttypes.h \
+       $(top_srcdir)/include/sys/isa_defs.h \
+       $(top_srcdir)/include/sys/kidmap.h \
+       $(top_srcdir)/include/sys/kmem.h \
+       $(top_srcdir)/include/sys/kmem_cache.h \
+       $(top_srcdir)/include/sys/kobj.h \
+       $(top_srcdir)/include/sys/kstat.h \
+       $(top_srcdir)/include/sys/list.h \
+       $(top_srcdir)/include/sys/mkdev.h \
+       $(top_srcdir)/include/sys/mntent.h \
+       $(top_srcdir)/include/sys/modctl.h \
+       $(top_srcdir)/include/sys/mode.h \
+       $(top_srcdir)/include/sys/mount.h \
+       $(top_srcdir)/include/sys/mutex.h \
+       $(top_srcdir)/include/sys/note.h \
+       $(top_srcdir)/include/sys/open.h \
+       $(top_srcdir)/include/sys/param.h \
+       $(top_srcdir)/include/sys/pathname.h \
+       $(top_srcdir)/include/sys/policy.h \
+       $(top_srcdir)/include/sys/pool.h \
+       $(top_srcdir)/include/sys/priv_impl.h \
+       $(top_srcdir)/include/sys/processor.h \
+       $(top_srcdir)/include/sys/proc.h \
+       $(top_srcdir)/include/sys/pset.h \
+       $(top_srcdir)/include/sys/random.h \
+       $(top_srcdir)/include/sys/refstr.h \
+       $(top_srcdir)/include/sys/resource.h \
+       $(top_srcdir)/include/sys/rwlock.h \
+       $(top_srcdir)/include/sys/sdt.h \
+       $(top_srcdir)/include/sys/sid.h \
+       $(top_srcdir)/include/sys/signal.h \
+       $(top_srcdir)/include/sys/stat.h \
+       $(top_srcdir)/include/sys/stropts.h \
+       $(top_srcdir)/include/sys/sunddi.h \
+       $(top_srcdir)/include/sys/sunldi.h \
+       $(top_srcdir)/include/sys/sysdc.h \
+       $(top_srcdir)/include/sys/sysevent.h \
+       $(top_srcdir)/include/sys/sysmacros.h \
+       $(top_srcdir)/include/sys/systeminfo.h \
+       $(top_srcdir)/include/sys/systm.h \
+       $(top_srcdir)/include/sys/taskq.h \
+       $(top_srcdir)/include/sys/thread.h \
+       $(top_srcdir)/include/sys/time.h \
+       $(top_srcdir)/include/sys/timer.h \
+       $(top_srcdir)/include/sys/t_lock.h \
+       $(top_srcdir)/include/sys/tsd.h \
+       $(top_srcdir)/include/sys/types32.h \
+       $(top_srcdir)/include/sys/types.h \
+       $(top_srcdir)/include/sys/u8_textprep.h \
+       $(top_srcdir)/include/sys/uio.h \
+       $(top_srcdir)/include/sys/unistd.h \
+       $(top_srcdir)/include/sys/user.h \
+       $(top_srcdir)/include/sys/va_list.h \
+       $(top_srcdir)/include/sys/varargs.h \
+       $(top_srcdir)/include/sys/vfs.h \
+       $(top_srcdir)/include/sys/vfs_opreg.h \
+       $(top_srcdir)/include/sys/vmem.h \
+       $(top_srcdir)/include/sys/vmsystm.h \
+       $(top_srcdir)/include/sys/vnode.h \
+       $(top_srcdir)/include/sys/zmod.h \
+       $(top_srcdir)/include/sys/zone.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/sys
+kernel_HEADERS = $(KERNEL_H)
+endif
+
diff --git a/spl/include/sys/Makefile.in b/spl/include/sys/Makefile.in
new file mode 100644 (file)
index 0000000..46e7c05
--- /dev/null
@@ -0,0 +1,932 @@
+# 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/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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/acl.h \
+       $(top_srcdir)/include/sys/acl_impl.h \
+       $(top_srcdir)/include/sys/atomic.h \
+       $(top_srcdir)/include/sys/attr.h \
+       $(top_srcdir)/include/sys/bitmap.h \
+       $(top_srcdir)/include/sys/bootconf.h \
+       $(top_srcdir)/include/sys/bootprops.h \
+       $(top_srcdir)/include/sys/buf.h \
+       $(top_srcdir)/include/sys/byteorder.h \
+       $(top_srcdir)/include/sys/callb.h \
+       $(top_srcdir)/include/sys/callo.h \
+       $(top_srcdir)/include/sys/cmn_err.h \
+       $(top_srcdir)/include/sys/compress.h \
+       $(top_srcdir)/include/sys/condvar.h \
+       $(top_srcdir)/include/sys/conf.h \
+       $(top_srcdir)/include/sys/console.h \
+       $(top_srcdir)/include/sys/cpupart.h \
+       $(top_srcdir)/include/sys/cpuvar.h \
+       $(top_srcdir)/include/sys/crc32.h \
+       $(top_srcdir)/include/sys/cred.h \
+       $(top_srcdir)/include/sys/ctype.h \
+       $(top_srcdir)/include/sys/ddi.h \
+       $(top_srcdir)/include/sys/debug.h \
+       $(top_srcdir)/include/sys/dirent.h \
+       $(top_srcdir)/include/sys/disp.h \
+       $(top_srcdir)/include/sys/dkio.h \
+       $(top_srcdir)/include/sys/dklabel.h \
+       $(top_srcdir)/include/sys/dnlc.h \
+       $(top_srcdir)/include/sys/dumphdr.h \
+       $(top_srcdir)/include/sys/efi_partition.h \
+       $(top_srcdir)/include/sys/errno.h \
+       $(top_srcdir)/include/sys/extdirent.h \
+       $(top_srcdir)/include/sys/fcntl.h \
+       $(top_srcdir)/include/sys/file.h \
+       $(top_srcdir)/include/sys/idmap.h \
+       $(top_srcdir)/include/sys/int_limits.h \
+       $(top_srcdir)/include/sys/int_types.h \
+       $(top_srcdir)/include/sys/inttypes.h \
+       $(top_srcdir)/include/sys/isa_defs.h \
+       $(top_srcdir)/include/sys/kidmap.h \
+       $(top_srcdir)/include/sys/kmem.h \
+       $(top_srcdir)/include/sys/kmem_cache.h \
+       $(top_srcdir)/include/sys/kobj.h \
+       $(top_srcdir)/include/sys/kstat.h \
+       $(top_srcdir)/include/sys/list.h \
+       $(top_srcdir)/include/sys/mkdev.h \
+       $(top_srcdir)/include/sys/mntent.h \
+       $(top_srcdir)/include/sys/modctl.h \
+       $(top_srcdir)/include/sys/mode.h \
+       $(top_srcdir)/include/sys/mount.h \
+       $(top_srcdir)/include/sys/mutex.h \
+       $(top_srcdir)/include/sys/note.h \
+       $(top_srcdir)/include/sys/open.h \
+       $(top_srcdir)/include/sys/param.h \
+       $(top_srcdir)/include/sys/pathname.h \
+       $(top_srcdir)/include/sys/policy.h \
+       $(top_srcdir)/include/sys/pool.h \
+       $(top_srcdir)/include/sys/priv_impl.h \
+       $(top_srcdir)/include/sys/processor.h \
+       $(top_srcdir)/include/sys/proc.h \
+       $(top_srcdir)/include/sys/pset.h \
+       $(top_srcdir)/include/sys/random.h \
+       $(top_srcdir)/include/sys/refstr.h \
+       $(top_srcdir)/include/sys/resource.h \
+       $(top_srcdir)/include/sys/rwlock.h \
+       $(top_srcdir)/include/sys/sdt.h \
+       $(top_srcdir)/include/sys/sid.h \
+       $(top_srcdir)/include/sys/signal.h \
+       $(top_srcdir)/include/sys/stat.h \
+       $(top_srcdir)/include/sys/stropts.h \
+       $(top_srcdir)/include/sys/sunddi.h \
+       $(top_srcdir)/include/sys/sunldi.h \
+       $(top_srcdir)/include/sys/sysdc.h \
+       $(top_srcdir)/include/sys/sysevent.h \
+       $(top_srcdir)/include/sys/sysmacros.h \
+       $(top_srcdir)/include/sys/systeminfo.h \
+       $(top_srcdir)/include/sys/systm.h \
+       $(top_srcdir)/include/sys/taskq.h \
+       $(top_srcdir)/include/sys/thread.h \
+       $(top_srcdir)/include/sys/time.h \
+       $(top_srcdir)/include/sys/timer.h \
+       $(top_srcdir)/include/sys/t_lock.h \
+       $(top_srcdir)/include/sys/tsd.h \
+       $(top_srcdir)/include/sys/types32.h \
+       $(top_srcdir)/include/sys/types.h \
+       $(top_srcdir)/include/sys/u8_textprep.h \
+       $(top_srcdir)/include/sys/uio.h \
+       $(top_srcdir)/include/sys/unistd.h \
+       $(top_srcdir)/include/sys/user.h \
+       $(top_srcdir)/include/sys/va_list.h \
+       $(top_srcdir)/include/sys/varargs.h \
+       $(top_srcdir)/include/sys/vfs.h \
+       $(top_srcdir)/include/sys/vfs_opreg.h \
+       $(top_srcdir)/include/sys/vmem.h \
+       $(top_srcdir)/include/sys/vmsystm.h \
+       $(top_srcdir)/include/sys/vnode.h \
+       $(top_srcdir)/include/sys/zmod.h \
+       $(top_srcdir)/include/sys/zone.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)"
+HEADERS = $(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 \
+       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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+SUBDIRS = fm fs sysevent
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/sys/acl.h \
+       $(top_srcdir)/include/sys/acl_impl.h \
+       $(top_srcdir)/include/sys/atomic.h \
+       $(top_srcdir)/include/sys/attr.h \
+       $(top_srcdir)/include/sys/bitmap.h \
+       $(top_srcdir)/include/sys/bootconf.h \
+       $(top_srcdir)/include/sys/bootprops.h \
+       $(top_srcdir)/include/sys/buf.h \
+       $(top_srcdir)/include/sys/byteorder.h \
+       $(top_srcdir)/include/sys/callb.h \
+       $(top_srcdir)/include/sys/callo.h \
+       $(top_srcdir)/include/sys/cmn_err.h \
+       $(top_srcdir)/include/sys/compress.h \
+       $(top_srcdir)/include/sys/condvar.h \
+       $(top_srcdir)/include/sys/conf.h \
+       $(top_srcdir)/include/sys/console.h \
+       $(top_srcdir)/include/sys/cpupart.h \
+       $(top_srcdir)/include/sys/cpuvar.h \
+       $(top_srcdir)/include/sys/crc32.h \
+       $(top_srcdir)/include/sys/cred.h \
+       $(top_srcdir)/include/sys/ctype.h \
+       $(top_srcdir)/include/sys/ddi.h \
+       $(top_srcdir)/include/sys/debug.h \
+       $(top_srcdir)/include/sys/dirent.h \
+       $(top_srcdir)/include/sys/disp.h \
+       $(top_srcdir)/include/sys/dkio.h \
+       $(top_srcdir)/include/sys/dklabel.h \
+       $(top_srcdir)/include/sys/dnlc.h \
+       $(top_srcdir)/include/sys/dumphdr.h \
+       $(top_srcdir)/include/sys/efi_partition.h \
+       $(top_srcdir)/include/sys/errno.h \
+       $(top_srcdir)/include/sys/extdirent.h \
+       $(top_srcdir)/include/sys/fcntl.h \
+       $(top_srcdir)/include/sys/file.h \
+       $(top_srcdir)/include/sys/idmap.h \
+       $(top_srcdir)/include/sys/int_limits.h \
+       $(top_srcdir)/include/sys/int_types.h \
+       $(top_srcdir)/include/sys/inttypes.h \
+       $(top_srcdir)/include/sys/isa_defs.h \
+       $(top_srcdir)/include/sys/kidmap.h \
+       $(top_srcdir)/include/sys/kmem.h \
+       $(top_srcdir)/include/sys/kmem_cache.h \
+       $(top_srcdir)/include/sys/kobj.h \
+       $(top_srcdir)/include/sys/kstat.h \
+       $(top_srcdir)/include/sys/list.h \
+       $(top_srcdir)/include/sys/mkdev.h \
+       $(top_srcdir)/include/sys/mntent.h \
+       $(top_srcdir)/include/sys/modctl.h \
+       $(top_srcdir)/include/sys/mode.h \
+       $(top_srcdir)/include/sys/mount.h \
+       $(top_srcdir)/include/sys/mutex.h \
+       $(top_srcdir)/include/sys/note.h \
+       $(top_srcdir)/include/sys/open.h \
+       $(top_srcdir)/include/sys/param.h \
+       $(top_srcdir)/include/sys/pathname.h \
+       $(top_srcdir)/include/sys/policy.h \
+       $(top_srcdir)/include/sys/pool.h \
+       $(top_srcdir)/include/sys/priv_impl.h \
+       $(top_srcdir)/include/sys/processor.h \
+       $(top_srcdir)/include/sys/proc.h \
+       $(top_srcdir)/include/sys/pset.h \
+       $(top_srcdir)/include/sys/random.h \
+       $(top_srcdir)/include/sys/refstr.h \
+       $(top_srcdir)/include/sys/resource.h \
+       $(top_srcdir)/include/sys/rwlock.h \
+       $(top_srcdir)/include/sys/sdt.h \
+       $(top_srcdir)/include/sys/sid.h \
+       $(top_srcdir)/include/sys/signal.h \
+       $(top_srcdir)/include/sys/stat.h \
+       $(top_srcdir)/include/sys/stropts.h \
+       $(top_srcdir)/include/sys/sunddi.h \
+       $(top_srcdir)/include/sys/sunldi.h \
+       $(top_srcdir)/include/sys/sysdc.h \
+       $(top_srcdir)/include/sys/sysevent.h \
+       $(top_srcdir)/include/sys/sysmacros.h \
+       $(top_srcdir)/include/sys/systeminfo.h \
+       $(top_srcdir)/include/sys/systm.h \
+       $(top_srcdir)/include/sys/taskq.h \
+       $(top_srcdir)/include/sys/thread.h \
+       $(top_srcdir)/include/sys/time.h \
+       $(top_srcdir)/include/sys/timer.h \
+       $(top_srcdir)/include/sys/t_lock.h \
+       $(top_srcdir)/include/sys/tsd.h \
+       $(top_srcdir)/include/sys/types32.h \
+       $(top_srcdir)/include/sys/types.h \
+       $(top_srcdir)/include/sys/u8_textprep.h \
+       $(top_srcdir)/include/sys/uio.h \
+       $(top_srcdir)/include/sys/unistd.h \
+       $(top_srcdir)/include/sys/user.h \
+       $(top_srcdir)/include/sys/va_list.h \
+       $(top_srcdir)/include/sys/varargs.h \
+       $(top_srcdir)/include/sys/vfs.h \
+       $(top_srcdir)/include/sys/vfs_opreg.h \
+       $(top_srcdir)/include/sys/vmem.h \
+       $(top_srcdir)/include/sys/vmsystm.h \
+       $(top_srcdir)/include/sys/vnode.h \
+       $(top_srcdir)/include/sys/zmod.h \
+       $(top_srcdir)/include/sys/zone.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/sys
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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)
+
+# 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)"; 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-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
+
+.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-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
+
+.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/spl/include/sys/acl.h b/spl/include/sys/acl.h
new file mode 100644 (file)
index 0000000..f4a3de5
--- /dev/null
@@ -0,0 +1,117 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ACL_H
+#define _SPL_ACL_H
+
+#include <sys/types.h>
+
+typedef struct ace {
+        uid_t a_who;
+        uint32_t a_access_mask;
+        uint16_t a_flags;
+        uint16_t a_type;
+} ace_t;
+
+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;
+
+#define MAX_ACL_ENTRIES                                        1024
+
+#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)
+
+#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
+
+#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
+
+#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)
+
+#define VSA_ACE                                         0x0010
+#define VSA_ACECNT                                      0x0020
+#define VSA_ACE_ALLTYPES                                0x0040
+#define VSA_ACE_ACLFLAGS                                0x0080
+
+#endif /* _SPL_ACL_H */
diff --git a/spl/include/sys/acl_impl.h b/spl/include/sys/acl_impl.h
new file mode 100644 (file)
index 0000000..67af713
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ACL_IMPL_H
+#define _SPL_ACL_IMPL_H
+
+#endif /* _SPL_ACL_IMPL_H */
diff --git a/spl/include/sys/atomic.h b/spl/include/sys/atomic.h
new file mode 100644 (file)
index 0000000..07b460e
--- /dev/null
@@ -0,0 +1,315 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ATOMIC_H
+#define _SPL_ATOMIC_H
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <sys/types.h>
+
+/*
+ * Two approaches to atomic operations are implemented each with its
+ * own benefits are drawbacks imposed by the Solaris API.  Neither
+ * approach handles the issue of word breaking when using a 64-bit
+ * atomic variable on a 32-bit arch.  The Solaris API would need to
+ * add an atomic read call to correctly support this.
+ *
+ * When ATOMIC_SPINLOCK is defined all atomic operations will be
+ * serialized through global spin locks.  This is bad for performance
+ * but it does allow a simple generic implementation.
+ *
+ * When ATOMIC_SPINLOCK is not defined the Linux atomic operations
+ * are used.  This is safe as long as the core Linux implementation
+ * doesn't change because we are relying on the fact that an atomic
+ * type is really just a uint32 or uint64.  If this changes at some
+ * point in the future we need to fall-back to the spin approach.
+ */
+#ifdef ATOMIC_SPINLOCK
+extern spinlock_t atomic32_lock;
+extern spinlock_t atomic64_lock;
+
+static __inline__ void
+atomic_inc_32(volatile uint32_t *target)
+{
+       spin_lock(&atomic32_lock);
+       (*target)++;
+       spin_unlock(&atomic32_lock);
+}
+
+static __inline__ void
+atomic_dec_32(volatile uint32_t *target)
+{
+       spin_lock(&atomic32_lock);
+       (*target)--;
+       spin_unlock(&atomic32_lock);
+}
+
+static __inline__ void
+atomic_add_32(volatile uint32_t *target, int32_t delta)
+{
+       spin_lock(&atomic32_lock);
+       *target += delta;
+       spin_unlock(&atomic32_lock);
+}
+
+static __inline__ void
+atomic_sub_32(volatile uint32_t *target, int32_t delta)
+{
+       spin_lock(&atomic32_lock);
+       *target -= delta;
+       spin_unlock(&atomic32_lock);
+}
+
+static __inline__ uint32_t
+atomic_inc_32_nv(volatile uint32_t *target)
+{
+       uint32_t nv;
+
+       spin_lock(&atomic32_lock);
+       nv = ++(*target);
+       spin_unlock(&atomic32_lock);
+
+       return nv;
+}
+
+static __inline__ uint32_t
+atomic_dec_32_nv(volatile uint32_t *target)
+{
+       uint32_t nv;
+
+       spin_lock(&atomic32_lock);
+       nv = --(*target);
+       spin_unlock(&atomic32_lock);
+
+       return nv;
+}
+
+static __inline__ uint32_t
+atomic_add_32_nv(volatile uint32_t *target, uint32_t delta)
+{
+       uint32_t nv;
+
+       spin_lock(&atomic32_lock);
+       *target += delta;
+       nv = *target;
+       spin_unlock(&atomic32_lock);
+
+       return nv;
+}
+
+static __inline__ uint32_t
+atomic_sub_32_nv(volatile uint32_t *target, uint32_t delta)
+{
+       uint32_t nv;
+
+       spin_lock(&atomic32_lock);
+       *target -= delta;
+       nv = *target;
+       spin_unlock(&atomic32_lock);
+
+       return nv;
+}
+
+static __inline__ uint32_t
+atomic_cas_32(volatile uint32_t *target,  uint32_t cmp,
+              uint32_t newval)
+{
+       uint32_t rc;
+
+       spin_lock(&atomic32_lock);
+       rc = *target;
+       if (*target == cmp)
+               *target = newval;
+
+       spin_unlock(&atomic32_lock);
+
+       return rc;
+}
+
+static __inline__ uint32_t
+atomic_swap_32(volatile uint32_t *target,  uint32_t newval)
+{
+       uint32_t rc;
+
+       spin_lock(&atomic32_lock);
+       rc = *target;
+       *target = newval;
+       spin_unlock(&atomic32_lock);
+
+       return rc;
+}
+
+static __inline__ void
+atomic_inc_64(volatile uint64_t *target)
+{
+       spin_lock(&atomic64_lock);
+       (*target)++;
+       spin_unlock(&atomic64_lock);
+}
+
+static __inline__ void
+atomic_dec_64(volatile uint64_t *target)
+{
+       spin_lock(&atomic64_lock);
+       (*target)--;
+       spin_unlock(&atomic64_lock);
+}
+
+static __inline__ void
+atomic_add_64(volatile uint64_t *target, uint64_t delta)
+{
+       spin_lock(&atomic64_lock);
+       *target += delta;
+       spin_unlock(&atomic64_lock);
+}
+
+static __inline__ void
+atomic_sub_64(volatile uint64_t *target, uint64_t delta)
+{
+       spin_lock(&atomic64_lock);
+       *target -= delta;
+       spin_unlock(&atomic64_lock);
+}
+
+static __inline__ uint64_t
+atomic_inc_64_nv(volatile uint64_t *target)
+{
+       uint64_t nv;
+
+       spin_lock(&atomic64_lock);
+       nv = ++(*target);
+       spin_unlock(&atomic64_lock);
+
+       return nv;
+}
+
+static __inline__ uint64_t
+atomic_dec_64_nv(volatile uint64_t *target)
+{
+       uint64_t nv;
+
+       spin_lock(&atomic64_lock);
+       nv = --(*target);
+       spin_unlock(&atomic64_lock);
+
+       return nv;
+}
+
+static __inline__ uint64_t
+atomic_add_64_nv(volatile uint64_t *target, uint64_t delta)
+{
+       uint64_t nv;
+
+       spin_lock(&atomic64_lock);
+       *target += delta;
+       nv = *target;
+       spin_unlock(&atomic64_lock);
+
+       return nv;
+}
+
+static __inline__ uint64_t
+atomic_sub_64_nv(volatile uint64_t *target, uint64_t delta)
+{
+       uint64_t nv;
+
+       spin_lock(&atomic64_lock);
+       *target -= delta;
+       nv = *target;
+       spin_unlock(&atomic64_lock);
+
+       return nv;
+}
+
+static __inline__ uint64_t
+atomic_cas_64(volatile uint64_t *target,  uint64_t cmp,
+              uint64_t newval)
+{
+       uint64_t rc;
+
+       spin_lock(&atomic64_lock);
+       rc = *target;
+       if (*target == cmp)
+               *target = newval;
+       spin_unlock(&atomic64_lock);
+
+       return rc;
+}
+
+static __inline__ uint64_t
+atomic_swap_64(volatile uint64_t *target,  uint64_t newval)
+{
+       uint64_t rc;
+
+       spin_lock(&atomic64_lock);
+       rc = *target;
+       *target = newval;
+       spin_unlock(&atomic64_lock);
+
+       return rc;
+}
+
+#else /* ATOMIC_SPINLOCK */
+
+#define atomic_inc_32(v)       atomic_inc((atomic_t *)(v))
+#define atomic_dec_32(v)       atomic_dec((atomic_t *)(v))
+#define atomic_add_32(v, i)    atomic_add((i), (atomic_t *)(v))
+#define atomic_sub_32(v, i)    atomic_sub((i), (atomic_t *)(v))
+#define atomic_inc_32_nv(v)    atomic_inc_return((atomic_t *)(v))
+#define atomic_dec_32_nv(v)    atomic_dec_return((atomic_t *)(v))
+#define atomic_add_32_nv(v, i) atomic_add_return((i), (atomic_t *)(v))
+#define atomic_sub_32_nv(v, i) atomic_sub_return((i), (atomic_t *)(v))
+#define atomic_cas_32(v, x, y) atomic_cmpxchg((atomic_t *)(v), x, y)
+#define atomic_swap_32(v, x)   atomic_xchg((atomic_t *)(v), x)
+#define atomic_inc_64(v)       atomic64_inc((atomic64_t *)(v))
+#define atomic_dec_64(v)       atomic64_dec((atomic64_t *)(v))
+#define atomic_add_64(v, i)    atomic64_add((i), (atomic64_t *)(v))
+#define atomic_sub_64(v, i)    atomic64_sub((i), (atomic64_t *)(v))
+#define atomic_inc_64_nv(v)    atomic64_inc_return((atomic64_t *)(v))
+#define atomic_dec_64_nv(v)    atomic64_dec_return((atomic64_t *)(v))
+#define atomic_add_64_nv(v, i) atomic64_add_return((i), (atomic64_t *)(v))
+#define atomic_sub_64_nv(v, i) atomic64_sub_return((i), (atomic64_t *)(v))
+#define atomic_cas_64(v, x, y) atomic64_cmpxchg((atomic64_t *)(v), x, y)
+#define atomic_swap_64(v, x)   atomic64_xchg((atomic64_t *)(v), x)
+
+#endif /* ATOMIC_SPINLOCK */
+
+#ifdef _LP64
+static __inline__ void *
+atomic_cas_ptr(volatile void *target,  void *cmp, void *newval)
+{
+       return (void *)atomic_cas_64((volatile uint64_t *)target,
+                                    (uint64_t)cmp, (uint64_t)newval);
+}
+#else /* _LP64 */
+static __inline__ void *
+atomic_cas_ptr(volatile void *target,  void *cmp, void *newval)
+{
+       return (void *)atomic_cas_32((volatile uint32_t *)target,
+                                    (uint32_t)cmp, (uint32_t)newval);
+}
+#endif /* _LP64 */
+
+#endif  /* _SPL_ATOMIC_H */
diff --git a/spl/include/sys/attr.h b/spl/include/sys/attr.h
new file mode 100644 (file)
index 0000000..5fb609c
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ATTR_H
+#define _SPL_ATTR_H
+
+#endif /* SPL_ATTR_H */
diff --git a/spl/include/sys/bitmap.h b/spl/include/sys/bitmap.h
new file mode 100644 (file)
index 0000000..e4acb0b
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_BITMAP_H
+#define _SPL_BITMAP_H
+
+#endif /* SPL_BITMAP_H */
diff --git a/spl/include/sys/bootconf.h b/spl/include/sys/bootconf.h
new file mode 100644 (file)
index 0000000..4e032ad
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_BOOTCONF_H
+#define _SPL_BOOTCONF_H
+
+#endif /* SPL_BOOTCONF_H */
diff --git a/spl/include/sys/bootprops.h b/spl/include/sys/bootprops.h
new file mode 100644 (file)
index 0000000..a562ec9
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_BOOTPROPS_H
+#define _SPL_BOOTPROPS_H
+
+#endif /* SPL_BOOTPROPS_H */
diff --git a/spl/include/sys/buf.h b/spl/include/sys/buf.h
new file mode 100644 (file)
index 0000000..8596c83
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_BUF_H
+#define _SPL_BUF_H
+
+#endif /* SPL_BUF_H */
diff --git a/spl/include/sys/byteorder.h b/spl/include/sys/byteorder.h
new file mode 100644 (file)
index 0000000..5350a0b
--- /dev/null
@@ -0,0 +1,46 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_BYTEORDER_H
+#define _SPL_BYTEORDER_H
+
+#include <asm/byteorder.h>
+
+#define LE_16(x)       cpu_to_le16(x)
+#define LE_32(x)       cpu_to_le32(x)
+#define LE_64(x)       cpu_to_le64(x)
+#define BE_16(x)       cpu_to_be16(x)
+#define BE_32(x)       cpu_to_be32(x)
+#define BE_64(x)       cpu_to_be64(x)
+
+#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))
+
+#endif /* SPL_BYTEORDER_H */
diff --git a/spl/include/sys/callb.h b/spl/include/sys/callb.h
new file mode 100644 (file)
index 0000000..fbe4128
--- /dev/null
@@ -0,0 +1,55 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CALLB_H
+#define _SPL_CALLB_H
+
+#include <linux/module.h>
+#include <sys/mutex.h>
+
+#define CALLB_CPR_ASSERT(cp)           ASSERT(MUTEX_HELD((cp)->cc_lockp));
+
+typedef struct callb_cpr {
+        kmutex_t        *cc_lockp;
+} callb_cpr_t;
+
+#define CALLB_CPR_INIT(cp, lockp, func, name)   {               \
+        (cp)->cc_lockp = lockp;                                 \
+}
+
+#define CALLB_CPR_SAFE_BEGIN(cp) {                              \
+       CALLB_CPR_ASSERT(cp);                                   \
+}
+
+#define CALLB_CPR_SAFE_END(cp, lockp) {                         \
+       CALLB_CPR_ASSERT(cp);                                   \
+}
+
+#define CALLB_CPR_EXIT(cp) {                                    \
+        ASSERT(MUTEX_HELD((cp)->cc_lockp));                     \
+        mutex_exit((cp)->cc_lockp);                             \
+}
+
+#endif  /* _SPL_CALLB_H */
+
diff --git a/spl/include/sys/callo.h b/spl/include/sys/callo.h
new file mode 100644 (file)
index 0000000..0d9fbcb
--- /dev/null
@@ -0,0 +1,52 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2013 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CALLO_H
+#define _SPL_CALLO_H
+
+/*
+ * Callout flags:
+ *
+ * CALLOUT_FLAG_ROUNDUP
+ *      Roundup the expiration time to the next resolution boundary.
+ *      If this flag is not specified, the expiration time is rounded down.
+ * CALLOUT_FLAG_ABSOLUTE
+ *      Normally, the expiration passed to the timeout API functions is an
+ *      expiration interval. If this flag is specified, then it is
+ *      interpreted as the expiration time itself.
+ * CALLOUT_FLAG_HRESTIME
+ *      Normally, callouts are not affected by changes to system time
+ *      (hrestime). This flag is used to create a callout that is affected
+ *      by system time. If system time changes, these timers must be
+ *      handled in a special way (see callout.c). These are used by condition
+ *      variables and LWP timers that need this behavior.
+ * CALLOUT_FLAG_32BIT
+ *      Legacy interfaces timeout() and realtime_timeout() pass this flag
+ *      to timeout_generic() to indicate that a 32-bit ID should be allocated.
+ */
+#define CALLOUT_FLAG_ROUNDUP            0x1
+#define CALLOUT_FLAG_ABSOLUTE           0x2
+#define CALLOUT_FLAG_HRESTIME           0x4
+#define CALLOUT_FLAG_32BIT              0x8
+
+#endif  /* _SPL_CALLB_H */
diff --git a/spl/include/sys/cmn_err.h b/spl/include/sys/cmn_err.h
new file mode 100644 (file)
index 0000000..1291510
--- /dev/null
@@ -0,0 +1,42 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CMN_ERR_H
+#define _SPL_CMN_ERR_H
+
+#include <sys/varargs.h>
+
+#define CE_CONT         0       /* continuation         */
+#define CE_NOTE         1       /* notice               */
+#define CE_WARN         2       /* warning              */
+#define CE_PANIC        3       /* panic                */
+#define CE_IGNORE       4       /* print nothing        */
+
+extern void cmn_err(int, const char *, ...);
+extern void vcmn_err(int, const char *, __va_list);
+extern void vpanic(const char *, __va_list);
+
+#define fm_panic       panic
+
+#endif /* SPL_CMN_ERR_H */
diff --git a/spl/include/sys/compress.h b/spl/include/sys/compress.h
new file mode 100644 (file)
index 0000000..55822f0
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_COMPRESS_H
+#define _SPL_COMPRESS_H
+
+#endif /* SPL_COMPRESS_H */
diff --git a/spl/include/sys/condvar.h b/spl/include/sys/condvar.h
new file mode 100644 (file)
index 0000000..efcf0dd
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SPL_CONDVAR_H
+#define        _SPL_CONDVAR_H
+
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/delay_compat.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/callo.h>
+
+/*
+ * The kcondvar_t struct is protected by mutex taken externally before
+ * calling any of the wait/signal funs, and passed into the wait funs.
+ */
+#define        CV_MAGIC                        0x346545f4
+#define        CV_DESTROY                      0x346545f5
+
+typedef struct {
+       int cv_magic;
+       wait_queue_head_t cv_event;
+       wait_queue_head_t cv_destroy;
+       atomic_t cv_refs;
+       atomic_t cv_waiters;
+       kmutex_t *cv_mutex;
+} kcondvar_t;
+
+typedef enum { CV_DEFAULT = 0, CV_DRIVER } kcv_type_t;
+
+extern void __cv_init(kcondvar_t *, char *, kcv_type_t, void *);
+extern void __cv_destroy(kcondvar_t *);
+extern void __cv_wait(kcondvar_t *, kmutex_t *);
+extern void __cv_wait_io(kcondvar_t *, kmutex_t *);
+extern void __cv_wait_sig(kcondvar_t *, kmutex_t *);
+extern clock_t __cv_timedwait(kcondvar_t *, kmutex_t *, clock_t);
+extern clock_t __cv_timedwait_sig(kcondvar_t *, kmutex_t *, clock_t);
+extern clock_t cv_timedwait_hires(kcondvar_t *, kmutex_t *, hrtime_t,
+    hrtime_t res, int flag);
+extern void __cv_signal(kcondvar_t *);
+extern void __cv_broadcast(kcondvar_t *c);
+
+#define        cv_init(cvp, name, type, arg)           __cv_init(cvp, name, type, arg)
+#define        cv_destroy(cvp)                         __cv_destroy(cvp)
+#define        cv_wait(cvp, mp)                        __cv_wait(cvp, mp)
+#define        cv_wait_io(cvp, mp)                     __cv_wait_io(cvp, mp)
+#define        cv_wait_sig(cvp, mp)                    __cv_wait_sig(cvp, mp)
+#define        cv_wait_interruptible(cvp, mp)          cv_wait_sig(cvp, mp)
+#define        cv_timedwait(cvp, mp, t)                __cv_timedwait(cvp, mp, t)
+#define        cv_timedwait_sig(cvp, mp, t)            __cv_timedwait_sig(cvp, mp, t)
+#define        cv_timedwait_interruptible(cvp, mp, t)  cv_timedwait_sig(cvp, mp, t)
+#define        cv_signal(cvp)                          __cv_signal(cvp)
+#define        cv_broadcast(cvp)                       __cv_broadcast(cvp)
+
+#endif /* _SPL_CONDVAR_H */
diff --git a/spl/include/sys/conf.h b/spl/include/sys/conf.h
new file mode 100644 (file)
index 0000000..eece0c7
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CONF_H
+#define _SPL_CONF_H
+
+#endif /* SPL_CONF_H */
diff --git a/spl/include/sys/console.h b/spl/include/sys/console.h
new file mode 100644 (file)
index 0000000..76ef618
--- /dev/null
@@ -0,0 +1,44 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_CONSOLE_H
+#define        _SPL_CONSOLE_H
+
+void
+console_vprintf(const char *fmt, va_list args)
+{
+        vprintk(fmt, args);
+}
+
+void
+console_printf(const char *fmt, ...)
+{
+        va_list args;
+
+        va_start(args, fmt);
+        console_vprintf(fmt, args);
+        va_end(args);
+}
+
+#endif /* _SPL_CONSOLE_H */
diff --git a/spl/include/sys/cpupart.h b/spl/include/sys/cpupart.h
new file mode 100644 (file)
index 0000000..fddeed6
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CPUPART_H
+#define _SPL_CPUPART_H
+
+#endif /* SPL_CPUPART_H */
diff --git a/spl/include/sys/cpuvar.h b/spl/include/sys/cpuvar.h
new file mode 100644 (file)
index 0000000..1284f94
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CPUVAR_H
+#define _SPL_CPUVAR_H
+
+#endif /* SPL_CPUVAR_H */
diff --git a/spl/include/sys/crc32.h b/spl/include/sys/crc32.h
new file mode 100644 (file)
index 0000000..1981f35
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CRC32_H
+#define _SPL_CRC32_H
+
+#endif /* SPL_CRC32_H */
diff --git a/spl/include/sys/cred.h b/spl/include/sys/cred.h
new file mode 100644 (file)
index 0000000..480e268
--- /dev/null
@@ -0,0 +1,86 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CRED_H
+#define _SPL_CRED_H
+
+#include <linux/module.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+typedef struct cred cred_t;
+
+#define        kcred           ((cred_t *)(init_task.cred))
+#define        CRED()          ((cred_t *)current_cred())
+
+/* Linux 4.9 API change, GROUP_AT was removed */
+#ifndef GROUP_AT
+#define        GROUP_AT(gi, i) ((gi)->gid[i])
+#endif
+
+#ifdef HAVE_KUIDGID_T
+
+/*
+ * Linux 3.8+ uses typedefs to redefine uid_t and gid_t. We have to rename the
+ * typedefs to recover the original types. We then can use them provided that
+ * we are careful about translating from k{g,u}id_t to the original versions
+ * and vice versa.
+ */
+#define        uid_t           xuid_t
+#define        gid_t           xgid_t
+#include <linux/uidgid.h>
+#undef uid_t
+#undef gid_t
+
+#define        KUID_TO_SUID(x)         (__kuid_val(x))
+#define        KGID_TO_SGID(x)         (__kgid_val(x))
+#define        SUID_TO_KUID(x)         (KUIDT_INIT(x))
+#define        SGID_TO_KGID(x)         (KGIDT_INIT(x))
+#define        KGIDP_TO_SGIDP(x)       (&(x)->val)
+
+#else /* HAVE_KUIDGID_T */
+
+#define        KUID_TO_SUID(x)         (x)
+#define        KGID_TO_SGID(x)         (x)
+#define        SUID_TO_KUID(x)         (x)
+#define        SGID_TO_KGID(x)         (x)
+#define        KGIDP_TO_SGIDP(x)       (x)
+
+#endif /* HAVE_KUIDGID_T */
+
+extern void crhold(cred_t *cr);
+extern void crfree(cred_t *cr);
+extern uid_t crgetuid(const cred_t *cr);
+extern uid_t crgetruid(const cred_t *cr);
+extern uid_t crgetsuid(const cred_t *cr);
+extern uid_t crgetfsuid(const cred_t *cr);
+extern gid_t crgetgid(const cred_t *cr);
+extern gid_t crgetrgid(const cred_t *cr);
+extern gid_t crgetsgid(const cred_t *cr);
+extern gid_t crgetfsgid(const cred_t *cr);
+extern int crgetngroups(const cred_t *cr);
+extern gid_t * crgetgroups(const cred_t *cr);
+extern int groupmember(gid_t gid, const cred_t *cr);
+
+#endif  /* _SPL_CRED_H */
diff --git a/spl/include/sys/ctype.h b/spl/include/sys/ctype.h
new file mode 100644 (file)
index 0000000..52037f9
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_CTYPE_H
+#define _SPL_CTYPE_H
+
+#include <linux/ctype.h>
+
+#endif /* SPL_CTYPE_H */
diff --git a/spl/include/sys/ddi.h b/spl/include/sys/ddi.h
new file mode 100644 (file)
index 0000000..2fa1388
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DDI_H
+#define _SPL_DDI_H
+
+#endif /* SPL_DDI_H */
diff --git a/spl/include/sys/debug.h b/spl/include/sys/debug.h
new file mode 100644 (file)
index 0000000..a377400
--- /dev/null
@@ -0,0 +1,121 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+/*
+ * Available Solaris debug functions.  All of the ASSERT() macros will be
+ * compiled out when NDEBUG is defined, this is the default behavior for
+ * the SPL.  To enable assertions use the --enable-debug with configure.
+ * The VERIFY() functions are never compiled out and cannot be disabled.
+ *
+ * PANIC()     - Panic the node and print message.
+ * ASSERT()    - Assert X is true, if not panic.
+ * ASSERTV()   - Wraps a variable declaration which is only used by ASSERT().
+ * ASSERT3S()  - Assert signed X OP Y is true, if not panic.
+ * ASSERT3U()  - Assert unsigned X OP Y is true, if not panic.
+ * ASSERT3P()  - Assert pointer X OP Y is true, if not panic.
+ * ASSERT0()   - Assert value is zero, if not panic.
+ * VERIFY()    - Verify X is true, if not panic.
+ * VERIFY3S()  - Verify signed X OP Y is true, if not panic.
+ * VERIFY3U()  - Verify unsigned X OP Y is true, if not panic.
+ * VERIFY3P()  - Verify pointer X OP Y is true, if not panic.
+ * VERIFY0()   - Verify value is zero, if not panic.
+ */
+
+#ifndef _SPL_DEBUG_H
+#define        _SPL_DEBUG_H
+
+/*
+ * Common DEBUG functionality.
+ */
+int spl_panic(const char *file, const char *func, int line,
+    const char *fmt, ...);
+void spl_dumpstack(void);
+
+#define        PANIC(fmt, a...)                                                \
+       spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
+
+#define        VERIFY(cond)                                                    \
+       (void)(unlikely(!(cond)) &&                                     \
+           spl_panic(__FILE__, __FUNCTION__, __LINE__,                 \
+           "%s", "VERIFY(" #cond ") failed\n"))
+
+#define        VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE, FMT, CAST)                  \
+       (void)((!((TYPE)(LEFT) OP (TYPE)(RIGHT))) &&                    \
+           spl_panic(__FILE__, __FUNCTION__, __LINE__,                 \
+           "VERIFY3(" #LEFT " " #OP " " #RIGHT ") "                    \
+           "failed (" FMT " " #OP " " FMT ")\n",                       \
+           CAST (LEFT), CAST (RIGHT)))
+
+#define        VERIFY3S(x,y,z) VERIFY3_IMPL(x, y, z, int64_t, "%lld", (long long))
+#define        VERIFY3U(x,y,z) VERIFY3_IMPL(x, y, z, uint64_t, "%llu",         \
+                                   (unsigned long long))
+#define        VERIFY3P(x,y,z) VERIFY3_IMPL(x, y, z, uintptr_t, "%p", (void *))
+#define        VERIFY0(x)      VERIFY3_IMPL(0, ==, x, int64_t, "%lld", (long long))
+
+#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]
+
+/*
+ * Debugging disabled (--disable-debug)
+ */
+#ifdef NDEBUG
+
+#define        SPL_DEBUG_STR           ""
+#define        ASSERT(x)               ((void)0)
+#define        ASSERTV(x)
+#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        IMPLY(A, B)             ((void)0)
+#define        EQUIV(A, B)             ((void)0)
+
+/*
+ * Debugging enabled (--enable-debug)
+ */
+#else
+
+#define        SPL_DEBUG_STR           " (DEBUG mode)"
+#define        ASSERT(cond)            VERIFY(cond)
+#define        ASSERTV(x)              x
+#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        IMPLY(A, B) \
+       ((void)(((!(A)) || (B)) || \
+           spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+           "(" #A ") implies (" #B ")")))
+#define        EQUIV(A, B) \
+       ((void)((!!(A) == !!(B)) || \
+           spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+           "(" #A ") is equivalent to (" #B ")")))
+
+#endif /* NDEBUG */
+
+#endif /* SPL_DEBUG_H */
diff --git a/spl/include/sys/dirent.h b/spl/include/sys/dirent.h
new file mode 100644 (file)
index 0000000..68f75da
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DIRENT_H
+#define _SPL_DIRENT_H
+
+#endif /* SPL_DIRENT_H */
diff --git a/spl/include/sys/disp.h b/spl/include/sys/disp.h
new file mode 100644 (file)
index 0000000..c3077a7
--- /dev/null
@@ -0,0 +1,34 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DISP_H
+#define _SPL_DISP_H
+
+#include <linux/preempt.h>
+
+#define        kpreempt(unused)        schedule()
+#define        kpreempt_disable()      preempt_disable()
+#define        kpreempt_enable()       preempt_enable()
+
+#endif /* SPL_DISP_H */
diff --git a/spl/include/sys/dkio.h b/spl/include/sys/dkio.h
new file mode 100644 (file)
index 0000000..d8c7007
--- /dev/null
@@ -0,0 +1,38 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DKIO_H
+#define        _SPL_DKIO_H
+
+struct dk_callback {
+       void (*dkc_callback)(void *dkc_cookie, int error);
+       void *dkc_cookie;
+       int dkc_flag;
+};
+
+#define        DKIOC                   (0x04 << 8)
+#define        DKIOCFLUSHWRITECACHE    (DKIOC | 34)
+#define        DKIOCTRIM               (DKIOC | 35)
+
+#endif /* _SPL_DKIO_H */
diff --git a/spl/include/sys/dklabel.h b/spl/include/sys/dklabel.h
new file mode 100644 (file)
index 0000000..74c0d50
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DKLABEL_H
+#define        _SPL_DKLABEL_H
+
+#endif /* _SPL_DKLABEL_H */
diff --git a/spl/include/sys/dnlc.h b/spl/include/sys/dnlc.h
new file mode 100644 (file)
index 0000000..99d16c8
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DNLC_H
+#define _SPL_DNLC_H
+
+#endif /* SPL_DNLC_H */
diff --git a/spl/include/sys/dumphdr.h b/spl/include/sys/dumphdr.h
new file mode 100644 (file)
index 0000000..1b45058
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_DUMPHDR_H
+#define _SPL_DUMPHDR_H
+
+#endif /* SPL_DUMPHDR_H */
diff --git a/spl/include/sys/efi_partition.h b/spl/include/sys/efi_partition.h
new file mode 100644 (file)
index 0000000..c392364
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_EFI_PARTITION_H
+#define _SPL_EFI_PARTITION_H
+
+#endif /* SPL_EFI_PARTITION_H */
diff --git a/spl/include/sys/errno.h b/spl/include/sys/errno.h
new file mode 100644 (file)
index 0000000..64d8482
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ERRNO_H
+#define _SPL_ERRNO_H
+
+#endif /* SPL_ERRNO_H */
diff --git a/spl/include/sys/extdirent.h b/spl/include/sys/extdirent.h
new file mode 100644 (file)
index 0000000..1a5c031
--- /dev/null
@@ -0,0 +1,29 @@
+/*****************************************************************************\
+ *  Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_EXTDIRENT_H
+#define        _SPL_EXTDIRENT_H
+
+#define        ED_CASE_CONFLICT        0x10
+
+#endif /* _SPL_EXTDIRENT_H */
diff --git a/spl/include/sys/fcntl.h b/spl/include/sys/fcntl.h
new file mode 100644 (file)
index 0000000..88b7a69
--- /dev/null
@@ -0,0 +1,37 @@
+/*****************************************************************************\
+ *  Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_FCNTL_H
+#define _SPL_FCNTL_H
+
+#include <asm/fcntl.h>
+
+#define F_FREESP 11
+
+#ifdef CONFIG_64BIT
+typedef struct flock flock64_t;
+#else
+typedef struct flock64 flock64_t;
+#endif /* CONFIG_64BIT */
+
+#endif /* _SPL_FCNTL_H */
diff --git a/spl/include/sys/file.h b/spl/include/sys/file.h
new file mode 100644 (file)
index 0000000..67b301c
--- /dev/null
@@ -0,0 +1,31 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_FILE_H
+#define _SPL_FILE_H
+
+#define        FIGNORECASE     0x00080000
+#define        FKIOCTL         0x80000000
+
+#endif /* SPL_FILE_H */
diff --git a/spl/include/sys/fm/Makefile.am b/spl/include/sys/fm/Makefile.am
new file mode 100644 (file)
index 0000000..2821cbe
--- /dev/null
@@ -0,0 +1,14 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/sys/fm/protocol.h \
+       $(top_srcdir)/include/sys/fm/util.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/sys/fm
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/sys/fm/Makefile.in b/spl/include/sys/fm/Makefile.in
new file mode 100644 (file)
index 0000000..cd8e7d8
--- /dev/null
@@ -0,0 +1,623 @@
+# 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/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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/sys/fm/protocol.h \
+       $(top_srcdir)/include/sys/fm/util.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/sys/fm
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/sys/fm/protocol.h b/spl/include/sys/fm/protocol.h
new file mode 100644 (file)
index 0000000..e9ce6ff
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_FM_PROTOCOL_H
+#define        _SPL_FM_PROTOCOL_H
+
+#endif /* _SPL_FM_PROTOCOL_H */
diff --git a/spl/include/sys/fm/util.h b/spl/include/sys/fm/util.h
new file mode 100644 (file)
index 0000000..7f2dbde
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_FM_UTIL_H
+#define        _SPL_FM_UTIL_H
+
+#endif /* _SPL_FM_UTIL_H */
diff --git a/spl/include/sys/fs/Makefile.am b/spl/include/sys/fs/Makefile.am
new file mode 100644 (file)
index 0000000..581083e
--- /dev/null
@@ -0,0 +1,13 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/sys/fs/swapnode.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/sys/fs
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/sys/fs/Makefile.in b/spl/include/sys/fs/Makefile.in
new file mode 100644 (file)
index 0000000..d7b244b
--- /dev/null
@@ -0,0 +1,621 @@
+# 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/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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/swapnode.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/sys/fs/swapnode.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/sys/fs
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/sys/fs/swapnode.h b/spl/include/sys/fs/swapnode.h
new file mode 100644 (file)
index 0000000..a5df129
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SWAPNODE_H
+#define _SPL_SWAPNODE_H
+
+#endif /* SPL_SWAPNODE_H */
diff --git a/spl/include/sys/idmap.h b/spl/include/sys/idmap.h
new file mode 100644 (file)
index 0000000..3618c65
--- /dev/null
@@ -0,0 +1,29 @@
+/*****************************************************************************\
+ *  Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_IDMAP_H
+#define _SPL_IDMAP_H
+
+#define IDMAP_WK_CREATOR_OWNER_UID     2147483648U
+
+#endif /* SPL_IDMAP_H */
diff --git a/spl/include/sys/int_limits.h b/spl/include/sys/int_limits.h
new file mode 100644 (file)
index 0000000..64f0a11
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_INT_LIMITS_H
+#define _SPL_INT_LIMITS_H
+
+#endif /* SPL_INT_LIMITS_H */
diff --git a/spl/include/sys/int_types.h b/spl/include/sys/int_types.h
new file mode 100644 (file)
index 0000000..582fded
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_INT_TYPES_H
+#define _SPL_INT_TYPES_H
+
+#include <sys/inttypes.h>
+
+#endif /* SPL_INT_TYPES_H */
diff --git a/spl/include/sys/inttypes.h b/spl/include/sys/inttypes.h
new file mode 100644 (file)
index 0000000..82e555c
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_INTTYPES_H
+#define _SPL_INTTYPES_H
+
+#endif /* SPL_INTTYPES_H */
diff --git a/spl/include/sys/isa_defs.h b/spl/include/sys/isa_defs.h
new file mode 100644 (file)
index 0000000..53dead3
--- /dev/null
@@ -0,0 +1,199 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_ISA_DEFS_H
+#define        _SPL_ISA_DEFS_H
+
+/* 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
+
+/* 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
+
+/* powerpc (ppc64) 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
+
+/* 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
+
+/* sparc arch specific defines */
+#elif defined(__sparc) || defined(__sparc__)
+
+#if !defined(__sparc)
+#define __sparc
+#endif
+
+#if !defined(__sparc__)
+#define __sparc__
+#endif
+
+#if defined(__arch64__)
+#if !defined(_LP64)
+#define _LP64
+#endif
+#else
+#if !defined(_ILP32)
+#define _ILP32
+#endif
+#endif
+
+#define _BIG_ENDIAN
+#define _SUNOS_VTOC_16
+
+/* 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
+
+/* 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
+
+#include <sys/byteorder.h>
+
+#if defined(__LITTLE_ENDIAN) && !defined(_LITTLE_ENDIAN)
+#define _LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+
+#if defined(__BIG_ENDIAN) && !defined(_BIG_ENDIAN)
+#define _BIG_ENDIAN __BIG_ENDIAN
+#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 or _BIG_ENDIAN are defined"
+#endif
+
+#endif /* _SPL_ISA_DEFS_H */
diff --git a/spl/include/sys/kidmap.h b/spl/include/sys/kidmap.h
new file mode 100644 (file)
index 0000000..3d67b51
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_KIDMAP_H
+#define _SPL_KIDMAP_H
+
+#include <sys/idmap.h>
+
+#endif /* SPL_KIDMAP_H */
diff --git a/spl/include/sys/kmem.h b/spl/include/sys/kmem.h
new file mode 100644 (file)
index 0000000..d4b3bf6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SPL_KMEM_H
+#define        _SPL_KMEM_H
+
+#include <sys/debug.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+extern int kmem_debugging(void);
+extern char *kmem_vasprintf(const char *fmt, va_list ap);
+extern char *kmem_asprintf(const char *fmt, ...);
+extern char *strdup(const char *str);
+extern void strfree(char *str);
+
+/*
+ * Memory allocation interfaces
+ */
+#define        KM_SLEEP        0x0000  /* can block for memory; success guaranteed */
+#define        KM_NOSLEEP      0x0001  /* cannot block for memory; may fail */
+#define        KM_PUSHPAGE     0x0004  /* can block for memory; may use reserve */
+#define        KM_ZERO         0x1000  /* zero the allocation */
+#define        KM_VMEM         0x2000  /* caller is vmem_* wrapper */
+
+#define        KM_PUBLIC_MASK  (KM_SLEEP | KM_NOSLEEP | KM_PUSHPAGE)
+
+/*
+ * Convert a KM_* flags mask to its Linux GFP_* counterpart.  The conversion
+ * function is context aware which means that KM_SLEEP allocations can be
+ * safely used in syncing contexts which have set PF_FSTRANS.
+ */
+static inline gfp_t
+kmem_flags_convert(int flags)
+{
+       gfp_t lflags = __GFP_NOWARN | __GFP_COMP;
+
+       if (flags & KM_NOSLEEP) {
+               lflags |= GFP_ATOMIC | __GFP_NORETRY;
+       } else {
+               lflags |= GFP_KERNEL;
+               if ((current->flags & PF_FSTRANS))
+                       lflags &= ~(__GFP_IO|__GFP_FS);
+       }
+
+       if (flags & KM_PUSHPAGE)
+               lflags |= __GFP_HIGH;
+
+       if (flags & KM_ZERO)
+               lflags |= __GFP_ZERO;
+
+       return (lflags);
+}
+
+typedef struct {
+       struct task_struct *fstrans_thread;
+       unsigned int saved_flags;
+} fstrans_cookie_t;
+
+#ifdef PF_MEMALLOC_NOIO
+#define        SPL_FSTRANS (PF_FSTRANS|PF_MEMALLOC_NOIO)
+#else
+#define        SPL_FSTRANS (PF_FSTRANS)
+#endif
+
+static inline fstrans_cookie_t
+spl_fstrans_mark(void)
+{
+       fstrans_cookie_t cookie;
+
+       cookie.fstrans_thread = current;
+       cookie.saved_flags = current->flags & SPL_FSTRANS;
+       current->flags |= SPL_FSTRANS;
+
+       return (cookie);
+}
+
+static inline void
+spl_fstrans_unmark(fstrans_cookie_t cookie)
+{
+       ASSERT3P(cookie.fstrans_thread, ==, current);
+       ASSERT((current->flags & SPL_FSTRANS) == SPL_FSTRANS);
+
+       current->flags &= ~SPL_FSTRANS;
+       current->flags |= cookie.saved_flags;
+}
+
+static inline int
+spl_fstrans_check(void)
+{
+       return (current->flags & PF_FSTRANS);
+}
+
+#ifdef HAVE_ATOMIC64_T
+#define        kmem_alloc_used_add(size)       atomic64_add(size, &kmem_alloc_used)
+#define        kmem_alloc_used_sub(size)       atomic64_sub(size, &kmem_alloc_used)
+#define        kmem_alloc_used_read()          atomic64_read(&kmem_alloc_used)
+#define        kmem_alloc_used_set(size)       atomic64_set(&kmem_alloc_used, size)
+extern atomic64_t kmem_alloc_used;
+extern unsigned long long kmem_alloc_max;
+#else  /* HAVE_ATOMIC64_T */
+#define        kmem_alloc_used_add(size)       atomic_add(size, &kmem_alloc_used)
+#define        kmem_alloc_used_sub(size)       atomic_sub(size, &kmem_alloc_used)
+#define        kmem_alloc_used_read()          atomic_read(&kmem_alloc_used)
+#define        kmem_alloc_used_set(size)       atomic_set(&kmem_alloc_used, size)
+extern atomic_t kmem_alloc_used;
+extern unsigned long long kmem_alloc_max;
+#endif /* HAVE_ATOMIC64_T */
+
+extern unsigned int spl_kmem_alloc_warn;
+extern unsigned int spl_kmem_alloc_max;
+
+#define        kmem_alloc(sz, fl)      spl_kmem_alloc((sz), (fl), __func__, __LINE__)
+#define        kmem_zalloc(sz, fl)     spl_kmem_zalloc((sz), (fl), __func__, __LINE__)
+#define        kmem_free(ptr, sz)      spl_kmem_free((ptr), (sz))
+
+extern void *spl_kmem_alloc(size_t sz, int fl, const char *func, int line);
+extern void *spl_kmem_zalloc(size_t sz, int fl, const char *func, int line);
+extern void spl_kmem_free(const void *ptr, size_t sz);
+
+/*
+ * The following functions are only available for internal use.
+ */
+extern void *spl_kmem_alloc_impl(size_t size, int flags, int node);
+extern void *spl_kmem_alloc_debug(size_t size, int flags, int node);
+extern void *spl_kmem_alloc_track(size_t size, int flags,
+    const char *func, int line, int node);
+extern void spl_kmem_free_impl(const void *buf, size_t size);
+extern void spl_kmem_free_debug(const void *buf, size_t size);
+extern void spl_kmem_free_track(const void *buf, size_t size);
+
+extern int spl_kmem_init(void);
+extern void spl_kmem_fini(void);
+
+#endif /* _SPL_KMEM_H */
diff --git a/spl/include/sys/kmem_cache.h b/spl/include/sys/kmem_cache.h
new file mode 100644 (file)
index 0000000..e971c2b
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SPL_KMEM_CACHE_H
+#define        _SPL_KMEM_CACHE_H
+
+#include <sys/taskq.h>
+
+/*
+ * Slab allocation interfaces.  The SPL slab differs from the standard
+ * Linux SLAB or SLUB primarily in that each cache may be backed by slabs
+ * allocated from the physical or virtal memory address space.  The virtual
+ * slabs allow for good behavior when allocation large objects of identical
+ * size.  This slab implementation also supports both constructors and
+ * destructors which the Linux slab does not.
+ */
+enum {
+       KMC_BIT_NOTOUCH         = 0,    /* Don't update ages */
+       KMC_BIT_NODEBUG         = 1,    /* Default behavior */
+       KMC_BIT_NOMAGAZINE      = 2,    /* XXX: Unsupported */
+       KMC_BIT_NOHASH          = 3,    /* XXX: Unsupported */
+       KMC_BIT_QCACHE          = 4,    /* XXX: Unsupported */
+       KMC_BIT_KMEM            = 5,    /* Use kmem cache */
+       KMC_BIT_VMEM            = 6,    /* Use vmem cache */
+       KMC_BIT_SLAB            = 7,    /* Use Linux slab cache */
+       KMC_BIT_OFFSLAB         = 8,    /* Objects not on slab */
+       KMC_BIT_NOEMERGENCY     = 9,    /* Disable emergency objects */
+       KMC_BIT_DEADLOCKED      = 14,   /* Deadlock detected */
+       KMC_BIT_GROWING         = 15,   /* Growing in progress */
+       KMC_BIT_REAPING         = 16,   /* Reaping in progress */
+       KMC_BIT_DESTROY         = 17,   /* Destroy in progress */
+       KMC_BIT_TOTAL           = 18,   /* Proc handler helper bit */
+       KMC_BIT_ALLOC           = 19,   /* Proc handler helper bit */
+       KMC_BIT_MAX             = 20,   /* Proc handler helper bit */
+};
+
+/* kmem move callback return values */
+typedef enum kmem_cbrc {
+       KMEM_CBRC_YES           = 0,    /* Object moved */
+       KMEM_CBRC_NO            = 1,    /* Object not moved */
+       KMEM_CBRC_LATER         = 2,    /* Object not moved, try again later */
+       KMEM_CBRC_DONT_NEED     = 3,    /* Neither object is needed */
+       KMEM_CBRC_DONT_KNOW     = 4,    /* Object unknown */
+} kmem_cbrc_t;
+
+#define        KMC_NOTOUCH             (1 << KMC_BIT_NOTOUCH)
+#define        KMC_NODEBUG             (1 << KMC_BIT_NODEBUG)
+#define        KMC_NOMAGAZINE          (1 << KMC_BIT_NOMAGAZINE)
+#define        KMC_NOHASH              (1 << KMC_BIT_NOHASH)
+#define        KMC_QCACHE              (1 << KMC_BIT_QCACHE)
+#define        KMC_KMEM                (1 << KMC_BIT_KMEM)
+#define        KMC_VMEM                (1 << KMC_BIT_VMEM)
+#define        KMC_SLAB                (1 << KMC_BIT_SLAB)
+#define        KMC_OFFSLAB             (1 << KMC_BIT_OFFSLAB)
+#define        KMC_NOEMERGENCY         (1 << KMC_BIT_NOEMERGENCY)
+#define        KMC_DEADLOCKED          (1 << KMC_BIT_DEADLOCKED)
+#define        KMC_GROWING             (1 << KMC_BIT_GROWING)
+#define        KMC_REAPING             (1 << KMC_BIT_REAPING)
+#define        KMC_DESTROY             (1 << KMC_BIT_DESTROY)
+#define        KMC_TOTAL               (1 << KMC_BIT_TOTAL)
+#define        KMC_ALLOC               (1 << KMC_BIT_ALLOC)
+#define        KMC_MAX                 (1 << KMC_BIT_MAX)
+
+#define        KMC_REAP_CHUNK          INT_MAX
+#define        KMC_DEFAULT_SEEKS       1
+
+#define        KMC_EXPIRE_AGE          0x1     /* Due to age */
+#define        KMC_EXPIRE_MEM          0x2     /* Due to low memory */
+
+#define        KMC_RECLAIM_ONCE        0x1     /* Force a single shrinker pass */
+
+extern unsigned int spl_kmem_cache_expire;
+extern struct list_head spl_kmem_cache_list;
+extern struct rw_semaphore spl_kmem_cache_sem;
+
+#define        SKM_MAGIC                       0x2e2e2e2e
+#define        SKO_MAGIC                       0x20202020
+#define        SKS_MAGIC                       0x22222222
+#define        SKC_MAGIC                       0x2c2c2c2c
+
+#define        SPL_KMEM_CACHE_DELAY            15      /* Minimum slab release age */
+#define        SPL_KMEM_CACHE_REAP             0       /* Default reap everything */
+#define        SPL_KMEM_CACHE_OBJ_PER_SLAB     8       /* Target objects per slab */
+#define        SPL_KMEM_CACHE_OBJ_PER_SLAB_MIN 1       /* Minimum objects per slab */
+#define        SPL_KMEM_CACHE_ALIGN            8       /* Default object alignment */
+#ifdef _LP64
+#define        SPL_KMEM_CACHE_MAX_SIZE         32      /* Max slab size in MB */
+#else
+#define        SPL_KMEM_CACHE_MAX_SIZE         4       /* Max slab size in MB */
+#endif
+
+#define        SPL_MAX_ORDER                   (MAX_ORDER - 3)
+#define        SPL_MAX_ORDER_NR_PAGES          (1 << (SPL_MAX_ORDER - 1))
+
+#ifdef CONFIG_SLUB
+#define        SPL_MAX_KMEM_CACHE_ORDER        PAGE_ALLOC_COSTLY_ORDER
+#define        SPL_MAX_KMEM_ORDER_NR_PAGES     (1 << (SPL_MAX_KMEM_CACHE_ORDER - 1))
+#else
+#define        SPL_MAX_KMEM_ORDER_NR_PAGES     (KMALLOC_MAX_SIZE >> PAGE_SHIFT)
+#endif
+
+#define        POINTER_IS_VALID(p)             0       /* Unimplemented */
+#define        POINTER_INVALIDATE(pp)                  /* Unimplemented */
+
+typedef int (*spl_kmem_ctor_t)(void *, void *, int);
+typedef void (*spl_kmem_dtor_t)(void *, void *);
+typedef void (*spl_kmem_reclaim_t)(void *);
+
+typedef struct spl_kmem_magazine {
+       uint32_t                skm_magic;      /* Sanity magic */
+       uint32_t                skm_avail;      /* Available objects */
+       uint32_t                skm_size;       /* Magazine size */
+       uint32_t                skm_refill;     /* Batch refill size */
+       struct spl_kmem_cache   *skm_cache;     /* Owned by cache */
+       unsigned long           skm_age;        /* Last cache access */
+       unsigned int            skm_cpu;        /* Owned by cpu */
+       void                    *skm_objs[0];   /* Object pointers */
+} spl_kmem_magazine_t;
+
+typedef struct spl_kmem_obj {
+       uint32_t                sko_magic;      /* Sanity magic */
+       void                    *sko_addr;      /* Buffer address */
+       struct spl_kmem_slab    *sko_slab;      /* Owned by slab */
+       struct list_head        sko_list;       /* Free object list linkage */
+} spl_kmem_obj_t;
+
+typedef struct spl_kmem_slab {
+       uint32_t                sks_magic;      /* Sanity magic */
+       uint32_t                sks_objs;       /* Objects per slab */
+       struct spl_kmem_cache   *sks_cache;     /* Owned by cache */
+       struct list_head        sks_list;       /* Slab list linkage */
+       struct list_head        sks_free_list;  /* Free object list */
+       unsigned long           sks_age;        /* Last modify jiffie */
+       uint32_t                sks_ref;        /* Ref count used objects */
+} spl_kmem_slab_t;
+
+typedef struct spl_kmem_alloc {
+       struct spl_kmem_cache   *ska_cache;     /* Owned by cache */
+       int                     ska_flags;      /* Allocation flags */
+       taskq_ent_t             ska_tqe;        /* Task queue entry */
+} spl_kmem_alloc_t;
+
+typedef struct spl_kmem_emergency {
+       struct rb_node          ske_node;       /* Emergency tree linkage */
+       unsigned long           ske_obj;        /* Buffer address */
+} spl_kmem_emergency_t;
+
+typedef struct spl_kmem_cache {
+       uint32_t                skc_magic;      /* Sanity magic */
+       uint32_t                skc_name_size;  /* Name length */
+       char                    *skc_name;      /* Name string */
+       spl_kmem_magazine_t     **skc_mag;      /* Per-CPU warm cache */
+       uint32_t                skc_mag_size;   /* Magazine size */
+       uint32_t                skc_mag_refill; /* Magazine refill count */
+       spl_kmem_ctor_t         skc_ctor;       /* Constructor */
+       spl_kmem_dtor_t         skc_dtor;       /* Destructor */
+       spl_kmem_reclaim_t      skc_reclaim;    /* Reclaimator */
+       void                    *skc_private;   /* Private data */
+       void                    *skc_vmp;       /* Unused */
+       struct kmem_cache       *skc_linux_cache; /* Linux slab cache if used */
+       unsigned long           skc_flags;      /* Flags */
+       uint32_t                skc_obj_size;   /* Object size */
+       uint32_t                skc_obj_align;  /* Object alignment */
+       uint32_t                skc_slab_objs;  /* Objects per slab */
+       uint32_t                skc_slab_size;  /* Slab size */
+       uint32_t                skc_delay;      /* Slab reclaim interval */
+       uint32_t                skc_reap;       /* Slab reclaim count */
+       atomic_t                skc_ref;        /* Ref count callers */
+       taskqid_t               skc_taskqid;    /* Slab reclaim task */
+       struct list_head        skc_list;       /* List of caches linkage */
+       struct list_head        skc_complete_list; /* Completely alloc'ed */
+       struct list_head        skc_partial_list;  /* Partially alloc'ed */
+       struct rb_root          skc_emergency_tree; /* Min sized objects */
+       spinlock_t              skc_lock;       /* Cache lock */
+       wait_queue_head_t       skc_waitq;      /* Allocation waiters */
+       uint64_t                skc_slab_fail;  /* Slab alloc failures */
+       uint64_t                skc_slab_create;  /* Slab creates */
+       uint64_t                skc_slab_destroy; /* Slab destroys */
+       uint64_t                skc_slab_total; /* Slab total current */
+       uint64_t                skc_slab_alloc; /* Slab alloc current */
+       uint64_t                skc_slab_max;   /* Slab max historic  */
+       uint64_t                skc_obj_total;  /* Obj total current */
+       uint64_t                skc_obj_alloc;  /* Obj alloc current */
+       uint64_t                skc_obj_max;    /* Obj max historic */
+       uint64_t                skc_obj_deadlock;  /* Obj emergency deadlocks */
+       uint64_t                skc_obj_emergency; /* Obj emergency current */
+       uint64_t                skc_obj_emergency_max; /* Obj emergency max */
+} spl_kmem_cache_t;
+#define        kmem_cache_t            spl_kmem_cache_t
+
+extern spl_kmem_cache_t *spl_kmem_cache_create(char *name, size_t size,
+    size_t align, spl_kmem_ctor_t ctor, spl_kmem_dtor_t dtor,
+    spl_kmem_reclaim_t reclaim, void *priv, void *vmp, int flags);
+extern void spl_kmem_cache_set_move(spl_kmem_cache_t *,
+    kmem_cbrc_t (*)(void *, void *, size_t, void *));
+extern void spl_kmem_cache_destroy(spl_kmem_cache_t *skc);
+extern void *spl_kmem_cache_alloc(spl_kmem_cache_t *skc, int flags);
+extern void spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj);
+extern void spl_kmem_cache_set_allocflags(spl_kmem_cache_t *skc, gfp_t flags);
+extern void spl_kmem_cache_reap_now(spl_kmem_cache_t *skc, int count);
+extern void spl_kmem_reap(void);
+
+#define        kmem_cache_create(name, size, align, ctor, dtor, rclm, priv, vmp, fl) \
+    spl_kmem_cache_create(name, size, align, ctor, dtor, rclm, priv, vmp, fl)
+#define        kmem_cache_set_move(skc, move)  spl_kmem_cache_set_move(skc, move)
+#define        kmem_cache_destroy(skc)         spl_kmem_cache_destroy(skc)
+#define        kmem_cache_alloc(skc, flags)    spl_kmem_cache_alloc(skc, flags)
+#define        kmem_cache_free(skc, obj)       spl_kmem_cache_free(skc, obj)
+#define        kmem_cache_reap_now(skc)        \
+    spl_kmem_cache_reap_now(skc, skc->skc_reap)
+#define        kmem_reap()                     spl_kmem_reap()
+
+/*
+ * The following functions are only available for internal use.
+ */
+extern int spl_kmem_cache_init(void);
+extern void spl_kmem_cache_fini(void);
+
+#endif /* _SPL_KMEM_CACHE_H */
diff --git a/spl/include/sys/kobj.h b/spl/include/sys/kobj.h
new file mode 100644 (file)
index 0000000..f95fa80
--- /dev/null
@@ -0,0 +1,42 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_KOBJ_H
+#define _SPL_KOBJ_H
+
+#include <sys/vnode.h>
+
+typedef struct _buf {
+       vnode_t *vp;
+} _buf_t;
+
+typedef struct _buf buf_t;
+
+extern struct _buf *kobj_open_file(const char *name);
+extern void kobj_close_file(struct _buf *file);
+extern int kobj_read_file(struct _buf *file, char *buf,
+                         ssize_t size, offset_t off);
+extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
+
+#endif /* SPL_KOBJ_H */
diff --git a/spl/include/sys/kstat.h b/spl/include/sys/kstat.h
new file mode 100644 (file)
index 0000000..faf6b81
--- /dev/null
@@ -0,0 +1,202 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_KSTAT_H
+#define _SPL_KSTAT_H
+
+#include <linux/module.h>
+#include <linux/proc_compat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+
+#define KSTAT_STRLEN            31
+#define KSTAT_RAW_MAX          (128*1024)
+
+/* For reference valid classes are:
+ * disk, tape, net, controller, vm, kvm, hat, streams, kstat, misc
+ */
+
+#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 stats; ks_ndata == 1 */
+#define KSTAT_TYPE_IO           3       /* I/O stats; ks_ndata == 1 */
+#define KSTAT_TYPE_TIMER        4       /* event timer; ks_ndata >= 1 */
+#define KSTAT_NUM_TYPES         5
+
+#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
+#define KSTAT_DATA_LONG         5
+#define KSTAT_DATA_ULONG        6
+#define KSTAT_DATA_STRING       7
+#define KSTAT_NUM_DATAS         8
+
+#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
+
+#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_UNSUPPORTED  (KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_WRITABLE | \
+                                KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_DORMANT)
+
+
+#define KS_MAGIC                0x9d9d9d9d
+
+/* Dynamic updates */
+#define KSTAT_READ              0
+#define KSTAT_WRITE             1
+
+struct kstat_s;
+typedef struct kstat_s kstat_t;
+
+typedef int kid_t;                                  /* unique kstat id */
+typedef int kstat_update_t(struct kstat_s *, int);  /* dynamic update cb */
+
+typedef struct kstat_module {
+       char             ksm_name[KSTAT_STRLEN+1];  /* module name */
+       struct list_head ksm_module_list;           /* module linkage */
+       struct list_head ksm_kstat_list;            /* list of kstat entries */
+       struct proc_dir_entry *ksm_proc;            /* proc entry */
+} kstat_module_t;
+
+typedef struct kstat_raw_ops {
+       int (*headers)(char *buf, size_t size);
+       int (*data)(char *buf, size_t size, void *data);
+       void *(*addr)(kstat_t *ksp, loff_t index);
+} kstat_raw_ops_t;
+
+struct kstat_s {
+       int              ks_magic;                  /* magic value */
+        kid_t            ks_kid;                    /* unique kstat ID */
+        hrtime_t         ks_crtime;                 /* creation time */
+       hrtime_t         ks_snaptime;               /* last access time */
+        char             ks_module[KSTAT_STRLEN+1]; /* provider module name */
+        int              ks_instance;               /* provider module instance */
+        char             ks_name[KSTAT_STRLEN+1];   /* kstat name */
+        char             ks_class[KSTAT_STRLEN+1];  /* kstat class */
+        uchar_t          ks_type;                   /* kstat data type */
+        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;              /* size of kstat data section */
+        struct proc_dir_entry *ks_proc;             /* proc linkage */
+        kstat_update_t   *ks_update;                /* dynamic updates */
+        void             *ks_private;               /* private data */
+       kmutex_t         ks_private_lock;           /* kstat private data lock */
+       kmutex_t         *ks_lock;                  /* kstat data lock */
+        struct list_head ks_list;                   /* kstat linkage */
+       kstat_module_t   *ks_owner;                 /* kstat module linkage */
+       kstat_raw_ops_t  ks_raw_ops;                /* ops table for raw type */
+       char             *ks_raw_buf;               /* buf used for raw ops */
+       size_t           ks_raw_bufsize;            /* size of raw ops buffer */
+};
+
+typedef struct kstat_named_s {
+        char             name[KSTAT_STRLEN];        /* name of counter */
+        uchar_t          data_type;                 /* data type */
+        union {
+                char            c[16];              /* 128-bit int */
+                int32_t         i32;                /* 32-bit signed int */
+                uint32_t        ui32;               /* 32-bit unsigned int */
+                int64_t         i64;                /* 64-bit signed int */
+                uint64_t        ui64;               /* 64-bit unsigned int */
+                long            l;                  /* native signed long */
+                ulong_t         ul;                 /* native unsigned long */
+                struct {
+                        union {
+                                char *ptr;          /* NULL-term string */
+                                char __pad[8];      /* 64-bit padding */
+                        } addr;
+                        uint32_t len;               /* # bytes for strlen + '\0' */
+                } string;
+        } value;
+} kstat_named_t;
+
+#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.string.addr.ptr)
+#define KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.string.len)
+
+typedef struct kstat_intr {
+        uint_t intrs[KSTAT_NUM_INTRS];
+} kstat_intr_t;
+
+typedef struct kstat_io {
+        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 */
+        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;
+
+typedef struct kstat_timer {
+        char         name[KSTAT_STRLEN+1]; /* event name */
+        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;
+
+int spl_kstat_init(void);
+void spl_kstat_fini(void);
+
+extern 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));
+extern kstat_t *__kstat_create(const char *ks_module, int ks_instance,
+                            const char *ks_name, const char *ks_class,
+                            uchar_t ks_type, uint_t ks_ndata,
+                            uchar_t ks_flags);
+extern void __kstat_install(kstat_t *ksp);
+extern void __kstat_delete(kstat_t *ksp);
+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 *);
+
+#define kstat_set_raw_ops(k,h,d,a)     __kstat_set_raw_ops(k,h,d,a)
+#define kstat_create(m,i,n,c,t,s,f)    __kstat_create(m,i,n,c,t,s,f)
+#define kstat_install(k)               __kstat_install(k)
+#define kstat_delete(k)                        __kstat_delete(k)
+
+#endif  /* _SPL_KSTAT_H */
diff --git a/spl/include/sys/list.h b/spl/include/sys/list.h
new file mode 100644 (file)
index 0000000..563784a
--- /dev/null
@@ -0,0 +1,219 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_LIST_H
+#define _SPL_LIST_H
+
+#include <sys/types.h>
+#include <linux/list.h>
+
+/*
+ * NOTE: I have implemented the Solaris list API in terms of the native
+ * linux API.  This has certain advantages in terms of leveraging the linux
+ * list debugging infrastructure, but it also means that the internals of a
+ * list differ slightly than on Solaris.  This is not a problem as long as
+ * all callers stick to the published API.  The two major differences are:
+ *
+ * 1) A list_node_t is mapped to a linux list_head struct which changes
+ *    the name of the list_next/list_prev pointers to next/prev respectively.
+ *
+ * 2) A list_node_t which is not attached to a list on Solaris is denoted
+ *    by having its list_next/list_prev pointers set to NULL.  Under linux
+ *    the next/prev pointers are set to LIST_POISON1 and LIST_POISON2
+ *    respectively.  At this moment this only impacts the implementation
+ *    of the list_link_init() and list_link_active() functions.
+ */
+
+typedef struct list_head list_node_t;
+
+typedef struct list {
+       size_t list_size;
+       size_t list_offset;
+       list_node_t list_head;
+} list_t;
+
+#define list_d2l(a, obj) ((list_node_t *)(((char *)obj) + (a)->list_offset))
+#define list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
+
+static inline int
+list_is_empty(list_t *list)
+{
+       return list_empty(&list->list_head);
+}
+
+static inline void
+list_link_init(list_node_t *node)
+{
+       node->next = LIST_POISON1;
+       node->prev = LIST_POISON2;
+}
+
+static inline 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;
+       INIT_LIST_HEAD(&list->list_head);
+}
+
+static inline void
+list_destroy(list_t *list)
+{
+       ASSERT(list);
+       ASSERT(list_is_empty(list));
+
+       list_del(&list->list_head);
+}
+
+static inline void
+list_insert_head(list_t *list, void *object)
+{
+       list_add(list_d2l(list, object), &list->list_head);
+}
+
+static inline void
+list_insert_tail(list_t *list, void *object)
+{
+       list_add_tail(list_d2l(list, object), &list->list_head);
+}
+
+static inline void
+list_insert_after(list_t *list, void *object, void *nobject)
+{
+       if (object == NULL)
+               list_insert_head(list, nobject);
+       else
+               list_add(list_d2l(list, nobject), list_d2l(list, object));
+}
+
+static inline void
+list_insert_before(list_t *list, void *object, void *nobject)
+{
+       if (object == NULL)
+               list_insert_tail(list, nobject);
+       else
+               list_add_tail(list_d2l(list, nobject), list_d2l(list, object));
+}
+
+static inline void
+list_remove(list_t *list, void *object)
+{
+       ASSERT(!list_is_empty(list));
+       list_del(list_d2l(list, object));
+}
+
+static inline void *
+list_remove_head(list_t *list)
+{
+       list_node_t *head = list->list_head.next;
+       if (head == &list->list_head)
+               return NULL;
+
+       list_del(head);
+       return list_object(list, head);
+}
+
+static inline void *
+list_remove_tail(list_t *list)
+{
+       list_node_t *tail = list->list_head.prev;
+       if (tail == &list->list_head)
+               return NULL;
+
+       list_del(tail);
+       return list_object(list, tail);
+}
+
+static inline void *
+list_head(list_t *list)
+{
+       if (list_is_empty(list))
+               return NULL;
+
+       return list_object(list, list->list_head.next);
+}
+
+static inline void *
+list_tail(list_t *list)
+{
+       if (list_is_empty(list))
+               return NULL;
+
+       return list_object(list, list->list_head.prev);
+}
+
+static inline void *
+list_next(list_t *list, void *object)
+{
+       list_node_t *node = list_d2l(list, object);
+
+       if (node->next != &list->list_head)
+               return list_object(list, node->next);
+
+       return NULL;
+}
+
+static inline void *
+list_prev(list_t *list, void *object)
+{
+       list_node_t *node = list_d2l(list, object);
+
+       if (node->prev != &list->list_head)
+               return list_object(list, node->prev);
+
+       return NULL;
+}
+
+static inline int
+list_link_active(list_node_t *node)
+{
+       return (node->next != LIST_POISON1) && (node->prev != LIST_POISON2);
+}
+
+static inline void
+spl_list_move_tail(list_t *dst, list_t *src)
+{
+       list_splice_init(&src->list_head, dst->list_head.prev);
+}
+
+#define list_move_tail(dst, src)       spl_list_move_tail(dst, src)
+
+static inline void
+list_link_replace(list_node_t *old_node, list_node_t *new_node)
+{
+       ASSERT(list_link_active(old_node));
+       ASSERT(!list_link_active(new_node));
+
+       new_node->next = old_node->next;
+       new_node->prev = old_node->prev;
+       old_node->prev->next = new_node;
+       old_node->next->prev = new_node;
+       list_link_init(old_node);
+}
+
+#endif /* SPL_LIST_H */
diff --git a/spl/include/sys/mkdev.h b/spl/include/sys/mkdev.h
new file mode 100644 (file)
index 0000000..d765b73
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MKDEV_H
+#define _SPL_MKDEV_H
+
+#endif /* SPL_MKDEV_H */
diff --git a/spl/include/sys/mntent.h b/spl/include/sys/mntent.h
new file mode 100644 (file)
index 0000000..66fae87
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MNTENT_H
+#define _SPL_MNTENT_H
+
+#endif /* SPL_MNTENT_H */
diff --git a/spl/include/sys/modctl.h b/spl/include/sys/modctl.h
new file mode 100644 (file)
index 0000000..8d79e53
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MODCTL_H
+#define _SPL_MODCTL_H
+
+#endif /* SPL_MODCTL_H */
diff --git a/spl/include/sys/mode.h b/spl/include/sys/mode.h
new file mode 100644 (file)
index 0000000..d09965e
--- /dev/null
@@ -0,0 +1,32 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MODE_H
+#define _SPL_MODE_H
+
+#define IFTOVT(mode)   vn_mode_to_vtype(mode)
+#define VTTOIF(vtype)  vn_vtype_to_mode(vtype)
+#define MAKEIMODE(T, M) (VTTOIF(T) | ((M) & ~S_IFMT))
+
+#endif /* SPL_MODE_H */
diff --git a/spl/include/sys/mount.h b/spl/include/sys/mount.h
new file mode 100644 (file)
index 0000000..ca1796d
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_MOUNT_H
+#define _SPL_MOUNT_H
+
+#endif /* SPL_MOUNT_H */
diff --git a/spl/include/sys/mutex.h b/spl/include/sys/mutex.h
new file mode 100644 (file)
index 0000000..be69dea
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SPL_MUTEX_H
+#define        _SPL_MUTEX_H
+
+#include <sys/types.h>
+#include <linux/mutex.h>
+#include <linux/compiler_compat.h>
+
+typedef enum {
+       MUTEX_DEFAULT   = 0,
+       MUTEX_SPIN      = 1,
+       MUTEX_ADAPTIVE  = 2
+} kmutex_type_t;
+
+typedef struct {
+       struct mutex            m_mutex;
+       spinlock_t              m_lock; /* used for serializing mutex_exit */
+#ifndef HAVE_MUTEX_OWNER
+       /* only when kernel doesn't have owner */
+       kthread_t               *m_owner;
+#endif
+} kmutex_t;
+
+#define        MUTEX(mp)               (&((mp)->m_mutex))
+
+static inline void
+spl_mutex_set_owner(kmutex_t *mp)
+{
+       /*
+        * kernel will handle its owner, so we don't need to do anything if it
+        * is defined.
+        */
+#ifndef HAVE_MUTEX_OWNER
+       mp->m_owner = current;
+#endif
+}
+
+static inline void
+spl_mutex_clear_owner(kmutex_t *mp)
+{
+#ifndef HAVE_MUTEX_OWNER
+       mp->m_owner = NULL;
+#endif
+}
+
+#ifdef HAVE_MUTEX_OWNER
+#define        mutex_owner(mp)         (ACCESS_ONCE(MUTEX(mp)->owner))
+#else
+#define        mutex_owner(mp)         (ACCESS_ONCE((mp)->m_owner))
+#endif
+#define        mutex_owned(mp)         (mutex_owner(mp) == current)
+#define        MUTEX_HELD(mp)          mutex_owned(mp)
+#define        MUTEX_NOT_HELD(mp)      (!MUTEX_HELD(mp))
+
+/*
+ * The following functions must be a #define and not static inline.
+ * This ensures that the native linux mutex functions (lock/unlock)
+ * will be correctly located in the users code which is important
+ * for the built in kernel lock analysis tools
+ */
+#undef mutex_init
+#define        mutex_init(mp, name, type, ibc)                         \
+{                                                              \
+       static struct lock_class_key __key;                     \
+       ASSERT(type == MUTEX_DEFAULT);                          \
+                                                               \
+       __mutex_init(MUTEX(mp), (name) ? (#name) : (#mp), &__key); \
+       spin_lock_init(&(mp)->m_lock);                          \
+       spl_mutex_clear_owner(mp);                              \
+}
+
+#undef mutex_destroy
+#define        mutex_destroy(mp)                                       \
+{                                                              \
+       VERIFY3P(mutex_owner(mp), ==, NULL);                    \
+}
+
+#define        mutex_tryenter(mp)                                      \
+({                                                             \
+       int _rc_;                                               \
+                                                               \
+       if ((_rc_ = mutex_trylock(MUTEX(mp))) == 1)             \
+               spl_mutex_set_owner(mp);                        \
+                                                               \
+       _rc_;                                                   \
+})
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define        mutex_enter_nested(mp, subclass)                        \
+{                                                              \
+       ASSERT3P(mutex_owner(mp), !=, current);                 \
+       mutex_lock_nested(MUTEX(mp), (subclass));               \
+       spl_mutex_set_owner(mp);                                \
+}
+#else /* CONFIG_DEBUG_LOCK_ALLOC */
+#define        mutex_enter_nested(mp, subclass)                        \
+{                                                              \
+       ASSERT3P(mutex_owner(mp), !=, current);                 \
+       mutex_lock(MUTEX(mp));                                  \
+       spl_mutex_set_owner(mp);                                \
+}
+#endif /*  CONFIG_DEBUG_LOCK_ALLOC */
+
+#define        mutex_enter(mp) mutex_enter_nested((mp), 0)
+
+/*
+ * The reason for the spinlock:
+ *
+ * The Linux mutex is designed with a fast-path/slow-path design such that it
+ * does not guarantee serialization upon itself, allowing a race where latter
+ * acquirers finish mutex_unlock before former ones.
+ *
+ * The race renders it unsafe to be used for serializing the freeing of an
+ * object in which the mutex is embedded, where the latter acquirer could go
+ * on to free the object while the former one is still doing mutex_unlock and
+ * causing memory corruption.
+ *
+ * However, there are many places in ZFS where the mutex is used for
+ * serializing object freeing, and the code is shared among other OSes without
+ * this issue. Thus, we need the spinlock to force the serialization on
+ * mutex_exit().
+ *
+ * See http://lwn.net/Articles/575477/ for the information about the race.
+ */
+#define        mutex_exit(mp)                                          \
+{                                                              \
+       spin_lock(&(mp)->m_lock);                               \
+       spl_mutex_clear_owner(mp);                              \
+       mutex_unlock(MUTEX(mp));                                \
+       spin_unlock(&(mp)->m_lock);                             \
+}
+
+int spl_mutex_init(void);
+void spl_mutex_fini(void);
+
+#endif /* _SPL_MUTEX_H */
diff --git a/spl/include/sys/note.h b/spl/include/sys/note.h
new file mode 100644 (file)
index 0000000..5117562
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_NOTE_H
+#define _SPL_NOTE_H
+
+#endif /* SPL_NOTE_H */
diff --git a/spl/include/sys/open.h b/spl/include/sys/open.h
new file mode 100644 (file)
index 0000000..e3ebd8c
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_OPEN_H
+#define _SPL_OPEN_H
+
+#endif /* SPL_OPEN_H */
diff --git a/spl/include/sys/param.h b/spl/include/sys/param.h
new file mode 100644 (file)
index 0000000..5b5b5f5
--- /dev/null
@@ -0,0 +1,36 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_PARAM_H
+#define _SPL_PARAM_H
+
+#include <asm/page.h>
+
+/* Pages to bytes and back */
+#define ptob(pages)                    (pages << PAGE_SHIFT)
+#define btop(bytes)                    (bytes >> PAGE_SHIFT)
+
+#define MAXUID                         UINT32_MAX
+
+#endif /* SPL_PARAM_H */
diff --git a/spl/include/sys/pathname.h b/spl/include/sys/pathname.h
new file mode 100644 (file)
index 0000000..71ea441
--- /dev/null
@@ -0,0 +1,35 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_PATHNAME_H
+#define _SPL_PATHNAME_H
+
+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;
+
+#endif /* SPL_PATHNAME_H */
diff --git a/spl/include/sys/policy.h b/spl/include/sys/policy.h
new file mode 100644 (file)
index 0000000..45e724b
--- /dev/null
@@ -0,0 +1,47 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_POLICY_H
+#define _SPL_POLICY_H
+
+#define        secpolicy_fs_unmount(c,vfs)                     (0)
+#define        secpolicy_nfs(c)                                (0)
+#define        secpolicy_sys_config(c,co)                      (0)
+#define        secpolicy_zfs(c)                                (0)
+#define        secpolicy_zinject(c)                            (0)
+#define        secpolicy_vnode_setids_setgids(c,id)            (0)
+#define        secpolicy_vnode_setid_retain(c, sr)             (0)
+#define        secpolicy_setid_clear(v, c)                     (0)
+#define        secpolicy_vnode_any_access(c,vp,o)              (0)
+#define        secpolicy_vnode_access2(c,cp,o,m1,m2)           (0)
+#define        secpolicy_vnode_chown(c,o)                      (0)
+#define        secpolicy_vnode_setdac(c,o)                     (0)
+#define        secpolicy_vnode_remove(c)                       (0)
+#define        secpolicy_vnode_setattr(c,v,a,o,f,func,n)       (0)
+#define        secpolicy_xvattr(x, o, c, t)                    (0)
+#define        secpolicy_vnode_stky_modify(c)                  (0)
+#define        secpolicy_setid_setsticky_clear(v,a,o,c)        (0)
+#define        secpolicy_basic_link(c)                         (0)
+
+#endif /* SPL_POLICY_H */
diff --git a/spl/include/sys/pool.h b/spl/include/sys/pool.h
new file mode 100644 (file)
index 0000000..bf6a0bb
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_POOL_H
+#define _SPL_POOL_H
+
+#include <sys/pset.h>
+
+#endif /* SPL_POOL_H */
diff --git a/spl/include/sys/priv_impl.h b/spl/include/sys/priv_impl.h
new file mode 100644 (file)
index 0000000..f1507a8
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_PRIV_IMPL_H
+#define _SPL_PRIV_IMPL_H
+
+#endif /* _SPL_PRIV_IMPL_H */
diff --git a/spl/include/sys/proc.h b/spl/include/sys/proc.h
new file mode 100644 (file)
index 0000000..dbaf416
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_PROC_H
+#define _SPL_PROC_H
+
+#endif /* SPL_PROC_H */
diff --git a/spl/include/sys/processor.h b/spl/include/sys/processor.h
new file mode 100644 (file)
index 0000000..60b1a21
--- /dev/null
@@ -0,0 +1,32 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_PROCESSOR_H
+#define        _SPL_PROCESSOR_H
+
+#define getcpuid() smp_processor_id()
+
+typedef int    processorid_t;
+
+#endif /* _SPL_PROCESSOR_H */
diff --git a/spl/include/sys/pset.h b/spl/include/sys/pset.h
new file mode 100644 (file)
index 0000000..2723d31
--- /dev/null
@@ -0,0 +1,38 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_PSET_H
+#define _SPL_PSET_H
+
+typedef int psetid_t;
+
+/* special processor set id's */
+#define PS_NONE         -1
+#define PS_QUERY        -2
+#define PS_MYID         -3
+#define PS_SOFT         -4
+#define PS_HARD         -5
+#define PS_QUERY_TYPE   -6
+
+#endif /* SPL_PSET_H */
diff --git a/spl/include/sys/random.h b/spl/include/sys/random.h
new file mode 100644 (file)
index 0000000..2bf581f
--- /dev/null
@@ -0,0 +1,45 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_RANDOM_H
+#define        _SPL_RANDOM_H
+
+#include <linux/module.h>
+#include <linux/random.h>
+
+static __inline__ int
+random_get_bytes(uint8_t *ptr, size_t len)
+{
+       get_random_bytes((void *)ptr,(int)len);
+       return 0;
+}
+
+static __inline__ int
+random_get_pseudo_bytes(uint8_t *ptr, size_t len)
+{
+       get_random_bytes((void *)ptr,(int)len);
+       return 0;
+}
+
+#endif /* _SPL_RANDOM_H */
diff --git a/spl/include/sys/refstr.h b/spl/include/sys/refstr.h
new file mode 100644 (file)
index 0000000..49a3417
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_REFSTR_H
+#define _SPL_REFSTR_H
+
+#endif /* SPL_REFSTR_H */
diff --git a/spl/include/sys/resource.h b/spl/include/sys/resource.h
new file mode 100644 (file)
index 0000000..fe33655
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_RESOURCE_H
+#define _SPL_RESOURCE_H
+
+#include <linux/resource.h>
+
+#endif /* SPL_RESOURCE_H */
diff --git a/spl/include/sys/rwlock.h b/spl/include/sys/rwlock.h
new file mode 100644 (file)
index 0000000..c8ed223
--- /dev/null
@@ -0,0 +1,199 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_RWLOCK_H
+#define _SPL_RWLOCK_H
+
+#include <sys/types.h>
+#include <linux/rwsem.h>
+#include <linux/rwsem_compat.h>
+
+typedef enum {
+        RW_DRIVER  = 2,
+        RW_DEFAULT = 4
+} krw_type_t;
+
+typedef enum {
+        RW_NONE   = 0,
+        RW_WRITER = 1,
+        RW_READER = 2
+} krw_t;
+
+typedef struct {
+        struct rw_semaphore rw_rwlock;
+        kthread_t *rw_owner;
+} krwlock_t;
+
+#define SEM(rwp)                        ((struct rw_semaphore *)(rwp))
+
+static inline void
+spl_rw_set_owner(krwlock_t *rwp)
+{
+        unsigned long flags;
+
+        spl_rwsem_lock_irqsave(&SEM(rwp)->wait_lock, flags);
+        rwp->rw_owner = current;
+        spl_rwsem_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
+}
+
+static inline void
+spl_rw_clear_owner(krwlock_t *rwp)
+{
+        unsigned long flags;
+
+        spl_rwsem_lock_irqsave(&SEM(rwp)->wait_lock, flags);
+        rwp->rw_owner = NULL;
+        spl_rwsem_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
+}
+
+static inline kthread_t *
+rw_owner(krwlock_t *rwp)
+{
+        unsigned long flags;
+        kthread_t *owner;
+
+        spl_rwsem_lock_irqsave(&SEM(rwp)->wait_lock, flags);
+        owner = rwp->rw_owner;
+        spl_rwsem_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
+
+        return owner;
+}
+
+static inline int
+RW_READ_HELD(krwlock_t *rwp)
+{
+       /*
+        * Linux 4.8 will set owner to 1 when read held instead of leave it
+        * NULL. So we check whether owner <= 1.
+        */
+       return (spl_rwsem_is_locked(SEM(rwp)) &&
+           (unsigned long)rw_owner(rwp) <= 1);
+}
+
+static inline int
+RW_WRITE_HELD(krwlock_t *rwp)
+{
+       return (spl_rwsem_is_locked(SEM(rwp)) && rw_owner(rwp) == current);
+}
+
+static inline int
+RW_LOCK_HELD(krwlock_t *rwp)
+{
+       return spl_rwsem_is_locked(SEM(rwp));
+}
+
+/*
+ * The following functions must be a #define and not static inline.
+ * This ensures that the native linux semaphore functions (down/up)
+ * will be correctly located in the users code which is important
+ * for the built in kernel lock analysis tools
+ */
+#define rw_init(rwp, name, type, arg)                                   \
+({                                                                      \
+        static struct lock_class_key __key;                             \
+                                                                        \
+        __init_rwsem(SEM(rwp), #rwp, &__key);                           \
+        spl_rw_clear_owner(rwp);                                        \
+})
+
+#define rw_destroy(rwp)                                                 \
+({                                                                      \
+        VERIFY(!RW_LOCK_HELD(rwp));                                     \
+})
+
+#define rw_tryenter(rwp, rw)                                            \
+({                                                                      \
+        int _rc_ = 0;                                                   \
+                                                                        \
+        switch (rw) {                                                   \
+        case RW_READER:                                                 \
+                _rc_ = down_read_trylock(SEM(rwp));                     \
+                break;                                                  \
+        case RW_WRITER:                                                 \
+                if ((_rc_ = down_write_trylock(SEM(rwp))))              \
+                        spl_rw_set_owner(rwp);                          \
+                break;                                                  \
+        default:                                                        \
+                VERIFY(0);                                              \
+        }                                                               \
+        _rc_;                                                           \
+})
+
+#define rw_enter(rwp, rw)                                               \
+({                                                                      \
+        switch (rw) {                                                   \
+        case RW_READER:                                                 \
+                down_read(SEM(rwp));                                    \
+                break;                                                  \
+        case RW_WRITER:                                                 \
+                down_write(SEM(rwp));                                   \
+                spl_rw_set_owner(rwp);                                  \
+                break;                                                  \
+        default:                                                        \
+                VERIFY(0);                                              \
+        }                                                               \
+})
+
+#define rw_exit(rwp)                                                    \
+({                                                                      \
+        if (RW_WRITE_HELD(rwp)) {                                       \
+                spl_rw_clear_owner(rwp);                                \
+                up_write(SEM(rwp));                                     \
+        } else {                                                        \
+                ASSERT(RW_READ_HELD(rwp));                              \
+                up_read(SEM(rwp));                                      \
+        }                                                               \
+})
+
+#define rw_downgrade(rwp)                                               \
+({                                                                      \
+        spl_rw_clear_owner(rwp);                                        \
+        downgrade_write(SEM(rwp));                                      \
+})
+
+/*
+ * This implementation of rw_tryupgrade() behaves slightly differently
+ * from its counterparts on other platforms.  It drops the RW_READER lock
+ * and then acquires the RW_WRITER lock leaving a small window where no
+ * lock is held.  On other platforms the lock is never released during
+ * the upgrade process.  This is necessary under Linux because the kernel
+ * does not provide an upgrade function.
+ */
+#define rw_tryupgrade(rwp)                                             \
+({                                                                     \
+       int _rc_ = 0;                                                   \
+                                                                       \
+       if (RW_WRITE_HELD(rwp)) {                                       \
+               _rc_ = 1;                                               \
+       } else {                                                        \
+               if ((_rc_ = rwsem_tryupgrade(SEM(rwp))))                \
+                       spl_rw_set_owner(rwp);                          \
+       }                                                               \
+       _rc_;                                                           \
+})
+
+int spl_rw_init(void);
+void spl_rw_fini(void);
+
+#endif /* _SPL_RWLOCK_H */
diff --git a/spl/include/sys/sdt.h b/spl/include/sys/sdt.h
new file mode 100644 (file)
index 0000000..287bfaa
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SDT_H
+#define _SPL_SDT_H
+
+#define SET_ERROR(x) (x)
+
+#endif /* SPL_SDT_H */
diff --git a/spl/include/sys/sid.h b/spl/include/sys/sid.h
new file mode 100644 (file)
index 0000000..8ee5d07
--- /dev/null
@@ -0,0 +1,61 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SID_H
+#define _SPL_SID_H
+
+typedef struct ksiddomain {
+       char            *kd_name;
+} ksiddomain_t;
+
+typedef enum ksid_index {
+       KSID_USER,
+       KSID_GROUP,
+       KSID_OWNER,
+       KSID_COUNT
+} ksid_index_t;
+
+typedef int ksid_t;
+
+static inline ksiddomain_t *
+ksid_lookupdomain(const char *dom)
+{
+        ksiddomain_t *kd;
+       int len = strlen(dom);
+
+        kd = kmem_zalloc(sizeof(ksiddomain_t), KM_SLEEP);
+        kd->kd_name = kmem_zalloc(len + 1, KM_SLEEP);
+       memcpy(kd->kd_name, dom, len);
+
+        return (kd);
+}
+
+static inline void
+ksiddomain_rele(ksiddomain_t *ksid)
+{
+       kmem_free(ksid->kd_name, strlen(ksid->kd_name) + 1);
+        kmem_free(ksid, sizeof(ksiddomain_t));
+}
+
+#endif /* _SPL_SID_H */
diff --git a/spl/include/sys/signal.h b/spl/include/sys/signal.h
new file mode 100644 (file)
index 0000000..823fea3
--- /dev/null
@@ -0,0 +1,50 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SIGNAL_H
+#define _SPL_SIGNAL_H
+
+#include <linux/sched.h>
+
+#define        FORREAL         0       /* Usual side-effects */
+#define        JUSTLOOKING     1       /* Don't stop the process */
+
+/* The "why" argument indicates the allowable side-effects of the call:
+ *
+ * FORREAL:  Extract the next pending signal from p_sig into p_cursig;
+ * stop the process if a stop has been requested or if a traced signal
+ * is pending.
+ *
+ * JUSTLOOKING:  Don't stop the process, just indicate whether or not
+ * a signal might be pending (FORREAL is needed to tell for sure).
+ */
+static __inline__ int
+issig(int why)
+{
+       ASSERT(why == FORREAL || why == JUSTLOOKING);
+
+       return signal_pending(current);
+}
+
+#endif /* SPL_SIGNAL_H */
diff --git a/spl/include/sys/stat.h b/spl/include/sys/stat.h
new file mode 100644 (file)
index 0000000..cde7556
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_STAT_H
+#define _SPL_STAT_H
+
+#include <linux/stat.h>
+
+#endif /* SPL_STAT_H */
diff --git a/spl/include/sys/stropts.h b/spl/include/sys/stropts.h
new file mode 100644 (file)
index 0000000..25c7ee1
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_STROPTS_H
+#define _SPL_STROPTS_H
+
+#endif /* SPL_STROPTS_H */
diff --git a/spl/include/sys/sunddi.h b/spl/include/sys/sunddi.h
new file mode 100644 (file)
index 0000000..c49b0c2
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SUNDDI_H
+#define _SPL_SUNDDI_H
+
+#include <sys/cred.h>
+#include <sys/uio.h>
+#include <sys/sunldi.h>
+#include <sys/mutex.h>
+#include <sys/u8_textprep.h>
+#include <sys/vnode.h>
+
+typedef int ddi_devid_t;
+
+#define        DDI_DEV_T_NONE                          ((dev_t)-1)
+#define        DDI_DEV_T_ANY                           ((dev_t)-2)
+#define        DI_MAJOR_T_UNKNOWN                      ((major_t)0)
+
+#define        DDI_PROP_DONTPASS                       0x0001
+#define        DDI_PROP_CANSLEEP                       0x0002
+
+#define        DDI_SUCCESS                             0
+#define        DDI_FAILURE                             -1
+
+#define        ddi_prop_lookup_string(x1,x2,x3,x4,x5)  (*x5 = NULL)
+#define        ddi_prop_free(x)                        (void)0
+#define        ddi_root_node()                         (void)0
+
+extern int ddi_strtoul(const char *, char **, int, unsigned long *);
+extern int ddi_strtol(const char *, char **, int, long *);
+extern int ddi_strtoull(const char *, char **, int, unsigned long long *);
+extern int ddi_strtoll(const char *, char **, int, long long *);
+
+extern int ddi_copyin(const void *from, void *to, size_t len, int flags);
+extern int ddi_copyout(const void *from, void *to, size_t len, int flags);
+
+#endif /* SPL_SUNDDI_H */
diff --git a/spl/include/sys/sunldi.h b/spl/include/sys/sunldi.h
new file mode 100644 (file)
index 0000000..b4ff739
--- /dev/null
@@ -0,0 +1,56 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SUNLDI_H
+#define _SPL_SUNLDI_H
+
+#include <sys/types.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+
+#define SECTOR_SIZE 512
+
+typedef struct modlinkage {
+       int ml_rev;
+       struct modlfs *ml_modlfs;
+       struct modldrv *ml_modldrv;
+       major_t ml_major;
+       unsigned ml_minors;
+       void *pad1;
+} modlinkage_t;
+
+typedef struct ldi_ident {
+       char li_modname[MAXNAMELEN];
+       dev_t li_dev;
+} *ldi_ident_t;
+
+typedef struct block_device *ldi_handle_t;
+
+extern int ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip);
+extern void ldi_ident_release(ldi_ident_t li);
+
+#endif /* SPL_SUNLDI_H */
diff --git a/spl/include/sys/sysdc.h b/spl/include/sys/sysdc.h
new file mode 100644 (file)
index 0000000..14ab48a
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SYSDC_H
+#define _SPL_SYSDC_H
+
+#endif /* SPL_SYSDC_H */
diff --git a/spl/include/sys/sysevent.h b/spl/include/sys/sysevent.h
new file mode 100644 (file)
index 0000000..5a7ca41
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_SYSEVENT_H
+#define        _SPL_SYSEVENT_H
+
+#endif /* _SPL_SYSEVENT_H */
diff --git a/spl/include/sys/sysevent/Makefile.am b/spl/include/sys/sysevent/Makefile.am
new file mode 100644 (file)
index 0000000..63d9af3
--- /dev/null
@@ -0,0 +1,13 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/sys/sysevent/eventdefs.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/sys/sysevent
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/sys/sysevent/Makefile.in b/spl/include/sys/sysevent/Makefile.in
new file mode 100644 (file)
index 0000000..74d8881
--- /dev/null
@@ -0,0 +1,622 @@
+# 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/sysevent
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/sysevent/eventdefs.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/sys/sysevent/eventdefs.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/sys/sysevent
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/sysevent/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu include/sys/sysevent/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/sys/sysevent/eventdefs.h b/spl/include/sys/sysevent/eventdefs.h
new file mode 100644 (file)
index 0000000..592c78a
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef        _SPL_SYSEVENT_EVENTDEFS_H
+#define        _SPL_SYSEVENT_EVENTDEFS_H
+
+#endif /* _SPL_SYSEVENT_EVENTDEFS_H */
diff --git a/spl/include/sys/sysmacros.h b/spl/include/sys/sysmacros.h
new file mode 100644 (file)
index 0000000..4a96e07
--- /dev/null
@@ -0,0 +1,233 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SYSMACROS_H
+#define _SPL_SYSMACROS_H
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <sys/debug.h>
+#include <sys/varargs.h>
+#include <sys/zone.h>
+#include <sys/signal.h>
+
+#ifdef HAVE_SCHED_RT_HEADER
+#include <linux/sched/rt.h>
+#endif
+
+#ifndef _KERNEL
+#define _KERNEL                                __KERNEL__
+#endif
+
+#define FALSE                          0
+#define TRUE                           1
+
+#define INT8_MAX                       (127)
+#define INT8_MIN                       (-128)
+#define UINT8_MAX                      (255)
+#define UINT8_MIN                      (0)
+
+#define INT16_MAX                      (32767)
+#define INT16_MIN                      (-32768)
+#define UINT16_MAX                     (65535)
+#define UINT16_MIN                     (0)
+
+#define INT32_MAX                      INT_MAX
+#define INT32_MIN                      INT_MIN
+#define UINT32_MAX                     UINT_MAX
+#define UINT32_MIN                     UINT_MIN
+
+#define INT64_MAX                      LLONG_MAX
+#define INT64_MIN                      LLONG_MIN
+#define UINT64_MAX                     ULLONG_MAX
+#define UINT64_MIN                     ULLONG_MIN
+
+#define NBBY                           8
+#define ENOTSUP                                EOPNOTSUPP
+
+#define MAXMSGLEN                      256
+#define MAXNAMELEN                     256
+#define MAXPATHLEN                     PATH_MAX
+#define MAXOFFSET_T                    LLONG_MAX
+#define MAXBSIZE                       8192
+#define DEV_BSIZE                      512
+#define DEV_BSHIFT                     9 /* log2(DEV_BSIZE) */
+
+#define proc_pageout                   NULL
+#define curproc                                current
+#define max_ncpus                      num_possible_cpus()
+#define boot_ncpus                     num_online_cpus()
+#define CPU_SEQID                      smp_processor_id()
+#define _NOTE(x)
+#define is_system_labeled()            0
+
+#ifndef RLIM64_INFINITY
+#define RLIM64_INFINITY                        (~0ULL)
+#endif
+
+/* 0..MAX_PRIO-1:              Process priority
+ * 0..MAX_RT_PRIO-1:           RT priority tasks
+ * MAX_RT_PRIO..MAX_PRIO-1:    SCHED_NORMAL tasks
+ *
+ * Treat shim tasks as SCHED_NORMAL tasks
+ */
+#define minclsyspri                    (MAX_PRIO-1)
+#define maxclsyspri                    (MAX_RT_PRIO)
+#define defclsyspri                    (DEFAULT_PRIO)
+
+#ifndef NICE_TO_PRIO
+#define NICE_TO_PRIO(nice)             (MAX_RT_PRIO + (nice) + 20)
+#endif
+#ifndef PRIO_TO_NICE
+#define PRIO_TO_NICE(prio)             ((prio) - MAX_RT_PRIO - 20)
+#endif
+
+/*
+ * Missing macros
+ */
+#ifndef PAGESIZE
+#define PAGESIZE                       PAGE_SIZE
+#endif
+
+/* from Solaris sys/byteorder.h */
+#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))
+
+/* Map some simple functions.
+ */
+#define bzero(ptr,size)                        memset(ptr,0,size)
+#define bcopy(src,dest,size)           memmove(dest,src,size)
+#define bcmp(src,dest,size)            memcmp((src), (dest), (size_t)(size))
+
+/* Dtrace probes do not exist in the linux kernel */
+#ifdef DTRACE_PROBE
+#undef  DTRACE_PROBE
+#endif  /* DTRACE_PROBE */
+#define DTRACE_PROBE(a)                                        ((void)0)
+
+#ifdef DTRACE_PROBE1
+#undef  DTRACE_PROBE1
+#endif  /* DTRACE_PROBE1 */
+#define DTRACE_PROBE1(a, b, c)                         ((void)0)
+
+#ifdef DTRACE_PROBE2
+#undef  DTRACE_PROBE2
+#endif  /* DTRACE_PROBE2 */
+#define DTRACE_PROBE2(a, b, c, d, e)                   ((void)0)
+
+#ifdef DTRACE_PROBE3
+#undef  DTRACE_PROBE3
+#endif  /* DTRACE_PROBE3 */
+#define DTRACE_PROBE3(a, b, c, d, e, f, g)             ((void)0)
+
+#ifdef DTRACE_PROBE4
+#undef  DTRACE_PROBE4
+#endif  /* DTRACE_PROBE4 */
+#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i)       ((void)0)
+
+/* Missing globals */
+extern char spl_version[32];
+extern unsigned long spl_hostid;
+
+/* Missing misc functions */
+extern uint32_t zone_get_hostid(void *zone);
+extern void spl_setup(void);
+extern void spl_cleanup(void);
+
+#define        highbit64(x)            fls64(x)
+#define        makedevice(maj,min)     makedev(maj,min)
+
+/* 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 DIV_ROUND_UP
+#define DIV_ROUND_UP(n,d)      (((n) + (d) - 1) / (d))
+#endif
+#ifndef roundup
+#define roundup(x, y)          ((((x) + ((y) - 1)) / (y)) * (y))
+#endif
+#ifndef howmany
+#define howmany(x, y)          (((x) + ((y) - 1)) / (y))
+#endif
+
+/*
+ * 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 P2PHASE(x, align)      ((x) & ((align) - 1))
+#define P2NPHASE(x, align)     (-(x) & ((align) - 1))
+#define ISP2(x)                        (((x) & ((x) - 1)) == 0)
+#define IS_P2ALIGNED(v, a)     ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1))==0)
+#define P2BOUNDARY(off, len, align) \
+                               (((off) ^ ((off) + (len) - 1)) > (align) - 1)
+
+/*
+ * 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)))
+
+#if defined(_KERNEL) && !defined(_KMEMUSER) && !defined(offsetof)
+
+/* avoid any possibility of clashing with <stddef.h> version */
+
+#define offsetof(s, m)  ((size_t)(&(((s *)0)->m)))
+#endif
+
+#endif  /* _SPL_SYSMACROS_H */
diff --git a/spl/include/sys/systeminfo.h b/spl/include/sys/systeminfo.h
new file mode 100644 (file)
index 0000000..5c0cc46
--- /dev/null
@@ -0,0 +1,36 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SYSTEMINFO_H
+#define _SPL_SYSTEMINFO_H
+
+#define HW_HOSTID_LEN          11              /* minimum buffer size needed */
+                                               /* to hold a decimal or hex */
+                                               /* hostid string */
+
+/* Supplemental definitions for Linux. */
+#define HW_HOSTID_PATH         "/etc/hostid"   /* binary configuration file */
+#define HW_HOSTID_MASK         0xFFFFFFFF      /* significant hostid bits */
+
+#endif /* SPL_SYSTEMINFO_H */
diff --git a/spl/include/sys/systm.h b/spl/include/sys/systm.h
new file mode 100644 (file)
index 0000000..3336fb3
--- /dev/null
@@ -0,0 +1,32 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SYSTM_H
+#define _SPL_SYSTM_H
+
+#include <sys/sunddi.h>
+
+typedef uintptr_t pc_t;
+
+#endif /* SPL_SYSTM_H */
diff --git a/spl/include/sys/t_lock.h b/spl/include/sys/t_lock.h
new file mode 100644 (file)
index 0000000..6c159f9
--- /dev/null
@@ -0,0 +1,33 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_T_LOCK_H
+#define _SPL_T_LOCK_H
+
+#include <sys/param.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+
+#endif /* SPL_T_LOCK_H */
diff --git a/spl/include/sys/taskq.h b/spl/include/sys/taskq.h
new file mode 100644 (file)
index 0000000..a43a86d
--- /dev/null
@@ -0,0 +1,137 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_TASKQ_H
+#define _SPL_TASKQ_H
+
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <sys/types.h>
+#include <sys/thread.h>
+
+#define TASKQ_NAMELEN          31
+
+#define TASKQ_PREPOPULATE      0x00000001
+#define TASKQ_CPR_SAFE         0x00000002
+#define TASKQ_DYNAMIC          0x00000004
+#define TASKQ_THREADS_CPU_PCT  0x00000008
+#define TASKQ_DC_BATCH         0x00000010
+#define TASKQ_ACTIVE           0x80000000
+
+/*
+ * Flags for taskq_dispatch. TQ_SLEEP/TQ_NOSLEEP should be same as
+ * KM_SLEEP/KM_NOSLEEP.  TQ_NOQUEUE/TQ_NOALLOC are set particularly
+ * large so as not to conflict with already used GFP_* defines.
+ */
+#define TQ_SLEEP               0x00000000
+#define TQ_NOSLEEP             0x00000001
+#define TQ_PUSHPAGE            0x00000002
+#define TQ_NOQUEUE             0x01000000
+#define TQ_NOALLOC             0x02000000
+#define TQ_NEW                 0x04000000
+#define TQ_FRONT               0x08000000
+
+typedef unsigned long taskqid_t;
+typedef void (task_func_t)(void *);
+
+typedef struct taskq {
+       spinlock_t              tq_lock;       /* protects taskq_t */
+       unsigned long           tq_lock_flags; /* interrupt state */
+       char                    *tq_name;      /* taskq name */
+       struct list_head        tq_thread_list;/* list of all threads */
+       struct list_head        tq_active_list;/* list of active threads */
+       int                     tq_nactive;    /* # of active threads */
+       int                     tq_nthreads;   /* # of existing threads */
+       int                     tq_nspawn;     /* # of threads being spawned */
+       int                     tq_maxthreads; /* # of threads maximum */
+       int                     tq_pri;        /* priority */
+       int                     tq_minalloc;   /* min task_t pool size */
+       int                     tq_maxalloc;   /* max task_t pool size */
+       int                     tq_nalloc;     /* cur task_t pool size */
+       uint_t                  tq_flags;      /* flags */
+       taskqid_t               tq_next_id;    /* next pend/work id */
+       taskqid_t               tq_lowest_id;  /* lowest pend/work id */
+       struct list_head        tq_free_list;  /* free task_t's */
+       struct list_head        tq_pend_list;  /* pending task_t's */
+       struct list_head        tq_prio_list;  /* priority pending task_t's */
+       struct list_head        tq_delay_list; /* delayed task_t's */
+       wait_queue_head_t       tq_work_waitq; /* new work waitq */
+       wait_queue_head_t       tq_wait_waitq; /* wait waitq */
+} taskq_t;
+
+typedef struct taskq_ent {
+       spinlock_t              tqent_lock;
+       wait_queue_head_t       tqent_waitq;
+       struct timer_list       tqent_timer;
+       struct list_head        tqent_list;
+       taskqid_t               tqent_id;
+       task_func_t             *tqent_func;
+       void                    *tqent_arg;
+       taskq_t                 *tqent_taskq;
+       uintptr_t               tqent_flags;
+} taskq_ent_t;
+
+#define TQENT_FLAG_PREALLOC     0x1
+#define TQENT_FLAG_CANCEL       0x2
+
+typedef struct taskq_thread {
+       struct list_head        tqt_thread_list;
+       struct list_head        tqt_active_list;
+       struct task_struct      *tqt_thread;
+       taskq_t                 *tqt_tq;
+       taskqid_t               tqt_id;
+       taskq_ent_t             *tqt_task;
+       uintptr_t               tqt_flags;
+} taskq_thread_t;
+
+/* Global system-wide dynamic task queue available for all consumers */
+extern taskq_t *system_taskq;
+
+extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
+extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *,
+    uint_t, clock_t);
+extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
+    taskq_ent_t *);
+extern int taskq_empty_ent(taskq_ent_t *);
+extern void taskq_init_ent(taskq_ent_t *);
+extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
+extern void taskq_destroy(taskq_t *);
+extern void taskq_wait_id(taskq_t *, taskqid_t);
+extern void taskq_wait_outstanding(taskq_t *, taskqid_t);
+extern void taskq_wait(taskq_t *);
+extern int taskq_cancel_id(taskq_t *, taskqid_t);
+extern int taskq_member(taskq_t *, void *);
+
+#define taskq_create_proc(name, nthreads, pri, min, max, proc, flags) \
+    taskq_create(name, nthreads, pri, min, max, flags)
+#define taskq_create_sysdc(name, nthreads, min, max, proc, dc, flags) \
+    taskq_create(name, nthreads, maxclsyspri, min, max, flags)
+
+int spl_taskq_init(void);
+void spl_taskq_fini(void);
+
+#endif  /* _SPL_TASKQ_H */
diff --git a/spl/include/sys/thread.h b/spl/include/sys/thread.h
new file mode 100644 (file)
index 0000000..433a076
--- /dev/null
@@ -0,0 +1,65 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_THREAD_H
+#define _SPL_THREAD_H
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/tsd.h>
+
+/*
+ * Thread interfaces
+ */
+#define TP_MAGIC                       0x53535353
+
+#define TS_SLEEP                       TASK_INTERRUPTIBLE
+#define TS_RUN                         TASK_RUNNING
+#define TS_ZOMB                                EXIT_ZOMBIE
+#define TS_STOPPED                     TASK_STOPPED
+
+typedef void (*thread_func_t)(void *);
+
+#define thread_create(stk, stksize, func, arg, len, pp, state, pri)      \
+       __thread_create(stk, stksize, (thread_func_t)func,               \
+                       #func, arg, len, pp, state, pri)
+#define thread_exit()                  __thread_exit()
+#define thread_join(t)                 VERIFY(0)
+#define curthread                      current
+#define getcomm()                      current->comm
+#define getpid()                       current->pid
+
+extern kthread_t *__thread_create(caddr_t stk, size_t  stksize,
+                                  thread_func_t func, const char *name,
+                                  void *args, size_t len, proc_t *pp,
+                                  int state, pri_t pri);
+extern void __thread_exit(void);
+extern struct task_struct *spl_kthread_create(int (*func)(void *),
+                       void *data, const char namefmt[], ...);
+
+#endif  /* _SPL_THREAD_H */
diff --git a/spl/include/sys/time.h b/spl/include/sys/time.h
new file mode 100644 (file)
index 0000000..6501661
--- /dev/null
@@ -0,0 +1,76 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_TIME_H
+#define        _SPL_TIME_H
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <sys/types.h>
+#include <sys/timer.h>
+
+#if defined(CONFIG_64BIT)
+#define        TIME_MAX                        INT64_MAX
+#define        TIME_MIN                        INT64_MIN
+#else
+#define        TIME_MAX                        INT32_MAX
+#define        TIME_MIN                        INT32_MIN
+#endif
+
+#define        SEC                             1
+#define        MILLISEC                        1000
+#define        MICROSEC                        1000000
+#define        NANOSEC                         1000000000
+
+#define        MSEC2NSEC(m)    ((hrtime_t)(m) * (NANOSEC / MILLISEC))
+#define        NSEC2MSEC(n)    ((n) / (NANOSEC / MILLISEC))
+
+static const int hz = HZ;
+
+#define        TIMESPEC_OVERFLOW(ts)           \
+       ((ts)->tv_sec < TIME_MIN || (ts)->tv_sec > TIME_MAX)
+
+static inline void
+gethrestime(timestruc_t *now)
+{
+       *now = current_kernel_time();
+}
+
+static inline time_t
+gethrestime_sec(void)
+{
+       struct timespec ts;
+       ts = current_kernel_time();
+       return (ts.tv_sec);
+}
+
+static inline hrtime_t
+gethrtime(void)
+{
+       struct timespec now;
+       getrawmonotonic(&now);
+       return (((hrtime_t)now.tv_sec * NSEC_PER_SEC) + now.tv_nsec);
+}
+
+#endif  /* _SPL_TIME_H */
diff --git a/spl/include/sys/timer.h b/spl/include/sys/timer.h
new file mode 100644 (file)
index 0000000..33d577e
--- /dev/null
@@ -0,0 +1,60 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_TIMER_H
+#define _SPL_TIMER_H
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#define lbolt                          ((clock_t)jiffies)
+#define lbolt64                                ((int64_t)get_jiffies_64())
+
+#define ddi_get_lbolt()                        ((clock_t)jiffies)
+#define ddi_get_lbolt64()              ((int64_t)get_jiffies_64())
+
+#define ddi_time_before(a, b)          (typecheck(clock_t, a) && \
+                                       typecheck(clock_t, b) && \
+                                       ((a) - (b) < 0))
+#define ddi_time_after(a, b)           ddi_time_before(b, a)
+#define ddi_time_before_eq(a, b)       (!ddi_time_after(a, b))
+#define ddi_time_after_eq(a, b)                ddi_time_before_eq(b, a)
+
+#define ddi_time_before64(a, b)                (typecheck(int64_t, a) && \
+                                       typecheck(int64_t, b) && \
+                                       ((a) - (b) < 0))
+#define ddi_time_after64(a, b)         ddi_time_before64(b, a)
+#define ddi_time_before_eq64(a, b)     (!ddi_time_after64(a, b))
+#define ddi_time_after_eq64(a, b)      ddi_time_before_eq64(b, a)
+
+#define delay(ticks)                   schedule_timeout_uninterruptible(ticks)
+
+#define SEC_TO_TICK(sec)               ((sec) * HZ)
+#define MSEC_TO_TICK(ms)               msecs_to_jiffies(ms)
+#define USEC_TO_TICK(us)               usecs_to_jiffies(us)
+#define NSEC_TO_TICK(ns)               usecs_to_jiffies(ns / NSEC_PER_USEC)
+
+#endif  /* _SPL_TIMER_H */
+
diff --git a/spl/include/sys/tsd.h b/spl/include/sys/tsd.h
new file mode 100644 (file)
index 0000000..ebc55b0
--- /dev/null
@@ -0,0 +1,45 @@
+/*****************************************************************************\
+ *  Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_TSD_H
+#define _SPL_TSD_H
+
+#include <sys/types.h>
+
+#define TSD_HASH_TABLE_BITS_DEFAULT    9
+#define TSD_KEYS_MAX                   32768
+#define DTOR_PID                       (PID_MAX_LIMIT+1)
+#define PID_KEY                                (TSD_KEYS_MAX+1)
+
+typedef void (*dtor_func_t)(void *);
+
+extern int tsd_set(uint_t, void *);
+extern void *tsd_get(uint_t);
+extern void tsd_create(uint_t *, dtor_func_t);
+extern void tsd_destroy(uint_t *);
+extern void tsd_exit(void);
+
+int spl_tsd_init(void);
+void spl_tsd_fini(void);
+
+#endif /* _SPL_TSD_H */
diff --git a/spl/include/sys/types.h b/spl/include/sys/types.h
new file mode 100644 (file)
index 0000000..d718ca0
--- /dev/null
@@ -0,0 +1,68 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_TYPES_H
+#define        _SPL_TYPES_H
+
+#include <linux/types.h>
+#include <sys/sysmacros.h>
+
+#ifndef ULLONG_MAX
+#define ULLONG_MAX                     (~0ULL)
+#endif
+
+#ifndef LLONG_MAX
+#define LLONG_MAX                      ((long long)(~0ULL>>1))
+#endif
+
+typedef enum { B_FALSE=0, B_TRUE=1 }   boolean_t;
+typedef unsigned long                  intptr_t;
+typedef unsigned long                  ulong_t;
+typedef unsigned int                   uint_t;
+typedef unsigned char                  uchar_t;
+typedef unsigned long long             u_longlong_t;
+typedef unsigned long long             u_offset_t;
+typedef unsigned long long             rlim64_t;
+typedef long long                      longlong_t;
+typedef long long                      offset_t;
+typedef struct task_struct             kthread_t;
+typedef struct task_struct             proc_t;
+typedef short                          pri_t;
+typedef struct timespec                        timestruc_t; /* definition per SVr4 */
+typedef struct timespec                        timespec_t;
+typedef longlong_t                     hrtime_t;
+typedef unsigned short                 ushort_t;
+typedef u_longlong_t                   len_t;
+typedef longlong_t                     diskaddr_t;
+typedef ushort_t                       o_mode_t;
+typedef uint_t                         major_t;
+typedef uint_t                         minor_t;
+typedef ulong_t                                pgcnt_t;
+typedef long                           spgcnt_t;
+typedef short                          index_t;
+typedef int                            id_t;
+
+extern proc_t p0;
+
+#endif /* _SPL_TYPES_H */
diff --git a/spl/include/sys/types32.h b/spl/include/sys/types32.h
new file mode 100644 (file)
index 0000000..6ee580f
--- /dev/null
@@ -0,0 +1,36 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_TYPES32_H
+#define        _SPL_TYPES32_H
+
+#include <sys/int_types.h>
+#include <sys/types.h>
+
+typedef uint32_t       caddr32_t;
+typedef int32_t                daddr32_t;
+typedef int32_t                time32_t;
+typedef uint32_t       size32_t;
+
+#endif /* _SPL_TYPES32_H */
diff --git a/spl/include/sys/u8_textprep.h b/spl/include/sys/u8_textprep.h
new file mode 100644 (file)
index 0000000..0a21c70
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_U8_TEXTPREP_H
+#define _SPL_U8_TEXTPREP_H
+
+#endif /* SPL_U8_TEXTPREP_H */
diff --git a/spl/include/sys/uio.h b/spl/include/sys/uio.h
new file mode 100644 (file)
index 0000000..404c037
--- /dev/null
@@ -0,0 +1,106 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Copyright (c) 2015 by Chunwei Chen. All rights reserved.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_UIO_H
+#define _SPL_UIO_H
+
+#include <linux/uio.h>
+#include <linux/blkdev.h>
+#include <asm/uaccess.h>
+#include <sys/types.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_BVEC =      3,
+} uio_seg_t;
+
+typedef struct uio {
+       union {
+               const struct iovec      *uio_iov;
+               const struct bio_vec    *uio_bvec;
+       };
+       int             uio_iovcnt;
+       offset_t        uio_loffset;
+       uio_seg_t       uio_segflg;
+       uint16_t        uio_fmode;
+       uint16_t        uio_extflg;
+       offset_t        uio_limit;
+       ssize_t         uio_resid;
+       size_t          uio_skip;
+} uio_t;
+
+typedef struct aio_req {
+       uio_t           *aio_uio;
+       void            *aio_private;
+} aio_req_t;
+
+typedef enum xuio_type {
+       UIOTYPE_ASYNCIO,
+       UIOTYPE_ZEROCOPY,
+} xuio_type_t;
+
+
+#define UIOA_IOV_MAX    16
+
+typedef struct uioa_page_s {
+       int     uioa_pfncnt;
+       void    **uioa_ppp;
+       caddr_t uioa_base;
+       size_t  uioa_len;
+} uioa_page_t;
+
+typedef struct xuio {
+       uio_t xu_uio;
+       enum xuio_type xu_type;
+       union {
+               struct {
+                       uint32_t xu_a_state;
+                       ssize_t xu_a_mbytes;
+                       uioa_page_t *xu_a_lcur;
+                       void **xu_a_lppp;
+                       void *xu_a_hwst[4];
+                       uioa_page_t xu_a_locked[UIOA_IOV_MAX];
+               } xu_aio;
+
+               struct {
+                       int xu_zc_rw;
+                       void *xu_zc_priv;
+               } 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 /* SPL_UIO_H */
diff --git a/spl/include/sys/unistd.h b/spl/include/sys/unistd.h
new file mode 100644 (file)
index 0000000..e1d93c6
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_UNISTD_H
+#define _SPL_UNISTD_H
+
+#endif /* SPL_UNISTD_H */
diff --git a/spl/include/sys/user.h b/spl/include/sys/user.h
new file mode 100644 (file)
index 0000000..ebbe8f6
--- /dev/null
@@ -0,0 +1,42 @@
+/*****************************************************************************\
+ *  Copyright (C) 2015 Cluster Inc.
+ *  Produced at ClusterHQ Inc (cf, DISCLAIMER).
+ *  Written by Richard Yao <richard.yao@clusterhq.com>.
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_USER_H
+#define _SPL_USER_H
+
+/*
+ * We have uf_info_t for areleasef(). We implement areleasef() using a global
+ * linked list of all open file descriptors with the task structs referenced,
+ * so accessing the correct descriptor from areleasef() only requires knowing
+ * about the Linux task_struct. Since this is internal to our compatibility
+ * layer, we make it an opaque type.
+ *
+ * XXX: If the descriptor changes under us, we would get an incorrect
+ * reference.
+ */
+
+struct uf_info;
+typedef struct uf_info uf_info_t;
+
+#define P_FINFO(x) ((uf_info_t *)x)
+
+#endif /* SPL_USER_H */
diff --git a/spl/include/sys/va_list.h b/spl/include/sys/va_list.h
new file mode 100644 (file)
index 0000000..9fa173b
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_VA_LIST_H
+#define _SPL_VA_LIST_H
+
+#endif /* SPL_VA_LIST_H */
diff --git a/spl/include/sys/varargs.h b/spl/include/sys/varargs.h
new file mode 100644 (file)
index 0000000..bf360ff
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_VARARGS_H
+#define _SPL_VARARGS_H
+
+#define __va_list                       va_list
+
+#endif /* SPL_VARARGS_H */
diff --git a/spl/include/sys/vfs.h b/spl/include/sys/vfs.h
new file mode 100644 (file)
index 0000000..f01dc11
--- /dev/null
@@ -0,0 +1,51 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ZFS_H
+#define _SPL_ZFS_H
+
+#include <linux/mount.h>
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include <linux/statfs.h>
+#include <linux/xattr.h>
+#include <linux/security.h>
+#include <linux/seq_file.h>
+
+#define        MAXFIDSZ        64
+
+typedef struct spl_fid {
+       union {
+               long fid_pad;
+               struct {
+                       ushort_t len;           /* length of data in bytes */
+                       char     data[MAXFIDSZ];/* data (variable len) */
+               } _fid;
+       } un;
+} fid_t;
+
+#define        fid_len         un._fid.len
+#define        fid_data        un._fid.data
+
+#endif /* SPL_ZFS_H */
diff --git a/spl/include/sys/vfs_opreg.h b/spl/include/sys/vfs_opreg.h
new file mode 100644 (file)
index 0000000..d3540c5
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_OPREG_H
+#define _SPL_OPREG_H
+
+#endif /* SPL_OPREG_H */
diff --git a/spl/include/sys/vmem.h b/spl/include/sys/vmem.h
new file mode 100644 (file)
index 0000000..a9b12ee
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SPL_VMEM_H
+#define        _SPL_VMEM_H
+
+#include <sys/kmem.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+typedef struct vmem { } vmem_t;
+
+extern vmem_t *heap_arena;
+extern vmem_t *zio_alloc_arena;
+extern vmem_t *zio_arena;
+
+extern size_t vmem_size(vmem_t *vmp, int typemask);
+
+/*
+ * Memory allocation interfaces
+ */
+#define        VMEM_ALLOC      0x01
+#define        VMEM_FREE       0x02
+
+#ifndef VMALLOC_TOTAL
+#define        VMALLOC_TOTAL   (VMALLOC_END - VMALLOC_START)
+#endif
+
+/*
+ * vmem_* is an interface to a low level arena-based memory allocator on
+ * Illumos that is used to allocate virtual address space. The kmem SLAB
+ * allocator allocates slabs from it. Then the generic allocation functions
+ * kmem_{alloc,zalloc,free}() are layered on top of SLAB allocators.
+ *
+ * On Linux, the primary means of doing allocations is via kmalloc(), which
+ * is similarly layered on top of something called the buddy allocator. The
+ * buddy allocator is not available to kernel modules, it uses physical
+ * memory addresses rather than virtual memory addresses and is prone to
+ * fragmentation.
+ *
+ * Linux sets aside a relatively small address space for in-kernel virtual
+ * memory from which allocations can be done using vmalloc().  It might seem
+ * like a good idea to use vmalloc() to implement something similar to
+ * Illumos' allocator. However, this has the following problems:
+ *
+ * 1. Page directory table allocations are hard coded to use GFP_KERNEL.
+ *    Consequently, any KM_PUSHPAGE or KM_NOSLEEP allocations done using
+ *    vmalloc() will not have proper semantics.
+ *
+ * 2. Address space exhaustion is a real issue on 32-bit platforms where
+ *    only a few 100MB are available. The kernel will handle it by spinning
+ *    when it runs out of address space.
+ *
+ * 3. All vmalloc() allocations and frees are protected by a single global
+ *    lock which serializes all allocations.
+ *
+ * 4. Accessing /proc/meminfo and /proc/vmallocinfo will iterate the entire
+ *    list. The former will sum the allocations while the latter will print
+ *    them to user space in a way that user space can keep the lock held
+ *    indefinitely.  When the total number of mapped allocations is large
+ *    (several 100,000) a large amount of time will be spent waiting on locks.
+ *
+ * 5. Linux has a wait_on_bit() locking primitive that assumes physical
+ *    memory is used, it simply does not work on virtual memory.  Certain
+ *    Linux structures (e.g. the superblock) use them and might be embedded
+ *    into a structure from Illumos.  This makes using Linux virtual memory
+ *    unsafe in certain situations.
+ *
+ * It follows that we cannot obtain identical semantics to those on Illumos.
+ * Consequently, we implement the kmem_{alloc,zalloc,free}() functions in
+ * such a way that they can be used as drop-in replacements for small vmem_*
+ * allocations (8MB in size or smaller) and map vmem_{alloc,zalloc,free}()
+ * to them.
+ */
+
+#define        vmem_alloc(sz, fl)      spl_vmem_alloc((sz), (fl), __func__, __LINE__)
+#define        vmem_zalloc(sz, fl)     spl_vmem_zalloc((sz), (fl), __func__, __LINE__)
+#define        vmem_free(ptr, sz)      spl_vmem_free((ptr), (sz))
+#define        vmem_qcache_reap(ptr)   ((void)0)
+
+extern void *spl_vmem_alloc(size_t sz, int fl, const char *func, int line);
+extern void *spl_vmem_zalloc(size_t sz, int fl, const char *func, int line);
+extern void spl_vmem_free(const void *ptr, size_t sz);
+
+int spl_vmem_init(void);
+void spl_vmem_fini(void);
+
+#endif /* _SPL_VMEM_H */
diff --git a/spl/include/sys/vmsystm.h b/spl/include/sys/vmsystm.h
new file mode 100644 (file)
index 0000000..9d334fe
--- /dev/null
@@ -0,0 +1,84 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_VMSYSTM_H
+#define _SPL_VMSYSTM_H
+
+#include <linux/mmzone.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+#include <sys/types.h>
+#include <asm/uaccess.h>
+
+#define        membar_producer()               smp_wmb()
+#define        physmem                         totalram_pages
+#define        freemem                 (nr_free_pages() + \
+                               global_page_state(NR_INACTIVE_FILE) + \
+                               global_page_state(NR_INACTIVE_ANON) + \
+                               global_page_state(NR_SLAB_RECLAIMABLE))
+
+#define        xcopyin(from, to, size)         copy_from_user(to, from, size)
+#define        xcopyout(from, to, size)        copy_to_user(to, from, size)
+
+static __inline__ int
+copyin(const void *from, void *to, size_t len)
+{
+       /* On error copyin routine returns -1 */
+       if (xcopyin(from, to, len))
+               return -1;
+
+       return 0;
+}
+
+static __inline__ int
+copyout(const void *from, void *to, size_t len)
+{
+       /* On error copyout routine returns -1 */
+       if (xcopyout(from, to, len))
+               return -1;
+
+       return 0;
+}
+
+static __inline__ int
+copyinstr(const void *from, void *to, size_t len, size_t *done)
+{
+       size_t rc;
+
+       if (len == 0)
+               return -ENAMETOOLONG;
+
+       /* XXX: Should return ENAMETOOLONG if 'strlen(from) > len' */
+
+       memset(to, 0, len);
+       rc = copyin(from, to, len - 1);
+       if (done != NULL)
+               *done = rc;
+
+       return 0;
+}
+
+#endif /* SPL_VMSYSTM_H */
diff --git a/spl/include/sys/vnode.h b/spl/include/sys/vnode.h
new file mode 100644 (file)
index 0000000..0b857d3
--- /dev/null
@@ -0,0 +1,207 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_VNODE_H
+#define _SPL_VNODE_H
+
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/fcntl.h>
+#include <linux/buffer_head.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fs_struct.h>
+#include <linux/mount.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/user.h>
+#include <sys/sunldi.h>
+
+/*
+ * Prior to linux-2.6.33 only O_DSYNC semantics were implemented and
+ * they used the O_SYNC flag.  As of linux-2.6.33 the this behavior
+ * was properly split in to O_SYNC and O_DSYNC respectively.
+ */
+#ifndef O_DSYNC
+#define O_DSYNC                O_SYNC
+#endif
+
+#define FREAD          1
+#define FWRITE         2
+#define FCREAT         O_CREAT
+#define FTRUNC         O_TRUNC
+#define FOFFMAX                O_LARGEFILE
+#define FSYNC          O_SYNC
+#define FDSYNC         O_DSYNC
+#define FRSYNC         O_SYNC
+#define FEXCL          O_EXCL
+#define FDIRECT                O_DIRECT
+#define FAPPEND                O_APPEND
+
+#define FNODSYNC       0x10000 /* fsync pseudo flag */
+#define FNOFOLLOW      0x20000 /* don't follow symlinks */
+
+#define F_FREESP       11      /* Free file space */
+
+
+/*
+ * The vnode AT_ flags are mapped to the Linux ATTR_* flags.
+ * This allows them to be used safely with an iattr structure.
+ * The AT_XVATTR flag has been added and mapped to the upper
+ * bit range to avoid conflicting with the standard Linux set.
+ */
+#undef AT_UID
+#undef AT_GID
+
+#define AT_MODE                ATTR_MODE
+#define AT_UID         ATTR_UID
+#define AT_GID         ATTR_GID
+#define AT_SIZE                ATTR_SIZE
+#define AT_ATIME       ATTR_ATIME
+#define AT_MTIME       ATTR_MTIME
+#define AT_CTIME       ATTR_CTIME
+
+#define ATTR_XVATTR    (1 << 31)
+#define AT_XVATTR      ATTR_XVATTR
+
+#define ATTR_IATTR_MASK        (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_SIZE | \
+                       ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_FILE)
+
+#define CRCREAT                0x01
+#define RMFILE         0x02
+
+#define B_INVAL                0x01
+#define B_TRUNC                0x02
+
+#define LOOKUP_DIR             0x01
+#define LOOKUP_XATTR           0x02
+#define CREATE_XATTR_DIR       0x04
+#define ATTR_NOACLCHECK                0x20
+
+typedef enum vtype {
+       VNON            = 0,
+       VREG            = 1,
+       VDIR            = 2,
+       VBLK            = 3,
+       VCHR            = 4,
+       VLNK            = 5,
+       VFIFO           = 6,
+       VDOOR           = 7,
+       VPROC           = 8,
+       VSOCK           = 9,
+       VPORT           = 10,
+       VBAD            = 11
+} vtype_t;
+
+typedef struct vattr {
+       enum vtype      va_type;        /* vnode type */
+       u_int           va_mask;        /* attribute bit-mask */
+       u_short         va_mode;        /* acc mode */
+       uid_t           va_uid;         /* owner uid */
+       gid_t           va_gid;         /* owner gid */
+       long            va_fsid;        /* fs id */
+       long            va_nodeid;      /* node # */
+       uint32_t        va_nlink;       /* # links */
+       uint64_t        va_size;        /* file size */
+       struct timespec va_atime;       /* last acc */
+       struct timespec va_mtime;       /* last mod */
+       struct timespec va_ctime;       /* last chg */
+       dev_t           va_rdev;        /* dev */
+       uint64_t        va_nblocks;     /* space used */
+       uint32_t        va_blksize;     /* block size */
+       uint32_t        va_seq;         /* sequence */
+       struct dentry   *va_dentry;     /* dentry to wire */
+} vattr_t;
+
+typedef struct vnode {
+       struct file     *v_file;
+       kmutex_t        v_lock;         /* protects vnode fields */
+       uint_t          v_flag;         /* vnode flags (see below) */
+       uint_t          v_count;        /* reference count */
+       void            *v_data;        /* private data for fs */
+       struct vfs      *v_vfsp;        /* ptr to containing VFS */
+       struct stdata   *v_stream;      /* associated stream */
+       enum vtype      v_type;         /* vnode type */
+       dev_t           v_rdev;         /* device (VCHR, VBLK) */
+       gfp_t           v_gfp_mask;     /* original mapping gfp mask */
+} vnode_t;
+
+typedef struct vn_file {
+       int             f_fd;           /* linux fd for lookup */
+       struct task_struct *f_task;     /* linux task this fd belongs to */
+       struct file     *f_file;        /* linux file struct */
+       atomic_t        f_ref;          /* ref count */
+       kmutex_t        f_lock;         /* struct lock */
+       loff_t          f_offset;       /* offset */
+       vnode_t         *f_vnode;       /* vnode */
+       struct list_head f_list;        /* list referenced file_t's */
+} file_t;
+
+extern vnode_t *vn_alloc(int flag);
+void vn_free(vnode_t *vp);
+extern vtype_t vn_mode_to_vtype(mode_t);
+extern mode_t vn_vtype_to_mode(vtype_t);
+extern int vn_open(const char *path, uio_seg_t seg, int flags, int mode,
+                  vnode_t **vpp, int x1, void *x2);
+extern int vn_openat(const char *path, uio_seg_t seg, int flags, int mode,
+                    vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd);
+extern int vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len,
+                  offset_t off, uio_seg_t seg, int x1, rlim64_t x2,
+                  void *x3, ssize_t *residp);
+extern int vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4);
+extern int vn_seek(vnode_t *vp, offset_t o, offset_t *op, void *ct);
+
+extern int vn_remove(const char *path, uio_seg_t seg, int flags);
+extern int vn_rename(const char *path1, const char *path2, int x1);
+extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4);
+extern int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4);
+extern int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
+    offset_t offset, void *x6, void *x7);
+extern file_t *vn_getf(int fd);
+extern void vn_releasef(int fd);
+extern void vn_areleasef(int fd, uf_info_t *fip);
+extern int vn_set_pwd(const char *filename);
+
+int spl_vn_init(void);
+void spl_vn_fini(void);
+
+#define VOP_CLOSE                              vn_close
+#define VOP_SEEK                               vn_seek
+#define VOP_GETATTR                            vn_getattr
+#define VOP_FSYNC                              vn_fsync
+#define VOP_SPACE                              vn_space
+#define VOP_PUTPAGE(vp, o, s, f, x1, x2)       ((void)0)
+#define vn_is_readonly(vp)                     0
+#define getf                                   vn_getf
+#define releasef                               vn_releasef
+#define areleasef                              vn_areleasef
+
+extern vnode_t *rootdir;
+
+#endif /* SPL_VNODE_H */
diff --git a/spl/include/sys/zmod.h b/spl/include/sys/zmod.h
new file mode 100644 (file)
index 0000000..15b0bc8
--- /dev/null
@@ -0,0 +1,69 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  z_compress_level/z_uncompress are nearly identical copies of the
+ *  compress2/uncompress functions provided by the official zlib package
+ *  available at http://zlib.net/.  The only changes made we to slightly
+ *  adapt the functions called to match the linux kernel implementation
+ *  of zlib.  The full zlib license follows:
+ *
+ *  zlib.h -- interface of the 'zlib' general purpose compression library
+ *  version 1.2.5, April 19th, 2010
+ *
+ *  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty.  In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  1. The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  2. Altered source versions must be plainly marked as such, and must not be
+ *     misrepresented as being the original software.
+ *  3. This notice may not be removed or altered from any source distribution.
+ *
+ *  Jean-loup Gailly
+ *  Mark Adler
+\*****************************************************************************/
+
+#ifndef _SPL_ZMOD_H
+#define _SPL_ZMOD_H
+
+#include <sys/types.h>
+#include <linux/zlib.h>
+
+extern int z_compress_level(void *dest, size_t *destLen, const void *source,
+    size_t sourceLen, int level);
+extern int z_uncompress(void *dest, size_t *destLen, const void *source,
+    size_t sourceLen);
+
+int spl_zlib_init(void);
+void spl_zlib_fini(void);
+
+#endif /* SPL_ZMOD_H */
diff --git a/spl/include/sys/zone.h b/spl/include/sys/zone.h
new file mode 100644 (file)
index 0000000..5a3c086
--- /dev/null
@@ -0,0 +1,36 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_ZONE_H
+#define _SPL_ZONE_H
+
+#include <sys/byteorder.h>
+
+#define        GLOBAL_ZONEID                   0
+
+#define        zone_dataset_visible(x, y)      (1)
+#define        crgetzoneid(x)                  (GLOBAL_ZONEID)
+#define        INGLOBALZONE(z)                 (1)
+
+#endif /* SPL_ZONE_H */
diff --git a/spl/include/unistd.h b/spl/include/unistd.h
new file mode 100644 (file)
index 0000000..e1d93c6
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_UNISTD_H
+#define _SPL_UNISTD_H
+
+#endif /* SPL_UNISTD_H */
diff --git a/spl/include/util/Makefile.am b/spl/include/util/Makefile.am
new file mode 100644 (file)
index 0000000..e2bf09f
--- /dev/null
@@ -0,0 +1,14 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/util/qsort.h \
+       $(top_srcdir)/include/util/sscanf.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/util
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/util/Makefile.in b/spl/include/util/Makefile.in
new file mode 100644 (file)
index 0000000..b01e799
--- /dev/null
@@ -0,0 +1,623 @@
+# 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/util
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/util/qsort.h \
+       $(top_srcdir)/include/util/sscanf.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/util/qsort.h \
+       $(top_srcdir)/include/util/sscanf.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/util
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/util/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu include/util/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/util/qsort.h b/spl/include/util/qsort.h
new file mode 100644 (file)
index 0000000..e55c4f8
--- /dev/null
@@ -0,0 +1,32 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_QSORT_H
+#define _SPL_QSORT_H
+
+#include <linux/sort.h>
+
+#define qsort(base, num, size, cmp)    sort(base, num, size, cmp, NULL)
+
+#endif /* SPL_QSORT_H */
diff --git a/spl/include/util/sscanf.h b/spl/include/util/sscanf.h
new file mode 100644 (file)
index 0000000..23f0b5d
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_UTIL_SSCANF_H
+#define _SPL_UTIL_SSCANF_H
+
+#endif /* SPL_UTIL_SSCAN_H */
diff --git a/spl/include/vm/Makefile.am b/spl/include/vm/Makefile.am
new file mode 100644 (file)
index 0000000..7faab0a
--- /dev/null
@@ -0,0 +1,15 @@
+COMMON_H =
+
+KERNEL_H = \
+       $(top_srcdir)/include/vm/anon.h \
+       $(top_srcdir)/include/vm/pvn.h \
+       $(top_srcdir)/include/vm/seg_kmem.h
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/spl-$(VERSION)/include/vm
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/spl/include/vm/Makefile.in b/spl/include/vm/Makefile.in
new file mode 100644 (file)
index 0000000..b052939
--- /dev/null
@@ -0,0 +1,625 @@
+# 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/vm
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/spl_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/vm/anon.h \
+       $(top_srcdir)/include/vm/pvn.h \
+       $(top_srcdir)/include/vm/seg_kmem.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)"
+HEADERS = $(kernel_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+COMMON_H = 
+KERNEL_H = \
+       $(top_srcdir)/include/vm/anon.h \
+       $(top_srcdir)/include/vm/pvn.h \
+       $(top_srcdir)/include/vm/seg_kmem.h
+
+USER_H = 
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/spl-$(VERSION)/include/vm
+@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(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/vm/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu include/vm/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)
+
+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)"; 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-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
+
+.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-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
+
+.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/spl/include/vm/anon.h b/spl/include/vm/anon.h
new file mode 100644 (file)
index 0000000..9c9c239
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_VM_ANON_H
+#define _SPL_VM_ANON_H
+
+#endif /* SPL_VM_ANON_H */
diff --git a/spl/include/vm/pvn.h b/spl/include/vm/pvn.h
new file mode 100644 (file)
index 0000000..f3b3081
--- /dev/null
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_VM_PVN_H
+#define _SPL_VM_PVN_H
+
+#endif /* SPL_VM_PVN_H */
diff --git a/spl/include/vm/seg_kmem.h b/spl/include/vm/seg_kmem.h
new file mode 100644 (file)
index 0000000..17df7b9
--- /dev/null
@@ -0,0 +1,30 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_SEG_KMEM_H
+#define _SPL_SEG_KMEM_H
+
+#include <sys/vmsystm.h>
+
+#endif /* SPL_SEG_KMEM_H */
diff --git a/spl/lib/Makefile.am b/spl/lib/Makefile.am
new file mode 100644 (file)
index 0000000..0f2826b
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+noinst_LTLIBRARIES = libcommon.la
+libcommon_la_SOURCES = list.c
+
+EXTRA_DIST = list.h
diff --git a/spl/lib/Makefile.in b/spl/lib/Makefile.in
new file mode 100644 (file)
index 0000000..4bd76fc
--- /dev/null
@@ -0,0 +1,655 @@
+# 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-2010 Lawrence Livermore National Security, LLC.
+# Copyright (C) 2007 The Regents of the University of California.
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+###############################################################################
+# Common rules for user space components.
+###############################################################################
+
+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 = lib
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libcommon_la_LIBADD =
+am_libcommon_la_OBJECTS = list.lo
+libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+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 = 
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libcommon_la_SOURCES)
+DIST_SOURCES = $(libcommon_la_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)
+# 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 $(top_srcdir)/config/Rules.am \
+       $(top_srcdir)/config/depcomp
+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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+DEFAULT_INCLUDES = -include ${top_builddir}/spl_config.h
+AM_LIBTOOLFLAGS = --silent
+AM_CPPFLAGS = -D__USE_LARGEFILE64
+AM_CFLAGS = -Wall -Wshadow -Wstrict-prototypes -fno-strict-aliasing \
+       ${DEBUG_CFLAGS}
+noinst_LTLIBRARIES = libcommon.la
+libcommon_la_SOURCES = list.c
+EXTRA_DIST = list.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/Rules.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 lib/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu lib/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_srcdir)/config/Rules.am $(am__empty):
+
+$(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):
+
+clean-noinstLTLIBRARIES:
+       -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+       @list='$(noinst_LTLIBRARIES)'; \
+       locs=`for p in $$list; do echo $$p; done | \
+             sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+             sort -u`; \
+       test -z "$$locs" || { \
+         echo rm -f $${locs}; \
+         rm -f $${locs}; \
+       }
+
+libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK)  $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+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 $(LTLIBRARIES)
+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 clean-noinstLTLIBRARIES \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+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 -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+       clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+       ctags-am distclean distclean-compile 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 maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       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/spl/lib/list.c b/spl/lib/list.c
new file mode 100644 (file)
index 0000000..55367e4
--- /dev/null
@@ -0,0 +1,827 @@
+/*****************************************************************************
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2001-2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Chris Dunlap <cdunlap@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is from LSD-Tools, the LLNL Software Development Toolbox.
+ *
+ *  LSD-Tools 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.
+ *
+ *  LSD-Tools 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 LSD-Tools.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Refer to "list.h" for documentation on public functions.
+ *****************************************************************************/
+
+#ifdef WITH_PTHREADS
+#  include <pthread.h>
+#endif /* WITH_PTHREADS */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "list.h"
+
+
+/*********************
+ *  lsd_fatal_error  *
+ *********************/
+
+#ifdef WITH_LSD_FATAL_ERROR_FUNC
+#  undef lsd_fatal_error
+   extern void lsd_fatal_error(char *file, int line, char *mesg);
+#else /* !WITH_LSD_FATAL_ERROR_FUNC */
+#  ifndef lsd_fatal_error
+#    include <errno.h>
+#    include <stdio.h>
+#    include <string.h>
+#    define lsd_fatal_error(file, line, mesg)                                 \
+       do {                                                                   \
+           fprintf(stderr, "ERROR: [%s:%d] %s: %s\n",                         \
+                   file, line, mesg, strerror(errno));                        \
+       } while (0)
+#  endif /* !lsd_fatal_error */
+#endif /* !WITH_LSD_FATAL_ERROR_FUNC */
+
+
+/*********************
+ *  lsd_nomem_error  *
+ *********************/
+
+#ifdef WITH_LSD_NOMEM_ERROR_FUNC
+#  undef lsd_nomem_error
+   extern void * lsd_nomem_error(char *file, int line, char *mesg);
+#else /* !WITH_LSD_NOMEM_ERROR_FUNC */
+#  ifndef lsd_nomem_error
+#    define lsd_nomem_error(file, line, mesg) (NULL)
+#  endif /* !lsd_nomem_error */
+#endif /* !WITH_LSD_NOMEM_ERROR_FUNC */
+
+
+/***************
+ *  Constants  *
+ ***************/
+
+#define LIST_ALLOC 32
+#define LIST_MAGIC 0xDEADBEEF
+
+
+/****************
+ *  Data Types  *
+ ****************/
+
+struct listNode {
+    void                 *data;         /* node's data                       */
+    struct listNode      *next;         /* next node in list                 */
+};
+
+struct listIterator {
+    struct list          *list;         /* the list being iterated           */
+    struct listNode      *pos;          /* the next node to be iterated      */
+    struct listNode     **prev;         /* addr of 'next' ptr to prv It node */
+    struct listIterator  *iNext;        /* iterator chain for list_destroy() */
+#ifndef NDEBUG
+    unsigned int          magic;        /* sentinel for asserting validity   */
+#endif /* !NDEBUG */
+};
+
+struct list {
+    struct listNode      *head;         /* head of the list                  */
+    struct listNode     **tail;         /* addr of last node's 'next' ptr    */
+    struct listIterator  *iNext;        /* iterator chain for list_destroy() */
+    ListDelF              fDel;         /* function to delete node data      */
+    int                   count;        /* number of nodes in list           */
+#ifdef WITH_PTHREADS
+    pthread_mutex_t       mutex;        /* mutex to protect access to list   */
+#endif /* WITH_PTHREADS */
+#ifndef NDEBUG
+    unsigned int          magic;        /* sentinel for asserting validity   */
+#endif /* !NDEBUG */
+};
+
+typedef struct listNode * ListNode;
+
+
+/****************
+ *  Prototypes  *
+ ****************/
+
+static void * list_node_create (List l, ListNode *pp, void *x);
+static void * list_node_destroy (List l, ListNode *pp);
+static List list_alloc (void);
+static void list_free (List l);
+static ListNode list_node_alloc (void);
+static void list_node_free (ListNode p);
+static ListIterator list_iterator_alloc (void);
+static void list_iterator_free (ListIterator i);
+static void * list_alloc_aux (int size, void *pfreelist);
+static void list_free_aux (void *x, void *pfreelist);
+
+
+/***************
+ *  Variables  *
+ ***************/
+
+static List list_free_lists = NULL;
+static ListNode list_free_nodes = NULL;
+static ListIterator list_free_iterators = NULL;
+
+#ifdef WITH_PTHREADS
+static pthread_mutex_t list_free_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif /* WITH_PTHREADS */
+
+
+/************
+ *  Macros  *
+ ************/
+
+#ifdef WITH_PTHREADS
+
+#  define list_mutex_init(mutex)                                              \
+     do {                                                                     \
+         int e = pthread_mutex_init(mutex, NULL);                             \
+         if (e != 0) {                                                        \
+             errno = e;                                                       \
+             lsd_fatal_error(__FILE__, __LINE__, "list mutex init");          \
+             abort();                                                         \
+         }                                                                    \
+     } while (0)
+
+#  define list_mutex_lock(mutex)                                              \
+     do {                                                                     \
+         int e = pthread_mutex_lock(mutex);                                   \
+         if (e != 0) {                                                        \
+             errno = e;                                                       \
+             lsd_fatal_error(__FILE__, __LINE__, "list mutex lock");          \
+             abort();                                                         \
+         }                                                                    \
+     } while (0)
+
+#  define list_mutex_unlock(mutex)                                            \
+     do {                                                                     \
+         int e = pthread_mutex_unlock(mutex);                                 \
+         if (e != 0) {                                                        \
+             errno = e;                                                       \
+             lsd_fatal_error(__FILE__, __LINE__, "list mutex unlock");        \
+             abort();                                                         \
+         }                                                                    \
+     } while (0)
+
+#  define list_mutex_destroy(mutex)                                           \
+     do {                                                                     \
+         int e = pthread_mutex_destroy(mutex);                                \
+         if (e != 0) {                                                        \
+             errno = e;                                                       \
+             lsd_fatal_error(__FILE__, __LINE__, "list mutex destroy");       \
+             abort();                                                         \
+         }                                                                    \
+     } while (0)
+
+#  ifndef NDEBUG
+     static int list_mutex_is_locked (pthread_mutex_t *mutex);
+#  endif /* !NDEBUG */
+
+#else /* !WITH_PTHREADS */
+
+#  define list_mutex_init(mutex)
+#  define list_mutex_lock(mutex)
+#  define list_mutex_unlock(mutex)
+#  define list_mutex_destroy(mutex)
+#  define list_mutex_is_locked(mutex) (1)
+
+#endif /* !WITH_PTHREADS */
+
+
+/***************
+ *  Functions  *
+ ***************/
+
+List
+list_create (ListDelF f)
+{
+    List l;
+
+    if (!(l = list_alloc()))
+        return(lsd_nomem_error(__FILE__, __LINE__, "list create"));
+    l->head = NULL;
+    l->tail = &l->head;
+    l->iNext = NULL;
+    l->fDel = f;
+    l->count = 0;
+    list_mutex_init(&l->mutex);
+    assert(l->magic = LIST_MAGIC);      /* set magic via assert abuse */
+    return(l);
+}
+
+
+void
+list_destroy (List l)
+{
+    ListIterator i, iTmp;
+    ListNode p, pTmp;
+
+    assert(l != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    i = l->iNext;
+    while (i) {
+        assert(i->magic == LIST_MAGIC);
+        iTmp = i->iNext;
+        assert(i->magic = ~LIST_MAGIC); /* clear magic via assert abuse */
+        list_iterator_free(i);
+        i = iTmp;
+    }
+    p = l->head;
+    while (p) {
+        pTmp = p->next;
+        if (p->data && l->fDel)
+            l->fDel(p->data);
+        list_node_free(p);
+        p = pTmp;
+    }
+    assert(l->magic = ~LIST_MAGIC);     /* clear magic via assert abuse */
+    list_mutex_unlock(&l->mutex);
+    list_mutex_destroy(&l->mutex);
+    list_free(l);
+    return;
+}
+
+
+int
+list_is_empty (List l)
+{
+    int n;
+
+    assert(l != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    n = l->count;
+    list_mutex_unlock(&l->mutex);
+    return(n == 0);
+}
+
+
+int
+list_count (List l)
+{
+    int n;
+
+    assert(l != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    n = l->count;
+    list_mutex_unlock(&l->mutex);
+    return(n);
+}
+
+
+void *
+list_append (List l, void *x)
+{
+    void *v;
+
+    assert(l != NULL);
+    assert(x != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = list_node_create(l, l->tail, x);
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+void *
+list_prepend (List l, void *x)
+{
+    void *v;
+
+    assert(l != NULL);
+    assert(x != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = list_node_create(l, &l->head, x);
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+void *
+list_find_first (List l, ListFindF f, void *key)
+{
+    ListNode p;
+    void *v = NULL;
+
+    assert(l != NULL);
+    assert(f != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    for (p=l->head; p; p=p->next) {
+        if (f(p->data, key)) {
+            v = p->data;
+            break;
+        }
+    }
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+int
+list_delete_all (List l, ListFindF f, void *key)
+{
+    ListNode *pp;
+    void *v;
+    int n = 0;
+
+    assert(l != NULL);
+    assert(f != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    pp = &l->head;
+    while (*pp) {
+        if (f((*pp)->data, key)) {
+            if ((v = list_node_destroy(l, pp))) {
+                if (l->fDel)
+                    l->fDel(v);
+                n++;
+            }
+        }
+        else {
+            pp = &(*pp)->next;
+        }
+    }
+    list_mutex_unlock(&l->mutex);
+    return(n);
+}
+
+
+int
+list_for_each (List l, ListForF f, void *arg)
+{
+    ListNode p;
+    int n = 0;
+
+    assert(l != NULL);
+    assert(f != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    for (p=l->head; p; p=p->next) {
+        n++;
+        if (f(p->data, arg) < 0) {
+            n = -n;
+            break;
+        }
+    }
+    list_mutex_unlock(&l->mutex);
+    return(n);
+}
+
+
+void
+list_sort (List l, ListCmpF f)
+{
+/*  Note: Time complexity O(n^2).
+ */
+    ListNode *pp, *ppPrev, *ppPos, pTmp;
+    ListIterator i;
+
+    assert(l != NULL);
+    assert(f != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    if (l->count > 1) {
+        ppPrev = &l->head;
+        pp = &(*ppPrev)->next;
+        while (*pp) {
+            if (f((*pp)->data, (*ppPrev)->data) < 0) {
+                ppPos = &l->head;
+                while (f((*pp)->data, (*ppPos)->data) >= 0)
+                    ppPos = &(*ppPos)->next;
+                pTmp = (*pp)->next;
+                (*pp)->next = *ppPos;
+                *ppPos = *pp;
+                *pp = pTmp;
+                if (ppPrev == ppPos)
+                    ppPrev = &(*ppPrev)->next;
+            }
+            else {
+                ppPrev = pp;
+                pp = &(*pp)->next;
+            }
+        }
+        l->tail = pp;
+
+        for (i=l->iNext; i; i=i->iNext) {
+            assert(i->magic == LIST_MAGIC);
+            i->pos = i->list->head;
+            i->prev = &i->list->head;
+        }
+    }
+    list_mutex_unlock(&l->mutex);
+    return;
+}
+
+
+void *
+list_push (List l, void *x)
+{
+    void *v;
+
+    assert(l != NULL);
+    assert(x != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = list_node_create(l, &l->head, x);
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+void *
+list_pop (List l)
+{
+    void *v;
+
+    assert(l != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = list_node_destroy(l, &l->head);
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+void *
+list_peek (List l)
+{
+    void *v;
+
+    assert(l != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = (l->head) ? l->head->data : NULL;
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+void *
+list_enqueue (List l, void *x)
+{
+    void *v;
+
+    assert(l != NULL);
+    assert(x != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = list_node_create(l, l->tail, x);
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+void *
+list_dequeue (List l)
+{
+    void *v;
+
+    assert(l != NULL);
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    v = list_node_destroy(l, &l->head);
+    list_mutex_unlock(&l->mutex);
+    return(v);
+}
+
+
+ListIterator
+list_iterator_create (List l)
+{
+    ListIterator i;
+
+    assert(l != NULL);
+    if (!(i = list_iterator_alloc()))
+        return(lsd_nomem_error(__FILE__, __LINE__, "list iterator create"));
+    i->list = l;
+    list_mutex_lock(&l->mutex);
+    assert(l->magic == LIST_MAGIC);
+    i->pos = l->head;
+    i->prev = &l->head;
+    i->iNext = l->iNext;
+    l->iNext = i;
+    assert(i->magic = LIST_MAGIC);      /* set magic via assert abuse */
+    list_mutex_unlock(&l->mutex);
+    return(i);
+}
+
+
+void
+list_iterator_reset (ListIterator i)
+{
+    assert(i != NULL);
+    assert(i->magic == LIST_MAGIC);
+    list_mutex_lock(&i->list->mutex);
+    assert(i->list->magic == LIST_MAGIC);
+    i->pos = i->list->head;
+    i->prev = &i->list->head;
+    list_mutex_unlock(&i->list->mutex);
+    return;
+}
+
+
+void
+list_iterator_destroy (ListIterator i)
+{
+    ListIterator *pi;
+
+    assert(i != NULL);
+    assert(i->magic == LIST_MAGIC);
+    list_mutex_lock(&i->list->mutex);
+    assert(i->list->magic == LIST_MAGIC);
+    for (pi=&i->list->iNext; *pi; pi=&(*pi)->iNext) {
+        assert((*pi)->magic == LIST_MAGIC);
+        if (*pi == i) {
+            *pi = (*pi)->iNext;
+            break;
+        }
+    }
+    list_mutex_unlock(&i->list->mutex);
+    assert(i->magic = ~LIST_MAGIC);     /* clear magic via assert abuse */
+    list_iterator_free(i);
+    return;
+}
+
+
+void *
+list_next (ListIterator i)
+{
+    ListNode p;
+
+    assert(i != NULL);
+    assert(i->magic == LIST_MAGIC);
+    list_mutex_lock(&i->list->mutex);
+    assert(i->list->magic == LIST_MAGIC);
+    if ((p = i->pos))
+        i->pos = p->next;
+    if (*i->prev != p)
+        i->prev = &(*i->prev)->next;
+    list_mutex_unlock(&i->list->mutex);
+    return(p ? p->data : NULL);
+}
+
+
+void *
+list_insert (ListIterator i, void *x)
+{
+    void *v;
+
+    assert(i != NULL);
+    assert(x != NULL);
+    assert(i->magic == LIST_MAGIC);
+    list_mutex_lock(&i->list->mutex);
+    assert(i->list->magic == LIST_MAGIC);
+    v = list_node_create(i->list, i->prev, x);
+    list_mutex_unlock(&i->list->mutex);
+    return(v);
+}
+
+
+void *
+list_find (ListIterator i, ListFindF f, void *key)
+{
+    void *v;
+
+    assert(i != NULL);
+    assert(f != NULL);
+    assert(i->magic == LIST_MAGIC);
+    while ((v=list_next(i)) && !f(v,key)) {;}
+    return(v);
+}
+
+
+void *
+list_remove (ListIterator i)
+{
+    void *v = NULL;
+
+    assert(i != NULL);
+    assert(i->magic == LIST_MAGIC);
+    list_mutex_lock(&i->list->mutex);
+    assert(i->list->magic == LIST_MAGIC);
+    if (*i->prev != i->pos)
+        v = list_node_destroy(i->list, i->prev);
+    list_mutex_unlock(&i->list->mutex);
+    return(v);
+}
+
+
+int
+list_delete (ListIterator i)
+{
+    void *v;
+
+    assert(i != NULL);
+    assert(i->magic == LIST_MAGIC);
+    if ((v = list_remove(i))) {
+        if (i->list->fDel)
+            i->list->fDel(v);
+        return(1);
+    }
+    return(0);
+}
+
+
+static void *
+list_node_create (List l, ListNode *pp, void *x)
+{
+/*  Inserts data pointed to by [x] into list [l] after [pp],
+ *    the address of the previous node's "next" ptr.
+ *  Returns a ptr to data [x], or NULL if insertion fails.
+ *  This routine assumes the list is already locked upon entry.
+ */
+    ListNode p;
+    ListIterator i;
+
+    assert(l != NULL);
+    assert(l->magic == LIST_MAGIC);
+    assert(list_mutex_is_locked(&l->mutex));
+    assert(pp != NULL);
+    assert(x != NULL);
+    if (!(p = list_node_alloc()))
+        return(lsd_nomem_error(__FILE__, __LINE__, "list node create"));
+    p->data = x;
+    if (!(p->next = *pp))
+        l->tail = &p->next;
+    *pp = p;
+    l->count++;
+    for (i=l->iNext; i; i=i->iNext) {
+        assert(i->magic == LIST_MAGIC);
+        if (i->prev == pp)
+            i->prev = &p->next;
+        else if (i->pos == p->next)
+            i->pos = p;
+        assert((i->pos == *i->prev) || (i->pos == (*i->prev)->next));
+    }
+    return(x);
+}
+
+
+static void *
+list_node_destroy (List l, ListNode *pp)
+{
+/*  Removes the node pointed to by [*pp] from from list [l],
+ *    where [pp] is the address of the previous node's "next" ptr.
+ *  Returns the data ptr associated with list item being removed,
+ *    or NULL if [*pp] points to the NULL element.
+ *  This routine assumes the list is already locked upon entry.
+ */
+    void *v;
+    ListNode p;
+    ListIterator i;
+
+    assert(l != NULL);
+    assert(l->magic == LIST_MAGIC);
+    assert(list_mutex_is_locked(&l->mutex));
+    assert(pp != NULL);
+    if (!(p = *pp))
+        return(NULL);
+    v = p->data;
+    if (!(*pp = p->next))
+        l->tail = pp;
+    l->count--;
+    for (i=l->iNext; i; i=i->iNext) {
+        assert(i->magic == LIST_MAGIC);
+        if (i->pos == p)
+            i->pos = p->next, i->prev = pp;
+        else if (i->prev == &p->next)
+            i->prev = pp;
+        assert((i->pos == *i->prev) || (i->pos == (*i->prev)->next));
+    }
+    list_node_free(p);
+    return(v);
+}
+
+
+static List
+list_alloc (void)
+{
+    return(list_alloc_aux(sizeof(struct list), &list_free_lists));
+}
+
+
+static void
+list_free (List l)
+{
+    list_free_aux(l, &list_free_lists);
+    return;
+}
+
+
+static ListNode
+list_node_alloc (void)
+{
+    return(list_alloc_aux(sizeof(struct listNode), &list_free_nodes));
+}
+
+
+static void
+list_node_free (ListNode p)
+{
+    list_free_aux(p, &list_free_nodes);
+    return;
+}
+
+
+static ListIterator
+list_iterator_alloc (void)
+{
+    return(list_alloc_aux(sizeof(struct listIterator), &list_free_iterators));
+}
+
+
+static void
+list_iterator_free (ListIterator i)
+{
+    list_free_aux(i, &list_free_iterators);
+    return;
+}
+
+
+static void *
+list_alloc_aux (int size, void *pfreelist)
+{
+/*  Allocates an object of [size] bytes from the freelist [*pfreelist].
+ *  Memory is added to the freelist in chunks of size LIST_ALLOC.
+ *  Returns a ptr to the object, or NULL if the memory request fails.
+ */
+    void **px;
+    void **pfree = pfreelist;
+    void **plast;
+
+    assert(sizeof(char) == 1);
+    assert(size >= (int)sizeof(void *));
+    assert(pfreelist != NULL);
+    assert(LIST_ALLOC > 0);
+    list_mutex_lock(&list_free_lock);
+    if (!*pfree) {
+        if ((*pfree = malloc(LIST_ALLOC * size))) {
+            px = *pfree;
+            plast = (void **) ((char *) *pfree + ((LIST_ALLOC - 1) * size));
+            while (px < plast)
+                *px = (char *) px + size, px = *px;
+            *plast = NULL;
+        }
+    }
+    if ((px = *pfree))
+        *pfree = *px;
+    else
+        errno = ENOMEM;
+    list_mutex_unlock(&list_free_lock);
+    return(px);
+}
+
+
+static void
+list_free_aux (void *x, void *pfreelist)
+{
+/*  Frees the object [x], returning it to the freelist [*pfreelist].
+ */
+    void **px = x;
+    void **pfree = pfreelist;
+
+    assert(x != NULL);
+    assert(pfreelist != NULL);
+    list_mutex_lock(&list_free_lock);
+    *px = *pfree;
+    *pfree = px;
+    list_mutex_unlock(&list_free_lock);
+    return;
+}
+
+
+#ifndef NDEBUG
+#ifdef WITH_PTHREADS
+static int
+list_mutex_is_locked (pthread_mutex_t *mutex)
+{
+/*  Returns true if the mutex is locked; o/w, returns false.
+ */
+    int rc;
+
+    assert(mutex != NULL);
+    rc = pthread_mutex_trylock(mutex);
+    return(rc == EBUSY ? 1 : 0);
+}
+#endif /* WITH_PTHREADS */
+#endif /* !NDEBUG */
diff --git a/spl/lib/list.h b/spl/lib/list.h
new file mode 100644 (file)
index 0000000..01adedd
--- /dev/null
@@ -0,0 +1,279 @@
+/*****************************************************************************
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2001-2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Chris Dunlap <cdunlap@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is from LSD-Tools, the LLNL Software Development Toolbox.
+ *
+ *  LSD-Tools 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.
+ *
+ *  LSD-Tools 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 LSD-Tools.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************/
+
+#ifndef LSD_LIST_H
+#define LSD_LIST_H
+
+
+/***********
+ *  Notes  *
+ ***********/
+/*
+ *  If NDEBUG is not defined, internal debug code will be enabled.  This is
+ *  intended for development use only and production code should define NDEBUG.
+ *
+ *  If WITH_LSD_FATAL_ERROR_FUNC is defined, the linker will expect to
+ *  find an external lsd_fatal_error(file,line,mesg) function.  By default,
+ *  lsd_fatal_error(file,line,mesg) is a macro definition that outputs an
+ *  error message to stderr.  This macro may be redefined to invoke another
+ *  routine instead.
+ *
+ *  If WITH_LSD_NOMEM_ERROR_FUNC is defined, the linker will expect to
+ *  find an external lsd_nomem_error(file,line,mesg) function.  By default,
+ *  lsd_nomem_error(file,line,mesg) is a macro definition that returns NULL.
+ *  This macro may be redefined to invoke another routine instead.
+ *
+ *  If WITH_PTHREADS is defined, these routines will be thread-safe.
+ */
+
+
+/****************
+ *  Data Types  *
+ ****************/
+
+typedef struct list * List;
+/*
+ *  List opaque data type.
+ */
+
+typedef struct listIterator * ListIterator;
+/*
+ *  List Iterator opaque data type.
+ */
+
+typedef void (*ListDelF) (void *x);
+/*
+ *  Function prototype to deallocate data stored in a list.
+ *    This function is responsible for freeing all memory associated
+ *    with an item, including all subordinate items (if applicable).
+ */
+
+typedef int (*ListCmpF) (void *x, void *y);
+/*
+ *  Function prototype for comparing two items in a list.
+ *  Returns less-than-zero if (x<y), zero if (x==y), and
+ *    greather-than-zero if (x>y).
+ */
+
+typedef int (*ListFindF) (void *x, void *key);
+/*
+ *  Function prototype for matching items in a list.
+ *  Returns non-zero if (x==key); o/w returns zero.
+ */
+
+typedef int (*ListForF) (void *x, void *arg);
+/*
+ *  Function prototype for operating on each item in a list.
+ *  Returns less-than-zero on error.
+ */
+
+
+/*******************************
+ *  General-Purpose Functions  *
+ *******************************/
+
+List list_create (ListDelF f);
+/*
+ *  Creates and returns a new empty list, or lsd_nomem_error() on failure.
+ *  The deletion function [f] is used to deallocate memory used by items
+ *    in the list; if this is NULL, memory associated with these items
+ *    will not be freed when the list is destroyed.
+ *  Note: Abandoning a list without calling list_destroy() will result
+ *    in a memory leak.
+ */
+
+void list_destroy (List l);
+/*
+ *  Destroys list [l], freeing memory used for list iterators and the
+ *    list itself; if a deletion function was specified when the list
+ *    was created, it will be called for each item in the list.
+ */
+
+int list_is_empty (List l);
+/*
+ *  Returns non-zero if list [l] is empty; o/w returns zero.
+ */
+
+int list_count (List l);
+/*
+ *  Returns the number of items in list [l].
+ */
+
+
+/***************************
+ *  List Access Functions  *
+ ***************************/
+
+void * list_append (List l, void *x);
+/*
+ *  Inserts data [x] at the end of list [l].
+ *  Returns the data's ptr, or lsd_nomem_error() if insertion failed.
+ */
+
+void * list_prepend (List l, void *x);
+/*
+ *  Inserts data [x] at the beginning of list [l].
+ *  Returns the data's ptr, or lsd_nomem_error() if insertion failed.
+ */
+
+void * list_find_first (List l, ListFindF f, void *key);
+/*
+ *  Traverses list [l] using [f] to match each item with [key].
+ *  Returns a ptr to the first item for which the function [f]
+ *    returns non-zero, or NULL if no such item is found.
+ *  Note: This function differs from list_find() in that it does not require
+ *    a list iterator; it should only be used when all list items are known
+ *    to be unique (according to the function [f]).
+ */
+
+int list_delete_all (List l, ListFindF f, void *key);
+/*
+ *  Traverses list [l] using [f] to match each item with [key].
+ *  Removes all items from the list for which the function [f] returns
+ *    non-zero; if a deletion function was specified when the list was
+ *    created, it will be called to deallocate each item being removed.
+ *  Returns a count of the number of items removed from the list.
+ */
+
+int list_for_each (List l, ListForF f, void *arg);
+/*
+ *  For each item in list [l], invokes the function [f] with [arg].
+ *  Returns a count of the number of items on which [f] was invoked.
+ *  If [f] returns <0 for a given item, the iteration is aborted and the
+ *    function returns the negative of that item's position in the list.
+ */
+
+void list_sort (List l, ListCmpF f);
+/*
+ *  Sorts list [l] into ascending order according to the function [f].
+ *  Note: Sorting a list resets all iterators associated with the list.
+ *  Note: The sort algorithm is stable.
+ */
+
+
+/****************************
+ *  Stack Access Functions  *
+ ****************************/
+
+void * list_push (List l, void *x);
+/*
+ *  Pushes data [x] onto the top of stack [l].
+ *  Returns the data's ptr, or lsd_nomem_error() if insertion failed.
+ */
+
+void * list_pop (List l);
+/*
+ *  Pops the data item at the top of the stack [l].
+ *  Returns the data's ptr, or NULL if the stack is empty.
+ */
+
+void * list_peek (List l);
+/*
+ *  Peeks at the data item at the top of the stack (or head of the queue) [l].
+ *  Returns the data's ptr, or NULL if the stack (or queue) is empty.
+ *  Note: The item is not removed from the list.
+ */
+
+
+/****************************
+ *  Queue Access Functions  *
+ ****************************/
+
+void * list_enqueue (List l, void *x);
+/*
+ *  Enqueues data [x] at the tail of queue [l].
+ *  Returns the data's ptr, or lsd_nomem_error() if insertion failed.
+ */
+
+void * list_dequeue (List l);
+/*
+ *  Dequeues the data item at the head of the queue [l].
+ *  Returns the data's ptr, or NULL if the queue is empty.
+ */
+
+
+/*****************************
+ *  List Iterator Functions  *
+ *****************************/
+
+ListIterator list_iterator_create (List l);
+/*
+ *  Creates and returns a list iterator for non-destructively traversing
+ *    list [l], or lsd_nomem_error() on failure.
+ */
+
+void list_iterator_reset (ListIterator i);
+/*
+ *  Resets the list iterator [i] to start traversal at the beginning
+ *    of the list.
+ */
+
+void list_iterator_destroy (ListIterator i);
+/*
+ *  Destroys the list iterator [i]; list iterators not explicitly destroyed
+ *    in this manner will be destroyed when the list is deallocated via
+ *    list_destroy().
+ */
+
+void * list_next (ListIterator i);
+/*
+ *  Returns a ptr to the next item's data,
+ *    or NULL once the end of the list is reached.
+ *  Example: i=list_iterator_create(i); while ((x=list_next(i))) {...}
+ */
+
+void * list_insert (ListIterator i, void *x);
+/*
+ *  Inserts data [x] immediately before the last item returned via list
+ *    iterator [i]; once the list iterator reaches the end of the list,
+ *    insertion is made at the list's end.
+ *  Returns the data's ptr, or lsd_nomem_error() if insertion failed.
+ */
+
+void * list_find (ListIterator i, ListFindF f, void *key);
+/*
+ *  Traverses the list from the point of the list iterator [i]
+ *    using [f] to match each item with [key].
+ *  Returns a ptr to the next item for which the function [f]
+ *    returns non-zero, or NULL once the end of the list is reached.
+ *  Example: i=list_iterator_reset(i); while ((x=list_find(i,f,k))) {...}
+ */
+
+void * list_remove (ListIterator i);
+/*
+ *  Removes from the list the last item returned via list iterator [i]
+ *    and returns the data's ptr.
+ *  Note: The client is responsible for freeing the returned data.
+ */
+
+int list_delete (ListIterator i);
+/*
+ *  Removes from the list the last item returned via list iterator [i];
+ *    if a deletion function was specified when the list was created,
+ *    it will be called to deallocate the item being removed.
+ *  Returns a count of the number of items removed from the list
+ *    (ie, '1' if the item was removed, and '0' otherwise).
+ */
+
+
+#endif /* !LSD_LIST_H */
diff --git a/spl/man/Makefile.am b/spl/man/Makefile.am
new file mode 100644 (file)
index 0000000..7791945
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = man1 man5
diff --git a/spl/man/Makefile.in b/spl/man/Makefile.in
new file mode 100644 (file)
index 0000000..1d074a3
--- /dev/null
@@ -0,0 +1,673 @@
+# 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 = man
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+SUBDIRS = man1 man5
+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 man/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu man/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/spl/man/man1/Makefile.am b/spl/man/man1/Makefile.am
new file mode 100644 (file)
index 0000000..d6becca
--- /dev/null
@@ -0,0 +1,4 @@
+dist_man_MANS = splat.1
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man1"
diff --git a/spl/man/man1/Makefile.in b/spl/man/man1/Makefile.in
new file mode 100644 (file)
index 0000000..67b56c8
--- /dev/null
@@ -0,0 +1,576 @@
+# 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 = man/man1
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_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__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; }; \
+  }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)"
+NROFF = nroff
+MANS = $(dist_man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(dist_man_MANS) $(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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+dist_man_MANS = splat.1
+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 man/man1/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu man/man1/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-man1: $(dist_man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(dist_man_MANS)'; \
+       test -n "$(man1dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.1[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man1:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man1dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.1[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+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 $(MANS)
+installdirs:
+       for dir in "$(DESTDIR)$(man1dir)"; 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-data-local install-man
+
+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-man1
+
+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-man
+
+uninstall-man: uninstall-man1
+
+.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-data-local install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-man1 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-man uninstall-man1
+
+.PRECIOUS: Makefile
+
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man1"
+
+# 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/spl/man/man1/splat.1 b/spl/man/man1/splat.1
new file mode 100644 (file)
index 0000000..37f8435
--- /dev/null
@@ -0,0 +1,94 @@
+'\" t
+.\"
+.\" Copyright 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
+.\"
+.TH splat 1 "2013 MAR 16" "ZFS on Linux" "User Commands"
+
+.SH NAME
+splat \- Solaris Porting LAyer Tests
+.SH SYNOPSIS
+.LP
+.BI "splat [\-chvx] < \-\-all | \-\-list | \-\-test " "subsystem" ":" "test" " [...] >"
+
+.SH DESCRIPTION
+This utility uses the splat.ko kernel module to test the spl.ko kernel
+module. Run "modprobe splat" before invoking \fBsplat\fR.
+
+.SH OPTIONS
+.HP
+.BI "\-a" "" ", \-\-all" ""
+.IP
+Run all available tests on all subsystems.
+.HP
+.BI "\-c" "" ", \-\-nocolor" ""
+.IP
+Disable output highlighting. By default, "Fail" is printed in red text
+and "Pass" is printed in green text.
+.HP
+.BI "\-h" "" ", \-\-help" ""
+.IP
+Print the usage message.
+.HP
+.BI "\-l" "" ", \-\-list" ""
+.IP
+For each spl.ko subsystem, print all available test names and
+hexidecimal identifiers with a short description.
+.HP
+.BI "\-t" " subsystem" ":" "test" ", \-\-test" " subsystem" ":" "test"
+.HP
+.BI "\-t" " subsystem" ":all" "" ", \-\-test" " subsystem" ":all" ""
+.IP
+Run the \fItest\fR diagnostic routine for the spl.ko \fIsubsystem\fR.
+Specify this option more than once to run multiple tests.
+
+The \fItest\fR and \fIsubsystem\fR parameters are the names or
+hexidecimal identifiers returned by the \fBsplat --list\fR command.
+
+If \fIsubsystem\fR is a name and not a hexidecimal identifier, then the
+\fBall\fR keyword can be used to run all available \fIsubsystem\fR
+tests.
+
+.HP
+.BI "\-v" "" ", \-\-verbose" ""
+.HP
+.IP
+Increase verbosity.
+.HP
+.BI "\-x" "" ", \-\-exit" ""
+.IP
+Stop running tests after the first failure.
+
+.SH "EXAMPLES"
+.LP
+Test everything in the spl.ko kernel module:
+.IP
+# splat --all --verbose
+.LP
+Test the entire kernel memory subsystem:
+.IP
+# splat --test kmem:all
+.LP
+Test the kernel compression and queue waiting facilities:
+.IP
+# splat --test zlib:compress/uncompress --test taskq:wait
+.LP
+This is the same as the previous command, except that the subsystems
+and tests are referenced by hexidecimal identifier instead of by name:
+.IP
+# splat -t 0x0f00:0x0f01 -t 0x0200:0x0204
+
+.SH "NOTES"
+All tests always return a green "Pass" result on a healthy system. Any
+red "Fail" result should be investigated or reported.
+
+.SH "BUGS"
+Some tests can deadlock the kernel if an X11 desktop is running,
+especially if a proprietary blob driver is loaded for the video
+hardware.
+
+.SH "AUTHORS"
+This man page was written by Darik Horn <dajhorn@vanadac.com>.
+
+.SH "SEE ALSO"
+.BR zpios (1),
+.BR ztest (1)
diff --git a/spl/man/man5/Makefile.am b/spl/man/man5/Makefile.am
new file mode 100644 (file)
index 0000000..fb22beb
--- /dev/null
@@ -0,0 +1,4 @@
+dist_man_MANS = spl-module-parameters.5
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man5"
diff --git a/spl/man/man5/Makefile.in b/spl/man/man5/Makefile.in
new file mode 100644 (file)
index 0000000..f56476a
--- /dev/null
@@ -0,0 +1,576 @@
+# 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 = man/man5
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_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__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; }; \
+  }
+man5dir = $(mandir)/man5
+am__installdirs = "$(DESTDIR)$(man5dir)"
+NROFF = nroff
+MANS = $(dist_man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(dist_man_MANS) $(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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+dist_man_MANS = spl-module-parameters.5
+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 man/man5/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu man/man5/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-man5: $(dist_man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(dist_man_MANS)'; \
+       test -n "$(man5dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.5[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man5:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man5dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.5[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
+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 $(MANS)
+installdirs:
+       for dir in "$(DESTDIR)$(man5dir)"; 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-data-local install-man
+
+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-man5
+
+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-man
+
+uninstall-man: uninstall-man5
+
+.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-data-local install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-man5 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-man uninstall-man5
+
+.PRECIOUS: Makefile
+
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man5"
+
+# 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/spl/man/man5/spl-module-parameters.5 b/spl/man/man5/spl-module-parameters.5
new file mode 100644 (file)
index 0000000..acdd5b6
--- /dev/null
@@ -0,0 +1,300 @@
+'\" te
+.\"
+.\" Copyright 2013 Turbo Fredriksson <turbo@bayour.com>. All rights reserved.
+.\"
+.TH SPL-MODULE-PARAMETERS 5 "Nov 18, 2013"
+.SH NAME
+spl\-module\-parameters \- SPL module parameters
+.SH DESCRIPTION
+.sp
+.LP
+Description of the different parameters to the SPL module.
+
+.SS "Module parameters"
+.sp
+.LP
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_expire\fR (uint)
+.ad
+.RS 12n
+Cache expiration is part of default Illumos cache behavior.  The idea is
+that objects in magazines which have not been recently accessed should be
+returned to the slabs periodically.  This is known as cache aging and
+when enabled objects will be typically returned after 15 seconds.
+.sp
+On the other hand Linux slabs are designed to never move objects back to
+the slabs unless there is memory pressure.  This is possible because under
+Linux the cache will be notified when memory is low and objects can be
+released.
+.sp
+By default only the Linux method is enabled.  It has been shown to improve
+responsiveness on low memory systems and not negatively impact the performance
+of systems with more memory.  This policy may be changed by setting the
+\fBspl_kmem_cache_expire\fR bit mask as follows, both policies may be enabled
+concurrently.
+.sp
+0x01 - Aging (Illumos), 0x02 - Low memory (Linux)
+.sp
+Default value: \fB0x02\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_reclaim\fR (uint)
+.ad
+.RS 12n
+When this is set it prevents Linux from being able to rapidly reclaim all the
+memory held by the kmem caches.  This may be useful in circumstances where
+it's preferable that Linux reclaim memory from some other subsystem first.
+Setting this will increase the likelihood out of memory events on a memory
+constrained system.
+.sp
+Default value: \fB0\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_obj_per_slab\fR (uint)
+.ad
+.RS 12n
+The preferred number of objects per slab in the cache.   In general, a larger
+value will increase the caches memory footprint while decreasing the time
+required to perform an allocation.  Conversely, a smaller value will minimize
+the footprint and improve cache reclaim time but individual allocations may
+take longer.
+.sp
+Default value: \fB8\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_obj_per_slab_min\fR (uint)
+.ad
+.RS 12n
+The minimum number of objects allowed per slab.  Normally slabs will contain
+\fBspl_kmem_cache_obj_per_slab\fR objects but for caches that contain very
+large objects it's desirable to only have a few, or even just one, object per
+slab.
+.sp
+Default value: \fB1\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_max_size\fR (uint)
+.ad
+.RS 12n
+The maximum size of a kmem cache slab in MiB.  This effectively limits
+the maximum cache object size to \fBspl_kmem_cache_max_size\fR /
+\fBspl_kmem_cache_obj_per_slab\fR.  Caches may not be created with
+object sized larger than this limit.
+.sp
+Default value: \fB32 (64-bit) or 4 (32-bit)\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_slab_limit\fR (uint)
+.ad
+.RS 12n
+For small objects the Linux slab allocator should be used to make the most
+efficient use of the memory.  However, large objects are not supported by
+the Linux slab and therefore the SPL implementation is preferred.  This
+value is used to determine the cutoff between a small and large object.
+.sp
+Objects of \fBspl_kmem_cache_slab_limit\fR or smaller will be allocated
+using the Linux slab allocator, large objects use the SPL allocator.  A
+cutoff of 16K was determined to be optimal for architectures using 4K pages.
+.sp
+Default value: \fB16,384\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_kmem_limit\fR (uint)
+.ad
+.RS 12n
+Depending on the size of a cache object it may be backed by kmalloc()'d
+or vmalloc()'d memory.  This is because the size of the required allocation
+greatly impacts the best way to allocate the memory.
+.sp
+When objects are small and only a small number of memory pages need to be
+allocated, ideally just one, then kmalloc() is very efficient.  However,
+when allocating multiple pages with kmalloc() it gets increasingly expensive
+because the pages must be physically contiguous.
+.sp
+For this reason we shift to vmalloc() for slabs of large objects which
+which removes the need for contiguous pages.  We cannot use vmalloc() in
+all cases because there is significant locking overhead involved.  This
+function takes a single global lock over the entire virtual address range
+which serializes all allocations.  Using slightly different allocation
+functions for small and large objects allows us to handle a wide range of
+object sizes.
+.sh
+The \fBspl_kmem_cache_kmem_limit\fR value is used to determine this cutoff
+size.  One quarter the PAGE_SIZE is used as the default value because
+\fBspl_kmem_cache_obj_per_slab\fR defaults to 16.  This means that at
+most we will need to allocate four contiguous pages.
+.sp
+Default value: \fBPAGE_SIZE/4\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_alloc_warn\fR (uint)
+.ad
+.RS 12n
+As a general rule kmem_alloc() allocations should be small, preferably
+just a few pages since they must by physically contiguous.  Therefore, a
+rate limited warning will be printed to the console for any kmem_alloc()
+which exceeds a reasonable threshold.
+.sp
+The default warning threshold is set to eight pages but capped at 32K to
+accommodate systems using large pages.  This value was selected to be small
+enough to ensure the largest allocations are quickly noticed and fixed.
+But large enough to avoid logging any warnings when a allocation size is
+larger than optimal but not a serious concern.  Since this value is tunable,
+developers are encouraged to set it lower when testing so any new largish
+allocations are quickly caught.  These warnings may be disabled by setting
+the threshold to zero.
+.sp
+Default value: \fB32,768\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_alloc_max\fR (uint)
+.ad
+.RS 12n
+Large kmem_alloc() allocations will fail if they exceed KMALLOC_MAX_SIZE.
+Allocations which are marginally smaller than this limit may succeed but
+should still be avoided due to the expense of locating a contiguous range
+of free pages.  Therefore, a maximum kmem size with reasonable safely
+margin of 4x is set.  Kmem_alloc() allocations larger than this maximum
+will quickly fail.  Vmem_alloc() allocations less than or equal to this
+value will use kmalloc(), but shift to vmalloc() when exceeding this value.
+.sp
+Default value: \fBKMALLOC_MAX_SIZE/4\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_kmem_cache_magazine_size\fR (uint)
+.ad
+.RS 12n
+Cache magazines are an optimization designed to minimize the cost of
+allocating memory.  They do this by keeping a per-cpu cache of recently
+freed objects, which can then be reallocated without taking a lock. This
+can improve performance on highly contended caches.  However, because
+objects in magazines will prevent otherwise empty slabs from being
+immediately released this may not be ideal for low memory machines.
+.sp
+For this reason \fBspl_kmem_cache_magazine_size\fR can be used to set a
+maximum magazine size.  When this value is set to 0 the magazine size will
+be automatically determined based on the object size.  Otherwise magazines
+will be limited to 2-256 objects per magazine (i.e per cpu).  Magazines
+may never be entirely disabled in this implementation.
+.sp
+Default value: \fB0\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_hostid\fR (ulong)
+.ad
+.RS 12n
+The system hostid, when set this can be used to uniquely identify a system.
+By default this value is set to zero which indicates the hostid is disabled.
+It can be explicitly enabled by placing a unique non-zero value in
+\fB/etc/hostid/\fR.
+.sp
+Default value: \fB0\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_hostid_path\fR (charp)
+.ad
+.RS 12n
+The expected path to locate the system hostid when specified.  This value
+may be overridden for non-standard configurations.
+.sp
+Default value: \fB/etc/hostid\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_bind\fR (int)
+.ad
+.RS 12n
+Bind taskq threads to specific CPUs.  When enabled all taskq threads will
+be distributed evenly  over the available CPUs.  By default, this behavior
+is disabled to allow the Linux scheduler the maximum flexibility to determine
+where a thread should run.
+.sp
+Default value: \fB0\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_dynamic\fR (int)
+.ad
+.RS 12n
+Allow dynamic taskqs.  When enabled taskqs which set the TASKQ_DYNAMIC flag
+will by default create only a single thread.  New threads will be created on
+demand up to a maximum allowed number to facilitate the completion of
+outstanding tasks.  Threads which are no longer needed will be promptly
+destroyed.  By default this behavior is enabled but it can be disabled to
+aid performance analysis or troubleshooting.
+.sp
+Default value: \fB1\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_priority\fR (int)
+.ad
+.RS 12n
+Allow newly created taskq threads to set a non-default scheduler priority.
+When enabled the priority specified when a taskq is created will be applied
+to all threads created by that taskq.  When disabled all threads will use
+the default Linux kernel thread priority.  By default, this behavior is
+enabled.
+.sp
+Default value: \fB1\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_sequential\fR (int)
+.ad
+.RS 12n
+The number of items a taskq worker thread must handle without interruption
+before requesting a new worker thread be spawned.  This is used to control
+how quickly taskqs ramp up the number of threads processing the queue.
+Because Linux thread creation and destruction are relatively inexpensive a
+small default value has been selected.  This means that normally threads will
+be created aggressively which is desirable.  Increasing this value will
+result in a slower thread creation rate which may be preferable for some
+configurations.
+.sp
+Default value: \fB4\fR
+.RE
diff --git a/spl/module/Makefile.in b/spl/module/Makefile.in
new file mode 100644 (file)
index 0000000..d4e62e1
--- /dev/null
@@ -0,0 +1,54 @@
+subdir-m += spl
+subdir-m += splat
+
+INSTALL_MOD_DIR ?= extra
+
+SPL_MODULE_CFLAGS  = -I@abs_top_srcdir@/include
+SPL_MODULE_CFLAGS += -include @abs_top_builddir@/spl_config.h
+export SPL_MODULE_CFLAGS
+
+modules:
+       $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ CONFIG_SPL=m $@
+
+clean:
+       @# Only cleanup the kernel build directories when CONFIG_KERNEL
+       @# is defined.  This indicates that kernel modules should be built.
+@CONFIG_KERNEL_TRUE@   $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ $@
+
+       if [ -f @LINUX_SYMBOLS@ ]; then $(RM) @LINUX_SYMBOLS@; fi
+       if [ -f Module.markers ]; then $(RM) Module.markers; fi
+
+modules_install:
+       @# Install the kernel modules
+       $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` $@ \
+               INSTALL_MOD_PATH=$(DESTDIR)$(INSTALL_MOD_PATH) \
+               INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \
+               KERNELRELEASE=@LINUX_VERSION@
+       @# Remove extraneous build products when packaging
+       kmoddir=$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@; \
+       if [ -n "$(DESTDIR)" ]; then \
+               find $$kmoddir -name 'modules.*' | xargs $(RM); \
+       fi
+       sysmap=$(DESTDIR)$(INSTALL_MOD_PATH)/boot/System.map-@LINUX_VERSION@; \
+       if [ -f $$sysmap ]; then \
+               depmod -ae -F $$sysmap @LINUX_VERSION@; \
+       fi
+
+modules_uninstall:
+       @# Uninstall the kernel modules
+       kmoddir=$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@
+       list='$(subdir-m)'; for subdir in $$list; do \
+               $(RM) -R $$kmoddir/$(INSTALL_MOD_DIR)/$$subdir; \
+       done
+
+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); \
+       done
+
+distclean maintainer-clean: clean
+install: modules_install
+uninstall: modules_uninstall
+all: modules
+check:
diff --git a/spl/module/spl/Makefile.in b/spl/module/spl/Makefile.in
new file mode 100644 (file)
index 0000000..a1f1ab8
--- /dev/null
@@ -0,0 +1,30 @@
+# Makefile.in for spl kernel module
+
+src = @abs_top_srcdir@/module/spl
+obj = @abs_builddir@
+
+MODULE := spl
+EXTRA_CFLAGS = $(SPL_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+# Solaris porting layer module
+obj-$(CONFIG_SPL) := $(MODULE).o
+
+$(MODULE)-objs += spl-proc.o
+$(MODULE)-objs += spl-kmem.o
+$(MODULE)-objs += spl-kmem-cache.o
+$(MODULE)-objs += spl-vmem.o
+$(MODULE)-objs += spl-thread.o
+$(MODULE)-objs += spl-taskq.o
+$(MODULE)-objs += spl-rwlock.o
+$(MODULE)-objs += spl-vnode.o
+$(MODULE)-objs += spl-err.o
+$(MODULE)-objs += spl-kobj.o
+$(MODULE)-objs += spl-generic.o
+$(MODULE)-objs += spl-atomic.o
+$(MODULE)-objs += spl-mutex.o
+$(MODULE)-objs += spl-kstat.o
+$(MODULE)-objs += spl-condvar.o
+$(MODULE)-objs += spl-xdr.o
+$(MODULE)-objs += spl-cred.o
+$(MODULE)-objs += spl-tsd.o
+$(MODULE)-objs += spl-zlib.o
diff --git a/spl/module/spl/spl-atomic.c b/spl/module/spl/spl-atomic.c
new file mode 100644 (file)
index 0000000..c46252c
--- /dev/null
@@ -0,0 +1,42 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Atomic Implementation.
+\*****************************************************************************/
+
+#include <sys/atomic.h>
+
+#ifdef DEBUG_SUBSYSTEM
+#undef DEBUG_SUBSYSTEM
+#endif
+
+#define DEBUG_SUBSYSTEM S_ATOMIC
+
+#ifdef ATOMIC_SPINLOCK
+/* Global atomic lock declarations */
+DEFINE_SPINLOCK(atomic32_lock);
+DEFINE_SPINLOCK(atomic64_lock);
+
+EXPORT_SYMBOL(atomic32_lock);
+EXPORT_SYMBOL(atomic64_lock);
+#endif /* ATOMIC_SPINLOCK */
diff --git a/spl/module/spl/spl-condvar.c b/spl/module/spl/spl-condvar.c
new file mode 100644 (file)
index 0000000..c420d18
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Solaris Porting Layer (SPL) Credential Implementation.
+ */
+
+#include <sys/condvar.h>
+#include <sys/time.h>
+
+void
+__cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg)
+{
+       ASSERT(cvp);
+       ASSERT(name == NULL);
+       ASSERT(type == CV_DEFAULT);
+       ASSERT(arg == NULL);
+
+       cvp->cv_magic = CV_MAGIC;
+       init_waitqueue_head(&cvp->cv_event);
+       init_waitqueue_head(&cvp->cv_destroy);
+       atomic_set(&cvp->cv_waiters, 0);
+       atomic_set(&cvp->cv_refs, 1);
+       cvp->cv_mutex = NULL;
+}
+EXPORT_SYMBOL(__cv_init);
+
+static int
+cv_destroy_wakeup(kcondvar_t *cvp)
+{
+       if (!atomic_read(&cvp->cv_waiters) && !atomic_read(&cvp->cv_refs)) {
+               ASSERT(cvp->cv_mutex == NULL);
+               ASSERT(!waitqueue_active(&cvp->cv_event));
+               return (1);
+       }
+
+       return (0);
+}
+
+void
+__cv_destroy(kcondvar_t *cvp)
+{
+       ASSERT(cvp);
+       ASSERT(cvp->cv_magic == CV_MAGIC);
+
+       cvp->cv_magic = CV_DESTROY;
+       atomic_dec(&cvp->cv_refs);
+
+       /* Block until all waiters are woken and references dropped. */
+       while (cv_destroy_wakeup(cvp) == 0)
+               wait_event_timeout(cvp->cv_destroy, cv_destroy_wakeup(cvp), 1);
+
+       ASSERT3P(cvp->cv_mutex, ==, NULL);
+       ASSERT3S(atomic_read(&cvp->cv_refs), ==, 0);
+       ASSERT3S(atomic_read(&cvp->cv_waiters), ==, 0);
+       ASSERT3S(waitqueue_active(&cvp->cv_event), ==, 0);
+}
+EXPORT_SYMBOL(__cv_destroy);
+
+static void
+cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state, int io)
+{
+       DEFINE_WAIT(wait);
+       kmutex_t *m;
+
+       ASSERT(cvp);
+       ASSERT(mp);
+       ASSERT(cvp->cv_magic == CV_MAGIC);
+       ASSERT(mutex_owned(mp));
+       atomic_inc(&cvp->cv_refs);
+
+       m = ACCESS_ONCE(cvp->cv_mutex);
+       if (!m)
+               m = xchg(&cvp->cv_mutex, mp);
+       /* Ensure the same mutex is used by all callers */
+       ASSERT(m == NULL || m == mp);
+
+       prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
+       atomic_inc(&cvp->cv_waiters);
+
+       /*
+        * Mutex should be dropped after prepare_to_wait() this
+        * ensures we're linked in to the waiters list and avoids the
+        * race where 'cvp->cv_waiters > 0' but the list is empty.
+        */
+       mutex_exit(mp);
+       if (io)
+               io_schedule();
+       else
+               schedule();
+
+       /* No more waiters a different mutex could be used */
+       if (atomic_dec_and_test(&cvp->cv_waiters)) {
+               /*
+                * This is set without any lock, so it's racy. But this is
+                * just for debug anyway, so make it best-effort
+                */
+               cvp->cv_mutex = NULL;
+               wake_up(&cvp->cv_destroy);
+       }
+
+       finish_wait(&cvp->cv_event, &wait);
+       atomic_dec(&cvp->cv_refs);
+
+       /*
+        * Hold mutex after we release the cvp, otherwise we could dead lock
+        * with a thread holding the mutex and call cv_destroy.
+        */
+       mutex_enter(mp);
+}
+
+void
+__cv_wait(kcondvar_t *cvp, kmutex_t *mp)
+{
+       cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE, 0);
+}
+EXPORT_SYMBOL(__cv_wait);
+
+void
+__cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp)
+{
+       cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE, 0);
+}
+EXPORT_SYMBOL(__cv_wait_sig);
+
+void
+__cv_wait_io(kcondvar_t *cvp, kmutex_t *mp)
+{
+       cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE, 1);
+}
+EXPORT_SYMBOL(__cv_wait_io);
+
+/*
+ * 'expire_time' argument is an absolute wall clock time in jiffies.
+ * Return value is time left (expire_time - now) or -1 if timeout occurred.
+ */
+static clock_t
+__cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
+    int state)
+{
+       DEFINE_WAIT(wait);
+       kmutex_t *m;
+       clock_t time_left;
+
+       ASSERT(cvp);
+       ASSERT(mp);
+       ASSERT(cvp->cv_magic == CV_MAGIC);
+       ASSERT(mutex_owned(mp));
+       atomic_inc(&cvp->cv_refs);
+
+       m = ACCESS_ONCE(cvp->cv_mutex);
+       if (!m)
+               m = xchg(&cvp->cv_mutex, mp);
+       /* Ensure the same mutex is used by all callers */
+       ASSERT(m == NULL || m == mp);
+
+       /* XXX - Does not handle jiffie wrap properly */
+       time_left = expire_time - jiffies;
+       if (time_left <= 0) {
+               /* XXX - doesn't reset cv_mutex */
+               atomic_dec(&cvp->cv_refs);
+               return (-1);
+       }
+
+       prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
+       atomic_inc(&cvp->cv_waiters);
+
+       /*
+        * Mutex should be dropped after prepare_to_wait() this
+        * ensures we're linked in to the waiters list and avoids the
+        * race where 'cvp->cv_waiters > 0' but the list is empty.
+        */
+       mutex_exit(mp);
+       time_left = schedule_timeout(time_left);
+
+       /* No more waiters a different mutex could be used */
+       if (atomic_dec_and_test(&cvp->cv_waiters)) {
+               /*
+                * This is set without any lock, so it's racy. But this is
+                * just for debug anyway, so make it best-effort
+                */
+               cvp->cv_mutex = NULL;
+               wake_up(&cvp->cv_destroy);
+       }
+
+       finish_wait(&cvp->cv_event, &wait);
+       atomic_dec(&cvp->cv_refs);
+
+       /*
+        * Hold mutex after we release the cvp, otherwise we could dead lock
+        * with a thread holding the mutex and call cv_destroy.
+        */
+       mutex_enter(mp);
+       return (time_left > 0 ? time_left : -1);
+}
+
+clock_t
+__cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
+{
+       return (__cv_timedwait_common(cvp, mp, exp_time, TASK_UNINTERRUPTIBLE));
+}
+EXPORT_SYMBOL(__cv_timedwait);
+
+clock_t
+__cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
+{
+       return (__cv_timedwait_common(cvp, mp, exp_time, TASK_INTERRUPTIBLE));
+}
+EXPORT_SYMBOL(__cv_timedwait_sig);
+
+/*
+ * 'expire_time' argument is an absolute clock time in nanoseconds.
+ * Return value is time left (expire_time - now) or -1 if timeout occurred.
+ */
+static clock_t
+__cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t expire_time,
+    int state)
+{
+       DEFINE_WAIT(wait);
+       kmutex_t *m;
+       hrtime_t time_left, now;
+       unsigned long time_left_us;
+
+       ASSERT(cvp);
+       ASSERT(mp);
+       ASSERT(cvp->cv_magic == CV_MAGIC);
+       ASSERT(mutex_owned(mp));
+       atomic_inc(&cvp->cv_refs);
+
+       m = ACCESS_ONCE(cvp->cv_mutex);
+       if (!m)
+               m = xchg(&cvp->cv_mutex, mp);
+       /* Ensure the same mutex is used by all callers */
+       ASSERT(m == NULL || m == mp);
+
+       now = gethrtime();
+       time_left = expire_time - now;
+       if (time_left <= 0) {
+               atomic_dec(&cvp->cv_refs);
+               return (-1);
+       }
+       time_left_us = time_left / NSEC_PER_USEC;
+
+       prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
+       atomic_inc(&cvp->cv_waiters);
+
+       /*
+        * Mutex should be dropped after prepare_to_wait() this
+        * ensures we're linked in to the waiters list and avoids the
+        * race where 'cvp->cv_waiters > 0' but the list is empty.
+        */
+       mutex_exit(mp);
+       /*
+        * Allow a 100 us range to give kernel an opportunity to coalesce
+        * interrupts
+        */
+       usleep_range(time_left_us, time_left_us + 100);
+
+       /* No more waiters a different mutex could be used */
+       if (atomic_dec_and_test(&cvp->cv_waiters)) {
+               /*
+                * This is set without any lock, so it's racy. But this is
+                * just for debug anyway, so make it best-effort
+                */
+               cvp->cv_mutex = NULL;
+               wake_up(&cvp->cv_destroy);
+       }
+
+       finish_wait(&cvp->cv_event, &wait);
+       atomic_dec(&cvp->cv_refs);
+
+       mutex_enter(mp);
+       time_left = expire_time - gethrtime();
+       return (time_left > 0 ? time_left : -1);
+}
+
+/*
+ * Compatibility wrapper for the cv_timedwait_hires() Illumos interface.
+ */
+clock_t
+cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag)
+{
+       if (res > 1) {
+               /*
+                * Align expiration to the specified resolution.
+                */
+               if (flag & CALLOUT_FLAG_ROUNDUP)
+                       tim += res - 1;
+               tim = (tim / res) * res;
+       }
+
+       if (!(flag & CALLOUT_FLAG_ABSOLUTE))
+               tim += gethrtime();
+
+       return (__cv_timedwait_hires(cvp, mp, tim, TASK_UNINTERRUPTIBLE));
+}
+EXPORT_SYMBOL(cv_timedwait_hires);
+
+void
+__cv_signal(kcondvar_t *cvp)
+{
+       ASSERT(cvp);
+       ASSERT(cvp->cv_magic == CV_MAGIC);
+       atomic_inc(&cvp->cv_refs);
+
+       /*
+        * All waiters are added with WQ_FLAG_EXCLUSIVE so only one
+        * waiter will be set runable with each call to wake_up().
+        * Additionally wake_up() holds a spin_lock assoicated with
+        * the wait queue to ensure we don't race waking up processes.
+        */
+       if (atomic_read(&cvp->cv_waiters) > 0)
+               wake_up(&cvp->cv_event);
+
+       atomic_dec(&cvp->cv_refs);
+}
+EXPORT_SYMBOL(__cv_signal);
+
+void
+__cv_broadcast(kcondvar_t *cvp)
+{
+       ASSERT(cvp);
+       ASSERT(cvp->cv_magic == CV_MAGIC);
+       atomic_inc(&cvp->cv_refs);
+
+       /*
+        * Wake_up_all() will wake up all waiters even those which
+        * have the WQ_FLAG_EXCLUSIVE flag set.
+        */
+       if (atomic_read(&cvp->cv_waiters) > 0)
+               wake_up_all(&cvp->cv_event);
+
+       atomic_dec(&cvp->cv_refs);
+}
+EXPORT_SYMBOL(__cv_broadcast);
diff --git a/spl/module/spl/spl-cred.c b/spl/module/spl/spl-cred.c
new file mode 100644 (file)
index 0000000..1d486c1
--- /dev/null
@@ -0,0 +1,206 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Credential Implementation.
+\*****************************************************************************/
+
+#include <sys/cred.h>
+
+#ifdef DEBUG_SUBSYSTEM
+#undef DEBUG_SUBSYSTEM
+#endif
+
+#define DEBUG_SUBSYSTEM S_CRED
+
+static int
+#ifdef HAVE_KUIDGID_T
+cr_groups_search(const struct group_info *group_info, kgid_t grp)
+#else
+cr_groups_search(const struct group_info *group_info, gid_t grp)
+#endif
+{
+       unsigned int left, right, mid;
+       int cmp;
+
+       if (!group_info)
+               return 0;
+
+       left = 0;
+       right = group_info->ngroups;
+       while (left < right) {
+               mid = (left + right) / 2;
+               cmp = KGID_TO_SGID(grp) -
+                   KGID_TO_SGID(GROUP_AT(group_info, mid));
+
+               if (cmp > 0)
+                       left = mid + 1;
+               else if (cmp < 0)
+                       right = mid;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+/* Hold a reference on the credential */
+void
+crhold(cred_t *cr)
+{
+       (void)get_cred((const cred_t *)cr);
+}
+
+/* Free a reference on the credential */
+void
+crfree(cred_t *cr)
+{
+       put_cred((const cred_t *)cr);
+}
+
+/* Return the number of supplemental groups */
+int
+crgetngroups(const cred_t *cr)
+{
+       struct group_info *gi;
+       int rc;
+
+       gi = cr->group_info;
+       rc = gi->ngroups;
+#ifndef HAVE_GROUP_INFO_GID
+       /*
+        * For Linux <= 4.8,
+        * crgetgroups will only returns gi->blocks[0], which contains only
+        * the first NGROUPS_PER_BLOCK groups.
+        */
+       if (rc > NGROUPS_PER_BLOCK) {
+               WARN_ON_ONCE(1);
+               rc = NGROUPS_PER_BLOCK;
+       }
+#endif
+       return rc;
+}
+
+/*
+ * Return an array of supplemental gids.  The returned address is safe
+ * to use as long as the caller has taken a reference with crhold().
+ *
+ * Linux 4.9 API change, group_info changed from 2d array via ->blocks to 1d
+ * array via ->gid.
+ */
+gid_t *
+crgetgroups(const cred_t *cr)
+{
+       struct group_info *gi;
+       gid_t *gids = NULL;
+
+       gi = cr->group_info;
+#ifdef HAVE_GROUP_INFO_GID
+       gids = KGIDP_TO_SGIDP(gi->gid);
+#else
+       if (gi->nblocks > 0)
+               gids = KGIDP_TO_SGIDP(gi->blocks[0]);
+#endif
+       return gids;
+}
+
+/* Check if the passed gid is available in supplied credential. */
+int
+groupmember(gid_t gid, const cred_t *cr)
+{
+       struct group_info *gi;
+       int rc;
+
+       gi = cr->group_info;
+       rc = cr_groups_search(gi, SGID_TO_KGID(gid));
+
+       return rc;
+}
+
+/* Return the effective user id */
+uid_t
+crgetuid(const cred_t *cr)
+{
+       return KUID_TO_SUID(cr->euid);
+}
+
+/* Return the real user id */
+uid_t
+crgetruid(const cred_t *cr)
+{
+       return KUID_TO_SUID(cr->uid);
+}
+
+/* Return the saved user id */
+uid_t
+crgetsuid(const cred_t *cr)
+{
+       return KUID_TO_SUID(cr->suid);
+}
+
+/* Return the filesystem user id */
+uid_t
+crgetfsuid(const cred_t *cr)
+{
+       return KUID_TO_SUID(cr->fsuid);
+}
+
+/* Return the effective group id */
+gid_t
+crgetgid(const cred_t *cr)
+{
+       return KGID_TO_SGID(cr->egid);
+}
+
+/* Return the real group id */
+gid_t
+crgetrgid(const cred_t *cr)
+{
+       return KGID_TO_SGID(cr->gid);
+}
+
+/* Return the saved group id */
+gid_t
+crgetsgid(const cred_t *cr)
+{
+       return KGID_TO_SGID(cr->sgid);
+}
+
+/* Return the filesystem group id */
+gid_t
+crgetfsgid(const cred_t *cr)
+{
+       return KGID_TO_SGID(cr->fsgid);
+}
+
+EXPORT_SYMBOL(crhold);
+EXPORT_SYMBOL(crfree);
+EXPORT_SYMBOL(crgetuid);
+EXPORT_SYMBOL(crgetruid);
+EXPORT_SYMBOL(crgetsuid);
+EXPORT_SYMBOL(crgetfsuid);
+EXPORT_SYMBOL(crgetgid);
+EXPORT_SYMBOL(crgetrgid);
+EXPORT_SYMBOL(crgetsgid);
+EXPORT_SYMBOL(crgetfsgid);
+EXPORT_SYMBOL(crgetngroups);
+EXPORT_SYMBOL(crgetgroups);
+EXPORT_SYMBOL(groupmember);
diff --git a/spl/module/spl/spl-err.c b/spl/module/spl/spl-err.c
new file mode 100644 (file)
index 0000000..14ff8a3
--- /dev/null
@@ -0,0 +1,117 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Error Implementation.
+\*****************************************************************************/
+
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <linux/ratelimit.h>
+
+/*
+ * Limit the number of stack traces dumped to not more than 5 every
+ * 60 seconds to prevent denial-of-service attacks from debug code.
+ */
+DEFINE_RATELIMIT_STATE(dumpstack_ratelimit_state, 60 * HZ, 5);
+
+void
+spl_dumpstack(void)
+{
+       if (__ratelimit(&dumpstack_ratelimit_state)) {
+               printk("Showing stack for process %d\n", current->pid);
+               dump_stack();
+       }
+}
+EXPORT_SYMBOL(spl_dumpstack);
+
+int
+spl_panic(const char *file, const char *func, int line, const char *fmt, ...) {
+       const char *newfile;
+       char msg[MAXMSGLEN];
+       va_list ap;
+
+       newfile = strrchr(file, '/');
+       if (newfile != NULL)
+               newfile = newfile + 1;
+       else
+               newfile = file;
+
+       va_start(ap, fmt);
+       (void) vsnprintf(msg, sizeof (msg), fmt, ap);
+       va_end(ap);
+
+       printk(KERN_EMERG "%s", msg);
+       printk(KERN_EMERG "PANIC at %s:%d:%s()\n", newfile, line, func);
+       spl_dumpstack();
+
+       /* Halt the thread to facilitate further debugging */
+       set_task_state(current, TASK_UNINTERRUPTIBLE);
+       while (1)
+               schedule();
+
+       /* Unreachable */
+       return (1);
+}
+EXPORT_SYMBOL(spl_panic);
+
+void
+vcmn_err(int ce, const char *fmt, va_list ap)
+{
+       char msg[MAXMSGLEN];
+
+       vsnprintf(msg, MAXMSGLEN - 1, fmt, ap);
+
+       switch (ce) {
+       case CE_IGNORE:
+               break;
+       case CE_CONT:
+               printk("%s", msg);
+               break;
+       case CE_NOTE:
+               printk(KERN_NOTICE "NOTICE: %s\n", msg);
+               break;
+       case CE_WARN:
+               printk(KERN_WARNING "WARNING: %s\n", msg);
+               break;
+       case CE_PANIC:
+               printk(KERN_EMERG "PANIC: %s\n", msg);
+               spl_dumpstack();
+
+               /* Halt the thread to facilitate further debugging */
+               set_task_state(current, TASK_UNINTERRUPTIBLE);
+               while (1)
+                       schedule();
+       }
+} /* vcmn_err() */
+EXPORT_SYMBOL(vcmn_err);
+
+void
+cmn_err(int ce, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vcmn_err(ce, fmt, ap);
+       va_end(ap);
+} /* cmn_err() */
+EXPORT_SYMBOL(cmn_err);
diff --git a/spl/module/spl/spl-generic.c b/spl/module/spl/spl-generic.c
new file mode 100644 (file)
index 0000000..c01a646
--- /dev/null
@@ -0,0 +1,605 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Generic Implementation.
+\*****************************************************************************/
+
+#include <sys/sysmacros.h>
+#include <sys/systeminfo.h>
+#include <sys/vmsystm.h>
+#include <sys/kobj.h>
+#include <sys/kmem.h>
+#include <sys/kmem_cache.h>
+#include <sys/vmem.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/taskq.h>
+#include <sys/tsd.h>
+#include <sys/zmod.h>
+#include <sys/debug.h>
+#include <sys/proc.h>
+#include <sys/kstat.h>
+#include <sys/file.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/math64_compat.h>
+#include <linux/proc_compat.h>
+
+char spl_version[32] = "SPL v" SPL_META_VERSION "-" SPL_META_RELEASE;
+EXPORT_SYMBOL(spl_version);
+
+unsigned long spl_hostid = 0;
+EXPORT_SYMBOL(spl_hostid);
+module_param(spl_hostid, ulong, 0644);
+MODULE_PARM_DESC(spl_hostid, "The system hostid.");
+
+proc_t p0;
+EXPORT_SYMBOL(p0);
+
+#if BITS_PER_LONG == 32
+/*
+ * Support 64/64 => 64 division on a 32-bit platform.  While the kernel
+ * provides a div64_u64() function for this we do not use it because the
+ * implementation is flawed.  There are cases which return incorrect
+ * results as late as linux-2.6.35.  Until this is fixed upstream the
+ * spl must provide its own implementation.
+ *
+ * This implementation is a slightly modified version of the algorithm
+ * proposed by the book 'Hacker's Delight'.  The original source can be
+ * found here and is available for use without restriction.
+ *
+ * http://www.hackersdelight.org/HDcode/newCode/divDouble.c
+ */
+
+/*
+ * Calculate number of leading of zeros for a 64-bit value.
+ */
+static int
+nlz64(uint64_t x) {
+       register int n = 0;
+
+       if (x == 0)
+               return 64;
+
+       if (x <= 0x00000000FFFFFFFFULL) {n = n + 32; x = x << 32;}
+       if (x <= 0x0000FFFFFFFFFFFFULL) {n = n + 16; x = x << 16;}
+       if (x <= 0x00FFFFFFFFFFFFFFULL) {n = n +  8; x = x <<  8;}
+       if (x <= 0x0FFFFFFFFFFFFFFFULL) {n = n +  4; x = x <<  4;}
+       if (x <= 0x3FFFFFFFFFFFFFFFULL) {n = n +  2; x = x <<  2;}
+       if (x <= 0x7FFFFFFFFFFFFFFFULL) {n = n +  1;}
+
+       return n;
+}
+
+/*
+ * Newer kernels have a div_u64() function but we define our own
+ * to simplify portibility between kernel versions.
+ */
+static inline uint64_t
+__div_u64(uint64_t u, uint32_t v)
+{
+       (void) do_div(u, v);
+       return u;
+}
+
+/*
+ * Implementation of 64-bit unsigned division for 32-bit machines.
+ *
+ * First the procedure takes care of the case in which the divisor is a
+ * 32-bit quantity. There are two subcases: (1) If the left half of the
+ * dividend is less than the divisor, one execution of do_div() is all that
+ * is required (overflow is not possible). (2) Otherwise it does two
+ * divisions, using the grade school method.
+ */
+uint64_t
+__udivdi3(uint64_t u, uint64_t v)
+{
+       uint64_t u0, u1, v1, q0, q1, k;
+       int n;
+
+       if (v >> 32 == 0) {                     // If v < 2**32:
+               if (u >> 32 < v) {              // If u/v cannot overflow,
+                       return __div_u64(u, v); // just do one division.
+               } else {                        // If u/v would overflow:
+                       u1 = u >> 32;           // Break u into two halves.
+                       u0 = u & 0xFFFFFFFF;
+                       q1 = __div_u64(u1, v);  // First quotient digit.
+                       k  = u1 - q1 * v;       // First remainder, < v.
+                       u0 += (k << 32);
+                       q0 = __div_u64(u0, v);  // Seconds quotient digit.
+                       return (q1 << 32) + q0;
+               }
+       } else {                                // If v >= 2**32:
+               n = nlz64(v);                   // 0 <= n <= 31.
+               v1 = (v << n) >> 32;            // Normalize divisor, MSB is 1.
+               u1 = u >> 1;                    // To ensure no overflow.
+               q1 = __div_u64(u1, v1);         // Get quotient from
+               q0 = (q1 << n) >> 31;           // Undo normalization and
+                                               // division of u by 2.
+               if (q0 != 0)                    // Make q0 correct or
+                       q0 = q0 - 1;            // too small by 1.
+               if ((u - q0 * v) >= v)
+                       q0 = q0 + 1;            // Now q0 is correct.
+
+               return q0;
+       }
+}
+EXPORT_SYMBOL(__udivdi3);
+
+/*
+ * Implementation of 64-bit signed division for 32-bit machines.
+ */
+int64_t
+__divdi3(int64_t u, int64_t v)
+{
+       int64_t q, t;
+       q = __udivdi3(abs64(u), abs64(v));
+       t = (u ^ v) >> 63;      // If u, v have different
+       return (q ^ t) - t;     // signs, negate q.
+}
+EXPORT_SYMBOL(__divdi3);
+
+/*
+ * Implementation of 64-bit unsigned modulo for 32-bit machines.
+ */
+uint64_t
+__umoddi3(uint64_t dividend, uint64_t divisor)
+{
+       return (dividend - (divisor * __udivdi3(dividend, divisor)));
+}
+EXPORT_SYMBOL(__umoddi3);
+
+#if defined(__arm) || defined(__arm__)
+/*
+ * Implementation of 64-bit (un)signed division for 32-bit arm machines.
+ *
+ * Run-time ABI for the ARM Architecture (page 20).  A pair of (unsigned)
+ * long longs is returned in {{r0, r1}, {r2,r3}}, the quotient in {r0, r1},
+ * and the remainder in {r2, r3}.  The return type is specifically left
+ * set to 'void' to ensure the compiler does not overwrite these registers
+ * during the return.  All results are in registers as per ABI
+ */
+void
+__aeabi_uldivmod(uint64_t u, uint64_t v)
+{
+       uint64_t res;
+       uint64_t mod;
+
+       res = __udivdi3(u, v);
+       mod = __umoddi3(u, v);
+       {
+               register uint32_t r0 asm("r0") = (res & 0xFFFFFFFF);
+               register uint32_t r1 asm("r1") = (res >> 32);
+               register uint32_t r2 asm("r2") = (mod & 0xFFFFFFFF);
+               register uint32_t r3 asm("r3") = (mod >> 32);
+
+               asm volatile(""
+                   : "+r"(r0), "+r"(r1), "+r"(r2),"+r"(r3)  /* output */
+                   : "r"(r0), "r"(r1), "r"(r2), "r"(r3));   /* input */
+
+               return; /* r0; */
+       }
+}
+EXPORT_SYMBOL(__aeabi_uldivmod);
+
+void
+__aeabi_ldivmod(int64_t u, int64_t v)
+{
+       int64_t res;
+       uint64_t mod;
+
+       res =  __divdi3(u, v);
+       mod = __umoddi3(u, v);
+       {
+               register uint32_t r0 asm("r0") = (res & 0xFFFFFFFF);
+               register uint32_t r1 asm("r1") = (res >> 32);
+               register uint32_t r2 asm("r2") = (mod & 0xFFFFFFFF);
+               register uint32_t r3 asm("r3") = (mod >> 32);
+
+               asm volatile(""
+                   : "+r"(r0), "+r"(r1), "+r"(r2),"+r"(r3)  /* output */
+                   : "r"(r0), "r"(r1), "r"(r2), "r"(r3));   /* input */
+
+               return; /* r0; */
+       }
+}
+EXPORT_SYMBOL(__aeabi_ldivmod);
+#endif /* __arm || __arm__ */
+#endif /* BITS_PER_LONG */
+
+/* NOTE: The strtoxx behavior is solely based on my reading of the Solaris
+ * ddi_strtol(9F) man page.  I have not verified the behavior of these
+ * functions against their Solaris counterparts.  It is possible that I
+ * may have misinterpreted the man page or the man page is incorrect.
+ */
+int ddi_strtoul(const char *, char **, int, unsigned long *);
+int ddi_strtol(const char *, char **, int, long *);
+int ddi_strtoull(const char *, char **, int, unsigned long long *);
+int ddi_strtoll(const char *, char **, int, long long *);
+
+#define define_ddi_strtoux(type, valtype)                              \
+int ddi_strtou##type(const char *str, char **endptr,                   \
+                    int base, valtype *result)                         \
+{                                                                      \
+       valtype last_value, value = 0;                                  \
+       char *ptr = (char *)str;                                        \
+       int flag = 1, digit;                                            \
+                                                                       \
+       if (strlen(ptr) == 0)                                           \
+               return EINVAL;                                          \
+                                                                       \
+       /* Auto-detect base based on prefix */                          \
+       if (!base) {                                                    \
+               if (str[0] == '0') {                                    \
+                       if (tolower(str[1])=='x' && isxdigit(str[2])) { \
+                               base = 16; /* hex */                    \
+                               ptr += 2;                               \
+                       } else if (str[1] >= '0' && str[1] < 8) {       \
+                               base = 8; /* octal */                   \
+                               ptr += 1;                               \
+                       } else {                                        \
+                               return EINVAL;                          \
+                       }                                               \
+               } else {                                                \
+                       base = 10; /* decimal */                        \
+               }                                                       \
+       }                                                               \
+                                                                       \
+       while (1) {                                                     \
+               if (isdigit(*ptr))                                      \
+                       digit = *ptr - '0';                             \
+               else if (isalpha(*ptr))                                 \
+                       digit = tolower(*ptr) - 'a' + 10;               \
+               else                                                    \
+                       break;                                          \
+                                                                       \
+               if (digit >= base)                                      \
+                       break;                                          \
+                                                                       \
+               last_value = value;                                     \
+               value = value * base + digit;                           \
+               if (last_value > value) /* Overflow */                  \
+                       return ERANGE;                                  \
+                                                                       \
+               flag = 1;                                               \
+               ptr++;                                                  \
+       }                                                               \
+                                                                       \
+       if (flag)                                                       \
+               *result = value;                                        \
+                                                                       \
+       if (endptr)                                                     \
+               *endptr = (char *)(flag ? ptr : str);                   \
+                                                                       \
+       return 0;                                                       \
+}                                                                      \
+
+#define define_ddi_strtox(type, valtype)                               \
+int ddi_strto##type(const char *str, char **endptr,                    \
+                      int base, valtype *result)                       \
+{                                                                      \
+       int rc;                                                         \
+                                                                       \
+       if (*str == '-') {                                              \
+               rc = ddi_strtou##type(str + 1, endptr, base, result);   \
+               if (!rc) {                                              \
+                       if (*endptr == str + 1)                         \
+                               *endptr = (char *)str;                  \
+                       else                                            \
+                               *result = -*result;                     \
+               }                                                       \
+       } else {                                                        \
+               rc = ddi_strtou##type(str, endptr, base, result);       \
+       }                                                               \
+                                                                       \
+       return rc;                                                      \
+}
+
+define_ddi_strtoux(l, unsigned long)
+define_ddi_strtox(l, long)
+define_ddi_strtoux(ll, unsigned long long)
+define_ddi_strtox(ll, long long)
+
+EXPORT_SYMBOL(ddi_strtoul);
+EXPORT_SYMBOL(ddi_strtol);
+EXPORT_SYMBOL(ddi_strtoll);
+EXPORT_SYMBOL(ddi_strtoull);
+
+int
+ddi_copyin(const void *from, void *to, size_t len, int flags)
+{
+       /* Fake ioctl() issued by kernel, 'from' is a kernel address */
+       if (flags & FKIOCTL) {
+               memcpy(to, from, len);
+               return 0;
+       }
+
+       return copyin(from, to, len);
+}
+EXPORT_SYMBOL(ddi_copyin);
+
+int
+ddi_copyout(const void *from, void *to, size_t len, int flags)
+{
+       /* Fake ioctl() issued by kernel, 'from' is a kernel address */
+       if (flags & FKIOCTL) {
+               memcpy(to, from, len);
+               return 0;
+       }
+
+       return copyout(from, to, len);
+}
+EXPORT_SYMBOL(ddi_copyout);
+
+#ifndef HAVE_PUT_TASK_STRUCT
+/*
+ * This is only a stub function which should never be used.  The SPL should
+ * never be putting away the last reference on a task structure so this will
+ * not be called.  However, we still need to define it so the module does not
+ * have undefined symbol at load time.  That all said if this impossible
+ * thing does somehow happen PANIC immediately so we know about it.
+ */
+void
+__put_task_struct(struct task_struct *t)
+{
+       PANIC("Unexpectly put last reference on task %d\n", (int)t->pid);
+}
+EXPORT_SYMBOL(__put_task_struct);
+#endif /* HAVE_PUT_TASK_STRUCT */
+
+/*
+ * Read the unique system identifier from the /etc/hostid file.
+ *
+ * The behavior of /usr/bin/hostid on Linux systems with the
+ * regular eglibc and coreutils is:
+ *
+ *   1. Generate the value if the /etc/hostid file does not exist
+ *      or if the /etc/hostid file is less than four bytes in size.
+ *
+ *   2. If the /etc/hostid file is at least 4 bytes, then return
+ *      the first four bytes [0..3] in native endian order.
+ *
+ *   3. Always ignore bytes [4..] if they exist in the file.
+ *
+ * Only the first four bytes are significant, even on systems that
+ * have a 64-bit word size.
+ *
+ * See:
+ *
+ *   eglibc: sysdeps/unix/sysv/linux/gethostid.c
+ *   coreutils: src/hostid.c
+ *
+ * Notes:
+ *
+ * The /etc/hostid file on Solaris is a text file that often reads:
+ *
+ *   # DO NOT EDIT
+ *   "0123456789"
+ *
+ * Directly copying this file to Linux results in a constant
+ * hostid of 4f442023 because the default comment constitutes
+ * the first four bytes of the file.
+ *
+ */
+
+char *spl_hostid_path = HW_HOSTID_PATH;
+module_param(spl_hostid_path, charp, 0444);
+MODULE_PARM_DESC(spl_hostid_path, "The system hostid file (/etc/hostid)");
+
+static int
+hostid_read(void)
+{
+       int result;
+       uint64_t size;
+       struct _buf *file;
+       uint32_t hostid = 0;
+
+       file = kobj_open_file(spl_hostid_path);
+
+       if (file == (struct _buf *)-1)
+               return -1;
+
+       result = kobj_get_filesize(file, &size);
+
+       if (result != 0) {
+               printk(KERN_WARNING
+                      "SPL: kobj_get_filesize returned %i on %s\n",
+                      result, spl_hostid_path);
+               kobj_close_file(file);
+               return -2;
+       }
+
+       if (size < sizeof(HW_HOSTID_MASK)) {
+               printk(KERN_WARNING
+                      "SPL: Ignoring the %s file because it is %llu bytes; "
+                      "expecting %lu bytes instead.\n", spl_hostid_path,
+                      size, (unsigned long)sizeof(HW_HOSTID_MASK));
+               kobj_close_file(file);
+               return -3;
+       }
+
+       /* Read directly into the variable like eglibc does. */
+       /* Short reads are okay; native behavior is preserved. */
+       result = kobj_read_file(file, (char *)&hostid, sizeof(hostid), 0);
+
+       if (result < 0) {
+               printk(KERN_WARNING
+                      "SPL: kobj_read_file returned %i on %s\n",
+                      result, spl_hostid_path);
+               kobj_close_file(file);
+               return -4;
+       }
+
+       /* Mask down to 32 bits like coreutils does. */
+       spl_hostid = hostid & HW_HOSTID_MASK;
+       kobj_close_file(file);
+       return 0;
+}
+
+uint32_t
+zone_get_hostid(void *zone)
+{
+       static int first = 1;
+
+       /* Only the global zone is supported */
+       ASSERT(zone == NULL);
+
+       if (first) {
+               first = 0;
+
+               spl_hostid &= HW_HOSTID_MASK;
+               /*
+                * Get the hostid if it was not passed as a module parameter.
+                * Try reading the /etc/hostid file directly.
+                */
+               if (spl_hostid == 0 && hostid_read())
+                       spl_hostid = 0;
+
+
+               printk(KERN_NOTICE "SPL: using hostid 0x%08x\n",
+                       (unsigned int) spl_hostid);
+       }
+
+       return spl_hostid;
+}
+EXPORT_SYMBOL(zone_get_hostid);
+
+static int
+spl_kvmem_init(void)
+{
+       int rc = 0;
+
+       rc = spl_kmem_init();
+       if (rc)
+               goto out1;
+
+       rc = spl_vmem_init();
+       if (rc)
+               goto out2;
+
+       rc = spl_kmem_cache_init();
+       if (rc)
+               goto out3;
+
+       return (rc);
+out3:
+       spl_vmem_fini();
+out2:
+       spl_kmem_fini();
+out1:
+       return (rc);
+}
+
+static void
+spl_kvmem_fini(void)
+{
+       spl_kmem_cache_fini();
+       spl_vmem_fini();
+       spl_kmem_fini();
+}
+
+static int __init
+spl_init(void)
+{
+       int rc = 0;
+
+       bzero(&p0, sizeof (proc_t));
+
+       if ((rc = spl_kvmem_init()))
+               goto out1;
+
+       if ((rc = spl_mutex_init()))
+               goto out2;
+
+       if ((rc = spl_rw_init()))
+               goto out3;
+
+       if ((rc = spl_taskq_init()))
+               goto out4;
+
+       if ((rc = spl_vn_init()))
+               goto out5;
+
+       if ((rc = spl_proc_init()))
+               goto out6;
+
+       if ((rc = spl_kstat_init()))
+               goto out7;
+
+       if ((rc = spl_tsd_init()))
+               goto out8;
+
+       if ((rc = spl_zlib_init()))
+               goto out9;
+
+       printk(KERN_NOTICE "SPL: Loaded module v%s-%s%s\n", SPL_META_VERSION,
+              SPL_META_RELEASE, SPL_DEBUG_STR);
+       return (rc);
+
+out9:
+       spl_tsd_fini();
+out8:
+       spl_kstat_fini();
+out7:
+       spl_proc_fini();
+out6:
+       spl_vn_fini();
+out5:
+       spl_taskq_fini();
+out4:
+       spl_rw_fini();
+out3:
+       spl_mutex_fini();
+out2:
+       spl_kvmem_fini();
+out1:
+       printk(KERN_NOTICE "SPL: Failed to Load Solaris Porting Layer "
+              "v%s-%s%s, rc = %d\n", SPL_META_VERSION, SPL_META_RELEASE,
+              SPL_DEBUG_STR, rc);
+
+       return (rc);
+}
+
+static void __exit
+spl_fini(void)
+{
+       printk(KERN_NOTICE "SPL: Unloaded module v%s-%s%s\n",
+              SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR);
+       spl_zlib_fini();
+       spl_tsd_fini();
+       spl_kstat_fini();
+       spl_proc_fini();
+       spl_vn_fini();
+       spl_taskq_fini();
+       spl_rw_fini();
+       spl_mutex_fini();
+       spl_kvmem_fini();
+}
+
+module_init(spl_init);
+module_exit(spl_fini);
+
+MODULE_DESCRIPTION("Solaris Porting Layer");
+MODULE_AUTHOR(SPL_META_AUTHOR);
+MODULE_LICENSE(SPL_META_LICENSE);
+MODULE_VERSION(SPL_META_VERSION "-" SPL_META_RELEASE);
diff --git a/spl/module/spl/spl-kmem-cache.c b/spl/module/spl/spl-kmem-cache.c
new file mode 100644 (file)
index 0000000..b58f128
--- /dev/null
@@ -0,0 +1,1734 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/kmem.h>
+#include <sys/kmem_cache.h>
+#include <sys/taskq.h>
+#include <sys/timer.h>
+#include <sys/vmem.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/mm_compat.h>
+#include <linux/wait_compat.h>
+#include <linux/prefetch.h>
+
+/*
+ * Within the scope of spl-kmem.c file the kmem_cache_* definitions
+ * are removed to allow access to the real Linux slab allocator.
+ */
+#undef kmem_cache_destroy
+#undef kmem_cache_create
+#undef kmem_cache_alloc
+#undef kmem_cache_free
+
+
+/*
+ * Linux 3.16 replaced smp_mb__{before,after}_{atomic,clear}_{dec,inc,bit}()
+ * with smp_mb__{before,after}_atomic() because they were redundant. This is
+ * only used inside our SLAB allocator, so we implement an internal wrapper
+ * here to give us smp_mb__{before,after}_atomic() on older kernels.
+ */
+#ifndef smp_mb__before_atomic
+#define        smp_mb__before_atomic(x) smp_mb__before_clear_bit(x)
+#endif
+
+#ifndef smp_mb__after_atomic
+#define        smp_mb__after_atomic(x) smp_mb__after_clear_bit(x)
+#endif
+
+/*
+ * Cache expiration was implemented because it was part of the default Solaris
+ * kmem_cache behavior.  The idea is that per-cpu objects which haven't been
+ * accessed in several seconds should be returned to the cache.  On the other
+ * hand Linux slabs never move objects back to the slabs unless there is
+ * memory pressure on the system.  By default the Linux method is enabled
+ * because it has been shown to improve responsiveness on low memory systems.
+ * This policy may be changed by setting KMC_EXPIRE_AGE or KMC_EXPIRE_MEM.
+ */
+unsigned int spl_kmem_cache_expire = KMC_EXPIRE_MEM;
+EXPORT_SYMBOL(spl_kmem_cache_expire);
+module_param(spl_kmem_cache_expire, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_expire, "By age (0x1) or low memory (0x2)");
+
+/*
+ * Cache magazines are an optimization designed to minimize the cost of
+ * allocating memory.  They do this by keeping a per-cpu cache of recently
+ * freed objects, which can then be reallocated without taking a lock. This
+ * can improve performance on highly contended caches.  However, because
+ * objects in magazines will prevent otherwise empty slabs from being
+ * immediately released this may not be ideal for low memory machines.
+ *
+ * For this reason spl_kmem_cache_magazine_size can be used to set a maximum
+ * magazine size.  When this value is set to 0 the magazine size will be
+ * automatically determined based on the object size.  Otherwise magazines
+ * will be limited to 2-256 objects per magazine (i.e per cpu).  Magazines
+ * may never be entirely disabled in this implementation.
+ */
+unsigned int spl_kmem_cache_magazine_size = 0;
+module_param(spl_kmem_cache_magazine_size, uint, 0444);
+MODULE_PARM_DESC(spl_kmem_cache_magazine_size,
+       "Default magazine size (2-256), set automatically (0)\n");
+
+/*
+ * The default behavior is to report the number of objects remaining in the
+ * cache.  This allows the Linux VM to repeatedly reclaim objects from the
+ * cache when memory is low satisfy other memory allocations.  Alternately,
+ * setting this value to KMC_RECLAIM_ONCE limits how aggressively the cache
+ * is reclaimed.  This may increase the likelihood of out of memory events.
+ */
+unsigned int spl_kmem_cache_reclaim = 0 /* KMC_RECLAIM_ONCE */;
+module_param(spl_kmem_cache_reclaim, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_reclaim, "Single reclaim pass (0x1)");
+
+unsigned int spl_kmem_cache_obj_per_slab = SPL_KMEM_CACHE_OBJ_PER_SLAB;
+module_param(spl_kmem_cache_obj_per_slab, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_obj_per_slab, "Number of objects per slab");
+
+unsigned int spl_kmem_cache_obj_per_slab_min = SPL_KMEM_CACHE_OBJ_PER_SLAB_MIN;
+module_param(spl_kmem_cache_obj_per_slab_min, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_obj_per_slab_min,
+       "Minimal number of objects per slab");
+
+unsigned int spl_kmem_cache_max_size = SPL_KMEM_CACHE_MAX_SIZE;
+module_param(spl_kmem_cache_max_size, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_max_size, "Maximum size of slab in MB");
+
+/*
+ * For small objects the Linux slab allocator should be used to make the most
+ * efficient use of the memory.  However, large objects are not supported by
+ * the Linux slab and therefore the SPL implementation is preferred.  A cutoff
+ * of 16K was determined to be optimal for architectures using 4K pages.
+ */
+#if PAGE_SIZE == 4096
+unsigned int spl_kmem_cache_slab_limit = 16384;
+#else
+unsigned int spl_kmem_cache_slab_limit = 0;
+#endif
+module_param(spl_kmem_cache_slab_limit, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_slab_limit,
+       "Objects less than N bytes use the Linux slab");
+
+/*
+ * This value defaults to a threshold designed to avoid allocations which
+ * have been deemed costly by the kernel.
+ */
+unsigned int spl_kmem_cache_kmem_limit =
+    ((1 << (PAGE_ALLOC_COSTLY_ORDER - 1)) * PAGE_SIZE) /
+    SPL_KMEM_CACHE_OBJ_PER_SLAB;
+module_param(spl_kmem_cache_kmem_limit, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_cache_kmem_limit,
+       "Objects less than N bytes use the kmalloc");
+
+/*
+ * The number of threads available to allocate new slabs for caches.  This
+ * should not need to be tuned but it is available for performance analysis.
+ */
+unsigned int spl_kmem_cache_kmem_threads = 4;
+module_param(spl_kmem_cache_kmem_threads, uint, 0444);
+MODULE_PARM_DESC(spl_kmem_cache_kmem_threads,
+       "Number of spl_kmem_cache threads");
+
+/*
+ * Slab allocation interfaces
+ *
+ * While the Linux slab implementation was inspired by the Solaris
+ * implementation I cannot use it to emulate the Solaris APIs.  I
+ * require two features which are not provided by the Linux slab.
+ *
+ * 1) Constructors AND destructors.  Recent versions of the Linux
+ *    kernel have removed support for destructors.  This is a deal
+ *    breaker for the SPL which contains particularly expensive
+ *    initializers for mutex's, condition variables, etc.  We also
+ *    require a minimal level of cleanup for these data types unlike
+ *    many Linux data types which do need to be explicitly destroyed.
+ *
+ * 2) Virtual address space backed slab.  Callers of the Solaris slab
+ *    expect it to work well for both small are very large allocations.
+ *    Because of memory fragmentation the Linux slab which is backed
+ *    by kmalloc'ed memory performs very badly when confronted with
+ *    large numbers of large allocations.  Basing the slab on the
+ *    virtual address space removes the need for contiguous pages
+ *    and greatly improve performance for large allocations.
+ *
+ * For these reasons, the SPL has its own slab implementation with
+ * the needed features.  It is not as highly optimized as either the
+ * Solaris or Linux slabs, but it should get me most of what is
+ * needed until it can be optimized or obsoleted by another approach.
+ *
+ * One serious concern I do have about this method is the relatively
+ * small virtual address space on 32bit arches.  This will seriously
+ * constrain the size of the slab caches and their performance.
+ */
+
+struct list_head spl_kmem_cache_list;   /* List of caches */
+struct rw_semaphore spl_kmem_cache_sem; /* Cache list lock */
+taskq_t *spl_kmem_cache_taskq;         /* Task queue for ageing / reclaim */
+
+static void spl_cache_shrink(spl_kmem_cache_t *skc, void *obj);
+
+SPL_SHRINKER_CALLBACK_FWD_DECLARE(spl_kmem_cache_generic_shrinker);
+SPL_SHRINKER_DECLARE(spl_kmem_cache_shrinker,
+       spl_kmem_cache_generic_shrinker, KMC_DEFAULT_SEEKS);
+
+static void *
+kv_alloc(spl_kmem_cache_t *skc, int size, int flags)
+{
+       gfp_t lflags = kmem_flags_convert(flags);
+       void *ptr;
+
+       if (skc->skc_flags & KMC_KMEM) {
+               ASSERT(ISP2(size));
+               ptr = (void *)__get_free_pages(lflags, get_order(size));
+       } else {
+               ptr = __vmalloc(size, lflags | __GFP_HIGHMEM, PAGE_KERNEL);
+       }
+
+       /* Resulting allocated memory will be page aligned */
+       ASSERT(IS_P2ALIGNED(ptr, PAGE_SIZE));
+
+       return (ptr);
+}
+
+static void
+kv_free(spl_kmem_cache_t *skc, void *ptr, int size)
+{
+       ASSERT(IS_P2ALIGNED(ptr, PAGE_SIZE));
+
+       /*
+        * The Linux direct reclaim path uses this out of band value to
+        * determine if forward progress is being made.  Normally this is
+        * incremented by kmem_freepages() which is part of the various
+        * Linux slab implementations.  However, since we are using none
+        * of that infrastructure we are responsible for incrementing it.
+        */
+       if (current->reclaim_state)
+               current->reclaim_state->reclaimed_slab += size >> PAGE_SHIFT;
+
+       if (skc->skc_flags & KMC_KMEM) {
+               ASSERT(ISP2(size));
+               free_pages((unsigned long)ptr, get_order(size));
+       } else {
+               vfree(ptr);
+       }
+}
+
+/*
+ * Required space for each aligned sks.
+ */
+static inline uint32_t
+spl_sks_size(spl_kmem_cache_t *skc)
+{
+       return (P2ROUNDUP_TYPED(sizeof (spl_kmem_slab_t),
+           skc->skc_obj_align, uint32_t));
+}
+
+/*
+ * Required space for each aligned object.
+ */
+static inline uint32_t
+spl_obj_size(spl_kmem_cache_t *skc)
+{
+       uint32_t align = skc->skc_obj_align;
+
+       return (P2ROUNDUP_TYPED(skc->skc_obj_size, align, uint32_t) +
+           P2ROUNDUP_TYPED(sizeof (spl_kmem_obj_t), align, uint32_t));
+}
+
+/*
+ * Lookup the spl_kmem_object_t for an object given that object.
+ */
+static inline spl_kmem_obj_t *
+spl_sko_from_obj(spl_kmem_cache_t *skc, void *obj)
+{
+       return (obj + P2ROUNDUP_TYPED(skc->skc_obj_size,
+           skc->skc_obj_align, uint32_t));
+}
+
+/*
+ * Required space for each offslab object taking in to account alignment
+ * restrictions and the power-of-two requirement of kv_alloc().
+ */
+static inline uint32_t
+spl_offslab_size(spl_kmem_cache_t *skc)
+{
+       return (1UL << (fls64(spl_obj_size(skc)) + 1));
+}
+
+/*
+ * It's important that we pack the spl_kmem_obj_t structure and the
+ * actual objects in to one large address space to minimize the number
+ * of calls to the allocator.  It is far better to do a few large
+ * allocations and then subdivide it ourselves.  Now which allocator
+ * we use requires balancing a few trade offs.
+ *
+ * For small objects we use kmem_alloc() because as long as you are
+ * only requesting a small number of pages (ideally just one) its cheap.
+ * However, when you start requesting multiple pages with kmem_alloc()
+ * it gets increasingly expensive since it requires contiguous pages.
+ * For this reason we shift to vmem_alloc() for slabs of large objects
+ * which removes the need for contiguous pages.  We do not use
+ * vmem_alloc() in all cases because there is significant locking
+ * overhead in __get_vm_area_node().  This function takes a single
+ * global lock when acquiring an available virtual address range which
+ * serializes all vmem_alloc()'s for all slab caches.  Using slightly
+ * different allocation functions for small and large objects should
+ * give us the best of both worlds.
+ *
+ * KMC_ONSLAB                       KMC_OFFSLAB
+ *
+ * +------------------------+       +-----------------+
+ * | spl_kmem_slab_t --+-+  |       | spl_kmem_slab_t |---+-+
+ * | skc_obj_size    <-+ |  |       +-----------------+   | |
+ * | spl_kmem_obj_t      |  |                             | |
+ * | skc_obj_size    <---+  |       +-----------------+   | |
+ * | spl_kmem_obj_t      |  |       | skc_obj_size    | <-+ |
+ * | ...                 v  |       | spl_kmem_obj_t  |     |
+ * +------------------------+       +-----------------+     v
+ */
+static spl_kmem_slab_t *
+spl_slab_alloc(spl_kmem_cache_t *skc, int flags)
+{
+       spl_kmem_slab_t *sks;
+       spl_kmem_obj_t *sko, *n;
+       void *base, *obj;
+       uint32_t obj_size, offslab_size = 0;
+       int i,  rc = 0;
+
+       base = kv_alloc(skc, skc->skc_slab_size, flags);
+       if (base == NULL)
+               return (NULL);
+
+       sks = (spl_kmem_slab_t *)base;
+       sks->sks_magic = SKS_MAGIC;
+       sks->sks_objs = skc->skc_slab_objs;
+       sks->sks_age = jiffies;
+       sks->sks_cache = skc;
+       INIT_LIST_HEAD(&sks->sks_list);
+       INIT_LIST_HEAD(&sks->sks_free_list);
+       sks->sks_ref = 0;
+       obj_size = spl_obj_size(skc);
+
+       if (skc->skc_flags & KMC_OFFSLAB)
+               offslab_size = spl_offslab_size(skc);
+
+       for (i = 0; i < sks->sks_objs; i++) {
+               if (skc->skc_flags & KMC_OFFSLAB) {
+                       obj = kv_alloc(skc, offslab_size, flags);
+                       if (!obj) {
+                               rc = -ENOMEM;
+                               goto out;
+                       }
+               } else {
+                       obj = base + spl_sks_size(skc) + (i * obj_size);
+               }
+
+               ASSERT(IS_P2ALIGNED(obj, skc->skc_obj_align));
+               sko = spl_sko_from_obj(skc, obj);
+               sko->sko_addr = obj;
+               sko->sko_magic = SKO_MAGIC;
+               sko->sko_slab = sks;
+               INIT_LIST_HEAD(&sko->sko_list);
+               list_add_tail(&sko->sko_list, &sks->sks_free_list);
+       }
+
+out:
+       if (rc) {
+               if (skc->skc_flags & KMC_OFFSLAB)
+                       list_for_each_entry_safe(sko,
+                           n, &sks->sks_free_list, sko_list)
+                               kv_free(skc, sko->sko_addr, offslab_size);
+
+               kv_free(skc, base, skc->skc_slab_size);
+               sks = NULL;
+       }
+
+       return (sks);
+}
+
+/*
+ * Remove a slab from complete or partial list, it must be called with
+ * the 'skc->skc_lock' held but the actual free must be performed
+ * outside the lock to prevent deadlocking on vmem addresses.
+ */
+static void
+spl_slab_free(spl_kmem_slab_t *sks,
+    struct list_head *sks_list, struct list_head *sko_list)
+{
+       spl_kmem_cache_t *skc;
+
+       ASSERT(sks->sks_magic == SKS_MAGIC);
+       ASSERT(sks->sks_ref == 0);
+
+       skc = sks->sks_cache;
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(spin_is_locked(&skc->skc_lock));
+
+       /*
+        * Update slab/objects counters in the cache, then remove the
+        * slab from the skc->skc_partial_list.  Finally add the slab
+        * and all its objects in to the private work lists where the
+        * destructors will be called and the memory freed to the system.
+        */
+       skc->skc_obj_total -= sks->sks_objs;
+       skc->skc_slab_total--;
+       list_del(&sks->sks_list);
+       list_add(&sks->sks_list, sks_list);
+       list_splice_init(&sks->sks_free_list, sko_list);
+}
+
+/*
+ * Reclaim empty slabs at the end of the partial list.
+ */
+static void
+spl_slab_reclaim(spl_kmem_cache_t *skc)
+{
+       spl_kmem_slab_t *sks, *m;
+       spl_kmem_obj_t *sko, *n;
+       LIST_HEAD(sks_list);
+       LIST_HEAD(sko_list);
+       uint32_t size = 0;
+
+       /*
+        * Empty slabs and objects must be moved to a private list so they
+        * can be safely freed outside the spin lock.  All empty slabs are
+        * at the end of skc->skc_partial_list, therefore once a non-empty
+        * slab is found we can stop scanning.
+        */
+       spin_lock(&skc->skc_lock);
+       list_for_each_entry_safe_reverse(sks, m,
+           &skc->skc_partial_list, sks_list) {
+
+               if (sks->sks_ref > 0)
+                       break;
+
+               spl_slab_free(sks, &sks_list, &sko_list);
+       }
+       spin_unlock(&skc->skc_lock);
+
+       /*
+        * The following two loops ensure all the object destructors are
+        * run, any offslab objects are freed, and the slabs themselves
+        * are freed.  This is all done outside the skc->skc_lock since
+        * this allows the destructor to sleep, and allows us to perform
+        * a conditional reschedule when a freeing a large number of
+        * objects and slabs back to the system.
+        */
+       if (skc->skc_flags & KMC_OFFSLAB)
+               size = spl_offslab_size(skc);
+
+       list_for_each_entry_safe(sko, n, &sko_list, sko_list) {
+               ASSERT(sko->sko_magic == SKO_MAGIC);
+
+               if (skc->skc_flags & KMC_OFFSLAB)
+                       kv_free(skc, sko->sko_addr, size);
+       }
+
+       list_for_each_entry_safe(sks, m, &sks_list, sks_list) {
+               ASSERT(sks->sks_magic == SKS_MAGIC);
+               kv_free(skc, sks, skc->skc_slab_size);
+       }
+}
+
+static spl_kmem_emergency_t *
+spl_emergency_search(struct rb_root *root, void *obj)
+{
+       struct rb_node *node = root->rb_node;
+       spl_kmem_emergency_t *ske;
+       unsigned long address = (unsigned long)obj;
+
+       while (node) {
+               ske = container_of(node, spl_kmem_emergency_t, ske_node);
+
+               if (address < ske->ske_obj)
+                       node = node->rb_left;
+               else if (address > ske->ske_obj)
+                       node = node->rb_right;
+               else
+                       return (ske);
+       }
+
+       return (NULL);
+}
+
+static int
+spl_emergency_insert(struct rb_root *root, spl_kmem_emergency_t *ske)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       spl_kmem_emergency_t *ske_tmp;
+       unsigned long address = ske->ske_obj;
+
+       while (*new) {
+               ske_tmp = container_of(*new, spl_kmem_emergency_t, ske_node);
+
+               parent = *new;
+               if (address < ske_tmp->ske_obj)
+                       new = &((*new)->rb_left);
+               else if (address > ske_tmp->ske_obj)
+                       new = &((*new)->rb_right);
+               else
+                       return (0);
+       }
+
+       rb_link_node(&ske->ske_node, parent, new);
+       rb_insert_color(&ske->ske_node, root);
+
+       return (1);
+}
+
+/*
+ * Allocate a single emergency object and track it in a red black tree.
+ */
+static int
+spl_emergency_alloc(spl_kmem_cache_t *skc, int flags, void **obj)
+{
+       gfp_t lflags = kmem_flags_convert(flags);
+       spl_kmem_emergency_t *ske;
+       int order = get_order(skc->skc_obj_size);
+       int empty;
+
+       /* Last chance use a partial slab if one now exists */
+       spin_lock(&skc->skc_lock);
+       empty = list_empty(&skc->skc_partial_list);
+       spin_unlock(&skc->skc_lock);
+       if (!empty)
+               return (-EEXIST);
+
+       ske = kmalloc(sizeof (*ske), lflags);
+       if (ske == NULL)
+               return (-ENOMEM);
+
+       ske->ske_obj = __get_free_pages(lflags, order);
+       if (ske->ske_obj == 0) {
+               kfree(ske);
+               return (-ENOMEM);
+       }
+
+       spin_lock(&skc->skc_lock);
+       empty = spl_emergency_insert(&skc->skc_emergency_tree, ske);
+       if (likely(empty)) {
+               skc->skc_obj_total++;
+               skc->skc_obj_emergency++;
+               if (skc->skc_obj_emergency > skc->skc_obj_emergency_max)
+                       skc->skc_obj_emergency_max = skc->skc_obj_emergency;
+       }
+       spin_unlock(&skc->skc_lock);
+
+       if (unlikely(!empty)) {
+               free_pages(ske->ske_obj, order);
+               kfree(ske);
+               return (-EINVAL);
+       }
+
+       *obj = (void *)ske->ske_obj;
+
+       return (0);
+}
+
+/*
+ * Locate the passed object in the red black tree and free it.
+ */
+static int
+spl_emergency_free(spl_kmem_cache_t *skc, void *obj)
+{
+       spl_kmem_emergency_t *ske;
+       int order = get_order(skc->skc_obj_size);
+
+       spin_lock(&skc->skc_lock);
+       ske = spl_emergency_search(&skc->skc_emergency_tree, obj);
+       if (ske) {
+               rb_erase(&ske->ske_node, &skc->skc_emergency_tree);
+               skc->skc_obj_emergency--;
+               skc->skc_obj_total--;
+       }
+       spin_unlock(&skc->skc_lock);
+
+       if (ske == NULL)
+               return (-ENOENT);
+
+       free_pages(ske->ske_obj, order);
+       kfree(ske);
+
+       return (0);
+}
+
+/*
+ * Release objects from the per-cpu magazine back to their slab.  The flush
+ * argument contains the max number of entries to remove from the magazine.
+ */
+static void
+__spl_cache_flush(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flush)
+{
+       int i, count = MIN(flush, skm->skm_avail);
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(skm->skm_magic == SKM_MAGIC);
+       ASSERT(spin_is_locked(&skc->skc_lock));
+
+       for (i = 0; i < count; i++)
+               spl_cache_shrink(skc, skm->skm_objs[i]);
+
+       skm->skm_avail -= count;
+       memmove(skm->skm_objs, &(skm->skm_objs[count]),
+           sizeof (void *) * skm->skm_avail);
+}
+
+static void
+spl_cache_flush(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flush)
+{
+       spin_lock(&skc->skc_lock);
+       __spl_cache_flush(skc, skm, flush);
+       spin_unlock(&skc->skc_lock);
+}
+
+static void
+spl_magazine_age(void *data)
+{
+       spl_kmem_cache_t *skc = (spl_kmem_cache_t *)data;
+       spl_kmem_magazine_t *skm = skc->skc_mag[smp_processor_id()];
+
+       ASSERT(skm->skm_magic == SKM_MAGIC);
+       ASSERT(skm->skm_cpu == smp_processor_id());
+       ASSERT(irqs_disabled());
+
+       /* There are no available objects or they are too young to age out */
+       if ((skm->skm_avail == 0) ||
+           time_before(jiffies, skm->skm_age + skc->skc_delay * HZ))
+               return;
+
+       /*
+        * Because we're executing in interrupt context we may have
+        * interrupted the holder of this lock.  To avoid a potential
+        * deadlock return if the lock is contended.
+        */
+       if (!spin_trylock(&skc->skc_lock))
+               return;
+
+       __spl_cache_flush(skc, skm, skm->skm_refill);
+       spin_unlock(&skc->skc_lock);
+}
+
+/*
+ * Called regularly to keep a downward pressure on the cache.
+ *
+ * Objects older than skc->skc_delay seconds in the per-cpu magazines will
+ * be returned to the caches.  This is done to prevent idle magazines from
+ * holding memory which could be better used elsewhere.  The delay is
+ * present to prevent thrashing the magazine.
+ *
+ * The newly released objects may result in empty partial slabs.  Those
+ * slabs should be released to the system.  Otherwise moving the objects
+ * out of the magazines is just wasted work.
+ */
+static void
+spl_cache_age(void *data)
+{
+       spl_kmem_cache_t *skc = (spl_kmem_cache_t *)data;
+       taskqid_t id = 0;
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+
+       /* Dynamically disabled at run time */
+       if (!(spl_kmem_cache_expire & KMC_EXPIRE_AGE))
+               return;
+
+       atomic_inc(&skc->skc_ref);
+
+       if (!(skc->skc_flags & KMC_NOMAGAZINE))
+               on_each_cpu(spl_magazine_age, skc, 1);
+
+       spl_slab_reclaim(skc);
+
+       while (!test_bit(KMC_BIT_DESTROY, &skc->skc_flags) && !id) {
+               id = taskq_dispatch_delay(
+                   spl_kmem_cache_taskq, spl_cache_age, skc, TQ_SLEEP,
+                   ddi_get_lbolt() + skc->skc_delay / 3 * HZ);
+
+               /* Destroy issued after dispatch immediately cancel it */
+               if (test_bit(KMC_BIT_DESTROY, &skc->skc_flags) && id)
+                       taskq_cancel_id(spl_kmem_cache_taskq, id);
+       }
+
+       spin_lock(&skc->skc_lock);
+       skc->skc_taskqid = id;
+       spin_unlock(&skc->skc_lock);
+
+       atomic_dec(&skc->skc_ref);
+}
+
+/*
+ * Size a slab based on the size of each aligned object plus spl_kmem_obj_t.
+ * When on-slab we want to target spl_kmem_cache_obj_per_slab.  However,
+ * for very small objects we may end up with more than this so as not
+ * to waste space in the minimal allocation of a single page.  Also for
+ * very large objects we may use as few as spl_kmem_cache_obj_per_slab_min,
+ * lower than this and we will fail.
+ */
+static int
+spl_slab_size(spl_kmem_cache_t *skc, uint32_t *objs, uint32_t *size)
+{
+       uint32_t sks_size, obj_size, max_size, tgt_size, tgt_objs;
+
+       if (skc->skc_flags & KMC_OFFSLAB) {
+               tgt_objs = spl_kmem_cache_obj_per_slab;
+               tgt_size = P2ROUNDUP(sizeof (spl_kmem_slab_t), PAGE_SIZE);
+
+               if ((skc->skc_flags & KMC_KMEM) &&
+                   (spl_obj_size(skc) > (SPL_MAX_ORDER_NR_PAGES * PAGE_SIZE)))
+                       return (-ENOSPC);
+       } else {
+               sks_size = spl_sks_size(skc);
+               obj_size = spl_obj_size(skc);
+               max_size = (spl_kmem_cache_max_size * 1024 * 1024);
+               tgt_size = (spl_kmem_cache_obj_per_slab * obj_size + sks_size);
+
+               /*
+                * KMC_KMEM slabs are allocated by __get_free_pages() which
+                * rounds up to the nearest order.  Knowing this the size
+                * should be rounded up to the next power of two with a hard
+                * maximum defined by the maximum allowed allocation order.
+                */
+               if (skc->skc_flags & KMC_KMEM) {
+                       max_size = SPL_MAX_ORDER_NR_PAGES * PAGE_SIZE;
+                       tgt_size = MIN(max_size,
+                           PAGE_SIZE * (1 << MAX(get_order(tgt_size) - 1, 1)));
+               }
+
+               if (tgt_size <= max_size) {
+                       tgt_objs = (tgt_size - sks_size) / obj_size;
+               } else {
+                       tgt_objs = (max_size - sks_size) / obj_size;
+                       tgt_size = (tgt_objs * obj_size) + sks_size;
+               }
+       }
+
+       if (tgt_objs == 0)
+               return (-ENOSPC);
+
+       *objs = tgt_objs;
+       *size = tgt_size;
+
+       return (0);
+}
+
+/*
+ * Make a guess at reasonable per-cpu magazine size based on the size of
+ * each object and the cost of caching N of them in each magazine.  Long
+ * term this should really adapt based on an observed usage heuristic.
+ */
+static int
+spl_magazine_size(spl_kmem_cache_t *skc)
+{
+       uint32_t obj_size = spl_obj_size(skc);
+       int size;
+
+       if (spl_kmem_cache_magazine_size > 0)
+               return (MAX(MIN(spl_kmem_cache_magazine_size, 256), 2));
+
+       /* Per-magazine sizes below assume a 4Kib page size */
+       if (obj_size > (PAGE_SIZE * 256))
+               size = 4;  /* Minimum 4Mib per-magazine */
+       else if (obj_size > (PAGE_SIZE * 32))
+               size = 16; /* Minimum 2Mib per-magazine */
+       else if (obj_size > (PAGE_SIZE))
+               size = 64; /* Minimum 256Kib per-magazine */
+       else if (obj_size > (PAGE_SIZE / 4))
+               size = 128; /* Minimum 128Kib per-magazine */
+       else
+               size = 256;
+
+       return (size);
+}
+
+/*
+ * Allocate a per-cpu magazine to associate with a specific core.
+ */
+static spl_kmem_magazine_t *
+spl_magazine_alloc(spl_kmem_cache_t *skc, int cpu)
+{
+       spl_kmem_magazine_t *skm;
+       int size = sizeof (spl_kmem_magazine_t) +
+           sizeof (void *) * skc->skc_mag_size;
+
+       skm = kmalloc_node(size, GFP_KERNEL, cpu_to_node(cpu));
+       if (skm) {
+               skm->skm_magic = SKM_MAGIC;
+               skm->skm_avail = 0;
+               skm->skm_size = skc->skc_mag_size;
+               skm->skm_refill = skc->skc_mag_refill;
+               skm->skm_cache = skc;
+               skm->skm_age = jiffies;
+               skm->skm_cpu = cpu;
+       }
+
+       return (skm);
+}
+
+/*
+ * Free a per-cpu magazine associated with a specific core.
+ */
+static void
+spl_magazine_free(spl_kmem_magazine_t *skm)
+{
+       ASSERT(skm->skm_magic == SKM_MAGIC);
+       ASSERT(skm->skm_avail == 0);
+       kfree(skm);
+}
+
+/*
+ * Create all pre-cpu magazines of reasonable sizes.
+ */
+static int
+spl_magazine_create(spl_kmem_cache_t *skc)
+{
+       int i;
+
+       if (skc->skc_flags & KMC_NOMAGAZINE)
+               return (0);
+
+       skc->skc_mag = kzalloc(sizeof (spl_kmem_magazine_t *) *
+           num_possible_cpus(), kmem_flags_convert(KM_SLEEP));
+       skc->skc_mag_size = spl_magazine_size(skc);
+       skc->skc_mag_refill = (skc->skc_mag_size + 1) / 2;
+
+       for_each_possible_cpu(i) {
+               skc->skc_mag[i] = spl_magazine_alloc(skc, i);
+               if (!skc->skc_mag[i]) {
+                       for (i--; i >= 0; i--)
+                               spl_magazine_free(skc->skc_mag[i]);
+
+                       kfree(skc->skc_mag);
+                       return (-ENOMEM);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Destroy all pre-cpu magazines.
+ */
+static void
+spl_magazine_destroy(spl_kmem_cache_t *skc)
+{
+       spl_kmem_magazine_t *skm;
+       int i;
+
+       if (skc->skc_flags & KMC_NOMAGAZINE)
+               return;
+
+       for_each_possible_cpu(i) {
+               skm = skc->skc_mag[i];
+               spl_cache_flush(skc, skm, skm->skm_avail);
+               spl_magazine_free(skm);
+       }
+
+       kfree(skc->skc_mag);
+}
+
+/*
+ * Create a object cache based on the following arguments:
+ * name                cache name
+ * size                cache object size
+ * align       cache object alignment
+ * ctor                cache object constructor
+ * dtor                cache object destructor
+ * reclaim     cache object reclaim
+ * priv                cache private data for ctor/dtor/reclaim
+ * vmp         unused must be NULL
+ * flags
+ *     KMC_NOTOUCH     Disable cache object aging (unsupported)
+ *     KMC_NODEBUG     Disable debugging (unsupported)
+ *     KMC_NOHASH      Disable hashing (unsupported)
+ *     KMC_QCACHE      Disable qcache (unsupported)
+ *     KMC_NOMAGAZINE  Enabled for kmem/vmem, Disabled for Linux slab
+ *     KMC_KMEM        Force kmem backed cache
+ *     KMC_VMEM        Force vmem backed cache
+ *     KMC_SLAB        Force Linux slab backed cache
+ *     KMC_OFFSLAB     Locate objects off the slab
+ */
+spl_kmem_cache_t *
+spl_kmem_cache_create(char *name, size_t size, size_t align,
+    spl_kmem_ctor_t ctor, spl_kmem_dtor_t dtor, spl_kmem_reclaim_t reclaim,
+    void *priv, void *vmp, int flags)
+{
+       gfp_t lflags = kmem_flags_convert(KM_SLEEP);
+       spl_kmem_cache_t *skc;
+       int rc;
+
+       /*
+        * Unsupported flags
+        */
+       ASSERT0(flags & KMC_NOMAGAZINE);
+       ASSERT0(flags & KMC_NOHASH);
+       ASSERT0(flags & KMC_QCACHE);
+       ASSERT(vmp == NULL);
+
+       might_sleep();
+
+       skc = kzalloc(sizeof (*skc), lflags);
+       if (skc == NULL)
+               return (NULL);
+
+       skc->skc_magic = SKC_MAGIC;
+       skc->skc_name_size = strlen(name) + 1;
+       skc->skc_name = (char *)kmalloc(skc->skc_name_size, lflags);
+       if (skc->skc_name == NULL) {
+               kfree(skc);
+               return (NULL);
+       }
+       strncpy(skc->skc_name, name, skc->skc_name_size);
+
+       skc->skc_ctor = ctor;
+       skc->skc_dtor = dtor;
+       skc->skc_reclaim = reclaim;
+       skc->skc_private = priv;
+       skc->skc_vmp = vmp;
+       skc->skc_linux_cache = NULL;
+       skc->skc_flags = flags;
+       skc->skc_obj_size = size;
+       skc->skc_obj_align = SPL_KMEM_CACHE_ALIGN;
+       skc->skc_delay = SPL_KMEM_CACHE_DELAY;
+       skc->skc_reap = SPL_KMEM_CACHE_REAP;
+       atomic_set(&skc->skc_ref, 0);
+
+       INIT_LIST_HEAD(&skc->skc_list);
+       INIT_LIST_HEAD(&skc->skc_complete_list);
+       INIT_LIST_HEAD(&skc->skc_partial_list);
+       skc->skc_emergency_tree = RB_ROOT;
+       spin_lock_init(&skc->skc_lock);
+       init_waitqueue_head(&skc->skc_waitq);
+       skc->skc_slab_fail = 0;
+       skc->skc_slab_create = 0;
+       skc->skc_slab_destroy = 0;
+       skc->skc_slab_total = 0;
+       skc->skc_slab_alloc = 0;
+       skc->skc_slab_max = 0;
+       skc->skc_obj_total = 0;
+       skc->skc_obj_alloc = 0;
+       skc->skc_obj_max = 0;
+       skc->skc_obj_deadlock = 0;
+       skc->skc_obj_emergency = 0;
+       skc->skc_obj_emergency_max = 0;
+
+       /*
+        * Verify the requested alignment restriction is sane.
+        */
+       if (align) {
+               VERIFY(ISP2(align));
+               VERIFY3U(align, >=, SPL_KMEM_CACHE_ALIGN);
+               VERIFY3U(align, <=, PAGE_SIZE);
+               skc->skc_obj_align = align;
+       }
+
+       /*
+        * When no specific type of slab is requested (kmem, vmem, or
+        * linuxslab) then select a cache type based on the object size
+        * and default tunables.
+        */
+       if (!(skc->skc_flags & (KMC_KMEM | KMC_VMEM | KMC_SLAB))) {
+
+               /*
+                * Objects smaller than spl_kmem_cache_slab_limit can
+                * use the Linux slab for better space-efficiency.  By
+                * default this functionality is disabled until its
+                * performance characteristics are fully understood.
+                */
+               if (spl_kmem_cache_slab_limit &&
+                   size <= (size_t)spl_kmem_cache_slab_limit)
+                       skc->skc_flags |= KMC_SLAB;
+
+               /*
+                * Small objects, less than spl_kmem_cache_kmem_limit per
+                * object should use kmem because their slabs are small.
+                */
+               else if (spl_obj_size(skc) <= spl_kmem_cache_kmem_limit)
+                       skc->skc_flags |= KMC_KMEM;
+
+               /*
+                * All other objects are considered large and are placed
+                * on vmem backed slabs.
+                */
+               else
+                       skc->skc_flags |= KMC_VMEM;
+       }
+
+       /*
+        * Given the type of slab allocate the required resources.
+        */
+       if (skc->skc_flags & (KMC_KMEM | KMC_VMEM)) {
+               rc = spl_slab_size(skc,
+                   &skc->skc_slab_objs, &skc->skc_slab_size);
+               if (rc)
+                       goto out;
+
+               rc = spl_magazine_create(skc);
+               if (rc)
+                       goto out;
+       } else {
+               unsigned long slabflags = 0;
+
+               if (size > (SPL_MAX_KMEM_ORDER_NR_PAGES * PAGE_SIZE)) {
+                       rc = EINVAL;
+                       goto out;
+               }
+
+#if defined(SLAB_USERCOPY)
+               /*
+                * Required for PAX-enabled kernels if the slab is to be
+                * used for coping between user and kernel space.
+                */
+               slabflags |= SLAB_USERCOPY;
+#endif
+
+               skc->skc_linux_cache = kmem_cache_create(
+                   skc->skc_name, size, align, slabflags, NULL);
+               if (skc->skc_linux_cache == NULL) {
+                       rc = ENOMEM;
+                       goto out;
+               }
+
+#if defined(HAVE_KMEM_CACHE_ALLOCFLAGS)
+               skc->skc_linux_cache->allocflags |= __GFP_COMP;
+#elif defined(HAVE_KMEM_CACHE_GFPFLAGS)
+               skc->skc_linux_cache->gfpflags |= __GFP_COMP;
+#endif
+               skc->skc_flags |= KMC_NOMAGAZINE;
+       }
+
+       if (spl_kmem_cache_expire & KMC_EXPIRE_AGE)
+               skc->skc_taskqid = taskq_dispatch_delay(spl_kmem_cache_taskq,
+                   spl_cache_age, skc, TQ_SLEEP,
+                   ddi_get_lbolt() + skc->skc_delay / 3 * HZ);
+
+       down_write(&spl_kmem_cache_sem);
+       list_add_tail(&skc->skc_list, &spl_kmem_cache_list);
+       up_write(&spl_kmem_cache_sem);
+
+       return (skc);
+out:
+       kfree(skc->skc_name);
+       kfree(skc);
+       return (NULL);
+}
+EXPORT_SYMBOL(spl_kmem_cache_create);
+
+/*
+ * Register a move callback for cache defragmentation.
+ * XXX: Unimplemented but harmless to stub out for now.
+ */
+void
+spl_kmem_cache_set_move(spl_kmem_cache_t *skc,
+    kmem_cbrc_t (move)(void *, void *, size_t, void *))
+{
+       ASSERT(move != NULL);
+}
+EXPORT_SYMBOL(spl_kmem_cache_set_move);
+
+/*
+ * Destroy a cache and all objects associated with the cache.
+ */
+void
+spl_kmem_cache_destroy(spl_kmem_cache_t *skc)
+{
+       DECLARE_WAIT_QUEUE_HEAD(wq);
+       taskqid_t id;
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(skc->skc_flags & (KMC_KMEM | KMC_VMEM | KMC_SLAB));
+
+       down_write(&spl_kmem_cache_sem);
+       list_del_init(&skc->skc_list);
+       up_write(&spl_kmem_cache_sem);
+
+       /* Cancel any and wait for any pending delayed tasks */
+       VERIFY(!test_and_set_bit(KMC_BIT_DESTROY, &skc->skc_flags));
+
+       spin_lock(&skc->skc_lock);
+       id = skc->skc_taskqid;
+       spin_unlock(&skc->skc_lock);
+
+       taskq_cancel_id(spl_kmem_cache_taskq, id);
+
+       /*
+        * Wait until all current callers complete, this is mainly
+        * to catch the case where a low memory situation triggers a
+        * cache reaping action which races with this destroy.
+        */
+       wait_event(wq, atomic_read(&skc->skc_ref) == 0);
+
+       if (skc->skc_flags & (KMC_KMEM | KMC_VMEM)) {
+               spl_magazine_destroy(skc);
+               spl_slab_reclaim(skc);
+       } else {
+               ASSERT(skc->skc_flags & KMC_SLAB);
+               kmem_cache_destroy(skc->skc_linux_cache);
+       }
+
+       spin_lock(&skc->skc_lock);
+
+       /*
+        * Validate there are no objects in use and free all the
+        * spl_kmem_slab_t, spl_kmem_obj_t, and object buffers.
+        */
+       ASSERT3U(skc->skc_slab_alloc, ==, 0);
+       ASSERT3U(skc->skc_obj_alloc, ==, 0);
+       ASSERT3U(skc->skc_slab_total, ==, 0);
+       ASSERT3U(skc->skc_obj_total, ==, 0);
+       ASSERT3U(skc->skc_obj_emergency, ==, 0);
+       ASSERT(list_empty(&skc->skc_complete_list));
+
+       spin_unlock(&skc->skc_lock);
+
+       kfree(skc->skc_name);
+       kfree(skc);
+}
+EXPORT_SYMBOL(spl_kmem_cache_destroy);
+
+/*
+ * Allocate an object from a slab attached to the cache.  This is used to
+ * repopulate the per-cpu magazine caches in batches when they run low.
+ */
+static void *
+spl_cache_obj(spl_kmem_cache_t *skc, spl_kmem_slab_t *sks)
+{
+       spl_kmem_obj_t *sko;
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(sks->sks_magic == SKS_MAGIC);
+       ASSERT(spin_is_locked(&skc->skc_lock));
+
+       sko = list_entry(sks->sks_free_list.next, spl_kmem_obj_t, sko_list);
+       ASSERT(sko->sko_magic == SKO_MAGIC);
+       ASSERT(sko->sko_addr != NULL);
+
+       /* Remove from sks_free_list */
+       list_del_init(&sko->sko_list);
+
+       sks->sks_age = jiffies;
+       sks->sks_ref++;
+       skc->skc_obj_alloc++;
+
+       /* Track max obj usage statistics */
+       if (skc->skc_obj_alloc > skc->skc_obj_max)
+               skc->skc_obj_max = skc->skc_obj_alloc;
+
+       /* Track max slab usage statistics */
+       if (sks->sks_ref == 1) {
+               skc->skc_slab_alloc++;
+
+               if (skc->skc_slab_alloc > skc->skc_slab_max)
+                       skc->skc_slab_max = skc->skc_slab_alloc;
+       }
+
+       return (sko->sko_addr);
+}
+
+/*
+ * Generic slab allocation function to run by the global work queues.
+ * It is responsible for allocating a new slab, linking it in to the list
+ * of partial slabs, and then waking any waiters.
+ */
+static void
+spl_cache_grow_work(void *data)
+{
+       spl_kmem_alloc_t *ska = (spl_kmem_alloc_t *)data;
+       spl_kmem_cache_t *skc = ska->ska_cache;
+       spl_kmem_slab_t *sks;
+
+       fstrans_cookie_t cookie = spl_fstrans_mark();
+       sks = spl_slab_alloc(skc, ska->ska_flags);
+       spl_fstrans_unmark(cookie);
+
+       spin_lock(&skc->skc_lock);
+       if (sks) {
+               skc->skc_slab_total++;
+               skc->skc_obj_total += sks->sks_objs;
+               list_add_tail(&sks->sks_list, &skc->skc_partial_list);
+       }
+
+       atomic_dec(&skc->skc_ref);
+       smp_mb__before_atomic();
+       clear_bit(KMC_BIT_GROWING, &skc->skc_flags);
+       clear_bit(KMC_BIT_DEADLOCKED, &skc->skc_flags);
+       smp_mb__after_atomic();
+       wake_up_all(&skc->skc_waitq);
+       spin_unlock(&skc->skc_lock);
+
+       kfree(ska);
+}
+
+/*
+ * Returns non-zero when a new slab should be available.
+ */
+static int
+spl_cache_grow_wait(spl_kmem_cache_t *skc)
+{
+       return (!test_bit(KMC_BIT_GROWING, &skc->skc_flags));
+}
+
+/*
+ * No available objects on any slabs, create a new slab.  Note that this
+ * functionality is disabled for KMC_SLAB caches which are backed by the
+ * Linux slab.
+ */
+static int
+spl_cache_grow(spl_kmem_cache_t *skc, int flags, void **obj)
+{
+       int remaining, rc = 0;
+
+       ASSERT0(flags & ~KM_PUBLIC_MASK);
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT((skc->skc_flags & KMC_SLAB) == 0);
+       might_sleep();
+       *obj = NULL;
+
+       /*
+        * Before allocating a new slab wait for any reaping to complete and
+        * then return so the local magazine can be rechecked for new objects.
+        */
+       if (test_bit(KMC_BIT_REAPING, &skc->skc_flags)) {
+               rc = spl_wait_on_bit(&skc->skc_flags, KMC_BIT_REAPING,
+                   TASK_UNINTERRUPTIBLE);
+               return (rc ? rc : -EAGAIN);
+       }
+
+       /*
+        * This is handled by dispatching a work request to the global work
+        * queue.  This allows us to asynchronously allocate a new slab while
+        * retaining the ability to safely fall back to a smaller synchronous
+        * allocations to ensure forward progress is always maintained.
+        */
+       if (test_and_set_bit(KMC_BIT_GROWING, &skc->skc_flags) == 0) {
+               spl_kmem_alloc_t *ska;
+
+               ska = kmalloc(sizeof (*ska), kmem_flags_convert(flags));
+               if (ska == NULL) {
+                       clear_bit_unlock(KMC_BIT_GROWING, &skc->skc_flags);
+                       smp_mb__after_atomic();
+                       wake_up_all(&skc->skc_waitq);
+                       return (-ENOMEM);
+               }
+
+               atomic_inc(&skc->skc_ref);
+               ska->ska_cache = skc;
+               ska->ska_flags = flags;
+               taskq_init_ent(&ska->ska_tqe);
+               taskq_dispatch_ent(spl_kmem_cache_taskq,
+                   spl_cache_grow_work, ska, 0, &ska->ska_tqe);
+       }
+
+       /*
+        * The goal here is to only detect the rare case where a virtual slab
+        * allocation has deadlocked.  We must be careful to minimize the use
+        * of emergency objects which are more expensive to track.  Therefore,
+        * we set a very long timeout for the asynchronous allocation and if
+        * the timeout is reached the cache is flagged as deadlocked.  From
+        * this point only new emergency objects will be allocated until the
+        * asynchronous allocation completes and clears the deadlocked flag.
+        */
+       if (test_bit(KMC_BIT_DEADLOCKED, &skc->skc_flags)) {
+               rc = spl_emergency_alloc(skc, flags, obj);
+       } else {
+               remaining = wait_event_timeout(skc->skc_waitq,
+                   spl_cache_grow_wait(skc), HZ / 10);
+
+               if (!remaining) {
+                       spin_lock(&skc->skc_lock);
+                       if (test_bit(KMC_BIT_GROWING, &skc->skc_flags)) {
+                               set_bit(KMC_BIT_DEADLOCKED, &skc->skc_flags);
+                               skc->skc_obj_deadlock++;
+                       }
+                       spin_unlock(&skc->skc_lock);
+               }
+
+               rc = -ENOMEM;
+       }
+
+       return (rc);
+}
+
+/*
+ * Refill a per-cpu magazine with objects from the slabs for this cache.
+ * Ideally the magazine can be repopulated using existing objects which have
+ * been released, however if we are unable to locate enough free objects new
+ * slabs of objects will be created.  On success NULL is returned, otherwise
+ * the address of a single emergency object is returned for use by the caller.
+ */
+static void *
+spl_cache_refill(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flags)
+{
+       spl_kmem_slab_t *sks;
+       int count = 0, rc, refill;
+       void *obj = NULL;
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(skm->skm_magic == SKM_MAGIC);
+
+       refill = MIN(skm->skm_refill, skm->skm_size - skm->skm_avail);
+       spin_lock(&skc->skc_lock);
+
+       while (refill > 0) {
+               /* No slabs available we may need to grow the cache */
+               if (list_empty(&skc->skc_partial_list)) {
+                       spin_unlock(&skc->skc_lock);
+
+                       local_irq_enable();
+                       rc = spl_cache_grow(skc, flags, &obj);
+                       local_irq_disable();
+
+                       /* Emergency object for immediate use by caller */
+                       if (rc == 0 && obj != NULL)
+                               return (obj);
+
+                       if (rc)
+                               goto out;
+
+                       /* Rescheduled to different CPU skm is not local */
+                       if (skm != skc->skc_mag[smp_processor_id()])
+                               goto out;
+
+                       /*
+                        * Potentially rescheduled to the same CPU but
+                        * allocations may have occurred from this CPU while
+                        * we were sleeping so recalculate max refill.
+                        */
+                       refill = MIN(refill, skm->skm_size - skm->skm_avail);
+
+                       spin_lock(&skc->skc_lock);
+                       continue;
+               }
+
+               /* Grab the next available slab */
+               sks = list_entry((&skc->skc_partial_list)->next,
+                   spl_kmem_slab_t, sks_list);
+               ASSERT(sks->sks_magic == SKS_MAGIC);
+               ASSERT(sks->sks_ref < sks->sks_objs);
+               ASSERT(!list_empty(&sks->sks_free_list));
+
+               /*
+                * Consume as many objects as needed to refill the requested
+                * cache.  We must also be careful not to overfill it.
+                */
+               while (sks->sks_ref < sks->sks_objs && refill-- > 0 &&
+                   ++count) {
+                       ASSERT(skm->skm_avail < skm->skm_size);
+                       ASSERT(count < skm->skm_size);
+                       skm->skm_objs[skm->skm_avail++] =
+                           spl_cache_obj(skc, sks);
+               }
+
+               /* Move slab to skc_complete_list when full */
+               if (sks->sks_ref == sks->sks_objs) {
+                       list_del(&sks->sks_list);
+                       list_add(&sks->sks_list, &skc->skc_complete_list);
+               }
+       }
+
+       spin_unlock(&skc->skc_lock);
+out:
+       return (NULL);
+}
+
+/*
+ * Release an object back to the slab from which it came.
+ */
+static void
+spl_cache_shrink(spl_kmem_cache_t *skc, void *obj)
+{
+       spl_kmem_slab_t *sks = NULL;
+       spl_kmem_obj_t *sko = NULL;
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(spin_is_locked(&skc->skc_lock));
+
+       sko = spl_sko_from_obj(skc, obj);
+       ASSERT(sko->sko_magic == SKO_MAGIC);
+       sks = sko->sko_slab;
+       ASSERT(sks->sks_magic == SKS_MAGIC);
+       ASSERT(sks->sks_cache == skc);
+       list_add(&sko->sko_list, &sks->sks_free_list);
+
+       sks->sks_age = jiffies;
+       sks->sks_ref--;
+       skc->skc_obj_alloc--;
+
+       /*
+        * Move slab to skc_partial_list when no longer full.  Slabs
+        * are added to the head to keep the partial list is quasi-full
+        * sorted order.  Fuller at the head, emptier at the tail.
+        */
+       if (sks->sks_ref == (sks->sks_objs - 1)) {
+               list_del(&sks->sks_list);
+               list_add(&sks->sks_list, &skc->skc_partial_list);
+       }
+
+       /*
+        * Move empty slabs to the end of the partial list so
+        * they can be easily found and freed during reclamation.
+        */
+       if (sks->sks_ref == 0) {
+               list_del(&sks->sks_list);
+               list_add_tail(&sks->sks_list, &skc->skc_partial_list);
+               skc->skc_slab_alloc--;
+       }
+}
+
+/*
+ * Allocate an object from the per-cpu magazine, or if the magazine
+ * is empty directly allocate from a slab and repopulate the magazine.
+ */
+void *
+spl_kmem_cache_alloc(spl_kmem_cache_t *skc, int flags)
+{
+       spl_kmem_magazine_t *skm;
+       void *obj = NULL;
+
+       ASSERT0(flags & ~KM_PUBLIC_MASK);
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(!test_bit(KMC_BIT_DESTROY, &skc->skc_flags));
+
+       /*
+        * Allocate directly from a Linux slab.  All optimizations are left
+        * to the underlying cache we only need to guarantee that KM_SLEEP
+        * callers will never fail.
+        */
+       if (skc->skc_flags & KMC_SLAB) {
+               struct kmem_cache *slc = skc->skc_linux_cache;
+               do {
+                       obj = kmem_cache_alloc(slc, kmem_flags_convert(flags));
+               } while ((obj == NULL) && !(flags & KM_NOSLEEP));
+
+               goto ret;
+       }
+
+       local_irq_disable();
+
+restart:
+       /*
+        * Safe to update per-cpu structure without lock, but
+        * in the restart case we must be careful to reacquire
+        * the local magazine since this may have changed
+        * when we need to grow the cache.
+        */
+       skm = skc->skc_mag[smp_processor_id()];
+       ASSERT(skm->skm_magic == SKM_MAGIC);
+
+       if (likely(skm->skm_avail)) {
+               /* Object available in CPU cache, use it */
+               obj = skm->skm_objs[--skm->skm_avail];
+               skm->skm_age = jiffies;
+       } else {
+               obj = spl_cache_refill(skc, skm, flags);
+               if ((obj == NULL) && !(flags & KM_NOSLEEP))
+                       goto restart;
+
+               local_irq_enable();
+               goto ret;
+       }
+
+       local_irq_enable();
+       ASSERT(obj);
+       ASSERT(IS_P2ALIGNED(obj, skc->skc_obj_align));
+
+ret:
+       /* Pre-emptively migrate object to CPU L1 cache */
+       if (obj) {
+               if (obj && skc->skc_ctor)
+                       skc->skc_ctor(obj, skc->skc_private, flags);
+               else
+                       prefetchw(obj);
+       }
+
+       return (obj);
+}
+EXPORT_SYMBOL(spl_kmem_cache_alloc);
+
+/*
+ * Free an object back to the local per-cpu magazine, there is no
+ * guarantee that this is the same magazine the object was originally
+ * allocated from.  We may need to flush entire from the magazine
+ * back to the slabs to make space.
+ */
+void
+spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj)
+{
+       spl_kmem_magazine_t *skm;
+       unsigned long flags;
+       int do_reclaim = 0;
+       int do_emergency = 0;
+
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(!test_bit(KMC_BIT_DESTROY, &skc->skc_flags));
+
+       /*
+        * Run the destructor
+        */
+       if (skc->skc_dtor)
+               skc->skc_dtor(obj, skc->skc_private);
+
+       /*
+        * Free the object from the Linux underlying Linux slab.
+        */
+       if (skc->skc_flags & KMC_SLAB) {
+               kmem_cache_free(skc->skc_linux_cache, obj);
+               return;
+       }
+
+       /*
+        * While a cache has outstanding emergency objects all freed objects
+        * must be checked.  However, since emergency objects will never use
+        * a virtual address these objects can be safely excluded as an
+        * optimization.
+        */
+       if (!is_vmalloc_addr(obj)) {
+               spin_lock(&skc->skc_lock);
+               do_emergency = (skc->skc_obj_emergency > 0);
+               spin_unlock(&skc->skc_lock);
+
+               if (do_emergency && (spl_emergency_free(skc, obj) == 0))
+                       return;
+       }
+
+       local_irq_save(flags);
+
+       /*
+        * Safe to update per-cpu structure without lock, but
+        * no remote memory allocation tracking is being performed
+        * it is entirely possible to allocate an object from one
+        * CPU cache and return it to another.
+        */
+       skm = skc->skc_mag[smp_processor_id()];
+       ASSERT(skm->skm_magic == SKM_MAGIC);
+
+       /*
+        * Per-CPU cache full, flush it to make space for this object,
+        * this may result in an empty slab which can be reclaimed once
+        * interrupts are re-enabled.
+        */
+       if (unlikely(skm->skm_avail >= skm->skm_size)) {
+               spl_cache_flush(skc, skm, skm->skm_refill);
+               do_reclaim = 1;
+       }
+
+       /* Available space in cache, use it */
+       skm->skm_objs[skm->skm_avail++] = obj;
+
+       local_irq_restore(flags);
+
+       if (do_reclaim)
+               spl_slab_reclaim(skc);
+}
+EXPORT_SYMBOL(spl_kmem_cache_free);
+
+/*
+ * The generic shrinker function for all caches.  Under Linux a shrinker
+ * may not be tightly coupled with a slab cache.  In fact Linux always
+ * systematically tries calling all registered shrinker callbacks which
+ * report that they contain unused objects.  Because of this we only
+ * register one shrinker function in the shim layer for all slab caches.
+ * We always attempt to shrink all caches when this generic shrinker
+ * is called.
+ *
+ * If sc->nr_to_scan is zero, the caller is requesting a query of the
+ * number of objects which can potentially be freed.  If it is nonzero,
+ * the request is to free that many objects.
+ *
+ * Linux kernels >= 3.12 have the count_objects and scan_objects callbacks
+ * in struct shrinker and also require the shrinker to return the number
+ * of objects freed.
+ *
+ * Older kernels require the shrinker to return the number of freeable
+ * objects following the freeing of nr_to_free.
+ *
+ * Linux semantics differ from those under Solaris, which are to
+ * free all available objects which may (and probably will) be more
+ * objects than the requested nr_to_scan.
+ */
+static spl_shrinker_t
+__spl_kmem_cache_generic_shrinker(struct shrinker *shrink,
+    struct shrink_control *sc)
+{
+       spl_kmem_cache_t *skc;
+       int alloc = 0;
+
+       /*
+        * No shrinking in a transaction context.  Can cause deadlocks.
+        */
+       if (sc->nr_to_scan && spl_fstrans_check())
+               return (SHRINK_STOP);
+
+       down_read(&spl_kmem_cache_sem);
+       list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
+               if (sc->nr_to_scan) {
+#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
+                       uint64_t oldalloc = skc->skc_obj_alloc;
+                       spl_kmem_cache_reap_now(skc,
+                           MAX(sc->nr_to_scan>>fls64(skc->skc_slab_objs), 1));
+                       if (oldalloc > skc->skc_obj_alloc)
+                               alloc += oldalloc - skc->skc_obj_alloc;
+#else
+                       spl_kmem_cache_reap_now(skc,
+                           MAX(sc->nr_to_scan>>fls64(skc->skc_slab_objs), 1));
+                       alloc += skc->skc_obj_alloc;
+#endif /* HAVE_SPLIT_SHRINKER_CALLBACK */
+               } else {
+                       /* Request to query number of freeable objects */
+                       alloc += skc->skc_obj_alloc;
+               }
+       }
+       up_read(&spl_kmem_cache_sem);
+
+       /*
+        * When KMC_RECLAIM_ONCE is set allow only a single reclaim pass.
+        * This functionality only exists to work around a rare issue where
+        * shrink_slabs() is repeatedly invoked by many cores causing the
+        * system to thrash.
+        */
+       if ((spl_kmem_cache_reclaim & KMC_RECLAIM_ONCE) && sc->nr_to_scan)
+               return (SHRINK_STOP);
+
+       return (MAX(alloc, 0));
+}
+
+SPL_SHRINKER_CALLBACK_WRAPPER(spl_kmem_cache_generic_shrinker);
+
+/*
+ * Call the registered reclaim function for a cache.  Depending on how
+ * many and which objects are released it may simply repopulate the
+ * local magazine which will then need to age-out.  Objects which cannot
+ * fit in the magazine we will be released back to their slabs which will
+ * also need to age out before being release.  This is all just best
+ * effort and we do not want to thrash creating and destroying slabs.
+ */
+void
+spl_kmem_cache_reap_now(spl_kmem_cache_t *skc, int count)
+{
+       ASSERT(skc->skc_magic == SKC_MAGIC);
+       ASSERT(!test_bit(KMC_BIT_DESTROY, &skc->skc_flags));
+
+       atomic_inc(&skc->skc_ref);
+
+       /*
+        * Execute the registered reclaim callback if it exists.
+        */
+       if (skc->skc_flags & KMC_SLAB) {
+               if (skc->skc_reclaim)
+                       skc->skc_reclaim(skc->skc_private);
+               goto out;
+       }
+
+       /*
+        * Prevent concurrent cache reaping when contended.
+        */
+       if (test_and_set_bit(KMC_BIT_REAPING, &skc->skc_flags))
+               goto out;
+
+       /*
+        * When a reclaim function is available it may be invoked repeatedly
+        * until at least a single slab can be freed.  This ensures that we
+        * do free memory back to the system.  This helps minimize the chance
+        * of an OOM event when the bulk of memory is used by the slab.
+        *
+        * When free slabs are already available the reclaim callback will be
+        * skipped.  Additionally, if no forward progress is detected despite
+        * a reclaim function the cache will be skipped to avoid deadlock.
+        *
+        * Longer term this would be the correct place to add the code which
+        * repacks the slabs in order minimize fragmentation.
+        */
+       if (skc->skc_reclaim) {
+               uint64_t objects = UINT64_MAX;
+               int do_reclaim;
+
+               do {
+                       spin_lock(&skc->skc_lock);
+                       do_reclaim =
+                           (skc->skc_slab_total > 0) &&
+                           ((skc->skc_slab_total-skc->skc_slab_alloc) == 0) &&
+                           (skc->skc_obj_alloc < objects);
+
+                       objects = skc->skc_obj_alloc;
+                       spin_unlock(&skc->skc_lock);
+
+                       if (do_reclaim)
+                               skc->skc_reclaim(skc->skc_private);
+
+               } while (do_reclaim);
+       }
+
+       /* Reclaim from the magazine and free all now empty slabs. */
+       if (spl_kmem_cache_expire & KMC_EXPIRE_MEM) {
+               spl_kmem_magazine_t *skm;
+               unsigned long irq_flags;
+
+               local_irq_save(irq_flags);
+               skm = skc->skc_mag[smp_processor_id()];
+               spl_cache_flush(skc, skm, skm->skm_avail);
+               local_irq_restore(irq_flags);
+       }
+
+       spl_slab_reclaim(skc);
+       clear_bit_unlock(KMC_BIT_REAPING, &skc->skc_flags);
+       smp_mb__after_atomic();
+       wake_up_bit(&skc->skc_flags, KMC_BIT_REAPING);
+out:
+       atomic_dec(&skc->skc_ref);
+}
+EXPORT_SYMBOL(spl_kmem_cache_reap_now);
+
+/*
+ * Reap all free slabs from all registered caches.
+ */
+void
+spl_kmem_reap(void)
+{
+       struct shrink_control sc;
+
+       sc.nr_to_scan = KMC_REAP_CHUNK;
+       sc.gfp_mask = GFP_KERNEL;
+
+       (void) __spl_kmem_cache_generic_shrinker(NULL, &sc);
+}
+EXPORT_SYMBOL(spl_kmem_reap);
+
+int
+spl_kmem_cache_init(void)
+{
+       init_rwsem(&spl_kmem_cache_sem);
+       INIT_LIST_HEAD(&spl_kmem_cache_list);
+       spl_kmem_cache_taskq = taskq_create("spl_kmem_cache",
+           spl_kmem_cache_kmem_threads, maxclsyspri,
+           spl_kmem_cache_kmem_threads * 8, INT_MAX,
+           TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
+       spl_register_shrinker(&spl_kmem_cache_shrinker);
+
+       return (0);
+}
+
+void
+spl_kmem_cache_fini(void)
+{
+       spl_unregister_shrinker(&spl_kmem_cache_shrinker);
+       taskq_destroy(spl_kmem_cache_taskq);
+}
diff --git a/spl/module/spl/spl-kmem.c b/spl/module/spl/spl-kmem.c
new file mode 100755 (executable)
index 0000000..2b68c29
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/debug.h>
+#include <sys/sysmacros.h>
+#include <sys/kmem.h>
+#include <sys/vmem.h>
+#include <linux/mm.h>
+#include <linux/ratelimit.h>
+
+/*
+ * As a general rule kmem_alloc() allocations should be small, preferably
+ * just a few pages since they must by physically contiguous.  Therefore, a
+ * rate limited warning will be printed to the console for any kmem_alloc()
+ * which exceeds a reasonable threshold.
+ *
+ * The default warning threshold is set to eight pages but capped at 32K to
+ * accommodate systems using large pages.  This value was selected to be small
+ * enough to ensure the largest allocations are quickly noticed and fixed.
+ * But large enough to avoid logging any warnings when a allocation size is
+ * larger than optimal but not a serious concern.  Since this value is tunable,
+ * developers are encouraged to set it lower when testing so any new largish
+ * allocations are quickly caught.  These warnings may be disabled by setting
+ * the threshold to zero.
+ */
+unsigned int spl_kmem_alloc_warn = MAX(8 * PAGE_SIZE, 32 * 1024);
+module_param(spl_kmem_alloc_warn, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_alloc_warn,
+       "Warning threshold in bytes for a kmem_alloc()");
+EXPORT_SYMBOL(spl_kmem_alloc_warn);
+
+/*
+ * Large kmem_alloc() allocations will fail if they exceed KMALLOC_MAX_SIZE.
+ * Allocations which are marginally smaller than this limit may succeed but
+ * should still be avoided due to the expense of locating a contiguous range
+ * of free pages.  Therefore, a maximum kmem size with reasonable safely
+ * margin of 4x is set.  Kmem_alloc() allocations larger than this maximum
+ * will quickly fail.  Vmem_alloc() allocations less than or equal to this
+ * value will use kmalloc(), but shift to vmalloc() when exceeding this value.
+ */
+unsigned int spl_kmem_alloc_max = (KMALLOC_MAX_SIZE >> 2);
+module_param(spl_kmem_alloc_max, uint, 0644);
+MODULE_PARM_DESC(spl_kmem_alloc_max,
+       "Maximum size in bytes for a kmem_alloc()");
+EXPORT_SYMBOL(spl_kmem_alloc_max);
+
+int
+kmem_debugging(void)
+{
+       return (0);
+}
+EXPORT_SYMBOL(kmem_debugging);
+
+char *
+kmem_vasprintf(const char *fmt, va_list ap)
+{
+       va_list aq;
+       char *ptr;
+
+       do {
+               va_copy(aq, ap);
+               ptr = kvasprintf(kmem_flags_convert(KM_SLEEP), fmt, aq);
+               va_end(aq);
+       } while (ptr == NULL);
+
+       return (ptr);
+}
+EXPORT_SYMBOL(kmem_vasprintf);
+
+char *
+kmem_asprintf(const char *fmt, ...)
+{
+       va_list ap;
+       char *ptr;
+
+       do {
+               va_start(ap, fmt);
+               ptr = kvasprintf(kmem_flags_convert(KM_SLEEP), fmt, ap);
+               va_end(ap);
+       } while (ptr == NULL);
+
+       return (ptr);
+}
+EXPORT_SYMBOL(kmem_asprintf);
+
+static char *
+__strdup(const char *str, int flags)
+{
+       char *ptr;
+       int n;
+
+       n = strlen(str);
+       ptr = kmalloc(n + 1, kmem_flags_convert(flags));
+       if (ptr)
+               memcpy(ptr, str, n + 1);
+
+       return (ptr);
+}
+
+char *
+strdup(const char *str)
+{
+       return (__strdup(str, KM_SLEEP));
+}
+EXPORT_SYMBOL(strdup);
+
+void
+strfree(char *str)
+{
+       kfree(str);
+}
+EXPORT_SYMBOL(strfree);
+
+/*
+ * Limit the number of large allocation stack traces dumped to not more than
+ * 5 every 60 seconds to prevent denial-of-service attacks from debug code.
+ */
+DEFINE_RATELIMIT_STATE(kmem_alloc_ratelimit_state, 60 * HZ, 5);
+
+/*
+ * General purpose unified implementation of kmem_alloc(). It is an
+ * amalgamation of Linux and Illumos allocator design. It should never be
+ * exported to ensure that code using kmem_alloc()/kmem_zalloc() remains
+ * relatively portable.  Consumers may only access this function through
+ * wrappers that enforce the common flags to ensure portability.
+ */
+inline void *
+spl_kmem_alloc_impl(size_t size, int flags, int node)
+{
+       gfp_t lflags = kmem_flags_convert(flags);
+       int use_vmem = 0;
+       void *ptr;
+
+       /*
+        * Log abnormally large allocations and rate limit the console output.
+        * Allocations larger than spl_kmem_alloc_warn should be performed
+        * through the vmem_alloc()/vmem_zalloc() interfaces.
+        */
+       if ((spl_kmem_alloc_warn > 0) && (size > spl_kmem_alloc_warn) &&
+           !(flags & KM_VMEM) && __ratelimit(&kmem_alloc_ratelimit_state)) {
+               printk(KERN_WARNING
+                   "Large kmem_alloc(%lu, 0x%x), please file an issue at:\n"
+                   "https://github.com/zfsonlinux/zfs/issues/new\n",
+                   (unsigned long)size, flags);
+               dump_stack();
+       }
+
+       /*
+        * Use a loop because kmalloc_node() can fail when GFP_KERNEL is used
+        * unlike kmem_alloc() with KM_SLEEP on Illumos.
+        */
+       do {
+               /*
+                * Calling kmalloc_node() when the size >= spl_kmem_alloc_max
+                * is unsafe.  This must fail for all for kmem_alloc() and
+                * kmem_zalloc() callers.
+                *
+                * For vmem_alloc() and vmem_zalloc() callers it is permissible
+                * to use __vmalloc().  However, in general use of __vmalloc()
+                * is strongly discouraged because a global lock must be
+                * acquired.  Contention on this lock can significantly
+                * impact performance so frequently manipulating the virtual
+                * address space is strongly discouraged.
+                */
+               if ((size > spl_kmem_alloc_max) || use_vmem) {
+                       if (flags & KM_VMEM) {
+                               ptr = __vmalloc(size, lflags, PAGE_KERNEL);
+                       } else {
+                               return (NULL);
+                       }
+               } else {
+                       ptr = kmalloc_node(size, lflags, node);
+               }
+
+               if (likely(ptr) || (flags & KM_NOSLEEP))
+                       return (ptr);
+
+               /*
+                * For vmem_alloc() and vmem_zalloc() callers retry immediately
+                * using __vmalloc() which is unlikely to fail.
+                */
+               if ((flags & KM_VMEM) && (use_vmem == 0))  {
+                       use_vmem = 1;
+                       continue;
+               }
+
+               if (unlikely(__ratelimit(&kmem_alloc_ratelimit_state))) {
+                       printk(KERN_WARNING
+                           "Possible memory allocation deadlock: "
+                           "size=%lu lflags=0x%x",
+                           (unsigned long)size, lflags);
+                       dump_stack();
+               }
+
+               /*
+                * Use cond_resched() instead of congestion_wait() to avoid
+                * deadlocking systems where there are no block devices.
+                */
+               cond_resched();
+       } while (1);
+
+       return (NULL);
+}
+
+inline void
+spl_kmem_free_impl(const void *buf, size_t size)
+{
+       if (is_vmalloc_addr(buf))
+               vfree(buf);
+       else
+               kfree(buf);
+}
+
+/*
+ * Memory allocation and accounting for kmem_* * style allocations.  When
+ * DEBUG_KMEM is enabled the total memory allocated will be tracked and
+ * any memory leaked will be reported during module unload.
+ *
+ * ./configure --enable-debug-kmem
+ */
+#ifdef DEBUG_KMEM
+
+/* Shim layer memory accounting */
+#ifdef HAVE_ATOMIC64_T
+atomic64_t kmem_alloc_used = ATOMIC64_INIT(0);
+unsigned long long kmem_alloc_max = 0;
+#else  /* HAVE_ATOMIC64_T */
+atomic_t kmem_alloc_used = ATOMIC_INIT(0);
+unsigned long long kmem_alloc_max = 0;
+#endif /* HAVE_ATOMIC64_T */
+
+EXPORT_SYMBOL(kmem_alloc_used);
+EXPORT_SYMBOL(kmem_alloc_max);
+
+inline void *
+spl_kmem_alloc_debug(size_t size, int flags, int node)
+{
+       void *ptr;
+
+       ptr = spl_kmem_alloc_impl(size, flags, node);
+       if (ptr) {
+               kmem_alloc_used_add(size);
+               if (unlikely(kmem_alloc_used_read() > kmem_alloc_max))
+                       kmem_alloc_max = kmem_alloc_used_read();
+       }
+
+       return (ptr);
+}
+
+inline void
+spl_kmem_free_debug(const void *ptr, size_t size)
+{
+       kmem_alloc_used_sub(size);
+       spl_kmem_free_impl(ptr, size);
+}
+
+/*
+ * When DEBUG_KMEM_TRACKING is enabled not only will total bytes be tracked
+ * but also the location of every alloc and free.  When the SPL module is
+ * unloaded a list of all leaked addresses and where they were allocated
+ * will be dumped to the console.  Enabling this feature has a significant
+ * impact on performance but it makes finding memory leaks straight forward.
+ *
+ * Not surprisingly with debugging enabled the xmem_locks are very highly
+ * contended particularly on xfree().  If we want to run with this detailed
+ * debugging enabled for anything other than debugging  we need to minimize
+ * the contention by moving to a lock per xmem_table entry model.
+ *
+ * ./configure --enable-debug-kmem-tracking
+ */
+#ifdef DEBUG_KMEM_TRACKING
+
+#include <linux/hash.h>
+#include <linux/ctype.h>
+
+#define        KMEM_HASH_BITS          10
+#define        KMEM_TABLE_SIZE         (1 << KMEM_HASH_BITS)
+
+typedef struct kmem_debug {
+       struct hlist_node kd_hlist;     /* Hash node linkage */
+       struct list_head kd_list;       /* List of all allocations */
+       void *kd_addr;                  /* Allocation pointer */
+       size_t kd_size;                 /* Allocation size */
+       const char *kd_func;            /* Allocation function */
+       int kd_line;                    /* Allocation line */
+} kmem_debug_t;
+
+static spinlock_t kmem_lock;
+static struct hlist_head kmem_table[KMEM_TABLE_SIZE];
+static struct list_head kmem_list;
+
+static kmem_debug_t *
+kmem_del_init(spinlock_t *lock, struct hlist_head *table,
+    int bits, const void *addr)
+{
+       struct hlist_head *head;
+       struct hlist_node *node;
+       struct kmem_debug *p;
+       unsigned long flags;
+
+       spin_lock_irqsave(lock, flags);
+
+       head = &table[hash_ptr((void *)addr, bits)];
+       hlist_for_each(node, head) {
+               p = list_entry(node, struct kmem_debug, kd_hlist);
+               if (p->kd_addr == addr) {
+                       hlist_del_init(&p->kd_hlist);
+                       list_del_init(&p->kd_list);
+                       spin_unlock_irqrestore(lock, flags);
+                       return (p);
+               }
+       }
+
+       spin_unlock_irqrestore(lock, flags);
+
+       return (NULL);
+}
+
+inline void *
+spl_kmem_alloc_track(size_t size, int flags,
+    const char *func, int line, int node)
+{
+       void *ptr = NULL;
+       kmem_debug_t *dptr;
+       unsigned long irq_flags;
+
+       dptr = kmalloc(sizeof (kmem_debug_t), kmem_flags_convert(flags));
+       if (dptr == NULL)
+               return (NULL);
+
+       dptr->kd_func = __strdup(func, flags);
+       if (dptr->kd_func == NULL) {
+               kfree(dptr);
+               return (NULL);
+       }
+
+       ptr = spl_kmem_alloc_debug(size, flags, node);
+       if (ptr == NULL) {
+               kfree(dptr->kd_func);
+               kfree(dptr);
+               return (NULL);
+       }
+
+       INIT_HLIST_NODE(&dptr->kd_hlist);
+       INIT_LIST_HEAD(&dptr->kd_list);
+
+       dptr->kd_addr = ptr;
+       dptr->kd_size = size;
+       dptr->kd_line = line;
+
+       spin_lock_irqsave(&kmem_lock, irq_flags);
+       hlist_add_head(&dptr->kd_hlist,
+           &kmem_table[hash_ptr(ptr, KMEM_HASH_BITS)]);
+       list_add_tail(&dptr->kd_list, &kmem_list);
+       spin_unlock_irqrestore(&kmem_lock, irq_flags);
+
+       return (ptr);
+}
+
+inline void
+spl_kmem_free_track(const void *ptr, size_t size)
+{
+       kmem_debug_t *dptr;
+
+       /* Ignore NULL pointer since we haven't tracked it at all*/
+       if (ptr == NULL)
+               return;
+
+       /* Must exist in hash due to kmem_alloc() */
+       dptr = kmem_del_init(&kmem_lock, kmem_table, KMEM_HASH_BITS, ptr);
+       ASSERT3P(dptr, !=, NULL);
+       ASSERT3S(dptr->kd_size, ==, size);
+
+       kfree(dptr->kd_func);
+       kfree(dptr);
+
+       spl_kmem_free_debug(ptr, size);
+}
+#endif /* DEBUG_KMEM_TRACKING */
+#endif /* DEBUG_KMEM */
+
+/*
+ * Public kmem_alloc(), kmem_zalloc() and kmem_free() interfaces.
+ */
+void *
+spl_kmem_alloc(size_t size, int flags, const char *func, int line)
+{
+       ASSERT0(flags & ~KM_PUBLIC_MASK);
+
+#if !defined(DEBUG_KMEM)
+       return (spl_kmem_alloc_impl(size, flags, NUMA_NO_NODE));
+#elif !defined(DEBUG_KMEM_TRACKING)
+       return (spl_kmem_alloc_debug(size, flags, NUMA_NO_NODE));
+#else
+       return (spl_kmem_alloc_track(size, flags, func, line, NUMA_NO_NODE));
+#endif
+}
+EXPORT_SYMBOL(spl_kmem_alloc);
+
+void *
+spl_kmem_zalloc(size_t size, int flags, const char *func, int line)
+{
+       ASSERT0(flags & ~KM_PUBLIC_MASK);
+
+       flags |= KM_ZERO;
+
+#if !defined(DEBUG_KMEM)
+       return (spl_kmem_alloc_impl(size, flags, NUMA_NO_NODE));
+#elif !defined(DEBUG_KMEM_TRACKING)
+       return (spl_kmem_alloc_debug(size, flags, NUMA_NO_NODE));
+#else
+       return (spl_kmem_alloc_track(size, flags, func, line, NUMA_NO_NODE));
+#endif
+}
+EXPORT_SYMBOL(spl_kmem_zalloc);
+
+void
+spl_kmem_free(const void *buf, size_t size)
+{
+#if !defined(DEBUG_KMEM)
+       return (spl_kmem_free_impl(buf, size));
+#elif !defined(DEBUG_KMEM_TRACKING)
+       return (spl_kmem_free_debug(buf, size));
+#else
+       return (spl_kmem_free_track(buf, size));
+#endif
+}
+EXPORT_SYMBOL(spl_kmem_free);
+
+#if defined(DEBUG_KMEM) && defined(DEBUG_KMEM_TRACKING)
+static char *
+spl_sprintf_addr(kmem_debug_t *kd, char *str, int len, int min)
+{
+       int size = ((len - 1) < kd->kd_size) ? (len - 1) : kd->kd_size;
+       int i, flag = 1;
+
+       ASSERT(str != NULL && len >= 17);
+       memset(str, 0, len);
+
+       /*
+        * Check for a fully printable string, and while we are at
+        * it place the printable characters in the passed buffer.
+        */
+       for (i = 0; i < size; i++) {
+               str[i] = ((char *)(kd->kd_addr))[i];
+               if (isprint(str[i])) {
+                       continue;
+               } else {
+                       /*
+                        * Minimum number of printable characters found
+                        * to make it worthwhile to print this as ascii.
+                        */
+                       if (i > min)
+                               break;
+
+                       flag = 0;
+                       break;
+               }
+       }
+
+       if (!flag) {
+               sprintf(str, "%02x%02x%02x%02x%02x%02x%02x%02x",
+                   *((uint8_t *)kd->kd_addr),
+                   *((uint8_t *)kd->kd_addr + 2),
+                   *((uint8_t *)kd->kd_addr + 4),
+                   *((uint8_t *)kd->kd_addr + 6),
+                   *((uint8_t *)kd->kd_addr + 8),
+                   *((uint8_t *)kd->kd_addr + 10),
+                   *((uint8_t *)kd->kd_addr + 12),
+                   *((uint8_t *)kd->kd_addr + 14));
+       }
+
+       return (str);
+}
+
+static int
+spl_kmem_init_tracking(struct list_head *list, spinlock_t *lock, int size)
+{
+       int i;
+
+       spin_lock_init(lock);
+       INIT_LIST_HEAD(list);
+
+       for (i = 0; i < size; i++)
+               INIT_HLIST_HEAD(&kmem_table[i]);
+
+       return (0);
+}
+
+static void
+spl_kmem_fini_tracking(struct list_head *list, spinlock_t *lock)
+{
+       unsigned long flags;
+       kmem_debug_t *kd;
+       char str[17];
+
+       spin_lock_irqsave(lock, flags);
+       if (!list_empty(list))
+               printk(KERN_WARNING "%-16s %-5s %-16s %s:%s\n", "address",
+                   "size", "data", "func", "line");
+
+       list_for_each_entry(kd, list, kd_list)
+               printk(KERN_WARNING "%p %-5d %-16s %s:%d\n", kd->kd_addr,
+                   (int)kd->kd_size, spl_sprintf_addr(kd, str, 17, 8),
+                   kd->kd_func, kd->kd_line);
+
+       spin_unlock_irqrestore(lock, flags);
+}
+#endif /* DEBUG_KMEM && DEBUG_KMEM_TRACKING */
+
+int
+spl_kmem_init(void)
+{
+#ifdef DEBUG_KMEM
+       kmem_alloc_used_set(0);
+
+#ifdef DEBUG_KMEM_TRACKING
+       spl_kmem_init_tracking(&kmem_list, &kmem_lock, KMEM_TABLE_SIZE);
+#endif /* DEBUG_KMEM_TRACKING */
+#endif /* DEBUG_KMEM */
+
+       return (0);
+}
+
+void
+spl_kmem_fini(void)
+{
+#ifdef DEBUG_KMEM
+       /*
+        * Display all unreclaimed memory addresses, including the
+        * allocation size and the first few bytes of what's located
+        * at that address to aid in debugging.  Performance is not
+        * a serious concern here since it is module unload time.
+        */
+       if (kmem_alloc_used_read() != 0)
+               printk(KERN_WARNING "kmem leaked %ld/%llu bytes\n",
+                   (unsigned long)kmem_alloc_used_read(), kmem_alloc_max);
+
+#ifdef DEBUG_KMEM_TRACKING
+       spl_kmem_fini_tracking(&kmem_list, &kmem_lock);
+#endif /* DEBUG_KMEM_TRACKING */
+#endif /* DEBUG_KMEM */
+}
diff --git a/spl/module/spl/spl-kobj.c b/spl/module/spl/spl-kobj.c
new file mode 100644 (file)
index 0000000..4dd14ba
--- /dev/null
@@ -0,0 +1,81 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Kobj Implementation.
+\*****************************************************************************/
+
+#include <sys/kobj.h>
+
+struct _buf *
+kobj_open_file(const char *name)
+{
+       struct _buf *file;
+       vnode_t *vp;
+       int rc;
+
+       file = kmalloc(sizeof(_buf_t), kmem_flags_convert(KM_SLEEP));
+       if (file == NULL)
+               return ((_buf_t *)-1UL);
+
+       if ((rc = vn_open(name, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0))) {
+               kfree(file);
+               return ((_buf_t *)-1UL);
+       }
+
+       file->vp = vp;
+
+       return (file);
+} /* kobj_open_file() */
+EXPORT_SYMBOL(kobj_open_file);
+
+void
+kobj_close_file(struct _buf *file)
+{
+       VOP_CLOSE(file->vp, 0, 0, 0, 0, 0);
+        kfree(file);
+} /* kobj_close_file() */
+EXPORT_SYMBOL(kobj_close_file);
+
+int
+kobj_read_file(struct _buf *file, char *buf, ssize_t size, offset_t off)
+{
+       return (vn_rdwr(UIO_READ, file->vp, buf, size, off,
+              UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL));
+} /* kobj_read_file() */
+EXPORT_SYMBOL(kobj_read_file);
+
+int
+kobj_get_filesize(struct _buf *file, uint64_t *size)
+{
+        vattr_t vap;
+       int rc;
+
+       rc = VOP_GETATTR(file->vp, &vap, 0, 0, NULL);
+       if (rc)
+               return (rc);
+
+        *size = vap.va_size;
+
+        return (rc);
+} /* kobj_get_filesize() */
+EXPORT_SYMBOL(kobj_get_filesize);
diff --git a/spl/module/spl/spl-kstat.c b/spl/module/spl/spl-kstat.c
new file mode 100644 (file)
index 0000000..e8917a3
--- /dev/null
@@ -0,0 +1,696 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Kstat Implementation.
+\*****************************************************************************/
+
+#include <linux/seq_file.h>
+#include <sys/kstat.h>
+#include <sys/vmem.h>
+
+#ifndef HAVE_PDE_DATA
+#define PDE_DATA(x) (PDE(x)->data)
+#endif
+
+static kmutex_t kstat_module_lock;
+static struct list_head kstat_module_list;
+static kid_t kstat_id;
+
+static int
+kstat_resize_raw(kstat_t *ksp)
+{
+       if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX)
+               return ENOMEM;
+
+       vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize);
+       ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX);
+       ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP);
+
+       return 0;
+}
+
+void
+kstat_waitq_enter(kstat_io_t *kiop)
+{
+       hrtime_t new, delta;
+       ulong_t wcnt;
+
+       new = gethrtime();
+       delta = new - kiop->wlastupdate;
+       kiop->wlastupdate = new;
+       wcnt = kiop->wcnt++;
+       if (wcnt != 0) {
+               kiop->wlentime += delta * wcnt;
+               kiop->wtime += delta;
+       }
+}
+EXPORT_SYMBOL(kstat_waitq_enter);
+
+void
+kstat_waitq_exit(kstat_io_t *kiop)
+{
+       hrtime_t new, delta;
+       ulong_t wcnt;
+
+       new = gethrtime();
+       delta = new - kiop->wlastupdate;
+       kiop->wlastupdate = new;
+       wcnt = kiop->wcnt--;
+       ASSERT((int)wcnt > 0);
+       kiop->wlentime += delta * wcnt;
+       kiop->wtime += delta;
+}
+EXPORT_SYMBOL(kstat_waitq_exit);
+
+void
+kstat_runq_enter(kstat_io_t *kiop)
+{
+       hrtime_t new, delta;
+       ulong_t rcnt;
+
+       new = gethrtime();
+       delta = new - kiop->rlastupdate;
+       kiop->rlastupdate = new;
+       rcnt = kiop->rcnt++;
+       if (rcnt != 0) {
+               kiop->rlentime += delta * rcnt;
+               kiop->rtime += delta;
+       }
+}
+EXPORT_SYMBOL(kstat_runq_enter);
+
+void
+kstat_runq_exit(kstat_io_t *kiop)
+{
+       hrtime_t new, delta;
+       ulong_t rcnt;
+
+       new = gethrtime();
+       delta = new - kiop->rlastupdate;
+       kiop->rlastupdate = new;
+       rcnt = kiop->rcnt--;
+       ASSERT((int)rcnt > 0);
+       kiop->rlentime += delta * rcnt;
+       kiop->rtime += delta;
+}
+EXPORT_SYMBOL(kstat_runq_exit);
+
+static int
+kstat_seq_show_headers(struct seq_file *f)
+{
+        kstat_t *ksp = (kstat_t *)f->private;
+       int rc = 0;
+
+        ASSERT(ksp->ks_magic == KS_MAGIC);
+
+        seq_printf(f, "%d %d 0x%02x %d %d %lld %lld\n",
+                  ksp->ks_kid, ksp->ks_type, ksp->ks_flags,
+                  ksp->ks_ndata, (int)ksp->ks_data_size,
+                  ksp->ks_crtime, ksp->ks_snaptime);
+
+       switch (ksp->ks_type) {
+                case KSTAT_TYPE_RAW:
+restart:
+                        if (ksp->ks_raw_ops.headers) {
+                                rc = ksp->ks_raw_ops.headers(
+                                    ksp->ks_raw_buf, ksp->ks_raw_bufsize);
+                               if (rc == ENOMEM && !kstat_resize_raw(ksp))
+                                       goto restart;
+                               if (!rc)
+                                       seq_puts(f, ksp->ks_raw_buf);
+                        } else {
+                                seq_printf(f, "raw data\n");
+                        }
+                        break;
+                case KSTAT_TYPE_NAMED:
+                        seq_printf(f, "%-31s %-4s %s\n",
+                                   "name", "type", "data");
+                        break;
+                case KSTAT_TYPE_INTR:
+                        seq_printf(f, "%-8s %-8s %-8s %-8s %-8s\n",
+                                   "hard", "soft", "watchdog",
+                                   "spurious", "multsvc");
+                        break;
+                case KSTAT_TYPE_IO:
+                        seq_printf(f,
+                                   "%-8s %-8s %-8s %-8s %-8s %-8s "
+                                   "%-8s %-8s %-8s %-8s %-8s %-8s\n",
+                                   "nread", "nwritten", "reads", "writes",
+                                   "wtime", "wlentime", "wupdate",
+                                   "rtime", "rlentime", "rupdate",
+                                   "wcnt", "rcnt");
+                        break;
+                case KSTAT_TYPE_TIMER:
+                        seq_printf(f,
+                                   "%-31s %-8s "
+                                   "%-8s %-8s %-8s %-8s %-8s\n",
+                                   "name", "events", "elapsed",
+                                   "min", "max", "start", "stop");
+                        break;
+                default:
+                        PANIC("Undefined kstat type %d\n", ksp->ks_type);
+        }
+
+       return -rc;
+}
+
+static int
+kstat_seq_show_raw(struct seq_file *f, unsigned char *p, int l)
+{
+        int i, j;
+
+        for (i = 0; ; i++) {
+                seq_printf(f, "%03x:", i);
+
+                for (j = 0; j < 16; j++) {
+                        if (i * 16 + j >= l) {
+                                seq_printf(f, "\n");
+                                goto out;
+                        }
+
+                        seq_printf(f, " %02x", (unsigned char)p[i * 16 + j]);
+                }
+                seq_printf(f, "\n");
+        }
+out:
+        return 0;
+}
+
+static int
+kstat_seq_show_named(struct seq_file *f, kstat_named_t *knp)
+{
+        seq_printf(f, "%-31s %-4d ", knp->name, knp->data_type);
+
+        switch (knp->data_type) {
+                case KSTAT_DATA_CHAR:
+                        knp->value.c[15] = '\0'; /* NULL terminate */
+                        seq_printf(f, "%-16s", knp->value.c);
+                        break;
+                /* XXX - We need to be more careful able what tokens are
+                 * used for each arch, for now this is correct for x86_64.
+                 */
+                case KSTAT_DATA_INT32:
+                        seq_printf(f, "%d", knp->value.i32);
+                        break;
+                case KSTAT_DATA_UINT32:
+                        seq_printf(f, "%u", knp->value.ui32);
+                        break;
+                case KSTAT_DATA_INT64:
+                        seq_printf(f, "%lld", (signed long long)knp->value.i64);
+                        break;
+                case KSTAT_DATA_UINT64:
+                        seq_printf(f, "%llu", (unsigned long long)knp->value.ui64);
+                        break;
+                case KSTAT_DATA_LONG:
+                        seq_printf(f, "%ld", knp->value.l);
+                        break;
+                case KSTAT_DATA_ULONG:
+                        seq_printf(f, "%lu", knp->value.ul);
+                        break;
+                case KSTAT_DATA_STRING:
+                        KSTAT_NAMED_STR_PTR(knp)
+                                [KSTAT_NAMED_STR_BUFLEN(knp)-1] = '\0';
+                        seq_printf(f, "%s", KSTAT_NAMED_STR_PTR(knp));
+                        break;
+                default:
+                        PANIC("Undefined kstat data type %d\n", knp->data_type);
+        }
+
+        seq_printf(f, "\n");
+
+        return 0;
+}
+
+static int
+kstat_seq_show_intr(struct seq_file *f, kstat_intr_t *kip)
+{
+        seq_printf(f, "%-8u %-8u %-8u %-8u %-8u\n",
+                   kip->intrs[KSTAT_INTR_HARD],
+                   kip->intrs[KSTAT_INTR_SOFT],
+                   kip->intrs[KSTAT_INTR_WATCHDOG],
+                   kip->intrs[KSTAT_INTR_SPURIOUS],
+                   kip->intrs[KSTAT_INTR_MULTSVC]);
+
+        return 0;
+}
+
+static int
+kstat_seq_show_io(struct seq_file *f, kstat_io_t *kip)
+{
+        seq_printf(f,
+                   "%-8llu %-8llu %-8u %-8u %-8lld %-8lld "
+                   "%-8lld %-8lld %-8lld %-8lld %-8u %-8u\n",
+                   kip->nread, kip->nwritten,
+                   kip->reads, kip->writes,
+                   kip->wtime, kip->wlentime, kip->wlastupdate,
+                   kip->rtime, kip->wlentime, kip->rlastupdate,
+                   kip->wcnt,  kip->rcnt);
+
+        return 0;
+}
+
+static int
+kstat_seq_show_timer(struct seq_file *f, kstat_timer_t *ktp)
+{
+        seq_printf(f,
+                   "%-31s %-8llu %-8lld %-8lld %-8lld %-8lld %-8lld\n",
+                   ktp->name, ktp->num_events, ktp->elapsed_time,
+                   ktp->min_time, ktp->max_time,
+                   ktp->start_time, ktp->stop_time);
+
+        return 0;
+}
+
+static int
+kstat_seq_show(struct seq_file *f, void *p)
+{
+        kstat_t *ksp = (kstat_t *)f->private;
+        int rc = 0;
+
+        ASSERT(ksp->ks_magic == KS_MAGIC);
+
+       switch (ksp->ks_type) {
+                case KSTAT_TYPE_RAW:
+restart:
+                        if (ksp->ks_raw_ops.data) {
+                                rc = ksp->ks_raw_ops.data(
+                                   ksp->ks_raw_buf, ksp->ks_raw_bufsize, p);
+                               if (rc == ENOMEM && !kstat_resize_raw(ksp))
+                                       goto restart;
+                               if (!rc)
+                                       seq_puts(f, ksp->ks_raw_buf);
+                        } else {
+                                ASSERT(ksp->ks_ndata == 1);
+                                rc = kstat_seq_show_raw(f, ksp->ks_data,
+                                                        ksp->ks_data_size);
+                        }
+                        break;
+                case KSTAT_TYPE_NAMED:
+                        rc = kstat_seq_show_named(f, (kstat_named_t *)p);
+                        break;
+                case KSTAT_TYPE_INTR:
+                        rc = kstat_seq_show_intr(f, (kstat_intr_t *)p);
+                        break;
+                case KSTAT_TYPE_IO:
+                        rc = kstat_seq_show_io(f, (kstat_io_t *)p);
+                        break;
+                case KSTAT_TYPE_TIMER:
+                        rc = kstat_seq_show_timer(f, (kstat_timer_t *)p);
+                        break;
+                default:
+                        PANIC("Undefined kstat type %d\n", ksp->ks_type);
+        }
+
+        return -rc;
+}
+
+int
+kstat_default_update(kstat_t *ksp, int rw)
+{
+       ASSERT(ksp != NULL);
+
+       if (rw == KSTAT_WRITE)
+               return (EACCES);
+
+       return 0;
+}
+
+static void *
+kstat_seq_data_addr(kstat_t *ksp, loff_t n)
+{
+        void *rc = NULL;
+
+       switch (ksp->ks_type) {
+                case KSTAT_TYPE_RAW:
+                        if (ksp->ks_raw_ops.addr)
+                                rc = ksp->ks_raw_ops.addr(ksp, n);
+                        else
+                                rc = ksp->ks_data;
+                        break;
+                case KSTAT_TYPE_NAMED:
+                        rc = ksp->ks_data + n * sizeof(kstat_named_t);
+                        break;
+                case KSTAT_TYPE_INTR:
+                        rc = ksp->ks_data + n * sizeof(kstat_intr_t);
+                        break;
+                case KSTAT_TYPE_IO:
+                        rc = ksp->ks_data + n * sizeof(kstat_io_t);
+                        break;
+                case KSTAT_TYPE_TIMER:
+                        rc = ksp->ks_data + n * sizeof(kstat_timer_t);
+                        break;
+                default:
+                        PANIC("Undefined kstat type %d\n", ksp->ks_type);
+        }
+
+        return (rc);
+}
+
+static void *
+kstat_seq_start(struct seq_file *f, loff_t *pos)
+{
+        loff_t n = *pos;
+        kstat_t *ksp = (kstat_t *)f->private;
+        ASSERT(ksp->ks_magic == KS_MAGIC);
+
+       mutex_enter(ksp->ks_lock);
+
+        if (ksp->ks_type == KSTAT_TYPE_RAW) {
+                ksp->ks_raw_bufsize = PAGE_SIZE;
+                ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP);
+        }
+
+        /* Dynamically update kstat, on error existing kstats are used */
+        (void) ksp->ks_update(ksp, KSTAT_READ);
+
+       ksp->ks_snaptime = gethrtime();
+
+        if (!n && kstat_seq_show_headers(f))
+               return (NULL);
+
+        if (n >= ksp->ks_ndata)
+                return (NULL);
+
+        return (kstat_seq_data_addr(ksp, n));
+}
+
+static void *
+kstat_seq_next(struct seq_file *f, void *p, loff_t *pos)
+{
+        kstat_t *ksp = (kstat_t *)f->private;
+        ASSERT(ksp->ks_magic == KS_MAGIC);
+
+        ++*pos;
+        if (*pos >= ksp->ks_ndata)
+                return (NULL);
+
+        return (kstat_seq_data_addr(ksp, *pos));
+}
+
+static void
+kstat_seq_stop(struct seq_file *f, void *v)
+{
+       kstat_t *ksp = (kstat_t *)f->private;
+       ASSERT(ksp->ks_magic == KS_MAGIC);
+
+       if (ksp->ks_type == KSTAT_TYPE_RAW)
+               vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize);
+
+       mutex_exit(ksp->ks_lock);
+}
+
+static struct seq_operations kstat_seq_ops = {
+        .show  = kstat_seq_show,
+        .start = kstat_seq_start,
+        .next  = kstat_seq_next,
+        .stop  = kstat_seq_stop,
+};
+
+static kstat_module_t *
+kstat_find_module(char *name)
+{
+       kstat_module_t *module;
+
+       list_for_each_entry(module, &kstat_module_list, ksm_module_list)
+               if (strncmp(name, module->ksm_name, KSTAT_STRLEN) == 0)
+                       return (module);
+
+       return (NULL);
+}
+
+static kstat_module_t *
+kstat_create_module(char *name)
+{
+       kstat_module_t *module;
+       struct proc_dir_entry *pde;
+
+       pde = proc_mkdir(name, proc_spl_kstat);
+       if (pde == NULL)
+               return (NULL);
+
+       module = kmem_alloc(sizeof (kstat_module_t), KM_SLEEP);
+       module->ksm_proc = pde;
+       strlcpy(module->ksm_name, name, KSTAT_STRLEN+1);
+       INIT_LIST_HEAD(&module->ksm_kstat_list);
+       list_add_tail(&module->ksm_module_list, &kstat_module_list);
+
+       return (module);
+
+}
+
+static void
+kstat_delete_module(kstat_module_t *module)
+{
+       ASSERT(list_empty(&module->ksm_kstat_list));
+       remove_proc_entry(module->ksm_name, proc_spl_kstat);
+       list_del(&module->ksm_module_list);
+       kmem_free(module, sizeof(kstat_module_t));
+}
+
+static int
+proc_kstat_open(struct inode *inode, struct file *filp)
+{
+        struct seq_file *f;
+        int rc;
+
+        rc = seq_open(filp, &kstat_seq_ops);
+        if (rc)
+                return rc;
+
+        f = filp->private_data;
+        f->private = PDE_DATA(inode);
+
+        return rc;
+}
+
+static ssize_t
+proc_kstat_write(struct file *filp, const char __user *buf,
+                size_t len, loff_t *ppos)
+{
+       struct seq_file *f = filp->private_data;
+       kstat_t *ksp = f->private;
+       int rc;
+
+       ASSERT(ksp->ks_magic == KS_MAGIC);
+
+       mutex_enter(ksp->ks_lock);
+       rc = ksp->ks_update(ksp, KSTAT_WRITE);
+       mutex_exit(ksp->ks_lock);
+
+       if (rc)
+               return (-rc);
+
+       *ppos += len;
+       return (len);
+}
+
+static struct file_operations proc_kstat_operations = {
+       .open           = proc_kstat_open,
+       .write          = proc_kstat_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+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))
+{
+       ksp->ks_raw_ops.headers = headers;
+       ksp->ks_raw_ops.data    = data;
+       ksp->ks_raw_ops.addr    = addr;
+}
+EXPORT_SYMBOL(__kstat_set_raw_ops);
+
+kstat_t *
+__kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
+             const char *ks_class, uchar_t ks_type, uint_t ks_ndata,
+             uchar_t ks_flags)
+{
+       kstat_t *ksp;
+
+       ASSERT(ks_module);
+       ASSERT(ks_instance == 0);
+       ASSERT(ks_name);
+       ASSERT(!(ks_flags & KSTAT_FLAG_UNSUPPORTED));
+
+       if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
+                ASSERT(ks_ndata == 1);
+
+       ksp = kmem_zalloc(sizeof(*ksp), KM_SLEEP);
+       if (ksp == NULL)
+               return ksp;
+
+       mutex_enter(&kstat_module_lock);
+       ksp->ks_kid = kstat_id;
+        kstat_id++;
+       mutex_exit(&kstat_module_lock);
+
+        ksp->ks_magic = KS_MAGIC;
+       mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL);
+       ksp->ks_lock = &ksp->ks_private_lock;
+       INIT_LIST_HEAD(&ksp->ks_list);
+
+       ksp->ks_crtime = gethrtime();
+        ksp->ks_snaptime = ksp->ks_crtime;
+       strncpy(ksp->ks_module, ks_module, KSTAT_STRLEN);
+       ksp->ks_instance = ks_instance;
+       strncpy(ksp->ks_name, ks_name, KSTAT_STRLEN);
+       strncpy(ksp->ks_class, ks_class, KSTAT_STRLEN);
+       ksp->ks_type = ks_type;
+       ksp->ks_flags = ks_flags;
+       ksp->ks_update = kstat_default_update;
+       ksp->ks_private = NULL;
+       ksp->ks_raw_ops.headers = NULL;
+       ksp->ks_raw_ops.data = NULL;
+       ksp->ks_raw_ops.addr = NULL;
+       ksp->ks_raw_buf = NULL;
+       ksp->ks_raw_bufsize = 0;
+
+       switch (ksp->ks_type) {
+                case KSTAT_TYPE_RAW:
+                       ksp->ks_ndata = 1;
+                        ksp->ks_data_size = ks_ndata;
+                        break;
+                case KSTAT_TYPE_NAMED:
+                       ksp->ks_ndata = ks_ndata;
+                        ksp->ks_data_size = ks_ndata * sizeof(kstat_named_t);
+                        break;
+                case KSTAT_TYPE_INTR:
+                       ksp->ks_ndata = ks_ndata;
+                        ksp->ks_data_size = ks_ndata * sizeof(kstat_intr_t);
+                        break;
+                case KSTAT_TYPE_IO:
+                       ksp->ks_ndata = ks_ndata;
+                        ksp->ks_data_size = ks_ndata * sizeof(kstat_io_t);
+                        break;
+                case KSTAT_TYPE_TIMER:
+                       ksp->ks_ndata = ks_ndata;
+                        ksp->ks_data_size = ks_ndata * sizeof(kstat_timer_t);
+                        break;
+                default:
+                        PANIC("Undefined kstat type %d\n", ksp->ks_type);
+        }
+
+       if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) {
+                ksp->ks_data = NULL;
+        } else {
+                ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP);
+                if (ksp->ks_data == NULL) {
+                        kmem_free(ksp, sizeof(*ksp));
+                        ksp = NULL;
+                }
+        }
+
+       return ksp;
+}
+EXPORT_SYMBOL(__kstat_create);
+
+void
+__kstat_install(kstat_t *ksp)
+{
+       kstat_module_t *module;
+       kstat_t *tmp;
+
+       ASSERT(ksp);
+
+       mutex_enter(&kstat_module_lock);
+
+       module = kstat_find_module(ksp->ks_module);
+       if (module == NULL) {
+               module = kstat_create_module(ksp->ks_module);
+               if (module == NULL)
+                       goto out;
+       }
+
+       /*
+        * Only one entry by this name per-module, on failure the module
+        * shouldn't be deleted because we know it has at least one entry.
+        */
+       list_for_each_entry(tmp, &module->ksm_kstat_list, ks_list)
+               if (strncmp(tmp->ks_name, ksp->ks_name, KSTAT_STRLEN) == 0)
+                       goto out;
+
+       list_add_tail(&ksp->ks_list, &module->ksm_kstat_list);
+
+       mutex_enter(ksp->ks_lock);
+       ksp->ks_owner = module;
+       ksp->ks_proc = proc_create_data(ksp->ks_name, 0644,
+           module->ksm_proc, &proc_kstat_operations, (void *)ksp);
+       if (ksp->ks_proc == NULL) {
+               list_del_init(&ksp->ks_list);
+               if (list_empty(&module->ksm_kstat_list))
+                       kstat_delete_module(module);
+       }
+       mutex_exit(ksp->ks_lock);
+out:
+       mutex_exit(&kstat_module_lock);
+}
+EXPORT_SYMBOL(__kstat_install);
+
+void
+__kstat_delete(kstat_t *ksp)
+{
+       kstat_module_t *module = ksp->ks_owner;
+
+       mutex_enter(&kstat_module_lock);
+       list_del_init(&ksp->ks_list);
+       mutex_exit(&kstat_module_lock);
+
+       if (ksp->ks_proc) {
+               remove_proc_entry(ksp->ks_name, module->ksm_proc);
+
+               /* Remove top level module directory if it's empty */
+               if (list_empty(&module->ksm_kstat_list))
+                       kstat_delete_module(module);
+       }
+
+       if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
+               kmem_free(ksp->ks_data, ksp->ks_data_size);
+
+       ksp->ks_lock = NULL;
+       mutex_destroy(&ksp->ks_private_lock);
+       kmem_free(ksp, sizeof(*ksp));
+
+       return;
+}
+EXPORT_SYMBOL(__kstat_delete);
+
+int
+spl_kstat_init(void)
+{
+       mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL);
+       INIT_LIST_HEAD(&kstat_module_list);
+        kstat_id = 0;
+       return (0);
+}
+
+void
+spl_kstat_fini(void)
+{
+       ASSERT(list_empty(&kstat_module_list));
+       mutex_destroy(&kstat_module_lock);
+}
+
diff --git a/spl/module/spl/spl-mutex.c b/spl/module/spl/spl-mutex.c
new file mode 100644 (file)
index 0000000..a29d488
--- /dev/null
@@ -0,0 +1,36 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Mutex Implementation.
+\*****************************************************************************/
+
+#include <sys/mutex.h>
+
+#ifdef DEBUG_SUBSYSTEM
+#undef DEBUG_SUBSYSTEM
+#endif
+
+#define DEBUG_SUBSYSTEM S_MUTEX
+
+int spl_mutex_init(void) { return 0; }
+void spl_mutex_fini(void) { }
diff --git a/spl/module/spl/spl-proc.c b/spl/module/spl/spl-proc.c
new file mode 100644 (file)
index 0000000..eb00505
--- /dev/null
@@ -0,0 +1,519 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Proc Implementation.
+\*****************************************************************************/
+
+#include <sys/systeminfo.h>
+#include <sys/kstat.h>
+#include <sys/kmem.h>
+#include <sys/kmem_cache.h>
+#include <sys/vmem.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/seq_file.h>
+#include <linux/proc_compat.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
+typedef struct ctl_table __no_const spl_ctl_table;
+#else
+typedef struct ctl_table spl_ctl_table;
+#endif
+
+static unsigned long table_min = 0;
+static unsigned long table_max = ~0;
+
+static struct ctl_table_header *spl_header = NULL;
+static struct proc_dir_entry *proc_spl = NULL;
+static struct proc_dir_entry *proc_spl_kmem = NULL;
+static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
+struct proc_dir_entry *proc_spl_kstat = NULL;
+
+static int
+proc_copyin_string(char *kbuffer, int kbuffer_size,
+                   const char *ubuffer, int ubuffer_size)
+{
+        int size;
+
+        if (ubuffer_size > kbuffer_size)
+                return -EOVERFLOW;
+
+        if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
+                return -EFAULT;
+
+        /* strip trailing whitespace */
+        size = strnlen(kbuffer, ubuffer_size);
+        while (size-- >= 0)
+                if (!isspace(kbuffer[size]))
+                        break;
+
+        /* empty string */
+        if (size < 0)
+                return -EINVAL;
+
+        /* no space to terminate */
+        if (size == kbuffer_size)
+                return -EOVERFLOW;
+
+        kbuffer[size + 1] = 0;
+        return 0;
+}
+
+static int
+proc_copyout_string(char *ubuffer, int ubuffer_size,
+                    const char *kbuffer, char *append)
+{
+        /* NB if 'append' != NULL, it's a single character to append to the
+         * copied out string - usually "\n", for /proc entries and
+         * (i.e. a terminating zero byte) for sysctl entries
+         */
+        int size = MIN(strlen(kbuffer), ubuffer_size);
+
+        if (copy_to_user(ubuffer, kbuffer, size))
+                return -EFAULT;
+
+        if (append != NULL && size < ubuffer_size) {
+                if (copy_to_user(ubuffer + size, append, 1))
+                        return -EFAULT;
+
+                size++;
+        }
+
+        return size;
+}
+
+#ifdef DEBUG_KMEM
+static int
+proc_domemused(struct ctl_table *table, int write,
+    void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+        int rc = 0;
+        unsigned long min = 0, max = ~0, val;
+        spl_ctl_table dummy = *table;
+
+        dummy.data = &val;
+        dummy.proc_handler = &proc_dointvec;
+        dummy.extra1 = &min;
+        dummy.extra2 = &max;
+
+        if (write) {
+                *ppos += *lenp;
+        } else {
+# ifdef HAVE_ATOMIC64_T
+                val = atomic64_read((atomic64_t *)table->data);
+# else
+                val = atomic_read((atomic_t *)table->data);
+# endif /* HAVE_ATOMIC64_T */
+                rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos);
+        }
+
+        return (rc);
+}
+#endif /* DEBUG_KMEM */
+
+static int
+proc_doslab(struct ctl_table *table, int write,
+    void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+        int rc = 0;
+        unsigned long min = 0, max = ~0, val = 0, mask;
+        spl_ctl_table dummy = *table;
+        spl_kmem_cache_t *skc;
+
+        dummy.data = &val;
+        dummy.proc_handler = &proc_dointvec;
+        dummy.extra1 = &min;
+        dummy.extra2 = &max;
+
+        if (write) {
+                *ppos += *lenp;
+        } else {
+                down_read(&spl_kmem_cache_sem);
+                mask = (unsigned long)table->data;
+
+                list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
+
+                       /* Only use slabs of the correct kmem/vmem type */
+                       if (!(skc->skc_flags & mask))
+                               continue;
+
+                       /* Sum the specified field for selected slabs */
+                       switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) {
+                       case KMC_TOTAL:
+                               val += skc->skc_slab_size * skc->skc_slab_total;
+                               break;
+                       case KMC_ALLOC:
+                               val += skc->skc_obj_size * skc->skc_obj_alloc;
+                               break;
+                       case KMC_MAX:
+                               val += skc->skc_obj_size * skc->skc_obj_max;
+                               break;
+                       }
+                }
+
+                up_read(&spl_kmem_cache_sem);
+                rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos);
+        }
+
+        return (rc);
+}
+
+static int
+proc_dohostid(struct ctl_table *table, int write,
+    void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+        int len, rc = 0;
+        char *end, str[32];
+
+        if (write) {
+                /* We can't use proc_doulongvec_minmax() in the write
+                 * case here because hostid while a hex value has no
+                 * leading 0x which confuses the helper function. */
+                rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
+                if (rc < 0)
+                        return (rc);
+
+                spl_hostid = simple_strtoul(str, &end, 16);
+                if (str == end)
+                        return (-EINVAL);
+
+        } else {
+                len = snprintf(str, sizeof(str), "%lx", spl_hostid);
+                if (*ppos >= len)
+                        rc = 0;
+                else
+                        rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
+
+                if (rc >= 0) {
+                        *lenp = rc;
+                        *ppos += rc;
+                }
+        }
+
+        return (rc);
+}
+
+static void
+slab_seq_show_headers(struct seq_file *f)
+{
+        seq_printf(f,
+            "--------------------- cache ----------"
+            "---------------------------------------------  "
+            "----- slab ------  "
+            "---- object -----  "
+            "--- emergency ---\n");
+        seq_printf(f,
+            "name                                  "
+            "  flags      size     alloc slabsize  objsize  "
+            "total alloc   max  "
+            "total alloc   max  "
+            "dlock alloc   max\n");
+}
+
+static int
+slab_seq_show(struct seq_file *f, void *p)
+{
+        spl_kmem_cache_t *skc = p;
+
+        ASSERT(skc->skc_magic == SKC_MAGIC);
+
+       /*
+        * Backed by Linux slab see /proc/slabinfo.
+        */
+       if (skc->skc_flags & KMC_SLAB)
+               return (0);
+
+        spin_lock(&skc->skc_lock);
+        seq_printf(f, "%-36s  ", skc->skc_name);
+        seq_printf(f, "0x%05lx %9lu %9lu %8u %8u  "
+            "%5lu %5lu %5lu  %5lu %5lu %5lu  %5lu %5lu %5lu\n",
+            (long unsigned)skc->skc_flags,
+            (long unsigned)(skc->skc_slab_size * skc->skc_slab_total),
+            (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc),
+            (unsigned)skc->skc_slab_size,
+            (unsigned)skc->skc_obj_size,
+            (long unsigned)skc->skc_slab_total,
+            (long unsigned)skc->skc_slab_alloc,
+            (long unsigned)skc->skc_slab_max,
+            (long unsigned)skc->skc_obj_total,
+            (long unsigned)skc->skc_obj_alloc,
+            (long unsigned)skc->skc_obj_max,
+            (long unsigned)skc->skc_obj_deadlock,
+            (long unsigned)skc->skc_obj_emergency,
+            (long unsigned)skc->skc_obj_emergency_max);
+
+        spin_unlock(&skc->skc_lock);
+
+        return 0;
+}
+
+static void *
+slab_seq_start(struct seq_file *f, loff_t *pos)
+{
+        struct list_head *p;
+        loff_t n = *pos;
+
+       down_read(&spl_kmem_cache_sem);
+        if (!n)
+                slab_seq_show_headers(f);
+
+        p = spl_kmem_cache_list.next;
+        while (n--) {
+                p = p->next;
+                if (p == &spl_kmem_cache_list)
+                        return (NULL);
+        }
+
+        return (list_entry(p, spl_kmem_cache_t, skc_list));
+}
+
+static void *
+slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
+{
+       spl_kmem_cache_t *skc = p;
+
+        ++*pos;
+        return ((skc->skc_list.next == &spl_kmem_cache_list) ?
+              NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
+}
+
+static void
+slab_seq_stop(struct seq_file *f, void *v)
+{
+       up_read(&spl_kmem_cache_sem);
+}
+
+static struct seq_operations slab_seq_ops = {
+        .show  = slab_seq_show,
+        .start = slab_seq_start,
+        .next  = slab_seq_next,
+        .stop  = slab_seq_stop,
+};
+
+static int
+proc_slab_open(struct inode *inode, struct file *filp)
+{
+        return seq_open(filp, &slab_seq_ops);
+}
+
+static struct file_operations proc_slab_operations = {
+        .open           = proc_slab_open,
+        .read           = seq_read,
+        .llseek         = seq_lseek,
+        .release        = seq_release,
+};
+
+static struct ctl_table spl_kmem_table[] = {
+#ifdef DEBUG_KMEM
+        {
+                .procname = "kmem_used",
+                .data     = &kmem_alloc_used,
+# ifdef HAVE_ATOMIC64_T
+                .maxlen   = sizeof(atomic64_t),
+# else
+                .maxlen   = sizeof(atomic_t),
+# endif /* HAVE_ATOMIC64_T */
+                .mode     = 0444,
+                .proc_handler = &proc_domemused,
+        },
+        {
+                .procname = "kmem_max",
+                .data     = &kmem_alloc_max,
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doulongvec_minmax,
+        },
+#endif /* DEBUG_KMEM */
+        {
+                .procname = "slab_kmem_total",
+               .data     = (void *)(KMC_KMEM | KMC_TOTAL),
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doslab,
+        },
+        {
+                .procname = "slab_kmem_alloc",
+               .data     = (void *)(KMC_KMEM | KMC_ALLOC),
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doslab,
+        },
+        {
+                .procname = "slab_kmem_max",
+               .data     = (void *)(KMC_KMEM | KMC_MAX),
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doslab,
+        },
+        {
+                .procname = "slab_vmem_total",
+               .data     = (void *)(KMC_VMEM | KMC_TOTAL),
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doslab,
+        },
+        {
+                .procname = "slab_vmem_alloc",
+               .data     = (void *)(KMC_VMEM | KMC_ALLOC),
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doslab,
+        },
+        {
+                .procname = "slab_vmem_max",
+               .data     = (void *)(KMC_VMEM | KMC_MAX),
+                .maxlen   = sizeof(unsigned long),
+                .extra1   = &table_min,
+                .extra2   = &table_max,
+                .mode     = 0444,
+                .proc_handler = &proc_doslab,
+        },
+       {0},
+};
+
+static struct ctl_table spl_kstat_table[] = {
+       {0},
+};
+
+static struct ctl_table spl_table[] = {
+        /* NB No .strategy entries have been provided since
+         * sysctl(8) prefers to go via /proc for portability.
+         */
+        {
+                .procname = "version",
+                .data     = spl_version,
+                .maxlen   = sizeof(spl_version),
+                .mode     = 0444,
+                .proc_handler = &proc_dostring,
+        },
+        {
+                .procname = "hostid",
+                .data     = &spl_hostid,
+                .maxlen   = sizeof(unsigned long),
+                .mode     = 0644,
+                .proc_handler = &proc_dohostid,
+        },
+       {
+               .procname = "kmem",
+               .mode     = 0555,
+               .child    = spl_kmem_table,
+       },
+       {
+               .procname = "kstat",
+               .mode     = 0555,
+               .child    = spl_kstat_table,
+       },
+        { 0 },
+};
+
+static struct ctl_table spl_dir[] = {
+        {
+                .procname = "spl",
+                .mode     = 0555,
+                .child    = spl_table,
+        },
+        { 0 }
+};
+
+static struct ctl_table spl_root[] = {
+       {
+#ifdef HAVE_CTL_NAME
+       .ctl_name = CTL_KERN,
+#endif
+       .procname = "kernel",
+       .mode = 0555,
+       .child = spl_dir,
+       },
+       { 0 }
+};
+
+int
+spl_proc_init(void)
+{
+       int rc = 0;
+
+        spl_header = register_sysctl_table(spl_root);
+       if (spl_header == NULL)
+               return (-EUNATCH);
+
+       proc_spl = proc_mkdir("spl", NULL);
+       if (proc_spl == NULL) {
+               rc = -EUNATCH;
+               goto out;
+       }
+
+        proc_spl_kmem = proc_mkdir("kmem", proc_spl);
+        if (proc_spl_kmem == NULL) {
+                rc = -EUNATCH;
+               goto out;
+       }
+
+       proc_spl_kmem_slab = proc_create_data("slab", 0444,
+               proc_spl_kmem, &proc_slab_operations, NULL);
+        if (proc_spl_kmem_slab == NULL) {
+               rc = -EUNATCH;
+               goto out;
+       }
+
+        proc_spl_kstat = proc_mkdir("kstat", proc_spl);
+        if (proc_spl_kstat == NULL) {
+                rc = -EUNATCH;
+               goto out;
+       }
+out:
+       if (rc) {
+               remove_proc_entry("kstat", proc_spl);
+               remove_proc_entry("slab", proc_spl_kmem);
+               remove_proc_entry("kmem", proc_spl);
+               remove_proc_entry("spl", NULL);
+               unregister_sysctl_table(spl_header);
+       }
+
+        return (rc);
+}
+
+void
+spl_proc_fini(void)
+{
+       remove_proc_entry("kstat", proc_spl);
+        remove_proc_entry("slab", proc_spl_kmem);
+       remove_proc_entry("kmem", proc_spl);
+       remove_proc_entry("spl", NULL);
+
+        ASSERT(spl_header != NULL);
+        unregister_sysctl_table(spl_header);
+}
diff --git a/spl/module/spl/spl-rwlock.c b/spl/module/spl/spl-rwlock.c
new file mode 100644 (file)
index 0000000..77f46f2
--- /dev/null
@@ -0,0 +1,86 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Reader/Writer Lock Implementation.
+\*****************************************************************************/
+
+#include <sys/rwlock.h>
+
+#ifdef DEBUG_SUBSYSTEM
+#undef DEBUG_SUBSYSTEM
+#endif
+
+#define DEBUG_SUBSYSTEM S_RWLOCK
+
+#if defined(CONFIG_RWSEM_GENERIC_SPINLOCK)
+static int
+__rwsem_tryupgrade(struct rw_semaphore *rwsem)
+{
+       int ret = 0;
+       unsigned long flags;
+       spl_rwsem_lock_irqsave(&rwsem->wait_lock, flags);
+       if (RWSEM_COUNT(rwsem) == SPL_RWSEM_SINGLE_READER_VALUE &&
+           list_empty(&rwsem->wait_list)) {
+               ret = 1;
+               RWSEM_COUNT(rwsem) = SPL_RWSEM_SINGLE_WRITER_VALUE;
+       }
+       spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags);
+       return (ret);
+}
+#elif defined(HAVE_RWSEM_ATOMIC_LONG_COUNT)
+static int
+__rwsem_tryupgrade(struct rw_semaphore *rwsem)
+{
+       long val;
+       val = atomic_long_cmpxchg(&rwsem->count, SPL_RWSEM_SINGLE_READER_VALUE,
+           SPL_RWSEM_SINGLE_WRITER_VALUE);
+       return (val == SPL_RWSEM_SINGLE_READER_VALUE);
+}
+#else
+static int
+__rwsem_tryupgrade(struct rw_semaphore *rwsem)
+{
+       typeof (rwsem->count) val;
+       val = cmpxchg(&rwsem->count, SPL_RWSEM_SINGLE_READER_VALUE,
+           SPL_RWSEM_SINGLE_WRITER_VALUE);
+       return (val == SPL_RWSEM_SINGLE_READER_VALUE);
+}
+#endif
+
+int
+rwsem_tryupgrade(struct rw_semaphore *rwsem)
+{
+       if (__rwsem_tryupgrade(rwsem)) {
+               rwsem_release(&rwsem->dep_map, 1, _RET_IP_);
+               rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_);
+#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
+               rwsem->owner = current;
+#endif
+               return (1);
+       }
+       return (0);
+}
+EXPORT_SYMBOL(rwsem_tryupgrade);
+
+int spl_rw_init(void) { return 0; }
+void spl_rw_fini(void) { }
diff --git a/spl/module/spl/spl-taskq.c b/spl/module/spl/spl-taskq.c
new file mode 100644 (file)
index 0000000..017b410
--- /dev/null
@@ -0,0 +1,1145 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Task Queue Implementation.
+\*****************************************************************************/
+
+#include <sys/taskq.h>
+#include <sys/kmem.h>
+
+int spl_taskq_thread_bind = 0;
+module_param(spl_taskq_thread_bind, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_bind, "Bind taskq thread to CPU by default");
+
+
+int spl_taskq_thread_dynamic = 0;
+module_param(spl_taskq_thread_dynamic, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_dynamic, "Allow dynamic taskq threads");
+
+int spl_taskq_thread_priority = 1;
+module_param(spl_taskq_thread_priority, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_priority,
+    "Allow non-default priority for taskq threads");
+
+int spl_taskq_thread_sequential = 4;
+module_param(spl_taskq_thread_sequential, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_sequential,
+    "Create new taskq threads after N sequential tasks");
+
+/* Global system-wide dynamic task queue available for all consumers */
+taskq_t *system_taskq;
+EXPORT_SYMBOL(system_taskq);
+
+/* Private dedicated taskq for creating new taskq threads on demand. */
+static taskq_t *dynamic_taskq;
+static taskq_thread_t *taskq_thread_create(taskq_t *);
+
+static int
+task_km_flags(uint_t flags)
+{
+       if (flags & TQ_NOSLEEP)
+               return KM_NOSLEEP;
+
+       if (flags & TQ_PUSHPAGE)
+               return KM_PUSHPAGE;
+
+       return KM_SLEEP;
+}
+
+/*
+ * NOTE: Must be called with tq->tq_lock held, returns a list_t which
+ * is not attached to the free, work, or pending taskq lists.
+ */
+static taskq_ent_t *
+task_alloc(taskq_t *tq, uint_t flags)
+{
+       taskq_ent_t *t;
+       int count = 0;
+
+       ASSERT(tq);
+       ASSERT(spin_is_locked(&tq->tq_lock));
+retry:
+       /* Acquire taskq_ent_t's from free list if available */
+       if (!list_empty(&tq->tq_free_list) && !(flags & TQ_NEW)) {
+               t = list_entry(tq->tq_free_list.next, taskq_ent_t, tqent_list);
+
+               ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC));
+               ASSERT(!(t->tqent_flags & TQENT_FLAG_CANCEL));
+               ASSERT(!timer_pending(&t->tqent_timer));
+
+               list_del_init(&t->tqent_list);
+               return (t);
+       }
+
+       /* Free list is empty and memory allocations are prohibited */
+       if (flags & TQ_NOALLOC)
+               return (NULL);
+
+       /* Hit maximum taskq_ent_t pool size */
+       if (tq->tq_nalloc >= tq->tq_maxalloc) {
+               if (flags & TQ_NOSLEEP)
+                       return (NULL);
+
+               /*
+                * Sleep periodically polling the free list for an available
+                * taskq_ent_t. Dispatching with TQ_SLEEP should always succeed
+                * but we cannot block forever waiting for an taskq_ent_t to
+                * show up in the free list, otherwise a deadlock can happen.
+                *
+                * Therefore, we need to allocate a new task even if the number
+                * of allocated tasks is above tq->tq_maxalloc, but we still
+                * end up delaying the task allocation by one second, thereby
+                * throttling the task dispatch rate.
+                */
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+               schedule_timeout(HZ / 100);
+               spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+               if (count < 100) {
+                       count++;
+                       goto retry;
+               }
+       }
+
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+       t = kmem_alloc(sizeof(taskq_ent_t), task_km_flags(flags));
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+       if (t) {
+               taskq_init_ent(t);
+               tq->tq_nalloc++;
+       }
+
+       return (t);
+}
+
+/*
+ * NOTE: Must be called with tq->tq_lock held, expects the taskq_ent_t
+ * to already be removed from the free, work, or pending taskq lists.
+ */
+static void
+task_free(taskq_t *tq, taskq_ent_t *t)
+{
+       ASSERT(tq);
+       ASSERT(t);
+       ASSERT(spin_is_locked(&tq->tq_lock));
+       ASSERT(list_empty(&t->tqent_list));
+       ASSERT(!timer_pending(&t->tqent_timer));
+
+       kmem_free(t, sizeof(taskq_ent_t));
+       tq->tq_nalloc--;
+}
+
+/*
+ * NOTE: Must be called with tq->tq_lock held, either destroys the
+ * taskq_ent_t if too many exist or moves it to the free list for later use.
+ */
+static void
+task_done(taskq_t *tq, taskq_ent_t *t)
+{
+       ASSERT(tq);
+       ASSERT(t);
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       /* Wake tasks blocked in taskq_wait_id() */
+       wake_up_all(&t->tqent_waitq);
+
+       list_del_init(&t->tqent_list);
+
+       if (tq->tq_nalloc <= tq->tq_minalloc) {
+               t->tqent_id = 0;
+               t->tqent_func = NULL;
+               t->tqent_arg = NULL;
+               t->tqent_flags = 0;
+
+               list_add_tail(&t->tqent_list, &tq->tq_free_list);
+       } else {
+               task_free(tq, t);
+       }
+}
+
+/*
+ * When a delayed task timer expires remove it from the delay list and
+ * add it to the priority list in order for immediate processing.
+ */
+static void
+task_expire(unsigned long data)
+{
+       taskq_ent_t *w, *t = (taskq_ent_t *)data;
+       taskq_t *tq = t->tqent_taskq;
+       struct list_head *l;
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+       if (t->tqent_flags & TQENT_FLAG_CANCEL) {
+               ASSERT(list_empty(&t->tqent_list));
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+               return;
+       }
+
+       /*
+        * The priority list must be maintained in strict task id order
+        * from lowest to highest for lowest_id to be easily calculable.
+        */
+       list_del(&t->tqent_list);
+       list_for_each_prev(l, &tq->tq_prio_list) {
+               w = list_entry(l, taskq_ent_t, tqent_list);
+               if (w->tqent_id < t->tqent_id) {
+                       list_add(&t->tqent_list, l);
+                       break;
+               }
+       }
+       if (l == &tq->tq_prio_list)
+               list_add(&t->tqent_list, &tq->tq_prio_list);
+
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       wake_up(&tq->tq_work_waitq);
+}
+
+/*
+ * Returns the lowest incomplete taskqid_t.  The taskqid_t may
+ * be queued on the pending list, on the priority list, on the
+ * delay list, or on the work list currently being handled, but
+ * it is not 100% complete yet.
+ */
+static taskqid_t
+taskq_lowest_id(taskq_t *tq)
+{
+       taskqid_t lowest_id = tq->tq_next_id;
+       taskq_ent_t *t;
+       taskq_thread_t *tqt;
+
+       ASSERT(tq);
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       if (!list_empty(&tq->tq_pend_list)) {
+               t = list_entry(tq->tq_pend_list.next, taskq_ent_t, tqent_list);
+               lowest_id = MIN(lowest_id, t->tqent_id);
+       }
+
+       if (!list_empty(&tq->tq_prio_list)) {
+               t = list_entry(tq->tq_prio_list.next, taskq_ent_t, tqent_list);
+               lowest_id = MIN(lowest_id, t->tqent_id);
+       }
+
+       if (!list_empty(&tq->tq_delay_list)) {
+               t = list_entry(tq->tq_delay_list.next, taskq_ent_t, tqent_list);
+               lowest_id = MIN(lowest_id, t->tqent_id);
+       }
+
+       if (!list_empty(&tq->tq_active_list)) {
+               tqt = list_entry(tq->tq_active_list.next, taskq_thread_t,
+                   tqt_active_list);
+               ASSERT(tqt->tqt_id != 0);
+               lowest_id = MIN(lowest_id, tqt->tqt_id);
+       }
+
+       return (lowest_id);
+}
+
+/*
+ * Insert a task into a list keeping the list sorted by increasing taskqid.
+ */
+static void
+taskq_insert_in_order(taskq_t *tq, taskq_thread_t *tqt)
+{
+       taskq_thread_t *w;
+       struct list_head *l;
+
+       ASSERT(tq);
+       ASSERT(tqt);
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       list_for_each_prev(l, &tq->tq_active_list) {
+               w = list_entry(l, taskq_thread_t, tqt_active_list);
+               if (w->tqt_id < tqt->tqt_id) {
+                       list_add(&tqt->tqt_active_list, l);
+                       break;
+               }
+       }
+       if (l == &tq->tq_active_list)
+               list_add(&tqt->tqt_active_list, &tq->tq_active_list);
+}
+
+/*
+ * Find and return a task from the given list if it exists.  The list
+ * must be in lowest to highest task id order.
+ */
+static taskq_ent_t *
+taskq_find_list(taskq_t *tq, struct list_head *lh, taskqid_t id)
+{
+       struct list_head *l;
+       taskq_ent_t *t;
+
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       list_for_each(l, lh) {
+               t = list_entry(l, taskq_ent_t, tqent_list);
+
+               if (t->tqent_id == id)
+                       return (t);
+
+               if (t->tqent_id > id)
+                       break;
+       }
+
+       return (NULL);
+}
+
+/*
+ * Find an already dispatched task given the task id regardless of what
+ * state it is in.  If a task is still pending or executing it will be
+ * returned and 'active' set appropriately.  If the task has already
+ * been run then NULL is returned.
+ */
+static taskq_ent_t *
+taskq_find(taskq_t *tq, taskqid_t id, int *active)
+{
+       taskq_thread_t *tqt;
+       struct list_head *l;
+       taskq_ent_t *t;
+
+       ASSERT(spin_is_locked(&tq->tq_lock));
+       *active = 0;
+
+       t = taskq_find_list(tq, &tq->tq_delay_list, id);
+       if (t)
+               return (t);
+
+       t = taskq_find_list(tq, &tq->tq_prio_list, id);
+       if (t)
+               return (t);
+
+       t = taskq_find_list(tq, &tq->tq_pend_list, id);
+       if (t)
+               return (t);
+
+       list_for_each(l, &tq->tq_active_list) {
+               tqt = list_entry(l, taskq_thread_t, tqt_active_list);
+               if (tqt->tqt_id == id) {
+                       t = tqt->tqt_task;
+                       *active = 1;
+                       return (t);
+               }
+       }
+
+       return (NULL);
+}
+
+/*
+ * Theory for the taskq_wait_id(), taskq_wait_outstanding(), and
+ * taskq_wait() functions below.
+ *
+ * Taskq waiting is accomplished by tracking the lowest outstanding task
+ * id and the next available task id.  As tasks are dispatched they are
+ * added to the tail of the pending, priority, or delay lists.  As worker
+ * threads become available the tasks are removed from the heads of these
+ * lists and linked to the worker threads.  This ensures the lists are
+ * kept sorted by lowest to highest task id.
+ *
+ * Therefore the lowest outstanding task id can be quickly determined by
+ * checking the head item from all of these lists.  This value is stored
+ * with the taskq as the lowest id.  It only needs to be recalculated when
+ * either the task with the current lowest id completes or is canceled.
+ *
+ * By blocking until the lowest task id exceeds the passed task id the
+ * taskq_wait_outstanding() function can be easily implemented.  Similarly,
+ * by blocking until the lowest task id matches the next task id taskq_wait()
+ * can be implemented.
+ *
+ * Callers should be aware that when there are multiple worked threads it
+ * is possible for larger task ids to complete before smaller ones.  Also
+ * when the taskq contains delay tasks with small task ids callers may
+ * block for a considerable length of time waiting for them to expire and
+ * execute.
+ */
+static int
+taskq_wait_id_check(taskq_t *tq, taskqid_t id)
+{
+       int active = 0;
+       int rc;
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       rc = (taskq_find(tq, id, &active) == NULL);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       return (rc);
+}
+
+/*
+ * The taskq_wait_id() function blocks until the passed task id completes.
+ * This does not guarantee that all lower task ids have completed.
+ */
+void
+taskq_wait_id(taskq_t *tq, taskqid_t id)
+{
+       wait_event(tq->tq_wait_waitq, taskq_wait_id_check(tq, id));
+}
+EXPORT_SYMBOL(taskq_wait_id);
+
+static int
+taskq_wait_outstanding_check(taskq_t *tq, taskqid_t id)
+{
+       int rc;
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       rc = (id < tq->tq_lowest_id);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       return (rc);
+}
+
+/*
+ * The taskq_wait_outstanding() function will block until all tasks with a
+ * lower taskqid than the passed 'id' have been completed.  Note that all
+ * task id's are assigned monotonically at dispatch time.  Zero may be
+ * passed for the id to indicate all tasks dispatch up to this point,
+ * but not after, should be waited for.
+ */
+void
+taskq_wait_outstanding(taskq_t *tq, taskqid_t id)
+{
+       id = id ? id : tq->tq_next_id - 1;
+       wait_event(tq->tq_wait_waitq, taskq_wait_outstanding_check(tq, id));
+}
+EXPORT_SYMBOL(taskq_wait_outstanding);
+
+static int
+taskq_wait_check(taskq_t *tq)
+{
+       int rc;
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       rc = (tq->tq_lowest_id == tq->tq_next_id);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       return (rc);
+}
+
+/*
+ * The taskq_wait() function will block until the taskq is empty.
+ * This means that if a taskq re-dispatches work to itself taskq_wait()
+ * callers will block indefinitely.
+ */
+void
+taskq_wait(taskq_t *tq)
+{
+       wait_event(tq->tq_wait_waitq, taskq_wait_check(tq));
+}
+EXPORT_SYMBOL(taskq_wait);
+
+static int
+taskq_member_impl(taskq_t *tq, void *t)
+{
+       struct list_head *l;
+       taskq_thread_t *tqt;
+       int found = 0;
+
+       ASSERT(tq);
+       ASSERT(t);
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       list_for_each(l, &tq->tq_thread_list) {
+               tqt = list_entry(l, taskq_thread_t, tqt_thread_list);
+               if (tqt->tqt_thread == (struct task_struct *)t) {
+                       found = 1;
+                       break;
+               }
+       }
+       return (found);
+}
+
+int
+taskq_member(taskq_t *tq, void *t)
+{
+       int found;
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       found = taskq_member_impl(tq, t);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       return (found);
+}
+EXPORT_SYMBOL(taskq_member);
+
+/*
+ * Cancel an already dispatched task given the task id.  Still pending tasks
+ * will be immediately canceled, and if the task is active the function will
+ * block until it completes.  Preallocated tasks which are canceled must be
+ * freed by the caller.
+ */
+int
+taskq_cancel_id(taskq_t *tq, taskqid_t id)
+{
+       taskq_ent_t *t;
+       int active = 0;
+       int rc = ENOENT;
+
+       ASSERT(tq);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       t = taskq_find(tq, id, &active);
+       if (t && !active) {
+               list_del_init(&t->tqent_list);
+               t->tqent_flags |= TQENT_FLAG_CANCEL;
+
+               /*
+                * When canceling the lowest outstanding task id we
+                * must recalculate the new lowest outstanding id.
+                */
+               if (tq->tq_lowest_id == t->tqent_id) {
+                       tq->tq_lowest_id = taskq_lowest_id(tq);
+                       ASSERT3S(tq->tq_lowest_id, >, t->tqent_id);
+               }
+
+               /*
+                * The task_expire() function takes the tq->tq_lock so drop
+                * drop the lock before synchronously cancelling the timer.
+                */
+               if (timer_pending(&t->tqent_timer)) {
+                       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+                       del_timer_sync(&t->tqent_timer);
+                       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+               }
+
+               if (!(t->tqent_flags & TQENT_FLAG_PREALLOC))
+                       task_done(tq, t);
+
+               rc = 0;
+       }
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       if (active) {
+               taskq_wait_id(tq, id);
+               rc = EBUSY;
+       }
+
+       return (rc);
+}
+EXPORT_SYMBOL(taskq_cancel_id);
+
+static int taskq_thread_spawn(taskq_t *tq);
+
+taskqid_t
+taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
+{
+       taskq_ent_t *t;
+       taskqid_t rc = 0;
+
+       ASSERT(tq);
+       ASSERT(func);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+       /* Taskq being destroyed and all tasks drained */
+       if (!(tq->tq_flags & TASKQ_ACTIVE))
+               goto out;
+
+       /* Do not queue the task unless there is idle thread for it */
+       ASSERT(tq->tq_nactive <= tq->tq_nthreads);
+       if ((flags & TQ_NOQUEUE) && (tq->tq_nactive == tq->tq_nthreads))
+               goto out;
+
+       if ((t = task_alloc(tq, flags)) == NULL)
+               goto out;
+
+       spin_lock(&t->tqent_lock);
+
+       /* Queue to the priority list instead of the pending list */
+       if (flags & TQ_FRONT)
+               list_add_tail(&t->tqent_list, &tq->tq_prio_list);
+       else
+               list_add_tail(&t->tqent_list, &tq->tq_pend_list);
+
+       t->tqent_id = rc = tq->tq_next_id;
+       tq->tq_next_id++;
+       t->tqent_func = func;
+       t->tqent_arg = arg;
+       t->tqent_taskq = tq;
+       t->tqent_timer.data = 0;
+       t->tqent_timer.function = NULL;
+       t->tqent_timer.expires = 0;
+
+       ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC));
+
+       spin_unlock(&t->tqent_lock);
+
+       wake_up(&tq->tq_work_waitq);
+out:
+       /* Spawn additional taskq threads if required. */
+       if (tq->tq_nactive == tq->tq_nthreads)
+               (void) taskq_thread_spawn(tq);
+
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+       return (rc);
+}
+EXPORT_SYMBOL(taskq_dispatch);
+
+taskqid_t
+taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg,
+    uint_t flags, clock_t expire_time)
+{
+       taskqid_t rc = 0;
+       taskq_ent_t *t;
+
+       ASSERT(tq);
+       ASSERT(func);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+       /* Taskq being destroyed and all tasks drained */
+       if (!(tq->tq_flags & TASKQ_ACTIVE))
+               goto out;
+
+       if ((t = task_alloc(tq, flags)) == NULL)
+               goto out;
+
+       spin_lock(&t->tqent_lock);
+
+       /* Queue to the delay list for subsequent execution */
+       list_add_tail(&t->tqent_list, &tq->tq_delay_list);
+
+       t->tqent_id = rc = tq->tq_next_id;
+       tq->tq_next_id++;
+       t->tqent_func = func;
+       t->tqent_arg = arg;
+       t->tqent_taskq = tq;
+       t->tqent_timer.data = (unsigned long)t;
+       t->tqent_timer.function = task_expire;
+       t->tqent_timer.expires = (unsigned long)expire_time;
+       add_timer(&t->tqent_timer);
+
+       ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC));
+
+       spin_unlock(&t->tqent_lock);
+out:
+       /* Spawn additional taskq threads if required. */
+       if (tq->tq_nactive == tq->tq_nthreads)
+               (void) taskq_thread_spawn(tq);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+       return (rc);
+}
+EXPORT_SYMBOL(taskq_dispatch_delay);
+
+void
+taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
+   taskq_ent_t *t)
+{
+       ASSERT(tq);
+       ASSERT(func);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+       /* Taskq being destroyed and all tasks drained */
+       if (!(tq->tq_flags & TASKQ_ACTIVE)) {
+               t->tqent_id = 0;
+               goto out;
+       }
+
+       spin_lock(&t->tqent_lock);
+
+       /*
+        * 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;
+
+       /* Queue to the priority list instead of the pending list */
+       if (flags & TQ_FRONT)
+               list_add_tail(&t->tqent_list, &tq->tq_prio_list);
+       else
+               list_add_tail(&t->tqent_list, &tq->tq_pend_list);
+
+       t->tqent_id = tq->tq_next_id;
+       tq->tq_next_id++;
+       t->tqent_func = func;
+       t->tqent_arg = arg;
+       t->tqent_taskq = tq;
+
+       spin_unlock(&t->tqent_lock);
+
+       wake_up(&tq->tq_work_waitq);
+out:
+       /* Spawn additional taskq threads if required. */
+       if (tq->tq_nactive == tq->tq_nthreads)
+               (void) taskq_thread_spawn(tq);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+}
+EXPORT_SYMBOL(taskq_dispatch_ent);
+
+int
+taskq_empty_ent(taskq_ent_t *t)
+{
+       return list_empty(&t->tqent_list);
+}
+EXPORT_SYMBOL(taskq_empty_ent);
+
+void
+taskq_init_ent(taskq_ent_t *t)
+{
+       spin_lock_init(&t->tqent_lock);
+       init_waitqueue_head(&t->tqent_waitq);
+       init_timer(&t->tqent_timer);
+       INIT_LIST_HEAD(&t->tqent_list);
+       t->tqent_id = 0;
+       t->tqent_func = NULL;
+       t->tqent_arg = NULL;
+       t->tqent_flags = 0;
+       t->tqent_taskq = NULL;
+}
+EXPORT_SYMBOL(taskq_init_ent);
+
+/*
+ * Return the next pending task, preference is given to tasks on the
+ * priority list which were dispatched with TQ_FRONT.
+ */
+static taskq_ent_t *
+taskq_next_ent(taskq_t *tq)
+{
+       struct list_head *list;
+
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       if (!list_empty(&tq->tq_prio_list))
+               list = &tq->tq_prio_list;
+       else if (!list_empty(&tq->tq_pend_list))
+               list = &tq->tq_pend_list;
+       else
+               return (NULL);
+
+       return (list_entry(list->next, taskq_ent_t, tqent_list));
+}
+
+/*
+ * Spawns a new thread for the specified taskq.
+ */
+static void
+taskq_thread_spawn_task(void *arg)
+{
+       taskq_t *tq = (taskq_t *)arg;
+
+       if (taskq_thread_create(tq) == NULL) {
+               /* restore spawning count if failed */
+               spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+               tq->tq_nspawn--;
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+       }
+}
+
+/*
+ * Spawn addition threads for dynamic taskqs (TASKQ_DYNMAIC) the current
+ * number of threads is insufficient to handle the pending tasks.  These
+ * new threads must be created by the dedicated dynamic_taskq to avoid
+ * deadlocks between thread creation and memory reclaim.  The system_taskq
+ * which is also a dynamic taskq cannot be safely used for this.
+ */
+static int
+taskq_thread_spawn(taskq_t *tq)
+{
+       int spawning = 0;
+
+       if (!(tq->tq_flags & TASKQ_DYNAMIC))
+               return (0);
+
+       if ((tq->tq_nthreads + tq->tq_nspawn < tq->tq_maxthreads) &&
+           (tq->tq_flags & TASKQ_ACTIVE)) {
+               spawning = (++tq->tq_nspawn);
+               taskq_dispatch(dynamic_taskq, taskq_thread_spawn_task,
+                   tq, TQ_NOSLEEP);
+       }
+
+       return (spawning);
+}
+
+/*
+ * Threads in a dynamic taskq should only exit once it has been completely
+ * drained and no other threads are actively servicing tasks.  This prevents
+ * threads from being created and destroyed more than is required.
+ *
+ * The first thread is the thread list is treated as the primary thread.
+ * There is nothing special about the primary thread but in order to avoid
+ * all the taskq pids from changing we opt to make it long running.
+ */
+static int
+taskq_thread_should_stop(taskq_t *tq, taskq_thread_t *tqt)
+{
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       if (!(tq->tq_flags & TASKQ_DYNAMIC))
+               return (0);
+
+       if (list_first_entry(&(tq->tq_thread_list), taskq_thread_t,
+           tqt_thread_list) == tqt)
+               return (0);
+
+       return
+           ((tq->tq_nspawn == 0) &&    /* No threads are being spawned */
+           (tq->tq_nactive == 0) &&    /* No threads are handling tasks */
+           (tq->tq_nthreads > 1) &&    /* More than 1 thread is running */
+           (!taskq_next_ent(tq)) &&    /* There are no pending tasks */
+           (spl_taskq_thread_dynamic));/* Dynamic taskqs are allowed */
+}
+
+static int
+taskq_thread(void *args)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       sigset_t blocked;
+       taskq_thread_t *tqt = args;
+       taskq_t *tq;
+       taskq_ent_t *t;
+       int seq_tasks = 0;
+
+       ASSERT(tqt);
+       tq = tqt->tqt_tq;
+       current->flags |= PF_NOFREEZE;
+
+       (void) spl_fstrans_mark();
+
+       sigfillset(&blocked);
+       sigprocmask(SIG_BLOCK, &blocked, NULL);
+       flush_signals(current);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       /*
+        * If we are dynamically spawned, decrease spawning count. Note that
+        * we could be created during taskq_create, in which case we shouldn't
+        * do the decrement. But it's fine because taskq_create will reset
+        * tq_nspawn later.
+        */
+       if (tq->tq_flags & TASKQ_DYNAMIC)
+               tq->tq_nspawn--;
+
+       /* Immediately exit if more threads than allowed were created. */
+       if (tq->tq_nthreads >= tq->tq_maxthreads)
+               goto error;
+
+       tq->tq_nthreads++;
+       list_add_tail(&tqt->tqt_thread_list, &tq->tq_thread_list);
+       wake_up(&tq->tq_wait_waitq);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       while (!kthread_should_stop()) {
+
+               if (list_empty(&tq->tq_pend_list) &&
+                   list_empty(&tq->tq_prio_list)) {
+
+                       if (taskq_thread_should_stop(tq, tqt)) {
+                               wake_up_all(&tq->tq_wait_waitq);
+                               break;
+                       }
+
+                       add_wait_queue_exclusive(&tq->tq_work_waitq, &wait);
+                       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+                       schedule();
+                       seq_tasks = 0;
+
+                       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+                       remove_wait_queue(&tq->tq_work_waitq, &wait);
+               } else {
+                       __set_current_state(TASK_RUNNING);
+               }
+
+               if ((t = taskq_next_ent(tq)) != NULL) {
+                       list_del_init(&t->tqent_list);
+
+                       /* In order to support recursively dispatching a
+                        * preallocated taskq_ent_t, tqent_id must be
+                        * stored prior to executing tqent_func. */
+                       tqt->tqt_id = t->tqent_id;
+                       tqt->tqt_task = t;
+
+                       /* We must store a copy of the flags prior to
+                        * servicing the task (servicing a prealloc'd task
+                        * returns the ownership of the tqent back to
+                        * the caller of taskq_dispatch). Thus,
+                        * tqent_flags _may_ change within the call. */
+                       tqt->tqt_flags = t->tqent_flags;
+
+                       taskq_insert_in_order(tq, tqt);
+                       tq->tq_nactive++;
+                       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+                       /* Perform the requested task */
+                       t->tqent_func(t->tqent_arg);
+
+                       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+                       tq->tq_nactive--;
+                       list_del_init(&tqt->tqt_active_list);
+                       tqt->tqt_task = NULL;
+
+                       /* For prealloc'd tasks, we don't free anything. */
+                       if (!(tqt->tqt_flags & TQENT_FLAG_PREALLOC))
+                               task_done(tq, t);
+
+                       /* When the current lowest outstanding taskqid is
+                        * done calculate the new lowest outstanding id */
+                       if (tq->tq_lowest_id == tqt->tqt_id) {
+                               tq->tq_lowest_id = taskq_lowest_id(tq);
+                               ASSERT3S(tq->tq_lowest_id, >, tqt->tqt_id);
+                       }
+
+                       /* Spawn additional taskq threads if required. */
+                       if ((++seq_tasks) > spl_taskq_thread_sequential &&
+                           taskq_thread_spawn(tq))
+                               seq_tasks = 0;
+
+                       tqt->tqt_id = 0;
+                       tqt->tqt_flags = 0;
+                       wake_up_all(&tq->tq_wait_waitq);
+               } else {
+                       if (taskq_thread_should_stop(tq, tqt))
+                               break;
+               }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+
+       }
+
+       __set_current_state(TASK_RUNNING);
+       tq->tq_nthreads--;
+       list_del_init(&tqt->tqt_thread_list);
+error:
+       kmem_free(tqt, sizeof (taskq_thread_t));
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       return (0);
+}
+
+static taskq_thread_t *
+taskq_thread_create(taskq_t *tq)
+{
+       static int last_used_cpu = 0;
+       taskq_thread_t *tqt;
+
+       tqt = kmem_alloc(sizeof (*tqt), KM_PUSHPAGE);
+       INIT_LIST_HEAD(&tqt->tqt_thread_list);
+       INIT_LIST_HEAD(&tqt->tqt_active_list);
+       tqt->tqt_tq = tq;
+       tqt->tqt_id = 0;
+
+       tqt->tqt_thread = spl_kthread_create(taskq_thread, tqt,
+           "%s", tq->tq_name);
+       if (tqt->tqt_thread == NULL) {
+               kmem_free(tqt, sizeof (taskq_thread_t));
+               return (NULL);
+       }
+
+       if (spl_taskq_thread_bind) {
+               last_used_cpu = (last_used_cpu + 1) % num_online_cpus();
+               kthread_bind(tqt->tqt_thread, last_used_cpu);
+       }
+
+       if (spl_taskq_thread_priority)
+               set_user_nice(tqt->tqt_thread, PRIO_TO_NICE(tq->tq_pri));
+
+       wake_up_process(tqt->tqt_thread);
+
+       return (tqt);
+}
+
+taskq_t *
+taskq_create(const char *name, int nthreads, pri_t pri,
+    int minalloc, int maxalloc, uint_t flags)
+{
+       taskq_t *tq;
+       taskq_thread_t *tqt;
+       int count = 0, rc = 0, i;
+
+       ASSERT(name != NULL);
+       ASSERT(minalloc >= 0);
+       ASSERT(maxalloc <= INT_MAX);
+       ASSERT(!(flags & (TASKQ_CPR_SAFE))); /* Unsupported */
+
+       /* Scale the number of threads using nthreads as a percentage */
+       if (flags & TASKQ_THREADS_CPU_PCT) {
+               ASSERT(nthreads <= 100);
+               ASSERT(nthreads >= 0);
+               nthreads = MIN(nthreads, 100);
+               nthreads = MAX(nthreads, 0);
+               nthreads = MAX((num_online_cpus() * nthreads) / 100, 1);
+       }
+
+       tq = kmem_alloc(sizeof (*tq), KM_PUSHPAGE);
+       if (tq == NULL)
+               return (NULL);
+
+       spin_lock_init(&tq->tq_lock);
+       INIT_LIST_HEAD(&tq->tq_thread_list);
+       INIT_LIST_HEAD(&tq->tq_active_list);
+       tq->tq_name       = strdup(name);
+       tq->tq_nactive    = 0;
+       tq->tq_nthreads   = 0;
+       tq->tq_nspawn     = 0;
+       tq->tq_maxthreads = nthreads;
+       tq->tq_pri        = pri;
+       tq->tq_minalloc   = minalloc;
+       tq->tq_maxalloc   = maxalloc;
+       tq->tq_nalloc     = 0;
+       tq->tq_flags      = (flags | TASKQ_ACTIVE);
+       tq->tq_next_id    = 1;
+       tq->tq_lowest_id  = 1;
+       INIT_LIST_HEAD(&tq->tq_free_list);
+       INIT_LIST_HEAD(&tq->tq_pend_list);
+       INIT_LIST_HEAD(&tq->tq_prio_list);
+       INIT_LIST_HEAD(&tq->tq_delay_list);
+       init_waitqueue_head(&tq->tq_work_waitq);
+       init_waitqueue_head(&tq->tq_wait_waitq);
+
+       if (flags & TASKQ_PREPOPULATE) {
+               spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+               for (i = 0; i < minalloc; i++)
+                       task_done(tq, task_alloc(tq, TQ_PUSHPAGE | TQ_NEW));
+
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+       }
+
+       if ((flags & TASKQ_DYNAMIC) && spl_taskq_thread_dynamic)
+               nthreads = 1;
+
+       for (i = 0; i < nthreads; i++) {
+               tqt = taskq_thread_create(tq);
+               if (tqt == NULL)
+                       rc = 1;
+               else
+                       count++;
+       }
+
+       /* Wait for all threads to be started before potential destroy */
+       wait_event(tq->tq_wait_waitq, tq->tq_nthreads == count);
+       /*
+        * taskq_thread might have touched nspawn, but we don't want them to
+        * because they're not dynamically spawned. So we reset it to 0
+        */
+       tq->tq_nspawn = 0;
+
+       if (rc) {
+               taskq_destroy(tq);
+               tq = NULL;
+       }
+
+       return (tq);
+}
+EXPORT_SYMBOL(taskq_create);
+
+void
+taskq_destroy(taskq_t *tq)
+{
+       struct task_struct *thread;
+       taskq_thread_t *tqt;
+       taskq_ent_t *t;
+
+       ASSERT(tq);
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       tq->tq_flags &= ~TASKQ_ACTIVE;
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       /*
+        * When TASKQ_ACTIVE is clear new tasks may not be added nor may
+        * new worker threads be spawned for dynamic taskq.
+        */
+       if (dynamic_taskq != NULL)
+               taskq_wait_outstanding(dynamic_taskq, 0);
+
+       taskq_wait(tq);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       /* wait for spawning threads to insert themselves to the list */
+       while (tq->tq_nspawn) {
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+               schedule_timeout_interruptible(1);
+               spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       }
+
+       /*
+        * Signal each thread to exit and block until it does.  Each thread
+        * is responsible for removing itself from the list and freeing its
+        * taskq_thread_t.  This allows for idle threads to opt to remove
+        * themselves from the taskq.  They can be recreated as needed.
+        */
+       while (!list_empty(&tq->tq_thread_list)) {
+               tqt = list_entry(tq->tq_thread_list.next,
+                   taskq_thread_t, tqt_thread_list);
+               thread = tqt->tqt_thread;
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+               kthread_stop(thread);
+
+               spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       }
+
+       while (!list_empty(&tq->tq_free_list)) {
+               t = list_entry(tq->tq_free_list.next, taskq_ent_t, tqent_list);
+
+               ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC));
+
+               list_del_init(&t->tqent_list);
+               task_free(tq, t);
+       }
+
+       ASSERT0(tq->tq_nthreads);
+       ASSERT0(tq->tq_nalloc);
+       ASSERT0(tq->tq_nspawn);
+       ASSERT(list_empty(&tq->tq_thread_list));
+       ASSERT(list_empty(&tq->tq_active_list));
+       ASSERT(list_empty(&tq->tq_free_list));
+       ASSERT(list_empty(&tq->tq_pend_list));
+       ASSERT(list_empty(&tq->tq_prio_list));
+       ASSERT(list_empty(&tq->tq_delay_list));
+
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       strfree(tq->tq_name);
+       kmem_free(tq, sizeof (taskq_t));
+}
+EXPORT_SYMBOL(taskq_destroy);
+
+int
+spl_taskq_init(void)
+{
+       system_taskq = taskq_create("spl_system_taskq", MAX(boot_ncpus, 64),
+           maxclsyspri, boot_ncpus, INT_MAX, TASKQ_PREPOPULATE|TASKQ_DYNAMIC);
+       if (system_taskq == NULL)
+               return (1);
+
+       dynamic_taskq = taskq_create("spl_dynamic_taskq", 1,
+           maxclsyspri, boot_ncpus, INT_MAX, TASKQ_PREPOPULATE);
+       if (dynamic_taskq == NULL) {
+               taskq_destroy(system_taskq);
+               return (1);
+       }
+
+       return (0);
+}
+
+void
+spl_taskq_fini(void)
+{
+       taskq_destroy(dynamic_taskq);
+       dynamic_taskq = NULL;
+
+       taskq_destroy(system_taskq);
+       system_taskq = NULL;
+}
diff --git a/spl/module/spl/spl-thread.c b/spl/module/spl/spl-thread.c
new file mode 100644 (file)
index 0000000..b0f4d57
--- /dev/null
@@ -0,0 +1,158 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Thread Implementation.
+\*****************************************************************************/
+
+#include <sys/thread.h>
+#include <sys/kmem.h>
+#include <sys/tsd.h>
+
+/*
+ * Thread interfaces
+ */
+typedef struct thread_priv_s {
+       unsigned long tp_magic;         /* Magic */
+        int tp_name_size;              /* Name size */
+        char *tp_name;                 /* Name (without _thread suffix) */
+       void (*tp_func)(void *);        /* Registered function */
+       void *tp_args;                  /* Args to be passed to function */
+       size_t tp_len;                  /* Len to be passed to function */
+       int tp_state;                   /* State to start thread at */
+       pri_t tp_pri;                   /* Priority to start threat at */
+} thread_priv_t;
+
+static int
+thread_generic_wrapper(void *arg)
+{
+       thread_priv_t *tp = (thread_priv_t *)arg;
+       void (*func)(void *);
+       void *args;
+
+       ASSERT(tp->tp_magic == TP_MAGIC);
+       func = tp->tp_func;
+       args = tp->tp_args;
+       set_current_state(tp->tp_state);
+       set_user_nice((kthread_t *)current, PRIO_TO_NICE(tp->tp_pri));
+       kmem_free(tp->tp_name, tp->tp_name_size);
+       kmem_free(tp, sizeof(thread_priv_t));
+
+       if (func)
+               func(args);
+
+       return 0;
+}
+
+void
+__thread_exit(void)
+{
+       tsd_exit();
+       complete_and_exit(NULL, 0);
+       /* Unreachable */
+}
+EXPORT_SYMBOL(__thread_exit);
+
+/* thread_create() may block forever if it cannot create a thread or
+ * allocate memory.  This is preferable to returning a NULL which Solaris
+ * style callers likely never check for... since it can't fail. */
+kthread_t *
+__thread_create(caddr_t stk, size_t  stksize, thread_func_t func,
+               const char *name, void *args, size_t len, proc_t *pp,
+               int state, pri_t pri)
+{
+       thread_priv_t *tp;
+       struct task_struct *tsk;
+       char *p;
+
+       /* Option pp is simply ignored */
+       /* Variable stack size unsupported */
+       ASSERT(stk == NULL);
+
+       tp = kmem_alloc(sizeof(thread_priv_t), KM_PUSHPAGE);
+       if (tp == NULL)
+               return (NULL);
+
+       tp->tp_magic = TP_MAGIC;
+       tp->tp_name_size = strlen(name) + 1;
+
+       tp->tp_name = kmem_alloc(tp->tp_name_size, KM_PUSHPAGE);
+        if (tp->tp_name == NULL) {
+               kmem_free(tp, sizeof(thread_priv_t));
+               return (NULL);
+       }
+
+       strncpy(tp->tp_name, name, tp->tp_name_size);
+
+       /* Strip trailing "_thread" from passed name which will be the func
+        * name since the exposed API has no parameter for passing a name.
+        */
+       p = strstr(tp->tp_name, "_thread");
+       if (p)
+               p[0] = '\0';
+
+       tp->tp_func  = func;
+       tp->tp_args  = args;
+       tp->tp_len   = len;
+       tp->tp_state = state;
+       tp->tp_pri   = pri;
+
+       tsk = spl_kthread_create(thread_generic_wrapper, (void *)tp,
+                            "%s", tp->tp_name);
+       if (IS_ERR(tsk))
+               return (NULL);
+
+       wake_up_process(tsk);
+       return ((kthread_t *)tsk);
+}
+EXPORT_SYMBOL(__thread_create);
+
+/*
+ * spl_kthread_create - Wrapper providing pre-3.13 semantics for
+ * kthread_create() in which it is not killable and less likely
+ * to return -ENOMEM.
+ */
+struct task_struct *
+spl_kthread_create(int (*func)(void *), void *data, const char namefmt[], ...)
+{
+       struct task_struct *tsk;
+       va_list args;
+       char name[TASK_COMM_LEN];
+
+       va_start(args, namefmt);
+       vsnprintf(name, sizeof(name), namefmt, args);
+       va_end(args);
+       do {
+               tsk = kthread_create(func, data, "%s", name);
+               if (IS_ERR(tsk)) {
+                       if (signal_pending(current)) {
+                               clear_thread_flag(TIF_SIGPENDING);
+                               continue;
+                       }
+                       if (PTR_ERR(tsk) == -ENOMEM)
+                               continue;
+                       return (NULL);
+               } else
+                       return (tsk);
+       } while (1);
+}
+EXPORT_SYMBOL(spl_kthread_create);
diff --git a/spl/module/spl/spl-tsd.c b/spl/module/spl/spl-tsd.c
new file mode 100644 (file)
index 0000000..4d0800e
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ *  Copyright (C) 2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ *  Solaris Porting Layer (SPL) Thread Specific Data Implementation.
+ *
+ *  Thread specific data has implemented using a hash table, this avoids
+ *  the need to add a member to the task structure and allows maximum
+ *  portability between kernels.  This implementation has been optimized
+ *  to keep the tsd_set() and tsd_get() times as small as possible.
+ *
+ *  The majority of the entries in the hash table are for specific tsd
+ *  entries.  These entries are hashed by the product of their key and
+ *  pid because by design the key and pid are guaranteed to be unique.
+ *  Their product also has the desirable properly that it will be uniformly
+ *  distributed over the hash bins providing neither the pid nor key is zero.
+ *  Under linux the zero pid is always the init process and thus won't be
+ *  used, and this implementation is careful to never to assign a zero key.
+ *  By default the hash table is sized to 512 bins which is expected to
+ *  be sufficient for light to moderate usage of thread specific data.
+ *
+ *  The hash table contains two additional type of entries.  They first
+ *  type is entry is called a 'key' entry and it is added to the hash during
+ *  tsd_create().  It is used to store the address of the destructor function
+ *  and it is used as an anchor point.  All tsd entries which use the same
+ *  key will be linked to this entry.  This is used during tsd_destory() to
+ *  quickly call the destructor function for all tsd associated with the key.
+ *  The 'key' entry may be looked up with tsd_hash_search() by passing the
+ *  key you wish to lookup and DTOR_PID constant as the pid.
+ *
+ *  The second type of entry is called a 'pid' entry and it is added to the
+ *  hash the first time a process set a key.  The 'pid' entry is also used
+ *  as an anchor and all tsd for the process will be linked to it.  This
+ *  list is using during tsd_exit() to ensure all registered destructors
+ *  are run for the process.  The 'pid' entry may be looked up with
+ *  tsd_hash_search() by passing the PID_KEY constant as the key, and
+ *  the process pid.  Note that tsd_exit() is called by thread_exit()
+ *  so if your using the Solaris thread API you should not need to call
+ *  tsd_exit() directly.
+ *
+ */
+
+#include <sys/kmem.h>
+#include <sys/thread.h>
+#include <sys/tsd.h>
+#include <linux/hash.h>
+
+typedef struct tsd_hash_bin {
+       spinlock_t              hb_lock;
+       struct hlist_head       hb_head;
+} tsd_hash_bin_t;
+
+typedef struct tsd_hash_table {
+       spinlock_t              ht_lock;
+       uint_t                  ht_bits;
+       uint_t                  ht_key;
+       tsd_hash_bin_t          *ht_bins;
+} tsd_hash_table_t;
+
+typedef struct tsd_hash_entry {
+       uint_t                  he_key;
+       pid_t                   he_pid;
+       dtor_func_t             he_dtor;
+       void                    *he_value;
+       struct hlist_node       he_list;
+       struct list_head        he_key_list;
+       struct list_head        he_pid_list;
+} tsd_hash_entry_t;
+
+static tsd_hash_table_t *tsd_hash_table = NULL;
+
+
+/*
+ * tsd_hash_search - searches hash table for tsd_hash_entry
+ * @table: hash table
+ * @key: search key
+ * @pid: search pid
+ */
+static tsd_hash_entry_t *
+tsd_hash_search(tsd_hash_table_t *table, uint_t key, pid_t pid)
+{
+       struct hlist_node *node;
+       tsd_hash_entry_t *entry;
+       tsd_hash_bin_t *bin;
+       ulong_t hash;
+
+       hash = hash_long((ulong_t)key * (ulong_t)pid, table->ht_bits);
+       bin = &table->ht_bins[hash];
+       spin_lock(&bin->hb_lock);
+       hlist_for_each(node, &bin->hb_head) {
+               entry = list_entry(node, tsd_hash_entry_t, he_list);
+               if ((entry->he_key == key) && (entry->he_pid == pid)) {
+                       spin_unlock(&bin->hb_lock);
+                       return (entry);
+               }
+       }
+
+       spin_unlock(&bin->hb_lock);
+       return (NULL);
+}
+
+/*
+ * tsd_hash_dtor - call the destructor and free all entries on the list
+ * @work: list of hash entries
+ *
+ * For a list of entries which have all already been removed from the
+ * hash call their registered destructor then free the associated memory.
+ */
+static void
+tsd_hash_dtor(struct hlist_head *work)
+{
+       tsd_hash_entry_t *entry;
+
+       while (!hlist_empty(work)) {
+               entry = hlist_entry(work->first, tsd_hash_entry_t, he_list);
+               hlist_del(&entry->he_list);
+
+               if (entry->he_dtor && entry->he_pid != DTOR_PID)
+                       entry->he_dtor(entry->he_value);
+
+               kmem_free(entry, sizeof (tsd_hash_entry_t));
+       }
+}
+
+/*
+ * tsd_hash_add - adds an entry to hash table
+ * @table: hash table
+ * @key: search key
+ * @pid: search pid
+ *
+ * The caller is responsible for ensuring the unique key/pid do not
+ * already exist in the hash table.  This possible because all entries
+ * are thread specific thus a concurrent thread will never attempt to
+ * add this key/pid.  Because multiple bins must be checked to add
+ * links to the dtor and pid entries the entire table is locked.
+ */
+static int
+tsd_hash_add(tsd_hash_table_t *table, uint_t key, pid_t pid, void *value)
+{
+       tsd_hash_entry_t *entry, *dtor_entry, *pid_entry;
+       tsd_hash_bin_t *bin;
+       ulong_t hash;
+       int rc = 0;
+
+       ASSERT3P(tsd_hash_search(table, key, pid), ==, NULL);
+
+       /* New entry allocate structure, set value, and add to hash */
+       entry = kmem_alloc(sizeof (tsd_hash_entry_t), KM_PUSHPAGE);
+       if (entry == NULL)
+               return (ENOMEM);
+
+       entry->he_key = key;
+       entry->he_pid = pid;
+       entry->he_value = value;
+       INIT_HLIST_NODE(&entry->he_list);
+       INIT_LIST_HEAD(&entry->he_key_list);
+       INIT_LIST_HEAD(&entry->he_pid_list);
+
+       spin_lock(&table->ht_lock);
+
+       /* Destructor entry must exist for all valid keys */
+       dtor_entry = tsd_hash_search(table, entry->he_key, DTOR_PID);
+       ASSERT3P(dtor_entry, !=, NULL);
+       entry->he_dtor = dtor_entry->he_dtor;
+
+       /* Process entry must exist for all valid processes */
+       pid_entry = tsd_hash_search(table, PID_KEY, entry->he_pid);
+       ASSERT3P(pid_entry, !=, NULL);
+
+       hash = hash_long((ulong_t)key * (ulong_t)pid, table->ht_bits);
+       bin = &table->ht_bins[hash];
+       spin_lock(&bin->hb_lock);
+
+       /* Add to the hash, key, and pid lists */
+       hlist_add_head(&entry->he_list, &bin->hb_head);
+       list_add(&entry->he_key_list, &dtor_entry->he_key_list);
+       list_add(&entry->he_pid_list, &pid_entry->he_pid_list);
+
+       spin_unlock(&bin->hb_lock);
+       spin_unlock(&table->ht_lock);
+
+       return (rc);
+}
+
+/*
+ * tsd_hash_add_key - adds a destructor entry to the hash table
+ * @table: hash table
+ * @keyp: search key
+ * @dtor: key destructor
+ *
+ * For every unique key there is a single entry in the hash which is used
+ * as anchor.  All other thread specific entries for this key are linked
+ * to this anchor via the 'he_key_list' list head.  On return they keyp
+ * will be set to the next available key for the hash table.
+ */
+static int
+tsd_hash_add_key(tsd_hash_table_t *table, uint_t *keyp, dtor_func_t dtor)
+{
+       tsd_hash_entry_t *tmp_entry, *entry;
+       tsd_hash_bin_t *bin;
+       ulong_t hash;
+       int keys_checked = 0;
+
+       ASSERT3P(table, !=, NULL);
+
+       /* Allocate entry to be used as a destructor for this key */
+       entry = kmem_alloc(sizeof (tsd_hash_entry_t), KM_PUSHPAGE);
+       if (entry == NULL)
+               return (ENOMEM);
+
+       /* Determine next available key value */
+       spin_lock(&table->ht_lock);
+       do {
+               /* Limited to TSD_KEYS_MAX concurrent unique keys */
+               if (table->ht_key++ > TSD_KEYS_MAX)
+                       table->ht_key = 1;
+
+               /* Ensure failure when all TSD_KEYS_MAX keys are in use */
+               if (keys_checked++ >= TSD_KEYS_MAX) {
+                       spin_unlock(&table->ht_lock);
+                       return (ENOENT);
+               }
+
+               tmp_entry = tsd_hash_search(table, table->ht_key, DTOR_PID);
+       } while (tmp_entry);
+
+       /* Add destructor entry in to hash table */
+       entry->he_key = *keyp = table->ht_key;
+       entry->he_pid = DTOR_PID;
+       entry->he_dtor = dtor;
+       entry->he_value = NULL;
+       INIT_HLIST_NODE(&entry->he_list);
+       INIT_LIST_HEAD(&entry->he_key_list);
+       INIT_LIST_HEAD(&entry->he_pid_list);
+
+       hash = hash_long((ulong_t)*keyp * (ulong_t)DTOR_PID, table->ht_bits);
+       bin = &table->ht_bins[hash];
+       spin_lock(&bin->hb_lock);
+
+       hlist_add_head(&entry->he_list, &bin->hb_head);
+
+       spin_unlock(&bin->hb_lock);
+       spin_unlock(&table->ht_lock);
+
+       return (0);
+}
+
+/*
+ * tsd_hash_add_pid - adds a process entry to the hash table
+ * @table: hash table
+ * @pid: search pid
+ *
+ * For every process these is a single entry in the hash which is used
+ * as anchor.  All other thread specific entries for this process are
+ * linked to this anchor via the 'he_pid_list' list head.
+ */
+static int
+tsd_hash_add_pid(tsd_hash_table_t *table, pid_t pid)
+{
+       tsd_hash_entry_t *entry;
+       tsd_hash_bin_t *bin;
+       ulong_t hash;
+
+       /* Allocate entry to be used as the process reference */
+       entry = kmem_alloc(sizeof (tsd_hash_entry_t), KM_PUSHPAGE);
+       if (entry == NULL)
+               return (ENOMEM);
+
+       spin_lock(&table->ht_lock);
+       entry->he_key = PID_KEY;
+       entry->he_pid = pid;
+       entry->he_dtor = NULL;
+       entry->he_value = NULL;
+       INIT_HLIST_NODE(&entry->he_list);
+       INIT_LIST_HEAD(&entry->he_key_list);
+       INIT_LIST_HEAD(&entry->he_pid_list);
+
+       hash = hash_long((ulong_t)PID_KEY * (ulong_t)pid, table->ht_bits);
+       bin = &table->ht_bins[hash];
+       spin_lock(&bin->hb_lock);
+
+       hlist_add_head(&entry->he_list, &bin->hb_head);
+
+       spin_unlock(&bin->hb_lock);
+       spin_unlock(&table->ht_lock);
+
+       return (0);
+}
+
+/*
+ * tsd_hash_del - delete an entry from hash table, key, and pid lists
+ * @table: hash table
+ * @key: search key
+ * @pid: search pid
+ */
+static void
+tsd_hash_del(tsd_hash_table_t *table, tsd_hash_entry_t *entry)
+{
+       ASSERT(spin_is_locked(&table->ht_lock));
+       hlist_del(&entry->he_list);
+       list_del_init(&entry->he_key_list);
+       list_del_init(&entry->he_pid_list);
+}
+
+/*
+ * tsd_hash_table_init - allocate a hash table
+ * @bits: hash table size
+ *
+ * A hash table with 2^bits bins will be created, it may not be resized
+ * after the fact and must be free'd with tsd_hash_table_fini().
+ */
+static tsd_hash_table_t *
+tsd_hash_table_init(uint_t bits)
+{
+       tsd_hash_table_t *table;
+       int hash, size = (1 << bits);
+
+       table = kmem_zalloc(sizeof (tsd_hash_table_t), KM_SLEEP);
+       if (table == NULL)
+               return (NULL);
+
+       table->ht_bins = kmem_zalloc(sizeof (tsd_hash_bin_t) * size, KM_SLEEP);
+       if (table->ht_bins == NULL) {
+               kmem_free(table, sizeof (tsd_hash_table_t));
+               return (NULL);
+       }
+
+       for (hash = 0; hash < size; hash++) {
+               spin_lock_init(&table->ht_bins[hash].hb_lock);
+               INIT_HLIST_HEAD(&table->ht_bins[hash].hb_head);
+       }
+
+       spin_lock_init(&table->ht_lock);
+       table->ht_bits = bits;
+       table->ht_key = 1;
+
+       return (table);
+}
+
+/*
+ * tsd_hash_table_fini - free a hash table
+ * @table: hash table
+ *
+ * Free a hash table allocated by tsd_hash_table_init().  If the hash
+ * table is not empty this function will call the proper destructor for
+ * all remaining entries before freeing the memory used by those entries.
+ */
+static void
+tsd_hash_table_fini(tsd_hash_table_t *table)
+{
+       HLIST_HEAD(work);
+       tsd_hash_bin_t *bin;
+       tsd_hash_entry_t *entry;
+       int size, i;
+
+       ASSERT3P(table, !=, NULL);
+       spin_lock(&table->ht_lock);
+       for (i = 0, size = (1 << table->ht_bits); i < size; i++) {
+               bin = &table->ht_bins[i];
+               spin_lock(&bin->hb_lock);
+               while (!hlist_empty(&bin->hb_head)) {
+                       entry = hlist_entry(bin->hb_head.first,
+                           tsd_hash_entry_t, he_list);
+                       tsd_hash_del(table, entry);
+                       hlist_add_head(&entry->he_list, &work);
+               }
+               spin_unlock(&bin->hb_lock);
+       }
+       spin_unlock(&table->ht_lock);
+
+       tsd_hash_dtor(&work);
+       kmem_free(table->ht_bins, sizeof (tsd_hash_bin_t)*(1<<table->ht_bits));
+       kmem_free(table, sizeof (tsd_hash_table_t));
+}
+
+/*
+ * tsd_remove_entry - remove a tsd entry for this thread
+ * @entry: entry to remove
+ *
+ * Remove the thread specific data @entry for this thread.
+ * If this is the last entry for this thread, also remove the PID entry.
+ */
+static void
+tsd_remove_entry(tsd_hash_entry_t *entry)
+{
+       HLIST_HEAD(work);
+       tsd_hash_table_t *table;
+       tsd_hash_entry_t *pid_entry;
+       tsd_hash_bin_t *pid_entry_bin, *entry_bin;
+       ulong_t hash;
+
+       table = tsd_hash_table;
+       ASSERT3P(table, !=, NULL);
+       ASSERT3P(entry, !=, NULL);
+
+       spin_lock(&table->ht_lock);
+
+       hash = hash_long((ulong_t)entry->he_key *
+           (ulong_t)entry->he_pid, table->ht_bits);
+       entry_bin = &table->ht_bins[hash];
+
+       /* save the possible pid_entry */
+       pid_entry = list_entry(entry->he_pid_list.next, tsd_hash_entry_t,
+           he_pid_list);
+
+       /* remove entry */
+       spin_lock(&entry_bin->hb_lock);
+       tsd_hash_del(table, entry);
+       hlist_add_head(&entry->he_list, &work);
+       spin_unlock(&entry_bin->hb_lock);
+
+       /* if pid_entry is indeed pid_entry, then remove it if it's empty */
+       if (pid_entry->he_key == PID_KEY &&
+           list_empty(&pid_entry->he_pid_list)) {
+               hash = hash_long((ulong_t)pid_entry->he_key *
+                   (ulong_t)pid_entry->he_pid, table->ht_bits);
+               pid_entry_bin = &table->ht_bins[hash];
+
+               spin_lock(&pid_entry_bin->hb_lock);
+               tsd_hash_del(table, pid_entry);
+               hlist_add_head(&pid_entry->he_list, &work);
+               spin_unlock(&pid_entry_bin->hb_lock);
+       }
+
+       spin_unlock(&table->ht_lock);
+
+       tsd_hash_dtor(&work);
+}
+
+/*
+ * tsd_set - set thread specific data
+ * @key: lookup key
+ * @value: value to set
+ *
+ * Caller must prevent racing tsd_create() or tsd_destroy(), protected
+ * from racing tsd_get() or tsd_set() because it is thread specific.
+ * This function has been optimized to be fast for the update case.
+ * When setting the tsd initially it will be slower due to additional
+ * required locking and potential memory allocations.
+ */
+int
+tsd_set(uint_t key, void *value)
+{
+       tsd_hash_table_t *table;
+       tsd_hash_entry_t *entry;
+       pid_t pid;
+       int rc;
+       /* mark remove if value is NULL */
+       boolean_t remove = (value == NULL);
+
+       table = tsd_hash_table;
+       pid = curthread->pid;
+       ASSERT3P(table, !=, NULL);
+
+       if ((key == 0) || (key > TSD_KEYS_MAX))
+               return (EINVAL);
+
+       /* Entry already exists in hash table update value */
+       entry = tsd_hash_search(table, key, pid);
+       if (entry) {
+               entry->he_value = value;
+               /* remove the entry */
+               if (remove)
+                       tsd_remove_entry(entry);
+               return (0);
+       }
+
+       /* don't create entry if value is NULL */
+       if (remove)
+               return (0);
+
+       /* Add a process entry to the hash if not yet exists */
+       entry = tsd_hash_search(table, PID_KEY, pid);
+       if (entry == NULL) {
+               rc = tsd_hash_add_pid(table, pid);
+               if (rc)
+                       return (rc);
+       }
+
+       rc = tsd_hash_add(table, key, pid, value);
+       return (rc);
+}
+EXPORT_SYMBOL(tsd_set);
+
+/*
+ * tsd_get - get thread specific data
+ * @key: lookup key
+ *
+ * Caller must prevent racing tsd_create() or tsd_destroy().  This
+ * implementation is designed to be fast and scalable, it does not
+ * lock the entire table only a single hash bin.
+ */
+void *
+tsd_get(uint_t key)
+{
+       tsd_hash_entry_t *entry;
+
+       ASSERT3P(tsd_hash_table, !=, NULL);
+
+       if ((key == 0) || (key > TSD_KEYS_MAX))
+               return (NULL);
+
+       entry = tsd_hash_search(tsd_hash_table, key, curthread->pid);
+       if (entry == NULL)
+               return (NULL);
+
+       return (entry->he_value);
+}
+EXPORT_SYMBOL(tsd_get);
+
+/*
+ * tsd_create - create thread specific data key
+ * @keyp: lookup key address
+ * @dtor: destructor called during tsd_destroy() or tsd_exit()
+ *
+ * Provided key must be set to 0 or it assumed to be already in use.
+ * The dtor is allowed to be NULL in which case no additional cleanup
+ * for the data is performed during tsd_destroy() or tsd_exit().
+ *
+ * Caller must prevent racing tsd_set() or tsd_get(), this function is
+ * safe from racing tsd_create(), tsd_destroy(), and tsd_exit().
+ */
+void
+tsd_create(uint_t *keyp, dtor_func_t dtor)
+{
+       ASSERT3P(keyp, !=, NULL);
+       if (*keyp)
+               return;
+
+       (void) tsd_hash_add_key(tsd_hash_table, keyp, dtor);
+}
+EXPORT_SYMBOL(tsd_create);
+
+/*
+ * tsd_destroy - destroy thread specific data
+ * @keyp: lookup key address
+ *
+ * Destroys the thread specific data on all threads which use this key.
+ *
+ * Caller must prevent racing tsd_set() or tsd_get(), this function is
+ * safe from racing tsd_create(), tsd_destroy(), and tsd_exit().
+ */
+void
+tsd_destroy(uint_t *keyp)
+{
+       HLIST_HEAD(work);
+       tsd_hash_table_t *table;
+       tsd_hash_entry_t *dtor_entry, *entry;
+       tsd_hash_bin_t *dtor_entry_bin, *entry_bin;
+       ulong_t hash;
+
+       table = tsd_hash_table;
+       ASSERT3P(table, !=, NULL);
+
+       spin_lock(&table->ht_lock);
+       dtor_entry = tsd_hash_search(table, *keyp, DTOR_PID);
+       if (dtor_entry == NULL) {
+               spin_unlock(&table->ht_lock);
+               return;
+       }
+
+       /*
+        * All threads which use this key must be linked off of the
+        * DTOR_PID entry.  They are removed from the hash table and
+        * linked in to a private working list to be destroyed.
+        */
+       while (!list_empty(&dtor_entry->he_key_list)) {
+               entry = list_entry(dtor_entry->he_key_list.next,
+                   tsd_hash_entry_t, he_key_list);
+               ASSERT3U(dtor_entry->he_key, ==, entry->he_key);
+               ASSERT3P(dtor_entry->he_dtor, ==, entry->he_dtor);
+
+               hash = hash_long((ulong_t)entry->he_key *
+                   (ulong_t)entry->he_pid, table->ht_bits);
+               entry_bin = &table->ht_bins[hash];
+
+               spin_lock(&entry_bin->hb_lock);
+               tsd_hash_del(table, entry);
+               hlist_add_head(&entry->he_list, &work);
+               spin_unlock(&entry_bin->hb_lock);
+       }
+
+       hash = hash_long((ulong_t)dtor_entry->he_key *
+           (ulong_t)dtor_entry->he_pid, table->ht_bits);
+       dtor_entry_bin = &table->ht_bins[hash];
+
+       spin_lock(&dtor_entry_bin->hb_lock);
+       tsd_hash_del(table, dtor_entry);
+       hlist_add_head(&dtor_entry->he_list, &work);
+       spin_unlock(&dtor_entry_bin->hb_lock);
+       spin_unlock(&table->ht_lock);
+
+       tsd_hash_dtor(&work);
+       *keyp = 0;
+}
+EXPORT_SYMBOL(tsd_destroy);
+
+/*
+ * tsd_exit - destroys all thread specific data for this thread
+ *
+ * Destroys all the thread specific data for this thread.
+ *
+ * Caller must prevent racing tsd_set() or tsd_get(), this function is
+ * safe from racing tsd_create(), tsd_destroy(), and tsd_exit().
+ */
+void
+tsd_exit(void)
+{
+       HLIST_HEAD(work);
+       tsd_hash_table_t *table;
+       tsd_hash_entry_t *pid_entry, *entry;
+       tsd_hash_bin_t *pid_entry_bin, *entry_bin;
+       ulong_t hash;
+
+       table = tsd_hash_table;
+       ASSERT3P(table, !=, NULL);
+
+       spin_lock(&table->ht_lock);
+       pid_entry = tsd_hash_search(table, PID_KEY, curthread->pid);
+       if (pid_entry == NULL) {
+               spin_unlock(&table->ht_lock);
+               return;
+       }
+
+       /*
+        * All keys associated with this pid must be linked off of the
+        * PID_KEY entry.  They are removed from the hash table and
+        * linked in to a private working list to be destroyed.
+        */
+
+       while (!list_empty(&pid_entry->he_pid_list)) {
+               entry = list_entry(pid_entry->he_pid_list.next,
+                   tsd_hash_entry_t, he_pid_list);
+               ASSERT3U(pid_entry->he_pid, ==, entry->he_pid);
+
+               hash = hash_long((ulong_t)entry->he_key *
+                   (ulong_t)entry->he_pid, table->ht_bits);
+               entry_bin = &table->ht_bins[hash];
+
+               spin_lock(&entry_bin->hb_lock);
+               tsd_hash_del(table, entry);
+               hlist_add_head(&entry->he_list, &work);
+               spin_unlock(&entry_bin->hb_lock);
+       }
+
+       hash = hash_long((ulong_t)pid_entry->he_key *
+           (ulong_t)pid_entry->he_pid, table->ht_bits);
+       pid_entry_bin = &table->ht_bins[hash];
+
+       spin_lock(&pid_entry_bin->hb_lock);
+       tsd_hash_del(table, pid_entry);
+       hlist_add_head(&pid_entry->he_list, &work);
+       spin_unlock(&pid_entry_bin->hb_lock);
+       spin_unlock(&table->ht_lock);
+
+       tsd_hash_dtor(&work);
+}
+EXPORT_SYMBOL(tsd_exit);
+
+int
+spl_tsd_init(void)
+{
+       tsd_hash_table = tsd_hash_table_init(TSD_HASH_TABLE_BITS_DEFAULT);
+       if (tsd_hash_table == NULL)
+               return (1);
+
+       return (0);
+}
+
+void
+spl_tsd_fini(void)
+{
+       tsd_hash_table_fini(tsd_hash_table);
+       tsd_hash_table = NULL;
+}
diff --git a/spl/module/spl/spl-vmem.c b/spl/module/spl/spl-vmem.c
new file mode 100644 (file)
index 0000000..e177988
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/debug.h>
+#include <sys/vmem.h>
+#include <linux/mm_compat.h>
+#include <linux/module.h>
+
+vmem_t *heap_arena = NULL;
+EXPORT_SYMBOL(heap_arena);
+
+vmem_t *zio_alloc_arena = NULL;
+EXPORT_SYMBOL(zio_alloc_arena);
+
+vmem_t *zio_arena = NULL;
+EXPORT_SYMBOL(zio_arena);
+
+size_t
+vmem_size(vmem_t *vmp, int typemask)
+{
+       ASSERT3P(vmp, ==, NULL);
+       ASSERT3S(typemask & VMEM_ALLOC, ==, VMEM_ALLOC);
+       ASSERT3S(typemask & VMEM_FREE, ==, VMEM_FREE);
+
+       return (VMALLOC_TOTAL);
+}
+EXPORT_SYMBOL(vmem_size);
+
+/*
+ * Public vmem_alloc(), vmem_zalloc() and vmem_free() interfaces.
+ */
+void *
+spl_vmem_alloc(size_t size, int flags, const char *func, int line)
+{
+       ASSERT0(flags & ~KM_PUBLIC_MASK);
+
+       flags |= KM_VMEM;
+
+#if !defined(DEBUG_KMEM)
+       return (spl_kmem_alloc_impl(size, flags, NUMA_NO_NODE));
+#elif !defined(DEBUG_KMEM_TRACKING)
+       return (spl_kmem_alloc_debug(size, flags, NUMA_NO_NODE));
+#else
+       return (spl_kmem_alloc_track(size, flags, func, line, NUMA_NO_NODE));
+#endif
+}
+EXPORT_SYMBOL(spl_vmem_alloc);
+
+void *
+spl_vmem_zalloc(size_t size, int flags, const char *func, int line)
+{
+       ASSERT0(flags & ~KM_PUBLIC_MASK);
+
+       flags |= (KM_VMEM | KM_ZERO);
+
+#if !defined(DEBUG_KMEM)
+       return (spl_kmem_alloc_impl(size, flags, NUMA_NO_NODE));
+#elif !defined(DEBUG_KMEM_TRACKING)
+       return (spl_kmem_alloc_debug(size, flags, NUMA_NO_NODE));
+#else
+       return (spl_kmem_alloc_track(size, flags, func, line, NUMA_NO_NODE));
+#endif
+}
+EXPORT_SYMBOL(spl_vmem_zalloc);
+
+void
+spl_vmem_free(const void *buf, size_t size)
+{
+#if !defined(DEBUG_KMEM)
+       return (spl_kmem_free_impl(buf, size));
+#elif !defined(DEBUG_KMEM_TRACKING)
+       return (spl_kmem_free_debug(buf, size));
+#else
+       return (spl_kmem_free_track(buf, size));
+#endif
+}
+EXPORT_SYMBOL(spl_vmem_free);
+
+int
+spl_vmem_init(void)
+{
+       return (0);
+}
+
+void
+spl_vmem_fini(void)
+{
+}
diff --git a/spl/module/spl/spl-vnode.c b/spl/module/spl/spl-vnode.c
new file mode 100644 (file)
index 0000000..f1ebcd2
--- /dev/null
@@ -0,0 +1,909 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Vnode Implementation.
+\*****************************************************************************/
+
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/kmem_cache.h>
+#include <linux/falloc.h>
+#include <linux/file_compat.h>
+
+vnode_t *rootdir = (vnode_t *)0xabcd1234;
+EXPORT_SYMBOL(rootdir);
+
+static spl_kmem_cache_t *vn_cache;
+static spl_kmem_cache_t *vn_file_cache;
+
+static DEFINE_SPINLOCK(vn_file_lock);
+static LIST_HEAD(vn_file_list);
+
+vtype_t
+vn_mode_to_vtype(mode_t mode)
+{
+       if (S_ISREG(mode))
+               return VREG;
+
+       if (S_ISDIR(mode))
+               return VDIR;
+
+       if (S_ISCHR(mode))
+               return VCHR;
+
+       if (S_ISBLK(mode))
+               return VBLK;
+
+       if (S_ISFIFO(mode))
+               return VFIFO;
+
+       if (S_ISLNK(mode))
+               return VLNK;
+
+       if (S_ISSOCK(mode))
+               return VSOCK;
+
+       if (S_ISCHR(mode))
+               return VCHR;
+
+       return VNON;
+} /* vn_mode_to_vtype() */
+EXPORT_SYMBOL(vn_mode_to_vtype);
+
+mode_t
+vn_vtype_to_mode(vtype_t vtype)
+{
+       if (vtype == VREG)
+               return S_IFREG;
+
+       if (vtype == VDIR)
+               return S_IFDIR;
+
+       if (vtype == VCHR)
+               return S_IFCHR;
+
+       if (vtype == VBLK)
+               return S_IFBLK;
+
+       if (vtype == VFIFO)
+               return S_IFIFO;
+
+       if (vtype == VLNK)
+               return S_IFLNK;
+
+       if (vtype == VSOCK)
+               return S_IFSOCK;
+
+       return VNON;
+} /* vn_vtype_to_mode() */
+EXPORT_SYMBOL(vn_vtype_to_mode);
+
+vnode_t *
+vn_alloc(int flag)
+{
+       vnode_t *vp;
+
+       vp = kmem_cache_alloc(vn_cache, flag);
+       if (vp != NULL) {
+               vp->v_file = NULL;
+               vp->v_type = 0;
+       }
+
+       return (vp);
+} /* vn_alloc() */
+EXPORT_SYMBOL(vn_alloc);
+
+void
+vn_free(vnode_t *vp)
+{
+       kmem_cache_free(vn_cache, vp);
+} /* vn_free() */
+EXPORT_SYMBOL(vn_free);
+
+int
+vn_open(const char *path, uio_seg_t seg, int flags, int mode,
+       vnode_t **vpp, int x1, void *x2)
+{
+       struct file *fp;
+       struct kstat stat;
+       int rc, saved_umask = 0;
+       gfp_t saved_gfp;
+       vnode_t *vp;
+
+       ASSERT(flags & (FWRITE | FREAD));
+       ASSERT(seg == UIO_SYSSPACE);
+       ASSERT(vpp);
+       *vpp = NULL;
+
+       if (!(flags & FCREAT) && (flags & FWRITE))
+               flags |= FEXCL;
+
+       /* Note for filp_open() the two low bits must be remapped to mean:
+        * 01 - read-only  -> 00 read-only
+        * 10 - write-only -> 01 write-only
+        * 11 - read-write -> 10 read-write
+        */
+       flags--;
+
+       if (flags & FCREAT)
+               saved_umask = xchg(&current->fs->umask, 0);
+
+       fp = filp_open(path, flags, mode);
+
+       if (flags & FCREAT)
+               (void)xchg(&current->fs->umask, saved_umask);
+
+       if (IS_ERR(fp))
+               return (-PTR_ERR(fp));
+
+#ifdef HAVE_2ARGS_VFS_GETATTR
+       rc = vfs_getattr(&fp->f_path, &stat);
+#else
+       rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
+#endif
+       if (rc) {
+               filp_close(fp, 0);
+               return (-rc);
+       }
+
+       vp = vn_alloc(KM_SLEEP);
+       if (!vp) {
+               filp_close(fp, 0);
+               return (ENOMEM);
+       }
+
+       saved_gfp = mapping_gfp_mask(fp->f_mapping);
+       mapping_set_gfp_mask(fp->f_mapping, saved_gfp & ~(__GFP_IO|__GFP_FS));
+
+       mutex_enter(&vp->v_lock);
+       vp->v_type = vn_mode_to_vtype(stat.mode);
+       vp->v_file = fp;
+       vp->v_gfp_mask = saved_gfp;
+       *vpp = vp;
+       mutex_exit(&vp->v_lock);
+
+       return (0);
+} /* vn_open() */
+EXPORT_SYMBOL(vn_open);
+
+int
+vn_openat(const char *path, uio_seg_t seg, int flags, int mode,
+         vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
+{
+       char *realpath;
+       int len, rc;
+
+       ASSERT(vp == rootdir);
+
+       len = strlen(path) + 2;
+       realpath = kmalloc(len, kmem_flags_convert(KM_SLEEP));
+       if (!realpath)
+               return (ENOMEM);
+
+       (void)snprintf(realpath, len, "/%s", path);
+       rc = vn_open(realpath, seg, flags, mode, vpp, x1, x2);
+       kfree(realpath);
+
+       return (rc);
+} /* vn_openat() */
+EXPORT_SYMBOL(vn_openat);
+
+int
+vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
+       uio_seg_t seg, int ioflag, rlim64_t x2, void *x3, ssize_t *residp)
+{
+       loff_t offset;
+       mm_segment_t saved_fs;
+       struct file *fp;
+       int rc;
+
+       ASSERT(uio == UIO_WRITE || uio == UIO_READ);
+       ASSERT(vp);
+       ASSERT(vp->v_file);
+       ASSERT(seg == UIO_SYSSPACE);
+       ASSERT((ioflag & ~FAPPEND) == 0);
+       ASSERT(x2 == RLIM64_INFINITY);
+
+       fp = vp->v_file;
+
+       offset = off;
+       if (ioflag & FAPPEND)
+               offset = fp->f_pos;
+
+       /* Writable user data segment must be briefly increased for this
+        * process so we can use the user space read call paths to write
+        * in to memory allocated by the kernel. */
+       saved_fs = get_fs();
+        set_fs(get_ds());
+
+       if (uio & UIO_WRITE)
+               rc = vfs_write(fp, addr, len, &offset);
+       else
+               rc = vfs_read(fp, addr, len, &offset);
+
+       set_fs(saved_fs);
+       fp->f_pos = offset;
+
+       if (rc < 0)
+               return (-rc);
+
+       if (residp) {
+               *residp = len - rc;
+       } else {
+               if (rc != len)
+                       return (EIO);
+       }
+
+       return (0);
+} /* vn_rdwr() */
+EXPORT_SYMBOL(vn_rdwr);
+
+int
+vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
+{
+       int rc;
+
+       ASSERT(vp);
+       ASSERT(vp->v_file);
+
+       mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
+       rc = filp_close(vp->v_file, 0);
+       vn_free(vp);
+
+       return (-rc);
+} /* vn_close() */
+EXPORT_SYMBOL(vn_close);
+
+/* vn_seek() does not actually seek it only performs bounds checking on the
+ * proposed seek.  We perform minimal checking and allow vn_rdwr() to catch
+ * anything more serious. */
+int
+vn_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, void *ct)
+{
+       return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
+}
+EXPORT_SYMBOL(vn_seek);
+
+/*
+ * spl_basename() takes a NULL-terminated string s as input containing a path.
+ * It returns a char pointer to a string and a length that describe the
+ * basename of the path. If the basename is not "." or "/", it will be an index
+ * into the string. While the string should be NULL terminated, the section
+ * referring to the basename is not. spl_basename is dual-licensed GPLv2+ and
+ * CC0. Anyone wishing to reuse it in another codebase may pick either license.
+ */
+static void
+spl_basename(const char *s, const char **str, int *len)
+{
+       size_t i, end;
+
+       ASSERT(str);
+       ASSERT(len);
+
+       if (!s || !*s) {
+               *str = ".";
+               *len = 1;
+               return;
+       }
+
+       i = strlen(s) - 1;
+
+       while (i && s[i--] == '/');
+
+       if (i == 0) {
+               *str = "/";
+               *len = 1;
+               return;
+       }
+
+       end = i;
+
+       for (end = i; i; i--) {
+               if (s[i] == '/') {
+                       *str = &s[i+1];
+                       *len = end - i + 1;
+                       return;
+               }
+       }
+
+       *str = s;
+       *len = end + 1;
+}
+
+static struct dentry *
+spl_kern_path_locked(const char *name, struct path *path)
+{
+       struct path parent;
+       struct dentry *dentry;
+       const char *basename;
+       int len;
+       int rc;
+
+       ASSERT(name);
+       ASSERT(path);
+
+       spl_basename(name, &basename, &len);
+
+       /* We do not accept "." or ".." */
+       if (len <= 2 && basename[0] == '.')
+               if (len == 1 || basename[1] == '.')
+                       return (ERR_PTR(-EACCES));
+
+       rc = kern_path(name, LOOKUP_PARENT, &parent);
+       if (rc)
+               return (ERR_PTR(rc));
+
+       /* use I_MUTEX_PARENT because vfs_unlink needs it */
+       spl_inode_lock_nested(parent.dentry->d_inode, I_MUTEX_PARENT);
+
+       dentry = lookup_one_len(basename, parent.dentry, len);
+       if (IS_ERR(dentry)) {
+               spl_inode_unlock(parent.dentry->d_inode);
+               path_put(&parent);
+       } else {
+               *path = parent;
+       }
+
+       return (dentry);
+}
+
+/* Based on do_unlinkat() from linux/fs/namei.c */
+int
+vn_remove(const char *path, uio_seg_t seg, int flags)
+{
+       struct dentry *dentry;
+       struct path parent;
+       struct inode *inode = NULL;
+       int rc = 0;
+
+       ASSERT(seg == UIO_SYSSPACE);
+       ASSERT(flags == RMFILE);
+
+       dentry = spl_kern_path_locked(path, &parent);
+       rc = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               if (parent.dentry->d_name.name[parent.dentry->d_name.len]) {
+                       rc = 0;
+                       goto slashes;
+               }
+
+               inode = dentry->d_inode;
+               if (inode) {
+                       atomic_inc(&inode->i_count);
+               } else {
+                       rc = 0;
+                       goto slashes;
+               }
+
+#ifdef HAVE_2ARGS_VFS_UNLINK
+               rc = vfs_unlink(parent.dentry->d_inode, dentry);
+#else
+               rc = vfs_unlink(parent.dentry->d_inode, dentry, NULL);
+#endif /* HAVE_2ARGS_VFS_UNLINK */
+exit1:
+               dput(dentry);
+       } else {
+               return (-rc);
+       }
+
+       spl_inode_unlock(parent.dentry->d_inode);
+       if (inode)
+               iput(inode);    /* truncate the inode here */
+
+       path_put(&parent);
+       return (-rc);
+
+slashes:
+       rc = !dentry->d_inode ? -ENOENT :
+           S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
+       goto exit1;
+} /* vn_remove() */
+EXPORT_SYMBOL(vn_remove);
+
+/* Based on do_rename() from linux/fs/namei.c */
+int
+vn_rename(const char *oldname, const char *newname, int x1)
+{
+       struct dentry *old_dir, *new_dir;
+       struct dentry *old_dentry, *new_dentry;
+       struct dentry *trap;
+       struct path old_parent, new_parent;
+       int rc = 0;
+
+       old_dentry = spl_kern_path_locked(oldname, &old_parent);
+       if (IS_ERR(old_dentry)) {
+               rc = PTR_ERR(old_dentry);
+               goto exit;
+       }
+
+       spl_inode_unlock(old_parent.dentry->d_inode);
+
+       new_dentry = spl_kern_path_locked(newname, &new_parent);
+       if (IS_ERR(new_dentry)) {
+               rc = PTR_ERR(new_dentry);
+               goto exit2;
+       }
+
+       spl_inode_unlock(new_parent.dentry->d_inode);
+
+       rc = -EXDEV;
+       if (old_parent.mnt != new_parent.mnt)
+               goto exit3;
+
+       old_dir = old_parent.dentry;
+       new_dir = new_parent.dentry;
+       trap = lock_rename(new_dir, old_dir);
+
+       /* source should not be ancestor of target */
+       rc = -EINVAL;
+       if (old_dentry == trap)
+               goto exit4;
+
+       /* target should not be an ancestor of source */
+       rc = -ENOTEMPTY;
+       if (new_dentry == trap)
+               goto exit4;
+
+       /* source must exist */
+       rc = -ENOENT;
+       if (!old_dentry->d_inode)
+               goto exit4;
+
+       /* unless the source is a directory trailing slashes give -ENOTDIR */
+       if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
+               rc = -ENOTDIR;
+               if (old_dentry->d_name.name[old_dentry->d_name.len])
+                       goto exit4;
+               if (new_dentry->d_name.name[new_dentry->d_name.len])
+                       goto exit4;
+       }
+
+#if defined(HAVE_4ARGS_VFS_RENAME)
+       rc = vfs_rename(old_dir->d_inode, old_dentry,
+           new_dir->d_inode, new_dentry);
+#elif defined(HAVE_5ARGS_VFS_RENAME)
+       rc = vfs_rename(old_dir->d_inode, old_dentry,
+           new_dir->d_inode, new_dentry, NULL);
+#else
+       rc = vfs_rename(old_dir->d_inode, old_dentry,
+           new_dir->d_inode, new_dentry, NULL, 0);
+#endif
+exit4:
+       unlock_rename(new_dir, old_dir);
+exit3:
+       dput(new_dentry);
+       path_put(&new_parent);
+exit2:
+       dput(old_dentry);
+       path_put(&old_parent);
+exit:
+       return (-rc);
+}
+EXPORT_SYMBOL(vn_rename);
+
+int
+vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4)
+{
+       struct file *fp;
+       struct kstat stat;
+       int rc;
+
+       ASSERT(vp);
+       ASSERT(vp->v_file);
+       ASSERT(vap);
+
+       fp = vp->v_file;
+
+#ifdef HAVE_2ARGS_VFS_GETATTR
+       rc = vfs_getattr(&fp->f_path, &stat);
+#else
+       rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
+#endif
+       if (rc)
+               return (-rc);
+
+       vap->va_type          = vn_mode_to_vtype(stat.mode);
+       vap->va_mode          = stat.mode;
+       vap->va_uid           = KUID_TO_SUID(stat.uid);
+       vap->va_gid           = KGID_TO_SGID(stat.gid);
+       vap->va_fsid          = 0;
+       vap->va_nodeid        = stat.ino;
+       vap->va_nlink         = stat.nlink;
+        vap->va_size          = stat.size;
+       vap->va_blksize       = stat.blksize;
+       vap->va_atime         = stat.atime;
+       vap->va_mtime         = stat.mtime;
+       vap->va_ctime         = stat.ctime;
+       vap->va_rdev          = stat.rdev;
+       vap->va_nblocks       = stat.blocks;
+
+       return (0);
+}
+EXPORT_SYMBOL(vn_getattr);
+
+int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
+{
+       int datasync = 0;
+       int error;
+       int fstrans;
+
+       ASSERT(vp);
+       ASSERT(vp->v_file);
+
+       if (flags & FDSYNC)
+               datasync = 1;
+
+       /*
+        * May enter XFS which generates a warning when PF_FSTRANS is set.
+        * To avoid this the flag is cleared over vfs_sync() and then reset.
+        */
+       fstrans = spl_fstrans_check();
+       if (fstrans)
+               current->flags &= ~(PF_FSTRANS);
+
+       error = -spl_filp_fsync(vp->v_file, datasync);
+       if (fstrans)
+               current->flags |= PF_FSTRANS;
+
+       return (error);
+} /* vn_fsync() */
+EXPORT_SYMBOL(vn_fsync);
+
+int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
+    offset_t offset, void *x6, void *x7)
+{
+       int error = EOPNOTSUPP;
+
+       if (cmd != F_FREESP || bfp->l_whence != 0)
+               return (EOPNOTSUPP);
+
+       ASSERT(vp);
+       ASSERT(vp->v_file);
+       ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
+
+#ifdef FALLOC_FL_PUNCH_HOLE
+       /*
+        * When supported by the underlying file system preferentially
+        * use the fallocate() callback to preallocate the space.
+        */
+       error = -spl_filp_fallocate(vp->v_file,
+           FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+           bfp->l_start, bfp->l_len);
+       if (error == 0)
+               return (0);
+#endif
+
+#ifdef HAVE_INODE_TRUNCATE_RANGE
+       if (vp->v_file->f_dentry && vp->v_file->f_dentry->d_inode &&
+           vp->v_file->f_dentry->d_inode->i_op &&
+           vp->v_file->f_dentry->d_inode->i_op->truncate_range) {
+               off_t end = bfp->l_start + bfp->l_len;
+               /*
+                * Judging from the code in shmem_truncate_range(),
+                * it seems the kernel expects the end offset to be
+                * inclusive and aligned to the end of a page.
+                */
+               if (end % PAGE_SIZE != 0) {
+                       end &= ~(off_t)(PAGE_SIZE - 1);
+                       if (end <= bfp->l_start)
+                               return (0);
+               }
+               --end;
+
+               vp->v_file->f_dentry->d_inode->i_op->truncate_range(
+                       vp->v_file->f_dentry->d_inode,
+                       bfp->l_start, end
+               );
+               return (0);
+       }
+#endif
+
+       return (error);
+}
+EXPORT_SYMBOL(vn_space);
+
+/* Function must be called while holding the vn_file_lock */
+static file_t *
+file_find(int fd, struct task_struct *task)
+{
+        file_t *fp;
+
+       ASSERT(spin_is_locked(&vn_file_lock));
+
+        list_for_each_entry(fp, &vn_file_list,  f_list) {
+               if (fd == fp->f_fd && fp->f_task == task) {
+                       ASSERT(atomic_read(&fp->f_ref) != 0);
+                        return fp;
+               }
+       }
+
+        return NULL;
+} /* file_find() */
+
+file_t *
+vn_getf(int fd)
+{
+        struct kstat stat;
+       struct file *lfp;
+       file_t *fp;
+       vnode_t *vp;
+       int rc = 0;
+
+       if (fd < 0)
+               return (NULL);
+
+       /* Already open just take an extra reference */
+       spin_lock(&vn_file_lock);
+
+       fp = file_find(fd, current);
+       if (fp) {
+               atomic_inc(&fp->f_ref);
+               spin_unlock(&vn_file_lock);
+               return (fp);
+       }
+
+       spin_unlock(&vn_file_lock);
+
+       /* File was not yet opened create the object and setup */
+       fp = kmem_cache_alloc(vn_file_cache, KM_SLEEP);
+       if (fp == NULL)
+               goto out;
+
+       mutex_enter(&fp->f_lock);
+
+       fp->f_fd = fd;
+       fp->f_task = current;
+       fp->f_offset = 0;
+       atomic_inc(&fp->f_ref);
+
+       lfp = fget(fd);
+       if (lfp == NULL)
+               goto out_mutex;
+
+       vp = vn_alloc(KM_SLEEP);
+       if (vp == NULL)
+               goto out_fget;
+
+#ifdef HAVE_2ARGS_VFS_GETATTR
+       rc = vfs_getattr(&lfp->f_path, &stat);
+#else
+       rc = vfs_getattr(lfp->f_path.mnt, lfp->f_dentry, &stat);
+#endif
+        if (rc)
+               goto out_vnode;
+
+       mutex_enter(&vp->v_lock);
+       vp->v_type = vn_mode_to_vtype(stat.mode);
+       vp->v_file = lfp;
+       mutex_exit(&vp->v_lock);
+
+       fp->f_vnode = vp;
+       fp->f_file = lfp;
+
+       /* Put it on the tracking list */
+       spin_lock(&vn_file_lock);
+       list_add(&fp->f_list, &vn_file_list);
+       spin_unlock(&vn_file_lock);
+
+       mutex_exit(&fp->f_lock);
+       return (fp);
+
+out_vnode:
+       vn_free(vp);
+out_fget:
+       fput(lfp);
+out_mutex:
+       mutex_exit(&fp->f_lock);
+       kmem_cache_free(vn_file_cache, fp);
+out:
+        return (NULL);
+} /* getf() */
+EXPORT_SYMBOL(getf);
+
+static void releasef_locked(file_t *fp)
+{
+       ASSERT(fp->f_file);
+       ASSERT(fp->f_vnode);
+
+       /* Unlinked from list, no refs, safe to free outside mutex */
+       fput(fp->f_file);
+       vn_free(fp->f_vnode);
+
+       kmem_cache_free(vn_file_cache, fp);
+}
+
+void
+vn_releasef(int fd)
+{
+       areleasef(fd, P_FINFO(current));
+}
+EXPORT_SYMBOL(releasef);
+
+void
+vn_areleasef(int fd, uf_info_t *fip)
+{
+       file_t *fp;
+       struct task_struct *task = (struct task_struct *)fip;
+
+       if (fd < 0)
+               return;
+
+       spin_lock(&vn_file_lock);
+       fp = file_find(fd, task);
+       if (fp) {
+               atomic_dec(&fp->f_ref);
+               if (atomic_read(&fp->f_ref) > 0) {
+                       spin_unlock(&vn_file_lock);
+                       return;
+               }
+
+               list_del(&fp->f_list);
+               releasef_locked(fp);
+       }
+       spin_unlock(&vn_file_lock);
+
+       return;
+} /* releasef() */
+EXPORT_SYMBOL(areleasef);
+
+
+static void
+#ifdef HAVE_SET_FS_PWD_WITH_CONST
+vn_set_fs_pwd(struct fs_struct *fs, const struct path *path)
+#else
+vn_set_fs_pwd(struct fs_struct *fs, struct path *path)
+#endif /* HAVE_SET_FS_PWD_WITH_CONST */
+{
+       struct path old_pwd;
+
+#ifdef HAVE_FS_STRUCT_SPINLOCK
+       spin_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       fs->pwd = *path;
+       path_get(path);
+       spin_unlock(&fs->lock);
+#else
+       write_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       fs->pwd = *path;
+       path_get(path);
+       write_unlock(&fs->lock);
+#endif /* HAVE_FS_STRUCT_SPINLOCK */
+
+       if (old_pwd.dentry)
+               path_put(&old_pwd);
+}
+
+int
+vn_set_pwd(const char *filename)
+{
+        struct path path;
+        mm_segment_t saved_fs;
+        int rc;
+
+        /*
+         * user_path_dir() and __user_walk() both expect 'filename' to be
+         * a user space address so we must briefly increase the data segment
+         * size to ensure strncpy_from_user() does not fail with -EFAULT.
+         */
+        saved_fs = get_fs();
+        set_fs(get_ds());
+
+        rc = user_path_dir(filename, &path);
+        if (rc)
+               goto out;
+
+        rc = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+        if (rc)
+               goto dput_and_out;
+
+        vn_set_fs_pwd(current->fs, &path);
+
+dput_and_out:
+        path_put(&path);
+out:
+       set_fs(saved_fs);
+
+        return (-rc);
+} /* vn_set_pwd() */
+EXPORT_SYMBOL(vn_set_pwd);
+
+static int
+vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+       struct vnode *vp = buf;
+
+       mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       return (0);
+} /* vn_cache_constructor() */
+
+static void
+vn_cache_destructor(void *buf, void *cdrarg)
+{
+       struct vnode *vp = buf;
+
+       mutex_destroy(&vp->v_lock);
+} /* vn_cache_destructor() */
+
+static int
+vn_file_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+       file_t *fp = buf;
+
+       atomic_set(&fp->f_ref, 0);
+        mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
+       INIT_LIST_HEAD(&fp->f_list);
+
+        return (0);
+} /* file_cache_constructor() */
+
+static void
+vn_file_cache_destructor(void *buf, void *cdrarg)
+{
+       file_t *fp = buf;
+
+       mutex_destroy(&fp->f_lock);
+} /* vn_file_cache_destructor() */
+
+int
+spl_vn_init(void)
+{
+       vn_cache = kmem_cache_create("spl_vn_cache",
+                                    sizeof(struct vnode), 64,
+                                    vn_cache_constructor,
+                                    vn_cache_destructor,
+                                    NULL, NULL, NULL, 0);
+
+       vn_file_cache = kmem_cache_create("spl_vn_file_cache",
+                                         sizeof(file_t), 64,
+                                         vn_file_cache_constructor,
+                                         vn_file_cache_destructor,
+                                         NULL, NULL, NULL, 0);
+       return (0);
+} /* vn_init() */
+
+void
+spl_vn_fini(void)
+{
+        file_t *fp, *next_fp;
+       int leaked = 0;
+
+       spin_lock(&vn_file_lock);
+
+        list_for_each_entry_safe(fp, next_fp, &vn_file_list,  f_list) {
+               list_del(&fp->f_list);
+               releasef_locked(fp);
+               leaked++;
+       }
+
+       spin_unlock(&vn_file_lock);
+
+       if (leaked > 0)
+               printk(KERN_WARNING "WARNING: %d vnode files leaked\n", leaked);
+
+       kmem_cache_destroy(vn_file_cache);
+       kmem_cache_destroy(vn_cache);
+
+       return;
+} /* vn_fini() */
diff --git a/spl/module/spl/spl-xdr.c b/spl/module/spl/spl-xdr.c
new file mode 100644 (file)
index 0000000..9405dc8
--- /dev/null
@@ -0,0 +1,514 @@
+/*****************************************************************************\
+ *  Copyright (c) 2008-2010 Sun Microsystems, Inc.
+ *  Written by Ricardo Correia <Ricardo.M.Correia@Sun.COM>
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) XDR Implementation.
+\*****************************************************************************/
+
+#include <linux/string.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/types.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/*
+ * SPL's XDR mem implementation.
+ *
+ * This is used by libnvpair to serialize/deserialize the name-value pair data
+ * structures into byte arrays in a well-defined and portable manner.
+ *
+ * These data structures are used by the DMU/ZFS to flexibly manipulate various
+ * information in memory and later serialize it/deserialize it to disk.
+ * Examples of usages include the pool configuration, lists of pool and dataset
+ * properties, etc.
+ *
+ * Reference documentation for the XDR representation and XDR operations can be
+ * found in RFC 1832 and xdr(3), respectively.
+ *
+ * ===  Implementation shortcomings ===
+ *
+ * It is assumed that the following C types have the following sizes:
+ *
+ * char/unsigned char:      1 byte
+ * short/unsigned short:    2 bytes
+ * int/unsigned int:        4 bytes
+ * longlong_t/u_longlong_t: 8 bytes
+ *
+ * The C standard allows these types to be larger (and in the case of ints,
+ * shorter), so if that is the case on some compiler/architecture, the build
+ * will fail (on purpose).
+ *
+ * If someone wants to fix the code to work properly on such environments, then:
+ *
+ * 1) Preconditions should be added to xdrmem_enc functions to make sure the
+ *    caller doesn't pass arguments which exceed the expected range.
+ * 2) Functions which take signed integers should be changed to properly do
+ *    sign extension.
+ * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
+ *    problems than this implementation.
+ *
+ * It is also assumed that:
+ *
+ * 1) Chars have 8 bits.
+ * 2) We can always do 32-bit-aligned int memory accesses and byte-aligned
+ *    memcpy, memset and memcmp.
+ * 3) Arrays passed to xdr_array() are packed and the compiler/architecture
+ *    supports element-sized-aligned memory accesses.
+ * 4) Negative integers are natively stored in two's complement binary
+ *    representation.
+ *
+ * No checks are done for the 4 assumptions above, though.
+ *
+ * === Caller expectations ===
+ *
+ * Existing documentation does not describe the semantics of XDR operations very
+ * well.  Therefore, some assumptions about failure semantics will be made and
+ * will be described below:
+ *
+ * 1) If any encoding operation fails (e.g., due to lack of buffer space), the
+ * the stream should be considered valid only up to the encoding operation
+ * previous to the one that first failed. However, the stream size as returned
+ * by xdr_control() cannot be considered to be strictly correct (it may be
+ * bigger).
+ *
+ * Putting it another way, if there is an encoding failure it's undefined
+ * whether anything is added to the stream in that operation and therefore
+ * neither xdr_control() nor future encoding operations on the same stream can
+ * be relied upon to produce correct results.
+ *
+ * 2) If a decoding operation fails, it's undefined whether anything will be
+ * decoded into passed buffers/pointers during that operation, or what the
+ * values on those buffers will look like.
+ *
+ * Future decoding operations on the same stream will also have similar
+ * undefined behavior.
+ *
+ * 3) When the first decoding operation fails it is OK to trust the results of
+ * previous decoding operations on the same stream, as long as the caller
+ * expects a failure to be possible (e.g. due to end-of-stream).
+ *
+ * However, this is highly discouraged because the caller should know the
+ * stream size and should be coded to expect any decoding failure to be data
+ * corruption due to hardware, accidental or even malicious causes, which should
+ * be handled gracefully in all cases.
+ *
+ * In very rare situations where there are strong reasons to believe the data
+ * can be trusted to be valid and non-tampered with, then the caller may assume
+ * a decoding failure to be a bug (e.g. due to mismatched data types) and may
+ * fail non-gracefully.
+ *
+ * 4) Non-zero padding bytes will cause the decoding operation to fail.
+ *
+ * 5) Zero bytes on string types will also cause the decoding operation to fail.
+ *
+ * 6) It is assumed that either the pointer to the stream buffer given by the
+ * caller is 32-bit aligned or the architecture supports non-32-bit-aligned int
+ * memory accesses.
+ *
+ * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
+ *
+ * 8) If a caller passes pointers to non-kernel memory (e.g., pointers to user
+ * space or MMIO space), the computer may explode.
+ */
+
+static struct xdr_ops xdrmem_encode_ops;
+static struct xdr_ops xdrmem_decode_ops;
+
+void
+xdrmem_create(XDR *xdrs, const caddr_t addr, const uint_t size,
+    const enum xdr_op op)
+{
+       switch (op) {
+               case XDR_ENCODE:
+                       xdrs->x_ops = &xdrmem_encode_ops;
+                       break;
+               case XDR_DECODE:
+                       xdrs->x_ops = &xdrmem_decode_ops;
+                       break;
+               default:
+                       xdrs->x_ops = NULL; /* Let the caller know we failed */
+                       return;
+       }
+
+       xdrs->x_op = op;
+       xdrs->x_addr = addr;
+       xdrs->x_addr_end = addr + size;
+
+       if (xdrs->x_addr_end < xdrs->x_addr) {
+               xdrs->x_ops = NULL;
+       }
+}
+EXPORT_SYMBOL(xdrmem_create);
+
+static bool_t
+xdrmem_control(XDR *xdrs, int req, void *info)
+{
+       struct xdr_bytesrec *rec = (struct xdr_bytesrec *) info;
+
+       if (req != XDR_GET_BYTES_AVAIL)
+               return FALSE;
+
+       rec->xc_is_last_record = TRUE; /* always TRUE in xdrmem streams */
+       rec->xc_num_avail = xdrs->x_addr_end - xdrs->x_addr;
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_enc_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
+{
+       uint_t size = roundup(cnt, 4);
+       uint_t pad;
+
+       if (size < cnt)
+               return FALSE; /* Integer overflow */
+
+       if (xdrs->x_addr > xdrs->x_addr_end)
+               return FALSE;
+
+       if (xdrs->x_addr_end - xdrs->x_addr < size)
+               return FALSE;
+
+       memcpy(xdrs->x_addr, cp, cnt);
+
+       xdrs->x_addr += cnt;
+
+       pad = size - cnt;
+       if (pad > 0) {
+               memset(xdrs->x_addr, 0, pad);
+               xdrs->x_addr += pad;
+       }
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_dec_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
+{
+       static uint32_t zero = 0;
+       uint_t size = roundup(cnt, 4);
+       uint_t pad;
+
+       if (size < cnt)
+               return FALSE; /* Integer overflow */
+
+       if (xdrs->x_addr > xdrs->x_addr_end)
+               return FALSE;
+
+       if (xdrs->x_addr_end - xdrs->x_addr < size)
+               return FALSE;
+
+       memcpy(cp, xdrs->x_addr, cnt);
+       xdrs->x_addr += cnt;
+
+       pad = size - cnt;
+       if (pad > 0) {
+               /* An inverted memchr() would be useful here... */
+               if (memcmp(&zero, xdrs->x_addr, pad) != 0)
+                       return FALSE;
+
+               xdrs->x_addr += pad;
+       }
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_enc_uint32(XDR *xdrs, uint32_t val)
+{
+       if (xdrs->x_addr + sizeof(uint32_t) > xdrs->x_addr_end)
+               return FALSE;
+
+       *((uint32_t *) xdrs->x_addr) = cpu_to_be32(val);
+
+       xdrs->x_addr += sizeof(uint32_t);
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_dec_uint32(XDR *xdrs, uint32_t *val)
+{
+       if (xdrs->x_addr + sizeof(uint32_t) > xdrs->x_addr_end)
+               return FALSE;
+
+       *val = be32_to_cpu(*((uint32_t *) xdrs->x_addr));
+
+       xdrs->x_addr += sizeof(uint32_t);
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_enc_char(XDR *xdrs, char *cp)
+{
+       uint32_t val;
+
+       BUILD_BUG_ON(sizeof(char) != 1);
+       val = *((unsigned char *) cp);
+
+       return xdrmem_enc_uint32(xdrs, val);
+}
+
+static bool_t
+xdrmem_dec_char(XDR *xdrs, char *cp)
+{
+       uint32_t val;
+
+       BUILD_BUG_ON(sizeof(char) != 1);
+
+       if (!xdrmem_dec_uint32(xdrs, &val))
+               return FALSE;
+
+       /*
+        * If any of the 3 other bytes are non-zero then val will be greater
+        * than 0xff and we fail because according to the RFC, this block does
+        * not have a char encoded in it.
+        */
+       if (val > 0xff)
+               return FALSE;
+
+       *((unsigned char *) cp) = val;
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_enc_ushort(XDR *xdrs, unsigned short *usp)
+{
+       BUILD_BUG_ON(sizeof(unsigned short) != 2);
+
+       return xdrmem_enc_uint32(xdrs, *usp);
+}
+
+static bool_t
+xdrmem_dec_ushort(XDR *xdrs, unsigned short *usp)
+{
+       uint32_t val;
+
+       BUILD_BUG_ON(sizeof(unsigned short) != 2);
+
+       if (!xdrmem_dec_uint32(xdrs, &val))
+               return FALSE;
+
+       /*
+        * Short ints are not in the RFC, but we assume similar logic as in
+        * xdrmem_dec_char().
+        */
+       if (val > 0xffff)
+               return FALSE;
+
+       *usp = val;
+
+       return TRUE;
+}
+
+static bool_t
+xdrmem_enc_uint(XDR *xdrs, unsigned *up)
+{
+       BUILD_BUG_ON(sizeof(unsigned) != 4);
+
+       return xdrmem_enc_uint32(xdrs, *up);
+}
+
+static bool_t
+xdrmem_dec_uint(XDR *xdrs, unsigned *up)
+{
+       BUILD_BUG_ON(sizeof(unsigned) != 4);
+
+       return xdrmem_dec_uint32(xdrs, (uint32_t *) up);
+}
+
+static bool_t
+xdrmem_enc_ulonglong(XDR *xdrs, u_longlong_t *ullp)
+{
+       BUILD_BUG_ON(sizeof(u_longlong_t) != 8);
+
+       if (!xdrmem_enc_uint32(xdrs, *ullp >> 32))
+               return FALSE;
+
+       return xdrmem_enc_uint32(xdrs, *ullp & 0xffffffff);
+}
+
+static bool_t
+xdrmem_dec_ulonglong(XDR *xdrs, u_longlong_t *ullp)
+{
+       uint32_t low, high;
+
+       BUILD_BUG_ON(sizeof(u_longlong_t) != 8);
+
+       if (!xdrmem_dec_uint32(xdrs, &high))
+               return FALSE;
+       if (!xdrmem_dec_uint32(xdrs, &low))
+               return FALSE;
+
+       *ullp = ((u_longlong_t) high << 32) | low;
+
+       return TRUE;
+}
+
+static bool_t
+xdr_enc_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
+    const uint_t elsize, const xdrproc_t elproc)
+{
+       uint_t i;
+       caddr_t addr = *arrp;
+
+       if (*sizep > maxsize || *sizep > UINT_MAX / elsize)
+               return FALSE;
+
+       if (!xdrmem_enc_uint(xdrs, sizep))
+               return FALSE;
+
+       for (i = 0; i < *sizep; i++) {
+               if (!elproc(xdrs, addr))
+                       return FALSE;
+               addr += elsize;
+       }
+
+       return TRUE;
+}
+
+static bool_t
+xdr_dec_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
+    const uint_t elsize, const xdrproc_t elproc)
+{
+       uint_t i, size;
+       bool_t alloc = FALSE;
+       caddr_t addr;
+
+       if (!xdrmem_dec_uint(xdrs, sizep))
+               return FALSE;
+
+       size = *sizep;
+
+       if (size > maxsize || size > UINT_MAX / elsize)
+               return FALSE;
+
+       /*
+        * The Solaris man page says: "If *arrp is NULL when decoding,
+        * xdr_array() allocates memory and *arrp points to it".
+        */
+       if (*arrp == NULL) {
+               BUILD_BUG_ON(sizeof(uint_t) > sizeof(size_t));
+
+               *arrp = kmem_alloc(size * elsize, KM_NOSLEEP);
+               if (*arrp == NULL)
+                       return FALSE;
+
+               alloc = TRUE;
+       }
+
+       addr = *arrp;
+
+       for (i = 0; i < size; i++) {
+               if (!elproc(xdrs, addr)) {
+                       if (alloc)
+                               kmem_free(*arrp, size * elsize);
+                       return FALSE;
+               }
+               addr += elsize;
+       }
+
+       return TRUE;
+}
+
+static bool_t
+xdr_enc_string(XDR *xdrs, char **sp, const uint_t maxsize)
+{
+       size_t slen = strlen(*sp);
+       uint_t len;
+
+       if (slen > maxsize)
+               return FALSE;
+
+       len = slen;
+
+       if (!xdrmem_enc_uint(xdrs, &len))
+               return FALSE;
+
+       return xdrmem_enc_bytes(xdrs, *sp, len);
+}
+
+static bool_t
+xdr_dec_string(XDR *xdrs, char **sp, const uint_t maxsize)
+{
+       uint_t size;
+       bool_t alloc = FALSE;
+
+       if (!xdrmem_dec_uint(xdrs, &size))
+               return FALSE;
+
+       if (size > maxsize || size > UINT_MAX - 1)
+               return FALSE;
+
+       /*
+        * Solaris man page: "If *sp is NULL when decoding, xdr_string()
+        * allocates memory and *sp points to it".
+        */
+       if (*sp == NULL) {
+               BUILD_BUG_ON(sizeof(uint_t) > sizeof(size_t));
+
+               *sp = kmem_alloc(size + 1, KM_NOSLEEP);
+               if (*sp == NULL)
+                       return FALSE;
+
+               alloc = TRUE;
+       }
+
+       if (!xdrmem_dec_bytes(xdrs, *sp, size))
+               goto fail;
+
+       if (memchr(*sp, 0, size) != NULL)
+               goto fail;
+
+       (*sp)[size] = '\0';
+
+       return TRUE;
+
+fail:
+       if (alloc)
+               kmem_free(*sp, size + 1);
+
+       return FALSE;
+}
+
+static struct xdr_ops xdrmem_encode_ops = {
+       .xdr_control      = xdrmem_control,
+       .xdr_char         = xdrmem_enc_char,
+       .xdr_u_short      = xdrmem_enc_ushort,
+       .xdr_u_int        = xdrmem_enc_uint,
+       .xdr_u_longlong_t = xdrmem_enc_ulonglong,
+       .xdr_opaque       = xdrmem_enc_bytes,
+       .xdr_string       = xdr_enc_string,
+       .xdr_array        = xdr_enc_array
+};
+
+static struct xdr_ops xdrmem_decode_ops = {
+       .xdr_control      = xdrmem_control,
+       .xdr_char         = xdrmem_dec_char,
+       .xdr_u_short      = xdrmem_dec_ushort,
+       .xdr_u_int        = xdrmem_dec_uint,
+       .xdr_u_longlong_t = xdrmem_dec_ulonglong,
+       .xdr_opaque       = xdrmem_dec_bytes,
+       .xdr_string       = xdr_dec_string,
+       .xdr_array        = xdr_dec_array
+};
+
diff --git a/spl/module/spl/spl-zlib.c b/spl/module/spl/spl-zlib.c
new file mode 100644 (file)
index 0000000..77c2a1d
--- /dev/null
@@ -0,0 +1,217 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  z_compress_level/z_uncompress are nearly identical copies of the
+ *  compress2/uncompress functions provided by the official zlib package
+ *  available at http://zlib.net/.  The only changes made we to slightly
+ *  adapt the functions called to match the linux kernel implementation
+ *  of zlib.  The full zlib license follows:
+ *
+ *  zlib.h -- interface of the 'zlib' general purpose compression library
+ *  version 1.2.5, April 19th, 2010
+ *
+ *  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty.  In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  1. The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  2. Altered source versions must be plainly marked as such, and must not be
+ *     misrepresented as being the original software.
+ *  3. This notice may not be removed or altered from any source distribution.
+ *
+ *  Jean-loup Gailly
+ *  Mark Adler
+\*****************************************************************************/
+
+
+#include <sys/kmem.h>
+#include <sys/kmem_cache.h>
+#include <sys/zmod.h>
+#include <linux/zlib_compat.h>
+
+static spl_kmem_cache_t *zlib_workspace_cache;
+
+/*
+ * A kmem_cache is used for the zlib workspaces to avoid having to vmalloc
+ * and vfree for every call.  Using a kmem_cache also has the advantage
+ * that improves the odds that the memory used will be local to this cpu.
+ * To further improve things it might be wise to create a dedicated per-cpu
+ * workspace for use.  This would take some additional care because we then
+ * must disable preemption around the critical section, and verify that
+ * zlib_deflate* and zlib_inflate* never internally call schedule().
+ */
+static void *
+zlib_workspace_alloc(int flags)
+{
+       return kmem_cache_alloc(zlib_workspace_cache, flags & ~(__GFP_FS));
+}
+
+static void
+zlib_workspace_free(void *workspace)
+{
+       kmem_cache_free(zlib_workspace_cache, workspace);
+}
+
+/*
+ * Compresses the source buffer into the destination buffer. The level
+ * parameter has the same meaning as in deflateInit.  sourceLen is the byte
+ * length of the source buffer. Upon entry, destLen is the total size of the
+ * destination buffer, which must be at least 0.1% larger than sourceLen plus
+ * 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+ *
+ * compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ * memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ * Z_STREAM_ERROR if the level parameter is invalid.
+ */
+int
+z_compress_level(void *dest, size_t *destLen, const void *source,
+                 size_t sourceLen, int level)
+{
+       z_stream stream;
+       int err;
+
+       stream.next_in = (Byte *)source;
+       stream.avail_in = (uInt)sourceLen;
+       stream.next_out = dest;
+       stream.avail_out = (uInt)*destLen;
+
+       if ((size_t)stream.avail_out != *destLen)
+               return Z_BUF_ERROR;
+
+       stream.workspace = zlib_workspace_alloc(KM_SLEEP);
+       if (!stream.workspace)
+               return Z_MEM_ERROR;
+
+       err = zlib_deflateInit(&stream, level);
+       if (err != Z_OK) {
+               zlib_workspace_free(stream.workspace);
+               return err;
+       }
+
+       err = zlib_deflate(&stream, Z_FINISH);
+       if (err != Z_STREAM_END) {
+               zlib_deflateEnd(&stream);
+               zlib_workspace_free(stream.workspace);
+               return err == Z_OK ? Z_BUF_ERROR : err;
+       }
+       *destLen = stream.total_out;
+
+       err = zlib_deflateEnd(&stream);
+       zlib_workspace_free(stream.workspace);
+
+       return err;
+}
+EXPORT_SYMBOL(z_compress_level);
+
+/*
+ * Decompresses the source buffer into the destination buffer.  sourceLen is
+ * the byte length of the source buffer. Upon entry, destLen is the total
+ * size of the destination buffer, which must be large enough to hold the
+ * entire uncompressed data. (The size of the uncompressed data must have
+ * been saved previously by the compressor and transmitted to the decompressor
+ * by some mechanism outside the scope of this compression library.)
+ * Upon exit, destLen is the actual size of the compressed buffer.
+ * This function can be used to decompress a whole file at once if the
+ * input file is mmap'ed.
+ *
+ * uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ * enough memory, Z_BUF_ERROR if there was not enough room in the output
+ * buffer, or Z_DATA_ERROR if the input data was corrupted.
+ */
+int
+z_uncompress(void *dest, size_t *destLen, const void *source, size_t sourceLen)
+{
+       z_stream stream;
+       int err;
+
+       stream.next_in = (Byte *)source;
+       stream.avail_in = (uInt)sourceLen;
+       stream.next_out = dest;
+       stream.avail_out = (uInt)*destLen;
+
+       if ((size_t)stream.avail_out != *destLen)
+               return Z_BUF_ERROR;
+
+       stream.workspace = zlib_workspace_alloc(KM_SLEEP);
+       if (!stream.workspace)
+               return Z_MEM_ERROR;
+
+       err = zlib_inflateInit(&stream);
+       if (err != Z_OK) {
+               zlib_workspace_free(stream.workspace);
+               return err;
+       }
+
+       err = zlib_inflate(&stream, Z_FINISH);
+       if (err != Z_STREAM_END) {
+               zlib_inflateEnd(&stream);
+               zlib_workspace_free(stream.workspace);
+
+               if (err == Z_NEED_DICT ||
+                  (err == Z_BUF_ERROR && stream.avail_in == 0))
+                       return Z_DATA_ERROR;
+
+               return err;
+       }
+       *destLen = stream.total_out;
+
+       err = zlib_inflateEnd(&stream);
+       zlib_workspace_free(stream.workspace);
+
+       return err;
+}
+EXPORT_SYMBOL(z_uncompress);
+
+int
+spl_zlib_init(void)
+{
+       int size;
+
+       size = MAX(spl_zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
+           zlib_inflate_workspacesize());
+
+       zlib_workspace_cache = kmem_cache_create(
+           "spl_zlib_workspace_cache",
+           size, 0, NULL, NULL, NULL, NULL, NULL,
+           KMC_VMEM | KMC_NOEMERGENCY);
+        if (!zlib_workspace_cache)
+               return (1);
+
+        return (0);
+}
+
+void
+spl_zlib_fini(void)
+{
+       kmem_cache_destroy(zlib_workspace_cache);
+        zlib_workspace_cache = NULL;
+}
diff --git a/spl/module/splat/Makefile.in b/spl/module/splat/Makefile.in
new file mode 100644 (file)
index 0000000..680f284
--- /dev/null
@@ -0,0 +1,28 @@
+# Makefile.in for splat kernel module
+
+src = @abs_top_srcdir@/module/splat
+obj = @abs_builddir@
+
+MODULE := splat
+EXTRA_CFLAGS = $(SPL_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+# Solaris Porting LAyer Tests
+obj-$(CONFIG_SPL) := $(MODULE).o
+
+$(MODULE)-objs += splat-ctl.o
+$(MODULE)-objs += splat-kmem.o
+$(MODULE)-objs += splat-taskq.o
+$(MODULE)-objs += splat-random.o
+$(MODULE)-objs += splat-mutex.o
+$(MODULE)-objs += splat-condvar.o
+$(MODULE)-objs += splat-thread.o
+$(MODULE)-objs += splat-rwlock.o
+$(MODULE)-objs += splat-time.o
+$(MODULE)-objs += splat-vnode.o
+$(MODULE)-objs += splat-kobj.o
+$(MODULE)-objs += splat-atomic.o
+$(MODULE)-objs += splat-list.o
+$(MODULE)-objs += splat-generic.o
+$(MODULE)-objs += splat-cred.o
+$(MODULE)-objs += splat-zlib.o
+$(MODULE)-objs += splat-linux.o
diff --git a/spl/module/splat/splat-atomic.c b/spl/module/splat/splat-atomic.c
new file mode 100644 (file)
index 0000000..999f4f0
--- /dev/null
@@ -0,0 +1,232 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Atomic Tests.
+\*****************************************************************************/
+
+#include <sys/atomic.h>
+#include <sys/thread.h>
+#include <sys/mutex.h>
+#include <linux/mm_compat.h>
+#include <linux/slab.h>
+#include "splat-internal.h"
+
+#define SPLAT_ATOMIC_NAME              "atomic"
+#define SPLAT_ATOMIC_DESC              "Kernel Atomic Tests"
+
+#define SPLAT_ATOMIC_TEST1_ID          0x0b01
+#define SPLAT_ATOMIC_TEST1_NAME                "64-bit"
+#define SPLAT_ATOMIC_TEST1_DESC                "Validate 64-bit atomic ops"
+
+#define SPLAT_ATOMIC_TEST_MAGIC                0x43435454UL
+#define SPLAT_ATOMIC_INIT_VALUE                10000000UL
+
+typedef enum {
+       SPLAT_ATOMIC_INC_64    = 0,
+       SPLAT_ATOMIC_DEC_64    = 1,
+       SPLAT_ATOMIC_ADD_64    = 2,
+       SPLAT_ATOMIC_SUB_64    = 3,
+       SPLAT_ATOMIC_ADD_64_NV = 4,
+       SPLAT_ATOMIC_SUB_64_NV = 5,
+       SPLAT_ATOMIC_COUNT_64  = 6
+} atomic_op_t;
+
+typedef struct atomic_priv {
+        unsigned long ap_magic;
+        struct file *ap_file;
+       kmutex_t ap_lock;
+        wait_queue_head_t ap_waitq;
+       volatile uint64_t ap_atomic;
+       volatile uint64_t ap_atomic_exited;
+       atomic_op_t ap_op;
+
+} atomic_priv_t;
+
+static void
+splat_atomic_work(void *priv)
+{
+       atomic_priv_t *ap;
+       atomic_op_t op;
+       int i;
+
+       ap = (atomic_priv_t *)priv;
+       ASSERT(ap->ap_magic == SPLAT_ATOMIC_TEST_MAGIC);
+
+       mutex_enter(&ap->ap_lock);
+       op = ap->ap_op;
+       wake_up(&ap->ap_waitq);
+       mutex_exit(&ap->ap_lock);
+
+        splat_vprint(ap->ap_file, SPLAT_ATOMIC_TEST1_NAME,
+                    "Thread %d successfully started: %lu/%lu\n", op,
+                    (long unsigned)ap->ap_atomic,
+                    (long unsigned)ap->ap_atomic_exited);
+
+       for (i = 0; i < SPLAT_ATOMIC_INIT_VALUE / 10; i++) {
+
+               /* Periodically sleep to mix up the ordering */
+               if ((i % (SPLAT_ATOMIC_INIT_VALUE / 100)) == 0) {
+                       splat_vprint(ap->ap_file, SPLAT_ATOMIC_TEST1_NAME,
+                            "Thread %d sleeping: %lu/%lu\n", op,
+                            (long unsigned)ap->ap_atomic,
+                            (long unsigned)ap->ap_atomic_exited);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ / 100);
+               }
+
+               switch (op) {
+                       case SPLAT_ATOMIC_INC_64:
+                               atomic_inc_64(&ap->ap_atomic);
+                               break;
+                       case SPLAT_ATOMIC_DEC_64:
+                               atomic_dec_64(&ap->ap_atomic);
+                               break;
+                       case SPLAT_ATOMIC_ADD_64:
+                               atomic_add_64(&ap->ap_atomic, 3);
+                               break;
+                       case SPLAT_ATOMIC_SUB_64:
+                               atomic_sub_64(&ap->ap_atomic, 3);
+                               break;
+                       case SPLAT_ATOMIC_ADD_64_NV:
+                               atomic_add_64_nv(&ap->ap_atomic, 5);
+                               break;
+                       case SPLAT_ATOMIC_SUB_64_NV:
+                               atomic_sub_64_nv(&ap->ap_atomic, 5);
+                               break;
+                       default:
+                               PANIC("Undefined op %d\n", op);
+               }
+       }
+
+       atomic_inc_64(&ap->ap_atomic_exited);
+
+        splat_vprint(ap->ap_file, SPLAT_ATOMIC_TEST1_NAME,
+                    "Thread %d successfully exited: %lu/%lu\n", op,
+                    (long unsigned)ap->ap_atomic,
+                    (long unsigned)ap->ap_atomic_exited);
+
+       wake_up(&ap->ap_waitq);
+       thread_exit();
+}
+
+static int
+splat_atomic_test1_cond(atomic_priv_t *ap, int started)
+{
+       return (ap->ap_atomic_exited == started);
+}
+
+static int
+splat_atomic_test1(struct file *file, void *arg)
+{
+       atomic_priv_t ap;
+        DEFINE_WAIT(wait);
+       kthread_t *thr;
+       int i, rc = 0;
+
+       ap.ap_magic = SPLAT_ATOMIC_TEST_MAGIC;
+       ap.ap_file = file;
+       mutex_init(&ap.ap_lock, SPLAT_ATOMIC_TEST1_NAME, MUTEX_DEFAULT, NULL);
+       init_waitqueue_head(&ap.ap_waitq);
+       ap.ap_atomic = SPLAT_ATOMIC_INIT_VALUE;
+       ap.ap_atomic_exited = 0;
+
+       for (i = 0; i < SPLAT_ATOMIC_COUNT_64; i++) {
+               mutex_enter(&ap.ap_lock);
+               ap.ap_op = i;
+
+               thr = (kthread_t *)thread_create(NULL, 0, splat_atomic_work,
+                                                &ap, 0, &p0, TS_RUN,
+                                                defclsyspri);
+               if (thr == NULL) {
+                       rc = -ESRCH;
+                       mutex_exit(&ap.ap_lock);
+                       break;
+               }
+
+               /* Prepare to wait, the new thread will wake us once it
+                * has made a copy of the unique private passed data */
+                prepare_to_wait(&ap.ap_waitq, &wait, TASK_UNINTERRUPTIBLE);
+               mutex_exit(&ap.ap_lock);
+               schedule();
+       }
+
+       wait_event(ap.ap_waitq, splat_atomic_test1_cond(&ap, i));
+
+       if (rc) {
+               splat_vprint(file, SPLAT_ATOMIC_TEST1_NAME, "Only started "
+                            "%d/%d test threads\n", i, SPLAT_ATOMIC_COUNT_64);
+               return rc;
+       }
+
+       if (ap.ap_atomic != SPLAT_ATOMIC_INIT_VALUE) {
+               splat_vprint(file, SPLAT_ATOMIC_TEST1_NAME,
+                            "Final value %lu does not match initial value %lu\n",
+                            (long unsigned)ap.ap_atomic, SPLAT_ATOMIC_INIT_VALUE);
+               return -EINVAL;
+       }
+
+        splat_vprint(file, SPLAT_ATOMIC_TEST1_NAME,
+                  "Success initial and final values match, %lu == %lu\n",
+                  (long unsigned)ap.ap_atomic, SPLAT_ATOMIC_INIT_VALUE);
+
+       mutex_destroy(&ap.ap_lock);
+
+       return 0;
+}
+
+splat_subsystem_t *
+splat_atomic_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_ATOMIC_NAME, SPLAT_NAME_SIZE);
+        strncpy(sub->desc.desc, SPLAT_ATOMIC_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+        INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_ATOMIC;
+
+        SPLAT_TEST_INIT(sub, SPLAT_ATOMIC_TEST1_NAME, SPLAT_ATOMIC_TEST1_DESC,
+                      SPLAT_ATOMIC_TEST1_ID, splat_atomic_test1);
+
+        return sub;
+}
+
+void
+splat_atomic_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+        SPLAT_TEST_FINI(sub, SPLAT_ATOMIC_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_atomic_id(void) {
+        return SPLAT_SUBSYSTEM_ATOMIC;
+}
diff --git a/spl/module/splat/splat-condvar.c b/spl/module/splat/splat-condvar.c
new file mode 100644 (file)
index 0000000..bdbaf79
--- /dev/null
@@ -0,0 +1,511 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Condition Variable Tests.
+\*****************************************************************************/
+
+#include <sys/condvar.h>
+#include <sys/timer.h>
+#include <sys/thread.h>
+#include "splat-internal.h"
+
+#define SPLAT_CONDVAR_NAME             "condvar"
+#define SPLAT_CONDVAR_DESC             "Kernel Condition Variable Tests"
+
+#define SPLAT_CONDVAR_TEST1_ID         0x0501
+#define SPLAT_CONDVAR_TEST1_NAME       "signal1"
+#define SPLAT_CONDVAR_TEST1_DESC       "Wake a single thread, cv_wait()/cv_signal()"
+
+#define SPLAT_CONDVAR_TEST2_ID         0x0502
+#define SPLAT_CONDVAR_TEST2_NAME       "broadcast1"
+#define SPLAT_CONDVAR_TEST2_DESC       "Wake all threads, cv_wait()/cv_broadcast()"
+
+#define SPLAT_CONDVAR_TEST3_ID         0x0503
+#define SPLAT_CONDVAR_TEST3_NAME       "signal2"
+#define SPLAT_CONDVAR_TEST3_DESC       "Wake a single thread, cv_wait_timeout()/cv_signal()"
+
+#define SPLAT_CONDVAR_TEST4_ID         0x0504
+#define SPLAT_CONDVAR_TEST4_NAME       "broadcast2"
+#define SPLAT_CONDVAR_TEST4_DESC       "Wake all threads, cv_wait_timeout()/cv_broadcast()"
+
+#define SPLAT_CONDVAR_TEST5_ID         0x0505
+#define SPLAT_CONDVAR_TEST5_NAME       "timeout"
+#define SPLAT_CONDVAR_TEST5_DESC       "Timeout thread, cv_wait_timeout()"
+
+#define SPLAT_CONDVAR_TEST_MAGIC       0x115599DDUL
+#define SPLAT_CONDVAR_TEST_NAME                "condvar"
+#define SPLAT_CONDVAR_TEST_COUNT       8
+
+typedef struct condvar_priv {
+       unsigned long cv_magic;
+       struct file *cv_file;
+       kcondvar_t cv_condvar;
+       kmutex_t cv_mtx;
+} condvar_priv_t;
+
+typedef struct condvar_thr {
+       const char *ct_name;
+       condvar_priv_t *ct_cvp;
+       struct task_struct *ct_thread;
+       int ct_rc;
+} condvar_thr_t;
+
+int
+splat_condvar_test12_thread(void *arg)
+{
+       condvar_thr_t *ct = (condvar_thr_t *)arg;
+       condvar_priv_t *cv = ct->ct_cvp;
+
+       ASSERT(cv->cv_magic == SPLAT_CONDVAR_TEST_MAGIC);
+
+       mutex_enter(&cv->cv_mtx);
+       splat_vprint(cv->cv_file, ct->ct_name,
+           "%s thread sleeping with %d waiters\n",
+           ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters));
+       cv_wait(&cv->cv_condvar, &cv->cv_mtx);
+       splat_vprint(cv->cv_file, ct->ct_name,
+           "%s thread woken %d waiters remain\n",
+           ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters));
+       mutex_exit(&cv->cv_mtx);
+
+       /* wait for main thread reap us */
+       while (!kthread_should_stop())
+               schedule();
+       return 0;
+}
+
+static int
+splat_condvar_test1(struct file *file, void *arg)
+{
+       int i, count = 0, rc = 0;
+       condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
+       condvar_priv_t cv;
+
+       cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
+       cv.cv_file = file;
+       mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
+       cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
+
+       /* Create some threads, the exact number isn't important just as
+        * long as we know how many we managed to create and should expect. */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               ct[i].ct_cvp = &cv;
+               ct[i].ct_name = SPLAT_CONDVAR_TEST1_NAME;
+               ct[i].ct_rc = 0;
+               ct[i].ct_thread = spl_kthread_create(splat_condvar_test12_thread,
+                   &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
+
+               if (!IS_ERR(ct[i].ct_thread)) {
+                       wake_up_process(ct[i].ct_thread);
+                       count++;
+               }
+       }
+
+       /* Wait until all threads are waiting on the condition variable */
+       while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
+               schedule();
+
+       /* Wake a single thread at a time, wait until it exits */
+       for (i = 1; i <= count; i++) {
+               cv_signal(&cv.cv_condvar);
+
+               while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i))
+                       schedule();
+
+               /* Correct behavior 1 thread woken */
+               if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i))
+                       continue;
+
+                splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Attempted to "
+                          "wake %d thread but work %d threads woke\n",
+                          1, count - atomic_read(&cv.cv_condvar.cv_waiters));
+               rc = -EINVAL;
+               break;
+       }
+
+       if (!rc)
+                splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Correctly woke "
+                          "%d sleeping threads %d at a time\n", count, 1);
+
+       /* Wait until that last nutex is dropped */
+       while (mutex_owner(&cv.cv_mtx))
+               schedule();
+
+       /* Wake everything for the failure case */
+       cv_broadcast(&cv.cv_condvar);
+       cv_destroy(&cv.cv_condvar);
+
+       /* wait for threads to exit */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               if (!IS_ERR(ct[i].ct_thread))
+                       kthread_stop(ct[i].ct_thread);
+       }
+       mutex_destroy(&cv.cv_mtx);
+
+       return rc;
+}
+
+static int
+splat_condvar_test2(struct file *file, void *arg)
+{
+       int i, count = 0, rc = 0;
+       condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
+       condvar_priv_t cv;
+
+       cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
+       cv.cv_file = file;
+       mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
+       cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
+
+       /* Create some threads, the exact number isn't important just as
+        * long as we know how many we managed to create and should expect. */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               ct[i].ct_cvp = &cv;
+               ct[i].ct_name = SPLAT_CONDVAR_TEST2_NAME;
+               ct[i].ct_rc = 0;
+               ct[i].ct_thread = spl_kthread_create(splat_condvar_test12_thread,
+                   &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
+
+               if (!IS_ERR(ct[i].ct_thread)) {
+                       wake_up_process(ct[i].ct_thread);
+                       count++;
+               }
+       }
+
+       /* Wait until all threads are waiting on the condition variable */
+       while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
+               schedule();
+
+       /* Wake all threads waiting on the condition variable */
+       cv_broadcast(&cv.cv_condvar);
+
+       /* Wait until all threads have exited */
+       while ((atomic_read(&cv.cv_condvar.cv_waiters) > 0) || mutex_owner(&cv.cv_mtx))
+               schedule();
+
+        splat_vprint(file, SPLAT_CONDVAR_TEST2_NAME, "Correctly woke all "
+                          "%d sleeping threads at once\n", count);
+
+       /* Wake everything for the failure case */
+       cv_destroy(&cv.cv_condvar);
+
+       /* wait for threads to exit */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               if (!IS_ERR(ct[i].ct_thread))
+                       kthread_stop(ct[i].ct_thread);
+       }
+       mutex_destroy(&cv.cv_mtx);
+
+       return rc;
+}
+
+int
+splat_condvar_test34_thread(void *arg)
+{
+       condvar_thr_t *ct = (condvar_thr_t *)arg;
+       condvar_priv_t *cv = ct->ct_cvp;
+       clock_t rc;
+
+       ASSERT(cv->cv_magic == SPLAT_CONDVAR_TEST_MAGIC);
+
+       mutex_enter(&cv->cv_mtx);
+       splat_vprint(cv->cv_file, ct->ct_name,
+           "%s thread sleeping with %d waiters\n",
+           ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters));
+
+       /* Sleep no longer than 3 seconds, for this test we should
+        * actually never sleep that long without being woken up. */
+       rc = cv_timedwait(&cv->cv_condvar, &cv->cv_mtx, lbolt + HZ * 3);
+       if (rc == -1) {
+               ct->ct_rc = -ETIMEDOUT;
+               splat_vprint(cv->cv_file, ct->ct_name, "%s thread timed out, "
+                   "should have been woken\n", ct->ct_thread->comm);
+       } else {
+               splat_vprint(cv->cv_file, ct->ct_name,
+                   "%s thread woken %d waiters remain\n",
+                   ct->ct_thread->comm,
+                   atomic_read(&cv->cv_condvar.cv_waiters));
+       }
+
+       mutex_exit(&cv->cv_mtx);
+
+       /* wait for main thread reap us */
+       while (!kthread_should_stop())
+               schedule();
+       return 0;
+}
+
+static int
+splat_condvar_test3(struct file *file, void *arg)
+{
+       int i, count = 0, rc = 0;
+       condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
+       condvar_priv_t cv;
+
+       cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
+       cv.cv_file = file;
+       mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
+       cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
+
+       /* Create some threads, the exact number isn't important just as
+        * long as we know how many we managed to create and should expect. */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               ct[i].ct_cvp = &cv;
+               ct[i].ct_name = SPLAT_CONDVAR_TEST3_NAME;
+               ct[i].ct_rc = 0;
+               ct[i].ct_thread = spl_kthread_create(splat_condvar_test34_thread,
+                   &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
+
+               if (!IS_ERR(ct[i].ct_thread)) {
+                       wake_up_process(ct[i].ct_thread);
+                       count++;
+               }
+       }
+
+       /* Wait until all threads are waiting on the condition variable */
+       while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
+               schedule();
+
+       /* Wake a single thread at a time, wait until it exits */
+       for (i = 1; i <= count; i++) {
+               cv_signal(&cv.cv_condvar);
+
+               while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i))
+                       schedule();
+
+               /* Correct behavior 1 thread woken */
+               if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i))
+                       continue;
+
+                splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Attempted to "
+                          "wake %d thread but work %d threads woke\n",
+                          1, count - atomic_read(&cv.cv_condvar.cv_waiters));
+               rc = -EINVAL;
+               break;
+       }
+
+       /* Validate no waiting thread timed out early */
+       for (i = 0; i < count; i++)
+               if (ct[i].ct_rc)
+                       rc = ct[i].ct_rc;
+
+       if (!rc)
+                splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Correctly woke "
+                          "%d sleeping threads %d at a time\n", count, 1);
+
+       /* Wait until that last nutex is dropped */
+       while (mutex_owner(&cv.cv_mtx))
+               schedule();
+
+       /* Wake everything for the failure case */
+       cv_broadcast(&cv.cv_condvar);
+       cv_destroy(&cv.cv_condvar);
+
+       /* wait for threads to exit */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               if (!IS_ERR(ct[i].ct_thread))
+                       kthread_stop(ct[i].ct_thread);
+       }
+       mutex_destroy(&cv.cv_mtx);
+
+       return rc;
+}
+
+static int
+splat_condvar_test4(struct file *file, void *arg)
+{
+       int i, count = 0, rc = 0;
+       condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
+       condvar_priv_t cv;
+
+       cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
+       cv.cv_file = file;
+       mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
+       cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
+
+       /* Create some threads, the exact number isn't important just as
+        * long as we know how many we managed to create and should expect. */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               ct[i].ct_cvp = &cv;
+               ct[i].ct_name = SPLAT_CONDVAR_TEST3_NAME;
+               ct[i].ct_rc = 0;
+               ct[i].ct_thread = spl_kthread_create(splat_condvar_test34_thread,
+                   &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
+
+               if (!IS_ERR(ct[i].ct_thread)) {
+                       wake_up_process(ct[i].ct_thread);
+                       count++;
+               }
+       }
+
+       /* Wait until all threads are waiting on the condition variable */
+       while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
+               schedule();
+
+       /* Wake a single thread at a time, wait until it exits */
+       for (i = 1; i <= count; i++) {
+               cv_signal(&cv.cv_condvar);
+
+               while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i))
+                       schedule();
+
+               /* Correct behavior 1 thread woken */
+               if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i))
+                       continue;
+
+                splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Attempted to "
+                          "wake %d thread but work %d threads woke\n",
+                          1, count - atomic_read(&cv.cv_condvar.cv_waiters));
+               rc = -EINVAL;
+               break;
+       }
+
+       /* Validate no waiting thread timed out early */
+       for (i = 0; i < count; i++)
+               if (ct[i].ct_rc)
+                       rc = ct[i].ct_rc;
+
+       if (!rc)
+                splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Correctly woke "
+                          "%d sleeping threads %d at a time\n", count, 1);
+
+       /* Wait until that last nutex is dropped */
+       while (mutex_owner(&cv.cv_mtx))
+               schedule();
+
+       /* Wake everything for the failure case */
+       cv_broadcast(&cv.cv_condvar);
+       cv_destroy(&cv.cv_condvar);
+
+       /* wait for threads to exit */
+       for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
+               if (!IS_ERR(ct[i].ct_thread))
+                       kthread_stop(ct[i].ct_thread);
+       }
+       mutex_destroy(&cv.cv_mtx);
+
+       return rc;
+}
+
+static int
+splat_condvar_test5(struct file *file, void *arg)
+{
+        kcondvar_t condvar;
+        kmutex_t mtx;
+       clock_t time_left, time_before, time_after, time_delta;
+       uint64_t whole_delta;
+       uint32_t remain_delta;
+       int rc = 0;
+
+       mutex_init(&mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
+       cv_init(&condvar, NULL, CV_DEFAULT, NULL);
+
+        splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME, "Thread going to sleep for "
+                  "%d second and expecting to be woken by timeout\n", 1);
+
+       /* Allow a 1 second timeout, plenty long to validate correctness. */
+       time_before = lbolt;
+       mutex_enter(&mtx);
+       time_left = cv_timedwait(&condvar, &mtx, lbolt + HZ);
+       mutex_exit(&mtx);
+       time_after = lbolt;
+       time_delta = time_after - time_before; /* XXX - Handle jiffie wrap */
+       whole_delta  = time_delta;
+       remain_delta = do_div(whole_delta, HZ);
+
+       if (time_left == -1) {
+               if (time_delta >= HZ) {
+                       splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME,
+                                  "Thread correctly timed out and was asleep "
+                                  "for %d.%d seconds (%d second min)\n",
+                                  (int)whole_delta, (int)remain_delta, 1);
+               } else {
+                       splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME,
+                                  "Thread correctly timed out but was only "
+                                  "asleep for %d.%d seconds (%d second "
+                                  "min)\n", (int)whole_delta,
+                                  (int)remain_delta, 1);
+                       rc = -ETIMEDOUT;
+               }
+       } else {
+               splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME,
+                          "Thread exited after only %d.%d seconds, it "
+                          "did not hit the %d second timeout\n",
+                          (int)whole_delta, (int)remain_delta, 1);
+               rc = -ETIMEDOUT;
+       }
+
+       cv_destroy(&condvar);
+       mutex_destroy(&mtx);
+
+       return rc;
+}
+
+splat_subsystem_t *
+splat_condvar_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_CONDVAR_NAME, SPLAT_NAME_SIZE);
+        strncpy(sub->desc.desc, SPLAT_CONDVAR_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+        INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_CONDVAR;
+
+        SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST1_NAME, SPLAT_CONDVAR_TEST1_DESC,
+                      SPLAT_CONDVAR_TEST1_ID, splat_condvar_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST2_NAME, SPLAT_CONDVAR_TEST2_DESC,
+                      SPLAT_CONDVAR_TEST2_ID, splat_condvar_test2);
+        SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST3_NAME, SPLAT_CONDVAR_TEST3_DESC,
+                      SPLAT_CONDVAR_TEST3_ID, splat_condvar_test3);
+        SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST4_NAME, SPLAT_CONDVAR_TEST4_DESC,
+                      SPLAT_CONDVAR_TEST4_ID, splat_condvar_test4);
+        SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST5_NAME, SPLAT_CONDVAR_TEST5_DESC,
+                      SPLAT_CONDVAR_TEST5_ID, splat_condvar_test5);
+
+        return sub;
+}
+
+void
+splat_condvar_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+        SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST5_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST4_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_condvar_id(void) {
+        return SPLAT_SUBSYSTEM_CONDVAR;
+}
diff --git a/spl/module/splat/splat-cred.c b/spl/module/splat/splat-cred.c
new file mode 100644 (file)
index 0000000..f6b70ce
--- /dev/null
@@ -0,0 +1,299 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Credential Tests.
+\*****************************************************************************/
+
+#include <sys/cred.h>
+#include <sys/random.h>
+#include "splat-internal.h"
+
+#define SPLAT_CRED_NAME                        "cred"
+#define SPLAT_CRED_DESC                        "Kernel Cred Tests"
+
+#define SPLAT_CRED_TEST1_ID            0x0e01
+#define SPLAT_CRED_TEST1_NAME          "cred"
+#define SPLAT_CRED_TEST1_DESC          "Task Credential Test"
+
+#define SPLAT_CRED_TEST2_ID            0x0e02
+#define SPLAT_CRED_TEST2_NAME          "kcred"
+#define SPLAT_CRED_TEST2_DESC          "Kernel Credential Test"
+
+#define SPLAT_CRED_TEST3_ID            0x0e03
+#define SPLAT_CRED_TEST3_NAME          "groupmember"
+#define SPLAT_CRED_TEST3_DESC          "Group Member Test"
+
+#define GROUP_STR_SIZE                 128
+#define GROUP_STR_REDZONE              16
+
+static int
+splat_cred_test1(struct file *file, void *arg)
+{
+       char str[GROUP_STR_SIZE];
+       uid_t uid, ruid, suid;
+       gid_t gid, rgid, sgid, *groups;
+       int ngroups, i, count = 0;
+       cred_t *cr = CRED();
+
+       uid  = crgetuid(cr);
+       ruid = crgetruid(cr);
+       suid = crgetsuid(cr);
+
+       gid  = crgetgid(cr);
+       rgid = crgetrgid(cr);
+       sgid = crgetsgid(cr);
+
+       ngroups = crgetngroups(cr);
+       groups = crgetgroups(cr);
+
+       memset(str, 0, GROUP_STR_SIZE);
+       for (i = 0; i < ngroups; i++) {
+               count += sprintf(str + count, "%d ", groups[i]);
+
+               if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) {
+                       splat_vprint(file, SPLAT_CRED_TEST1_NAME,
+                                    "Failed too many group entries for temp "
+                                    "buffer: %d, %s\n", ngroups, str);
+                       return -ENOSPC;
+               }
+       }
+
+       splat_vprint(file, SPLAT_CRED_TEST1_NAME,
+                    "uid: %d ruid: %d suid: %d "
+                    "gid: %d rgid: %d sgid: %d\n",
+                    uid, ruid, suid, gid, rgid, sgid);
+       splat_vprint(file, SPLAT_CRED_TEST1_NAME,
+                    "ngroups: %d groups: %s\n", ngroups, str);
+
+       if (uid || ruid || suid || gid || rgid || sgid) {
+               splat_vprint(file, SPLAT_CRED_TEST1_NAME,
+                            "Failed expected all uids+gids to be %d\n", 0);
+               return -EIDRM;
+       }
+
+       if (ngroups > NGROUPS_MAX) {
+               splat_vprint(file, SPLAT_CRED_TEST1_NAME,
+                            "Failed ngroups must not exceed NGROUPS_MAX: "
+                            "%d > %d\n", ngroups, NGROUPS_MAX);
+               return -EIDRM;
+       }
+
+       splat_vprint(file, SPLAT_CRED_TEST1_NAME,
+                    "Success sane CRED(): %d\n", 0);
+
+        return 0;
+} /* splat_cred_test1() */
+
+static int
+splat_cred_test2(struct file *file, void *arg)
+{
+       char str[GROUP_STR_SIZE];
+       uid_t uid, ruid, suid;
+       gid_t gid, rgid, sgid, *groups;
+       int ngroups, i, count = 0;
+
+       crhold(kcred);
+
+       uid  = crgetuid(kcred);
+       ruid = crgetruid(kcred);
+       suid = crgetsuid(kcred);
+
+       gid  = crgetgid(kcred);
+       rgid = crgetrgid(kcred);
+       sgid = crgetsgid(kcred);
+
+       ngroups = crgetngroups(kcred);
+       groups  = crgetgroups(kcred);
+
+       memset(str, 0, GROUP_STR_SIZE);
+       for (i = 0; i < ngroups; i++) {
+               count += sprintf(str + count, "%d ", groups[i]);
+
+               if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) {
+                       splat_vprint(file, SPLAT_CRED_TEST2_NAME,
+                                    "Failed too many group entries for temp "
+                                    "buffer: %d, %s\n", ngroups, str);
+                       crfree(kcred);
+                       return -ENOSPC;
+               }
+       }
+
+       crfree(kcred);
+
+       splat_vprint(file, SPLAT_CRED_TEST2_NAME,
+                    "uid: %d ruid: %d suid: %d "
+                    "gid: %d rgid: %d sgid: %d\n",
+                    uid, ruid, suid, gid, rgid, sgid);
+       splat_vprint(file, SPLAT_CRED_TEST2_NAME,
+                    "ngroups: %d groups: %s\n", ngroups, str);
+
+       if (uid || ruid || suid || gid || rgid || sgid) {
+               splat_vprint(file, SPLAT_CRED_TEST2_NAME,
+                            "Failed expected all uids+gids to be %d\n", 0);
+               return -EIDRM;
+       }
+
+       if (ngroups > NGROUPS_MAX) {
+               splat_vprint(file, SPLAT_CRED_TEST2_NAME,
+                            "Failed ngroups must not exceed NGROUPS_MAX: "
+                            "%d > %d\n", ngroups, NGROUPS_MAX);
+               return -EIDRM;
+       }
+
+       splat_vprint(file, SPLAT_CRED_TEST2_NAME,
+                    "Success sane kcred: %d\n", 0);
+
+        return 0;
+} /* splat_cred_test2() */
+
+#define        SPLAT_NGROUPS   32
+/*
+ * Verify the groupmember() works correctly by constructing an interesting
+ * CRED() and checking that the expected gids are part of it.
+ */
+static int
+splat_cred_test3(struct file *file, void *arg)
+{
+       gid_t known_gid, missing_gid, tmp_gid;
+       unsigned char rnd;
+       struct group_info *gi;
+       int i, rc;
+
+       get_random_bytes((void *)&rnd, 1);
+       known_gid = (rnd > 0) ? rnd : 1;
+       missing_gid = 0;
+
+       /*
+        * Create an interesting known set of gids for test purposes. The
+        * gids are pseudo randomly selected are will be in the range of
+        * 1:(NGROUPS_MAX-1).  Gid 0 is explicitly avoided so we can reliably
+        * test for its absence in the test cases.
+        */
+       gi = groups_alloc(SPLAT_NGROUPS);
+       if (gi == NULL) {
+               splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed create "
+                   "group_info for known gids: %d\n", -ENOMEM);
+               rc = -ENOMEM;
+               goto show_groups;
+       }
+
+       for (i = 0, tmp_gid = known_gid; i < SPLAT_NGROUPS; i++) {
+               splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Adding gid %d "
+                   "to current CRED() (%d/%d)\n", tmp_gid, i, gi->ngroups);
+#ifdef HAVE_KUIDGID_T
+               GROUP_AT(gi, i) = make_kgid(current_user_ns(), tmp_gid);
+#else
+               GROUP_AT(gi, i) = tmp_gid;
+#endif /* HAVE_KUIDGID_T */
+               tmp_gid = ((tmp_gid * 17) % (NGROUPS_MAX - 1)) + 1;
+       }
+
+       /* Set the new groups in the CRED() and release our reference. */
+       rc = set_current_groups(gi);
+       put_group_info(gi);
+
+       if (rc) {
+               splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed to add "
+                   "gid %d to current group: %d\n", known_gid, rc);
+               goto show_groups;
+       }
+
+       /* Verify groupmember() finds the known_gid in the CRED() */
+       rc = groupmember(known_gid, CRED());
+       if (!rc) {
+               splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed to find "
+                   "known gid %d in CRED()'s groups.\n", known_gid);
+               rc = -EIDRM;
+               goto show_groups;
+       }
+
+       /* Verify groupmember() does NOT finds the missing gid in the CRED() */
+       rc = groupmember(missing_gid, CRED());
+       if (rc) {
+               splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed missing "
+                   "gid %d was found in CRED()'s groups.\n", missing_gid);
+               rc = -EIDRM;
+               goto show_groups;
+       }
+
+       splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Success groupmember() "
+           "correctly detects expected gids in CRED(): %d\n", rc);
+
+show_groups:
+       if (rc) {
+               int i, grps = crgetngroups(CRED());
+
+               splat_vprint(file, SPLAT_CRED_TEST3_NAME, "%d groups: ", grps);
+               for (i = 0; i < grps; i++)
+                       splat_print(file, "%d ", crgetgroups(CRED())[i]);
+               splat_print(file, "%s", "\n");
+       }
+
+
+       return (rc);
+} /* splat_cred_test3() */
+
+splat_subsystem_t *
+splat_cred_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_CRED_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_CRED_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_CRED;
+
+        SPLAT_TEST_INIT(sub, SPLAT_CRED_TEST1_NAME, SPLAT_CRED_TEST1_DESC,
+                     SPLAT_CRED_TEST1_ID, splat_cred_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_CRED_TEST2_NAME, SPLAT_CRED_TEST2_DESC,
+                     SPLAT_CRED_TEST2_ID, splat_cred_test2);
+        SPLAT_TEST_INIT(sub, SPLAT_CRED_TEST3_NAME, SPLAT_CRED_TEST3_DESC,
+                     SPLAT_CRED_TEST3_ID, splat_cred_test3);
+
+        return sub;
+} /* splat_cred_init() */
+
+void
+splat_cred_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_CRED_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_CRED_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_CRED_TEST1_ID);
+
+        kfree(sub);
+} /* splat_cred_fini() */
+
+int
+splat_cred_id(void)
+{
+        return SPLAT_SUBSYSTEM_CRED;
+} /* splat_cred_id() */
diff --git a/spl/module/splat/splat-ctl.c b/spl/module/splat/splat-ctl.c
new file mode 100644 (file)
index 0000000..4d4148d
--- /dev/null
@@ -0,0 +1,671 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Test Control Interface.
+ *
+ *  The 'splat' (Solaris Porting LAyer Tests) module is designed as a
+ *  framework which runs various in kernel regression tests to validate
+ *  the SPL primitives honor the Solaris ABI.
+ *
+ *  The splat module is constructed of various splat_* source files each
+ *  of which contain regression tests for a particular subsystem.  For
+ *  example, the splat_kmem.c file contains all the tests for validating
+ *  the kmem interfaces have been implemented correctly.  When the splat
+ *  module is loaded splat_*_init() will be called for each subsystems
+ *  tests.  It is the responsibility of splat_*_init() to register all
+ *  the tests for this subsystem using the SPLAT_TEST_INIT() macro.
+ *  Similarly splat_*_fini() is called when the splat module is removed
+ *  and is responsible for unregistering its tests via the SPLAT_TEST_FINI
+ *  macro.  Once a test is registered it can then be run with an ioctl()
+ *  call which specifies the subsystem and test to be run.  The provided
+ *  splat command line tool can be used to display all available
+ *  subsystems and tests.  It can also be used to run the full suite
+ *  of regression tests or particular tests.
+\*****************************************************************************/
+
+#include <sys/debug.h>
+#include <sys/mutex.h>
+#include <sys/types.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include "splat-internal.h"
+
+static struct list_head splat_module_list;
+static spinlock_t splat_module_lock;
+
+static int
+splat_open(struct inode *inode, struct file *file)
+{
+       splat_info_t *info;
+
+       info = (splat_info_t *)kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL)
+               return -ENOMEM;
+
+       mutex_init(&info->info_lock, SPLAT_NAME, MUTEX_DEFAULT, NULL);
+       info->info_size = SPLAT_INFO_BUFFER_SIZE;
+       info->info_buffer = (char *)vmalloc(SPLAT_INFO_BUFFER_SIZE);
+       if (info->info_buffer == NULL) {
+               kfree(info);
+               return -ENOMEM;
+       }
+       memset(info->info_buffer, 0, info->info_size);
+
+       info->info_head = info->info_buffer;
+       file->private_data = (void *)info;
+
+       splat_print(file, "%s\n", spl_version);
+
+       return 0;
+}
+
+static int
+splat_release(struct inode *inode, struct file *file)
+{
+       splat_info_t *info = (splat_info_t *)file->private_data;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       mutex_destroy(&info->info_lock);
+       vfree(info->info_buffer);
+       kfree(info);
+
+       return 0;
+}
+
+static int
+splat_buffer_clear(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
+{
+       splat_info_t *info = (splat_info_t *)file->private_data;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       mutex_enter(&info->info_lock);
+       memset(info->info_buffer, 0, info->info_size);
+       info->info_head = info->info_buffer;
+       mutex_exit(&info->info_lock);
+
+       return 0;
+}
+
+static int
+splat_buffer_size(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
+{
+       splat_info_t *info = (splat_info_t *)file->private_data;
+       char *buf;
+       int min, size, rc = 0;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       mutex_enter(&info->info_lock);
+       if (kcfg->cfg_arg1 > 0) {
+
+               size = kcfg->cfg_arg1;
+               buf = (char *)vmalloc(size);
+               if (buf == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               /* Zero fill and truncate contents when coping buffer */
+               min = ((size < info->info_size) ? size : info->info_size);
+               memset(buf, 0, size);
+               memcpy(buf, info->info_buffer, min);
+               vfree(info->info_buffer);
+               info->info_size = size;
+               info->info_buffer = buf;
+               info->info_head = info->info_buffer;
+       }
+
+       kcfg->cfg_rc1 = info->info_size;
+
+       if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
+               rc = -EFAULT;
+out:
+       mutex_exit(&info->info_lock);
+
+       return rc;
+}
+
+
+static splat_subsystem_t *
+splat_subsystem_find(int id) {
+       splat_subsystem_t *sub;
+
+        spin_lock(&splat_module_lock);
+        list_for_each_entry(sub, &splat_module_list, subsystem_list) {
+               if (id == sub->desc.id) {
+                       spin_unlock(&splat_module_lock);
+                       return sub;
+               }
+        }
+        spin_unlock(&splat_module_lock);
+
+       return NULL;
+}
+
+static int
+splat_subsystem_count(splat_cfg_t *kcfg, unsigned long arg)
+{
+       splat_subsystem_t *sub;
+       int i = 0;
+
+        spin_lock(&splat_module_lock);
+        list_for_each_entry(sub, &splat_module_list, subsystem_list)
+               i++;
+
+        spin_unlock(&splat_module_lock);
+       kcfg->cfg_rc1 = i;
+
+       if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int
+splat_subsystem_list(splat_cfg_t *kcfg, unsigned long arg)
+{
+       splat_subsystem_t *sub;
+       splat_cfg_t *tmp;
+       int size, i = 0;
+
+       /* Structure will be sized large enough for N subsystem entries
+        * which is passed in by the caller.  On exit the number of
+        * entries filled in with valid subsystems will be stored in
+        * cfg_rc1.  If the caller does not provide enough entries
+        * for all subsystems we will truncate the list to avoid overrun.
+        */
+       size = sizeof(*tmp) + kcfg->cfg_data.splat_subsystems.size *
+              sizeof(splat_user_t);
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       /* Local 'tmp' is used as the structure copied back to user space */
+       memset(tmp, 0, size);
+       memcpy(tmp, kcfg, sizeof(*kcfg));
+
+        spin_lock(&splat_module_lock);
+        list_for_each_entry(sub, &splat_module_list, subsystem_list) {
+               strncpy(tmp->cfg_data.splat_subsystems.descs[i].name,
+                       sub->desc.name, SPLAT_NAME_SIZE);
+               strncpy(tmp->cfg_data.splat_subsystems.descs[i].desc,
+                       sub->desc.desc, SPLAT_DESC_SIZE);
+               tmp->cfg_data.splat_subsystems.descs[i].id = sub->desc.id;
+
+               /* Truncate list if we are about to overrun alloc'ed memory */
+               if ((i++) == kcfg->cfg_data.splat_subsystems.size)
+                       break;
+        }
+        spin_unlock(&splat_module_lock);
+       tmp->cfg_rc1 = i;
+
+       if (copy_to_user((struct splat_cfg_t __user *)arg, tmp, size)) {
+               kfree(tmp);
+               return -EFAULT;
+       }
+
+       kfree(tmp);
+       return 0;
+}
+
+static int
+splat_test_count(splat_cfg_t *kcfg, unsigned long arg)
+{
+       splat_subsystem_t *sub;
+       splat_test_t *test;
+       int i = 0;
+
+       /* Subsystem ID passed as arg1 */
+       sub = splat_subsystem_find(kcfg->cfg_arg1);
+       if (sub == NULL)
+               return -EINVAL;
+
+        spin_lock(&(sub->test_lock));
+        list_for_each_entry(test, &(sub->test_list), test_list)
+               i++;
+
+        spin_unlock(&(sub->test_lock));
+       kcfg->cfg_rc1 = i;
+
+       if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int
+splat_test_list(splat_cfg_t *kcfg, unsigned long arg)
+{
+       splat_subsystem_t *sub;
+       splat_test_t *test;
+       splat_cfg_t *tmp;
+       int size, i = 0;
+
+       /* Subsystem ID passed as arg1 */
+       sub = splat_subsystem_find(kcfg->cfg_arg1);
+       if (sub == NULL)
+               return -EINVAL;
+
+       /* Structure will be sized large enough for N test entries
+        * which is passed in by the caller.  On exit the number of
+        * entries filled in with valid tests will be stored in
+        * cfg_rc1.  If the caller does not provide enough entries
+        * for all tests we will truncate the list to avoid overrun.
+        */
+       size = sizeof(*tmp)+kcfg->cfg_data.splat_tests.size*sizeof(splat_user_t);
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       /* Local 'tmp' is used as the structure copied back to user space */
+       memset(tmp, 0, size);
+       memcpy(tmp, kcfg, sizeof(*kcfg));
+
+        spin_lock(&(sub->test_lock));
+        list_for_each_entry(test, &(sub->test_list), test_list) {
+               strncpy(tmp->cfg_data.splat_tests.descs[i].name,
+                       test->desc.name, SPLAT_NAME_SIZE);
+               strncpy(tmp->cfg_data.splat_tests.descs[i].desc,
+                       test->desc.desc, SPLAT_DESC_SIZE);
+               tmp->cfg_data.splat_tests.descs[i].id = test->desc.id;
+
+               /* Truncate list if we are about to overrun alloc'ed memory */
+               if ((i++) == kcfg->cfg_data.splat_tests.size)
+                       break;
+        }
+        spin_unlock(&(sub->test_lock));
+       tmp->cfg_rc1 = i;
+
+       if (copy_to_user((struct splat_cfg_t __user *)arg, tmp, size)) {
+               kfree(tmp);
+               return -EFAULT;
+       }
+
+       kfree(tmp);
+       return 0;
+}
+
+static int
+splat_validate(struct file *file, splat_subsystem_t *sub, int cmd, void *arg)
+{
+        splat_test_t *test;
+
+        spin_lock(&(sub->test_lock));
+        list_for_each_entry(test, &(sub->test_list), test_list) {
+                if (test->desc.id == cmd) {
+                       spin_unlock(&(sub->test_lock));
+                        return test->test(file, arg);
+                }
+        }
+        spin_unlock(&(sub->test_lock));
+
+        return -EINVAL;
+}
+
+static int
+splat_ioctl_cfg(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       splat_cfg_t kcfg;
+       int rc = 0;
+
+       /* User and kernel space agree about arg size */
+       if (_IOC_SIZE(cmd) != sizeof(kcfg))
+               return -EBADMSG;
+
+       if (copy_from_user(&kcfg, (splat_cfg_t *)arg, sizeof(kcfg)))
+               return -EFAULT;
+
+       if (kcfg.cfg_magic != SPLAT_CFG_MAGIC) {
+               splat_print(file, "Bad config magic 0x%x != 0x%x\n",
+                         kcfg.cfg_magic, SPLAT_CFG_MAGIC);
+               return -EINVAL;
+       }
+
+       switch (kcfg.cfg_cmd) {
+               case SPLAT_CFG_BUFFER_CLEAR:
+                       /* cfg_arg1 - Unused
+                        * cfg_rc1  - Unused
+                        */
+                       rc = splat_buffer_clear(file, &kcfg, arg);
+                       break;
+               case SPLAT_CFG_BUFFER_SIZE:
+                       /* cfg_arg1 - 0 - query size; >0 resize
+                        * cfg_rc1  - Set to current buffer size
+                        */
+                       rc = splat_buffer_size(file, &kcfg, arg);
+                       break;
+               case SPLAT_CFG_SUBSYSTEM_COUNT:
+                       /* cfg_arg1 - Unused
+                        * cfg_rc1  - Set to number of subsystems
+                        */
+                       rc = splat_subsystem_count(&kcfg, arg);
+                       break;
+               case SPLAT_CFG_SUBSYSTEM_LIST:
+                       /* cfg_arg1 - Unused
+                        * cfg_rc1  - Set to number of subsystems
+                        * cfg_data.splat_subsystems - Set with subsystems
+                        */
+                       rc = splat_subsystem_list(&kcfg, arg);
+                       break;
+               case SPLAT_CFG_TEST_COUNT:
+                       /* cfg_arg1 - Set to a target subsystem
+                        * cfg_rc1  - Set to number of tests
+                        */
+                       rc = splat_test_count(&kcfg, arg);
+                       break;
+               case SPLAT_CFG_TEST_LIST:
+                       /* cfg_arg1 - Set to a target subsystem
+                        * cfg_rc1  - Set to number of tests
+                        * cfg_data.splat_subsystems - Populated with tests
+                        */
+                       rc = splat_test_list(&kcfg, arg);
+                       break;
+               default:
+                       splat_print(file, "Bad config command %d\n",
+                                   kcfg.cfg_cmd);
+                       rc = -EINVAL;
+                       break;
+       }
+
+       return rc;
+}
+
+static int
+splat_ioctl_cmd(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       splat_subsystem_t *sub;
+       splat_cmd_t kcmd;
+       int rc = -EINVAL;
+       void *data = NULL;
+
+       /* User and kernel space agree about arg size */
+       if (_IOC_SIZE(cmd) != sizeof(kcmd))
+               return -EBADMSG;
+
+       if (copy_from_user(&kcmd, (splat_cfg_t *)arg, sizeof(kcmd)))
+               return -EFAULT;
+
+       if (kcmd.cmd_magic != SPLAT_CMD_MAGIC) {
+               splat_print(file, "Bad command magic 0x%x != 0x%x\n",
+                         kcmd.cmd_magic, SPLAT_CFG_MAGIC);
+               return -EINVAL;
+       }
+
+       /* Allocate memory for any opaque data the caller needed to pass on */
+       if (kcmd.cmd_data_size > 0) {
+               data = (void *)kmalloc(kcmd.cmd_data_size, GFP_KERNEL);
+               if (data == NULL)
+                       return -ENOMEM;
+
+               if (copy_from_user(data, (void *)(arg + offsetof(splat_cmd_t,
+                                  cmd_data_str)), kcmd.cmd_data_size)) {
+                       kfree(data);
+                       return -EFAULT;
+               }
+       }
+
+       sub = splat_subsystem_find(kcmd.cmd_subsystem);
+       if (sub != NULL)
+               rc = splat_validate(file, sub, kcmd.cmd_test, data);
+       else
+               rc = -EINVAL;
+
+       if (data != NULL)
+               kfree(data);
+
+       return rc;
+}
+
+static long
+splat_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int rc = 0;
+
+       /* Ignore tty ioctls */
+       if ((cmd & 0xffffff00) == ((int)'T') << 8)
+               return -ENOTTY;
+
+       switch (cmd) {
+               case SPLAT_CFG:
+                       rc = splat_ioctl_cfg(file, cmd, arg);
+                       break;
+               case SPLAT_CMD:
+                       rc = splat_ioctl_cmd(file, cmd, arg);
+                       break;
+               default:
+                       splat_print(file, "Bad ioctl command %d\n", cmd);
+                       rc = -EINVAL;
+                       break;
+       }
+
+       return rc;
+}
+
+#ifdef CONFIG_COMPAT
+/* Compatibility handler for ioctls from 32-bit ELF binaries */
+static long
+splat_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return splat_unlocked_ioctl(file, cmd, arg);
+}
+#endif /* CONFIG_COMPAT */
+
+/* I'm not sure why you would want to write in to this buffer from
+ * user space since its principle use is to pass test status info
+ * back to the user space, but I don't see any reason to prevent it.
+ */
+static ssize_t splat_write(struct file *file, const char __user *buf,
+                         size_t count, loff_t *ppos)
+{
+       splat_info_t *info = (splat_info_t *)file->private_data;
+       int rc = 0;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       mutex_enter(&info->info_lock);
+
+       /* Write beyond EOF */
+       if (*ppos >= info->info_size) {
+               rc = -EFBIG;
+               goto out;
+       }
+
+       /* Resize count if beyond EOF */
+       if (*ppos + count > info->info_size)
+               count = info->info_size - *ppos;
+
+       if (copy_from_user(info->info_buffer, buf, count)) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       *ppos += count;
+       rc = count;
+out:
+       mutex_exit(&info->info_lock);
+       return rc;
+}
+
+static ssize_t splat_read(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       splat_info_t *info = (splat_info_t *)file->private_data;
+       int rc = 0;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       mutex_enter(&info->info_lock);
+
+       /* Read beyond EOF */
+       if (*ppos >= info->info_size)
+               goto out;
+
+       /* Resize count if beyond EOF */
+       if (*ppos + count > info->info_size)
+               count = info->info_size - *ppos;
+
+       if (copy_to_user(buf, info->info_buffer + *ppos, count)) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       *ppos += count;
+       rc = count;
+out:
+       mutex_exit(&info->info_lock);
+       return rc;
+}
+
+static loff_t splat_seek(struct file *file, loff_t offset, int origin)
+{
+       splat_info_t *info = (splat_info_t *)file->private_data;
+       int rc = -EINVAL;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       mutex_enter(&info->info_lock);
+
+       switch (origin) {
+       case 0: /* SEEK_SET - No-op just do it */
+               break;
+       case 1: /* SEEK_CUR - Seek from current */
+               offset = file->f_pos + offset;
+               break;
+       case 2: /* SEEK_END - Seek from end */
+               offset = info->info_size + offset;
+               break;
+       }
+
+       if (offset >= 0) {
+               file->f_pos = offset;
+               file->f_version = 0;
+               rc = offset;
+       }
+
+       mutex_exit(&info->info_lock);
+
+       return rc;
+}
+
+static struct file_operations splat_fops = {
+       .owner          = THIS_MODULE,
+       .open           = splat_open,
+       .release        = splat_release,
+       .unlocked_ioctl = splat_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = splat_compat_ioctl,
+#endif
+       .read           = splat_read,
+       .write          = splat_write,
+       .llseek         = splat_seek,
+};
+
+static struct miscdevice splat_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = SPLAT_NAME,
+       .fops           = &splat_fops,
+};
+
+static int __init
+splat_init(void)
+{
+       int error;
+
+       spin_lock_init(&splat_module_lock);
+       INIT_LIST_HEAD(&splat_module_list);
+
+       SPLAT_SUBSYSTEM_INIT(kmem);
+       SPLAT_SUBSYSTEM_INIT(taskq);
+       SPLAT_SUBSYSTEM_INIT(krng);
+       SPLAT_SUBSYSTEM_INIT(mutex);
+       SPLAT_SUBSYSTEM_INIT(condvar);
+       SPLAT_SUBSYSTEM_INIT(thread);
+       SPLAT_SUBSYSTEM_INIT(rwlock);
+       SPLAT_SUBSYSTEM_INIT(time);
+       SPLAT_SUBSYSTEM_INIT(vnode);
+       SPLAT_SUBSYSTEM_INIT(kobj);
+       SPLAT_SUBSYSTEM_INIT(atomic);
+       SPLAT_SUBSYSTEM_INIT(list);
+       SPLAT_SUBSYSTEM_INIT(generic);
+       SPLAT_SUBSYSTEM_INIT(cred);
+       SPLAT_SUBSYSTEM_INIT(zlib);
+       SPLAT_SUBSYSTEM_INIT(linux);
+
+       error = misc_register(&splat_misc);
+       if (error) {
+               printk(KERN_INFO "SPLAT: misc_register() failed %d\n", error);
+       } else {
+               printk(KERN_INFO "SPLAT: Loaded module v%s-%s%s\n",
+                   SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR);
+       }
+
+       return (error);
+}
+
+static void __exit
+splat_fini(void)
+{
+       misc_deregister(&splat_misc);
+
+       SPLAT_SUBSYSTEM_FINI(linux);
+       SPLAT_SUBSYSTEM_FINI(zlib);
+       SPLAT_SUBSYSTEM_FINI(cred);
+       SPLAT_SUBSYSTEM_FINI(generic);
+       SPLAT_SUBSYSTEM_FINI(list);
+       SPLAT_SUBSYSTEM_FINI(atomic);
+       SPLAT_SUBSYSTEM_FINI(kobj);
+       SPLAT_SUBSYSTEM_FINI(vnode);
+       SPLAT_SUBSYSTEM_FINI(time);
+       SPLAT_SUBSYSTEM_FINI(rwlock);
+       SPLAT_SUBSYSTEM_FINI(thread);
+       SPLAT_SUBSYSTEM_FINI(condvar);
+       SPLAT_SUBSYSTEM_FINI(mutex);
+       SPLAT_SUBSYSTEM_FINI(krng);
+       SPLAT_SUBSYSTEM_FINI(taskq);
+       SPLAT_SUBSYSTEM_FINI(kmem);
+
+       ASSERT(list_empty(&splat_module_list));
+       printk(KERN_INFO "SPLAT: Unloaded module v%s-%s%s\n",
+           SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR);
+}
+
+module_init(splat_init);
+module_exit(splat_fini);
+
+MODULE_DESCRIPTION("Solaris Porting LAyer Tests");
+MODULE_AUTHOR(SPL_META_AUTHOR);
+MODULE_LICENSE(SPL_META_LICENSE);
+MODULE_VERSION(SPL_META_VERSION "-" SPL_META_RELEASE);
diff --git a/spl/module/splat/splat-generic.c b/spl/module/splat/splat-generic.c
new file mode 100644 (file)
index 0000000..3f8119b
--- /dev/null
@@ -0,0 +1,367 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Generic Tests.
+\*****************************************************************************/
+
+#include <sys/sunddi.h>
+#include <linux/math64_compat.h>
+#include "splat-internal.h"
+
+#define SPLAT_GENERIC_NAME             "generic"
+#define SPLAT_GENERIC_DESC             "Kernel Generic Tests"
+
+#define SPLAT_GENERIC_TEST1_ID         0x0d01
+#define SPLAT_GENERIC_TEST1_NAME       "ddi_strtoul"
+#define SPLAT_GENERIC_TEST1_DESC       "ddi_strtoul Test"
+
+#define SPLAT_GENERIC_TEST2_ID         0x0d02
+#define SPLAT_GENERIC_TEST2_NAME       "ddi_strtol"
+#define SPLAT_GENERIC_TEST2_DESC       "ddi_strtol Test"
+
+#define SPLAT_GENERIC_TEST3_ID         0x0d03
+#define SPLAT_GENERIC_TEST3_NAME       "ddi_strtoull"
+#define SPLAT_GENERIC_TEST3_DESC       "ddi_strtoull Test"
+
+#define SPLAT_GENERIC_TEST4_ID         0x0d04
+#define SPLAT_GENERIC_TEST4_NAME       "ddi_strtoll"
+#define SPLAT_GENERIC_TEST4_DESC       "ddi_strtoll Test"
+
+# define SPLAT_GENERIC_TEST5_ID                0x0d05
+# define SPLAT_GENERIC_TEST5_NAME      "udivdi3"
+# define SPLAT_GENERIC_TEST5_DESC      "Unsigned Div-64 Test"
+
+# define SPLAT_GENERIC_TEST6_ID                0x0d06
+# define SPLAT_GENERIC_TEST6_NAME      "divdi3"
+# define SPLAT_GENERIC_TEST6_DESC      "Signed Div-64 Test"
+
+#define STR_POS                                "123456789"
+#define STR_NEG                                "-123456789"
+#define STR_BASE                       "0xabcdef"
+#define STR_RANGE_MAX                  "10000000000000000"
+#define STR_RANGE_MIN                  "-10000000000000000"
+#define STR_INVAL1                     "12345U"
+#define STR_INVAL2                     "invald"
+
+#define VAL_POS                                123456789
+#define VAL_NEG                                -123456789
+#define VAL_BASE                       0xabcdef
+#define VAL_INVAL1                     12345U
+
+#define define_generic_msg_strtox(type, valtype)                       \
+static void                                                            \
+generic_msg_strto##type(struct file *file, char *msg, int rc, int *err, \
+                       const char *s, valtype d, char *endptr)         \
+{                                                                      \
+       splat_vprint(file, SPLAT_GENERIC_TEST1_NAME,                    \
+                    "%s (%d) %s: %s == %lld, 0x%p\n",                  \
+                    rc ? "Fail" : "Pass", *err, msg, s,                \
+                    (unsigned long long)d, endptr);                    \
+       *err = rc;                                                      \
+}
+
+define_generic_msg_strtox(ul, unsigned long);
+define_generic_msg_strtox(l, long);
+define_generic_msg_strtox(ull, unsigned long long);
+define_generic_msg_strtox(ll, long long);
+
+#define define_splat_generic_test_strtox(type, valtype)                        \
+static int                                                             \
+splat_generic_test_strto##type(struct file *file, void *arg)           \
+{                                                                      \
+       int rc, rc1, rc2, rc3, rc4, rc5, rc6, rc7;                      \
+       char str[20], *endptr;                                          \
+       valtype r;                                                      \
+                                                                       \
+       /* Positive value: expect success */                            \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc1 = ddi_strto##type(STR_POS, &endptr, 10, &r);                \
+       if (rc1 == 0 && r == VAL_POS && endptr && *endptr == '\0')      \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "positive", rc , &rc1,            \
+                               STR_POS, r, endptr);                    \
+                                                                       \
+       /* Negative value: expect success */                            \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       strcpy(str, STR_NEG);                                           \
+       rc2 = ddi_strto##type(str, &endptr, 10, &r);                    \
+       if (#type[0] == 'u') {                                          \
+               if (rc2 == 0 && r == 0 && endptr == str)                \
+                       rc = 0;                                         \
+       } else {                                                        \
+               if (rc2 == 0 && r == VAL_NEG &&                         \
+                   endptr && *endptr == '\0')                          \
+                       rc = 0;                                         \
+       }                                                               \
+                                                                       \
+       generic_msg_strto##type(file, "negative", rc, &rc2,             \
+                               STR_NEG, r, endptr);                    \
+                                                                       \
+       /* Non decimal base: expect sucess */                           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc3 = ddi_strto##type(STR_BASE, &endptr, 0, &r);                \
+       if (rc3 == 0 && r == VAL_BASE && endptr && *endptr == '\0')     \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "base", rc, &rc3,                 \
+                               STR_BASE, r, endptr);                   \
+                                                                       \
+       /* Max out of range: failure expected, r unchanged */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc4 = ddi_strto##type(STR_RANGE_MAX, &endptr, 16, &r);          \
+       if (rc4 == ERANGE && r == 0 && endptr == NULL)                  \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "max", rc, &rc4,                  \
+                               STR_RANGE_MAX, r, endptr);              \
+                                                                       \
+       /* Min out of range: failure expected, r unchanged */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       strcpy(str, STR_RANGE_MIN);                                     \
+       rc5 = ddi_strto##type(str, &endptr, 16, &r);                    \
+       if (#type[0] == 'u') {                                          \
+               if (rc5 == 0 && r == 0 && endptr == str)                \
+                       rc = 0;                                         \
+       } else {                                                        \
+               if (rc5 == ERANGE && r == 0 && endptr == NULL)          \
+                       rc = 0;                                         \
+       }                                                               \
+                                                                       \
+       generic_msg_strto##type(file, "min", rc, &rc5,                  \
+                               STR_RANGE_MIN, r, endptr);              \
+                                                                       \
+       /* Invalid string: success expected, endptr == 'U' */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc6 = ddi_strto##type(STR_INVAL1, &endptr, 10, &r);             \
+       if (rc6 == 0 && r == VAL_INVAL1 && endptr && *endptr == 'U')    \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "invalid", rc, &rc6,              \
+                               STR_INVAL1, r, endptr);                 \
+                                                                       \
+       /* Invalid string: failure expected, endptr == str */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       strcpy(str, STR_INVAL2);                                        \
+       rc7 = ddi_strto##type(str, &endptr, 10, &r);                    \
+       if (rc7 == 0 && r == 0 && endptr == str)                        \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "invalid", rc, &rc7,              \
+                               STR_INVAL2, r, endptr);                 \
+                                                                       \
+        return (rc1 || rc2 || rc3 || rc4 || rc5 || rc6 || rc7) ?       \
+               -EINVAL : 0;                                            \
+}
+
+define_splat_generic_test_strtox(ul, unsigned long);
+define_splat_generic_test_strtox(l, long);
+define_splat_generic_test_strtox(ull, unsigned long long);
+define_splat_generic_test_strtox(ll, long long);
+
+/*
+ * The entries in the table are used in all combinations and the
+ * return value is checked to ensure it is range.  On 32-bit
+ * systems __udivdi3 will be invoked for the 64-bit division.
+ * On 64-bit system the native 64-bit divide will be used so
+ * __udivdi3 isn't used but we might as well stil run the test.
+ */
+static int
+splat_generic_test_udivdi3(struct file *file, void *arg)
+{
+       const uint64_t tabu[] = {
+           0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+           10, 11, 12, 13, 14, 15, 16, 1000, 2003,
+           32765, 32766, 32767, 32768, 32769, 32760,
+           65533, 65534, 65535, 65536, 65537, 65538,
+           0x7ffffffeULL, 0x7fffffffULL, 0x80000000ULL, 0x80000001ULL,
+           0x7000000000000000ULL, 0x7000000080000000ULL, 0x7000000080000001ULL,
+           0x7fffffffffffffffULL, 0x7fffffff8fffffffULL, 0x7fffffff8ffffff1ULL,
+           0x7fffffff00000000ULL, 0x7fffffff80000000ULL, 0x7fffffff00000001ULL,
+           0x8000000000000000ULL, 0x8000000080000000ULL, 0x8000000080000001ULL,
+           0xc000000000000000ULL, 0xc000000080000000ULL, 0xc000000080000001ULL,
+           0xfffffffffffffffdULL, 0xfffffffffffffffeULL, 0xffffffffffffffffULL,
+       };
+       uint64_t uu, vu, qu, ru;
+       int n, i, j, errors = 0;
+
+       splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, "%s",
+           "Testing unsigned 64-bit division.\n");
+       n = sizeof(tabu) / sizeof(tabu[0]);
+       for (i = 0; i < n; i++) {
+               for (j = 1; j < n; j++) {
+                       uu = tabu[i];
+                       vu = tabu[j];
+                       qu = uu / vu; /* __udivdi3 */
+                       ru = uu - qu * vu;
+                       if (qu > uu || ru >= vu) {
+                               splat_vprint(file, SPLAT_GENERIC_TEST5_NAME,
+                                   "%016llx/%016llx != %016llx rem %016llx\n",
+                                   uu, vu, qu, ru);
+                               errors++;
+                       }
+               }
+       }
+
+       if (errors) {
+               splat_vprint(file, SPLAT_GENERIC_TEST5_NAME,
+                   "Failed %d/%d tests\n", errors, n * (n - 1));
+               return -ERANGE;
+       }
+
+       splat_vprint(file, SPLAT_GENERIC_TEST5_NAME,
+           "Passed all %d tests\n", n * (n - 1));
+
+       return 0;
+}
+
+/*
+ * The entries the table are used in all combinations, with + and - signs
+ * preceding them.  The return value is checked to ensure it is range.
+ * On 32-bit systems __divdi3 will be invoked for the 64-bit division.
+ * On 64-bit system the native 64-bit divide will be used so __divdi3
+ *  isn't used but we might as well stil run the test.
+ */
+static int
+splat_generic_test_divdi3(struct file *file, void *arg)
+{
+       const int64_t tabs[] = {
+           0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+           10, 11, 12, 13, 14, 15, 16, 1000, 2003,
+           32765, 32766, 32767, 32768, 32769, 32760,
+           65533, 65534, 65535, 65536, 65537, 65538,
+           0x7ffffffeLL, 0x7fffffffLL, 0x80000000LL, 0x80000001LL,
+           0x7000000000000000LL, 0x7000000080000000LL, 0x7000000080000001LL,
+           0x7fffffffffffffffLL, 0x7fffffff8fffffffLL, 0x7fffffff8ffffff1LL,
+           0x7fffffff00000000LL, 0x7fffffff80000000LL, 0x7fffffff00000001LL,
+           0x0123456789abcdefLL, 0x00000000abcdef01LL, 0x0000000012345678LL,
+#if BITS_PER_LONG == 32
+           0x8000000000000000LL, 0x8000000080000000LL, 0x8000000080000001LL,
+#endif
+       };
+       int64_t u, v, q, r;
+       int n, i, j, k, errors = 0;
+
+       splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, "%s",
+           "Testing signed 64-bit division.\n");
+       n = sizeof(tabs) / sizeof(tabs[0]);
+       for (i = 0; i < n; i++) {
+               for (j = 1; j < n; j++) {
+                       for (k = 0; k <= 3; k++) {
+                               u = (k & 1)  ? -tabs[i] : tabs[i];
+                               v = (k >= 2) ? -tabs[j] : tabs[j];
+
+                               q = u / v; /* __divdi3 */
+                               r = u - q * v;
+                               if (abs64(q) >  abs64(u) ||
+                                   abs64(r) >= abs64(v) ||
+                                   (r != 0 && (r ^ u) < 0)) {
+                                       splat_vprint(file,
+                                           SPLAT_GENERIC_TEST6_NAME,
+                                           "%016llx/%016llx != %016llx "
+                                           "rem %016llx\n", u, v, q, r);
+                                       errors++;
+                               }
+                       }
+               }
+       }
+
+       if (errors) {
+               splat_vprint(file, SPLAT_GENERIC_TEST6_NAME,
+                   "Failed %d/%d tests\n", errors, n * (n - 1));
+               return -ERANGE;
+       }
+
+       splat_vprint(file, SPLAT_GENERIC_TEST6_NAME,
+           "Passed all %d tests\n", n * (n - 1));
+
+       return 0;
+}
+
+splat_subsystem_t *
+splat_generic_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_GENERIC_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_GENERIC_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_GENERIC;
+
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST1_NAME, SPLAT_GENERIC_TEST1_DESC,
+                       SPLAT_GENERIC_TEST1_ID, splat_generic_test_strtoul);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST2_NAME, SPLAT_GENERIC_TEST2_DESC,
+                       SPLAT_GENERIC_TEST2_ID, splat_generic_test_strtol);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST3_NAME, SPLAT_GENERIC_TEST3_DESC,
+                       SPLAT_GENERIC_TEST3_ID, splat_generic_test_strtoull);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST4_NAME, SPLAT_GENERIC_TEST4_DESC,
+                       SPLAT_GENERIC_TEST4_ID, splat_generic_test_strtoll);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST5_NAME, SPLAT_GENERIC_TEST5_DESC,
+                       SPLAT_GENERIC_TEST5_ID, splat_generic_test_udivdi3);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST6_NAME, SPLAT_GENERIC_TEST6_DESC,
+                       SPLAT_GENERIC_TEST6_ID, splat_generic_test_divdi3);
+
+        return sub;
+}
+
+void
+splat_generic_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST6_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST5_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST4_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_generic_id(void)
+{
+        return SPLAT_SUBSYSTEM_GENERIC;
+}
diff --git a/spl/module/splat/splat-internal.h b/spl/module/splat/splat-internal.h
new file mode 100644 (file)
index 0000000..36cf04d
--- /dev/null
@@ -0,0 +1,220 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPLAT_INTERNAL_H
+#define _SPLAT_INTERNAL_H
+
+#include "splat-ctl.h"
+#include <sys/mutex.h>
+#include <linux/file_compat.h>
+#include <linux/version.h>
+
+#define SPLAT_SUBSYSTEM_INIT(type)                                      \
+({      splat_subsystem_t *_sub_;                                       \
+                                                                        \
+        _sub_ = (splat_subsystem_t *)splat_##type##_init();             \
+        if (_sub_ == NULL) {                                            \
+                printk(KERN_ERR "splat: Error initializing: " #type "\n"); \
+        } else {                                                        \
+                spin_lock(&splat_module_lock);                          \
+                list_add_tail(&(_sub_->subsystem_list),                        \
+                             &splat_module_list);                      \
+                spin_unlock(&splat_module_lock);                        \
+        }                                                               \
+})
+
+#define SPLAT_SUBSYSTEM_FINI(type)                                      \
+({      splat_subsystem_t *_sub_, *_tmp_;                               \
+        int _id_, _flag_ = 0;                                           \
+                                                                        \
+       _id_ = splat_##type##_id();                                     \
+        spin_lock(&splat_module_lock);                                  \
+        list_for_each_entry_safe(_sub_, _tmp_,  &splat_module_list,    \
+                                subsystem_list) {                      \
+                if (_sub_->desc.id == _id_) {                           \
+                        list_del_init(&(_sub_->subsystem_list));        \
+                        spin_unlock(&splat_module_lock);                \
+                        splat_##type##_fini(_sub_);                     \
+                       spin_lock(&splat_module_lock);                  \
+                        _flag_ = 1;                                     \
+                }                                                       \
+        }                                                               \
+        spin_unlock(&splat_module_lock);                                \
+                                                                        \
+       if (!_flag_)                                                    \
+                printk(KERN_ERR "splat: Error finalizing: " #type "\n"); \
+})
+
+#define SPLAT_TEST_INIT(sub, n, d, tid, func)                          \
+({      splat_test_t *_test_;                                           \
+                                                                        \
+       _test_ = (splat_test_t *)kmalloc(sizeof(*_test_), GFP_KERNEL);  \
+        if (_test_ == NULL) {                                          \
+               printk(KERN_ERR "splat: Error initializing: " n "/" #tid" \n");\
+       } else {                                                        \
+               memset(_test_, 0, sizeof(*_test_));                     \
+               strncpy(_test_->desc.name, n, SPLAT_NAME_SIZE-1);       \
+               strncpy(_test_->desc.desc, d, SPLAT_DESC_SIZE-1);       \
+               _test_->desc.id = tid;                                  \
+               _test_->test = func;                                    \
+               INIT_LIST_HEAD(&(_test_->test_list));                   \
+                spin_lock(&((sub)->test_lock));                                \
+                list_add_tail(&(_test_->test_list),&((sub)->test_list));\
+                spin_unlock(&((sub)->test_lock));                      \
+        }                                                              \
+})
+
+#define SPLAT_TEST_FINI(sub, tid)                                      \
+({      splat_test_t *_test_, *_tmp_;                                   \
+        int _flag_ = 0;                                                        \
+                                                                        \
+        spin_lock(&((sub)->test_lock));                                        \
+        list_for_each_entry_safe(_test_, _tmp_,                                \
+                                &((sub)->test_list), test_list) {      \
+                if (_test_->desc.id == tid) {                           \
+                        list_del_init(&(_test_->test_list));           \
+                       kfree(_test_);                                  \
+                        _flag_ = 1;                                     \
+                }                                                       \
+        }                                                               \
+        spin_unlock(&((sub)->test_lock));                              \
+                                                                        \
+       if (!_flag_)                                                    \
+                printk(KERN_ERR "splat: Error finalizing: " #tid "\n");        \
+})
+
+typedef int (*splat_test_func_t)(struct file *, void *);
+
+typedef struct splat_test {
+       struct list_head test_list;
+       splat_user_t desc;
+       splat_test_func_t test;
+} splat_test_t;
+
+typedef struct splat_subsystem {
+       struct list_head subsystem_list;/* List had to chain entries */
+       splat_user_t desc;
+       spinlock_t test_lock;
+       struct list_head test_list;
+} splat_subsystem_t;
+
+#define SPLAT_INFO_BUFFER_SIZE         65536
+#define SPLAT_INFO_BUFFER_REDZONE      256
+
+typedef struct splat_info {
+       kmutex_t info_lock;
+       int info_size;
+       char *info_buffer;
+       char *info_head;        /* Internal kernel use only */
+} splat_info_t;
+
+#define sym2str(sym)                   (char *)(#sym)
+
+#define splat_print(file, format, args...)                             \
+({     splat_info_t *_info_ = (splat_info_t *)file->private_data;      \
+       int _rc_;                                                       \
+                                                                       \
+       ASSERT(_info_);                                                 \
+       ASSERT(_info_->info_buffer);                                    \
+                                                                       \
+       mutex_enter(&_info_->info_lock);                                \
+                                                                       \
+       /* Don't allow the kernel to start a write in the red zone */   \
+       if ((int)(_info_->info_head - _info_->info_buffer) >            \
+           (SPLAT_INFO_BUFFER_SIZE - SPLAT_INFO_BUFFER_REDZONE)) {     \
+               _rc_ = -EOVERFLOW;                                      \
+       } else {                                                        \
+               _rc_ = sprintf(_info_->info_head, format, args);        \
+               if (_rc_ >= 0)                                          \
+                       _info_->info_head += _rc_;                      \
+       }                                                               \
+                                                                       \
+       mutex_exit(&_info_->info_lock);                                 \
+       _rc_;                                                           \
+})
+
+#define splat_vprint(file, test, format, args...)                      \
+       splat_print(file, "%*s: " format, SPLAT_NAME_SIZE, test, args)
+
+#define splat_locked_test(lock, test)                                  \
+({                                                                     \
+       int _rc_;                                                       \
+       spin_lock(lock);                                                \
+       _rc_ = (test) ? 1 : 0;                                          \
+       spin_unlock(lock);                                              \
+       _rc_;                                                           \
+})
+
+splat_subsystem_t *splat_condvar_init(void);
+splat_subsystem_t *splat_kmem_init(void);
+splat_subsystem_t *splat_mutex_init(void);
+splat_subsystem_t *splat_krng_init(void);
+splat_subsystem_t *splat_rwlock_init(void);
+splat_subsystem_t *splat_taskq_init(void);
+splat_subsystem_t *splat_thread_init(void);
+splat_subsystem_t *splat_time_init(void);
+splat_subsystem_t *splat_vnode_init(void);
+splat_subsystem_t *splat_kobj_init(void);
+splat_subsystem_t *splat_atomic_init(void);
+splat_subsystem_t *splat_list_init(void);
+splat_subsystem_t *splat_generic_init(void);
+splat_subsystem_t *splat_cred_init(void);
+splat_subsystem_t *splat_zlib_init(void);
+splat_subsystem_t *splat_linux_init(void);
+
+void splat_condvar_fini(splat_subsystem_t *);
+void splat_kmem_fini(splat_subsystem_t *);
+void splat_mutex_fini(splat_subsystem_t *);
+void splat_krng_fini(splat_subsystem_t *);
+void splat_rwlock_fini(splat_subsystem_t *);
+void splat_taskq_fini(splat_subsystem_t *);
+void splat_thread_fini(splat_subsystem_t *);
+void splat_time_fini(splat_subsystem_t *);
+void splat_vnode_fini(splat_subsystem_t *);
+void splat_kobj_fini(splat_subsystem_t *);
+void splat_atomic_fini(splat_subsystem_t *);
+void splat_list_fini(splat_subsystem_t *);
+void splat_generic_fini(splat_subsystem_t *);
+void splat_cred_fini(splat_subsystem_t *);
+void splat_zlib_fini(splat_subsystem_t *);
+void splat_linux_fini(splat_subsystem_t *);
+
+int splat_condvar_id(void);
+int splat_kmem_id(void);
+int splat_mutex_id(void);
+int splat_krng_id(void);
+int splat_rwlock_id(void);
+int splat_taskq_id(void);
+int splat_thread_id(void);
+int splat_time_id(void);
+int splat_vnode_id(void);
+int splat_kobj_id(void);
+int splat_atomic_id(void);
+int splat_list_id(void);
+int splat_generic_id(void);
+int splat_cred_id(void);
+int splat_zlib_id(void);
+int splat_linux_id(void);
+
+#endif /* _SPLAT_INTERNAL_H */
diff --git a/spl/module/splat/splat-kmem.c b/spl/module/splat/splat-kmem.c
new file mode 100644 (file)
index 0000000..b3fd1a8
--- /dev/null
@@ -0,0 +1,1398 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Kmem Tests.
+\*****************************************************************************/
+
+#include <sys/kmem.h>
+#include <sys/kmem_cache.h>
+#include <sys/vmem.h>
+#include <sys/random.h>
+#include <sys/thread.h>
+#include <sys/vmsystm.h>
+#include "splat-internal.h"
+
+#define SPLAT_KMEM_NAME                        "kmem"
+#define SPLAT_KMEM_DESC                        "Kernel Malloc/Slab Tests"
+
+#define SPLAT_KMEM_TEST1_ID            0x0101
+#define SPLAT_KMEM_TEST1_NAME          "kmem_alloc"
+#define SPLAT_KMEM_TEST1_DESC          "Memory allocation test (kmem_alloc)"
+
+#define SPLAT_KMEM_TEST2_ID            0x0102
+#define SPLAT_KMEM_TEST2_NAME          "kmem_zalloc"
+#define SPLAT_KMEM_TEST2_DESC          "Memory allocation test (kmem_zalloc)"
+
+#define SPLAT_KMEM_TEST3_ID            0x0103
+#define SPLAT_KMEM_TEST3_NAME          "vmem_alloc"
+#define SPLAT_KMEM_TEST3_DESC          "Memory allocation test (vmem_alloc)"
+
+#define SPLAT_KMEM_TEST4_ID            0x0104
+#define SPLAT_KMEM_TEST4_NAME          "vmem_zalloc"
+#define SPLAT_KMEM_TEST4_DESC          "Memory allocation test (vmem_zalloc)"
+
+#define SPLAT_KMEM_TEST5_ID            0x0105
+#define SPLAT_KMEM_TEST5_NAME          "slab_small"
+#define SPLAT_KMEM_TEST5_DESC          "Slab ctor/dtor test (small)"
+
+#define SPLAT_KMEM_TEST6_ID            0x0106
+#define SPLAT_KMEM_TEST6_NAME          "slab_large"
+#define SPLAT_KMEM_TEST6_DESC          "Slab ctor/dtor test (large)"
+
+#define SPLAT_KMEM_TEST7_ID            0x0107
+#define SPLAT_KMEM_TEST7_NAME          "slab_align"
+#define SPLAT_KMEM_TEST7_DESC          "Slab alignment test"
+
+#define SPLAT_KMEM_TEST8_ID            0x0108
+#define SPLAT_KMEM_TEST8_NAME          "slab_reap"
+#define SPLAT_KMEM_TEST8_DESC          "Slab reaping test"
+
+#define SPLAT_KMEM_TEST9_ID            0x0109
+#define SPLAT_KMEM_TEST9_NAME          "slab_age"
+#define SPLAT_KMEM_TEST9_DESC          "Slab aging test"
+
+#define SPLAT_KMEM_TEST10_ID           0x010a
+#define SPLAT_KMEM_TEST10_NAME         "slab_lock"
+#define SPLAT_KMEM_TEST10_DESC         "Slab locking test"
+
+#if 0
+#define SPLAT_KMEM_TEST11_ID           0x010b
+#define SPLAT_KMEM_TEST11_NAME         "slab_overcommit"
+#define SPLAT_KMEM_TEST11_DESC         "Slab memory overcommit test"
+#endif
+
+#define SPLAT_KMEM_TEST13_ID           0x010d
+#define SPLAT_KMEM_TEST13_NAME         "slab_reclaim"
+#define SPLAT_KMEM_TEST13_DESC         "Slab direct memory reclaim test"
+
+#define SPLAT_KMEM_ALLOC_COUNT         10
+#define SPLAT_VMEM_ALLOC_COUNT         10
+
+
+static int
+splat_kmem_test1(struct file *file, void *arg)
+{
+       void *ptr[SPLAT_KMEM_ALLOC_COUNT];
+       int size = PAGE_SIZE;
+       int i, count, rc = 0;
+
+       while ((!rc) && (size <= spl_kmem_alloc_warn)) {
+               count = 0;
+
+               for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) {
+                       ptr[i] = kmem_alloc(size, KM_SLEEP);
+                       if (ptr[i])
+                               count++;
+               }
+
+               for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++)
+                       if (ptr[i])
+                               kmem_free(ptr[i], size);
+
+               splat_vprint(file, SPLAT_KMEM_TEST1_NAME,
+                          "%d byte allocations, %d/%d successful\n",
+                          size, count, SPLAT_KMEM_ALLOC_COUNT);
+               if (count != SPLAT_KMEM_ALLOC_COUNT)
+                       rc = -ENOMEM;
+
+               size *= 2;
+       }
+
+       return rc;
+}
+
+static int
+splat_kmem_test2(struct file *file, void *arg)
+{
+       void *ptr[SPLAT_KMEM_ALLOC_COUNT];
+       int size = PAGE_SIZE;
+       int i, j, count, rc = 0;
+
+       while ((!rc) && (size <= spl_kmem_alloc_warn)) {
+               count = 0;
+
+               for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) {
+                       ptr[i] = kmem_zalloc(size, KM_SLEEP);
+                       if (ptr[i])
+                               count++;
+               }
+
+               /* Ensure buffer has been zero filled */
+               for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) {
+                       for (j = 0; j < size; j++) {
+                               if (((char *)ptr[i])[j] != '\0') {
+                                       splat_vprint(file,SPLAT_KMEM_TEST2_NAME,
+                                                 "%d-byte allocation was "
+                                                 "not zeroed\n", size);
+                                       rc = -EFAULT;
+                               }
+                       }
+               }
+
+               for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++)
+                       if (ptr[i])
+                               kmem_free(ptr[i], size);
+
+               splat_vprint(file, SPLAT_KMEM_TEST2_NAME,
+                          "%d byte allocations, %d/%d successful\n",
+                          size, count, SPLAT_KMEM_ALLOC_COUNT);
+               if (count != SPLAT_KMEM_ALLOC_COUNT)
+                       rc = -ENOMEM;
+
+               size *= 2;
+       }
+
+       return rc;
+}
+
+static int
+splat_kmem_test3(struct file *file, void *arg)
+{
+       void *ptr[SPLAT_VMEM_ALLOC_COUNT];
+       int size = PAGE_SIZE;
+       int i, count, rc = 0;
+
+       /*
+        * Test up to 4x the maximum kmem_alloc() size to ensure both
+        * the kmem_alloc() and vmem_alloc() call paths are used.
+        */
+       while ((!rc) && (size <= (4 * spl_kmem_alloc_max))) {
+               count = 0;
+
+               for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) {
+                       ptr[i] = vmem_alloc(size, KM_SLEEP);
+                       if (ptr[i])
+                               count++;
+               }
+
+               for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++)
+                       if (ptr[i])
+                               vmem_free(ptr[i], size);
+
+               splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
+                          "%d byte allocations, %d/%d successful\n",
+                          size, count, SPLAT_VMEM_ALLOC_COUNT);
+               if (count != SPLAT_VMEM_ALLOC_COUNT)
+                       rc = -ENOMEM;
+
+               size *= 2;
+       }
+
+       return rc;
+}
+
+static int
+splat_kmem_test4(struct file *file, void *arg)
+{
+       void *ptr[SPLAT_VMEM_ALLOC_COUNT];
+       int size = PAGE_SIZE;
+       int i, j, count, rc = 0;
+
+       /*
+        * Test up to 4x the maximum kmem_zalloc() size to ensure both
+        * the kmem_zalloc() and vmem_zalloc() call paths are used.
+        */
+       while ((!rc) && (size <= (4 * spl_kmem_alloc_max))) {
+               count = 0;
+
+               for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) {
+                       ptr[i] = vmem_zalloc(size, KM_SLEEP);
+                       if (ptr[i])
+                               count++;
+               }
+
+               /* Ensure buffer has been zero filled */
+               for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) {
+                       for (j = 0; j < size; j++) {
+                               if (((char *)ptr[i])[j] != '\0') {
+                                       splat_vprint(file, SPLAT_KMEM_TEST4_NAME,
+                                                 "%d-byte allocation was "
+                                                 "not zeroed\n", size);
+                                       rc = -EFAULT;
+                               }
+                       }
+               }
+
+               for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++)
+                       if (ptr[i])
+                               vmem_free(ptr[i], size);
+
+               splat_vprint(file, SPLAT_KMEM_TEST4_NAME,
+                          "%d byte allocations, %d/%d successful\n",
+                          size, count, SPLAT_VMEM_ALLOC_COUNT);
+               if (count != SPLAT_VMEM_ALLOC_COUNT)
+                       rc = -ENOMEM;
+
+               size *= 2;
+       }
+
+       return rc;
+}
+
+#define SPLAT_KMEM_TEST_MAGIC          0x004488CCUL
+#define SPLAT_KMEM_CACHE_NAME          "kmem_test"
+#define SPLAT_KMEM_OBJ_COUNT           1024
+#define SPLAT_KMEM_OBJ_RECLAIM         32 /* objects */
+#define SPLAT_KMEM_THREADS             32
+
+#define KCP_FLAG_READY                 0x01
+
+typedef struct kmem_cache_data {
+       unsigned long kcd_magic;
+       struct list_head kcd_node;
+       int kcd_flag;
+       char kcd_buf[0];
+} kmem_cache_data_t;
+
+typedef struct kmem_cache_thread {
+       spinlock_t kct_lock;
+       int kct_id;
+       struct list_head kct_list;
+} kmem_cache_thread_t;
+
+typedef struct kmem_cache_priv {
+       unsigned long kcp_magic;
+       struct file *kcp_file;
+       kmem_cache_t *kcp_cache;
+       spinlock_t kcp_lock;
+       wait_queue_head_t kcp_ctl_waitq;
+       wait_queue_head_t kcp_thr_waitq;
+       int kcp_flags;
+       int kcp_kct_count;
+       kmem_cache_thread_t *kcp_kct[SPLAT_KMEM_THREADS];
+       int kcp_size;
+       int kcp_align;
+       int kcp_count;
+       int kcp_alloc;
+       int kcp_rc;
+} kmem_cache_priv_t;
+
+static kmem_cache_priv_t *
+splat_kmem_cache_test_kcp_alloc(struct file *file, char *name,
+                               int size, int align, int alloc)
+{
+       kmem_cache_priv_t *kcp;
+
+       kcp = kmem_zalloc(sizeof(kmem_cache_priv_t), KM_SLEEP);
+       if (!kcp)
+               return NULL;
+
+       kcp->kcp_magic = SPLAT_KMEM_TEST_MAGIC;
+       kcp->kcp_file = file;
+       kcp->kcp_cache = NULL;
+       spin_lock_init(&kcp->kcp_lock);
+       init_waitqueue_head(&kcp->kcp_ctl_waitq);
+       init_waitqueue_head(&kcp->kcp_thr_waitq);
+       kcp->kcp_flags = 0;
+       kcp->kcp_kct_count = -1;
+       kcp->kcp_size = size;
+       kcp->kcp_align = align;
+       kcp->kcp_count = 0;
+       kcp->kcp_alloc = alloc;
+       kcp->kcp_rc = 0;
+
+       return kcp;
+}
+
+static void
+splat_kmem_cache_test_kcp_free(kmem_cache_priv_t *kcp)
+{
+       kmem_free(kcp, sizeof(kmem_cache_priv_t));
+}
+
+static kmem_cache_thread_t *
+splat_kmem_cache_test_kct_alloc(kmem_cache_priv_t *kcp, int id)
+{
+       kmem_cache_thread_t *kct;
+
+       ASSERT3S(id, <, SPLAT_KMEM_THREADS);
+       ASSERT(kcp->kcp_kct[id] == NULL);
+
+       kct = kmem_zalloc(sizeof(kmem_cache_thread_t), KM_SLEEP);
+       if (!kct)
+               return NULL;
+
+       spin_lock_init(&kct->kct_lock);
+       kct->kct_id = id;
+       INIT_LIST_HEAD(&kct->kct_list);
+
+       spin_lock(&kcp->kcp_lock);
+       kcp->kcp_kct[id] = kct;
+       spin_unlock(&kcp->kcp_lock);
+
+       return kct;
+}
+
+static void
+splat_kmem_cache_test_kct_free(kmem_cache_priv_t *kcp,
+                              kmem_cache_thread_t *kct)
+{
+       spin_lock(&kcp->kcp_lock);
+       kcp->kcp_kct[kct->kct_id] = NULL;
+       spin_unlock(&kcp->kcp_lock);
+
+       kmem_free(kct, sizeof(kmem_cache_thread_t));
+}
+
+static void
+splat_kmem_cache_test_kcd_free(kmem_cache_priv_t *kcp,
+                              kmem_cache_thread_t *kct)
+{
+       kmem_cache_data_t *kcd;
+
+       spin_lock(&kct->kct_lock);
+       while (!list_empty(&kct->kct_list)) {
+               kcd = list_entry(kct->kct_list.next,
+                                kmem_cache_data_t, kcd_node);
+               list_del(&kcd->kcd_node);
+               spin_unlock(&kct->kct_lock);
+
+               kmem_cache_free(kcp->kcp_cache, kcd);
+
+               spin_lock(&kct->kct_lock);
+       }
+       spin_unlock(&kct->kct_lock);
+}
+
+static int
+splat_kmem_cache_test_kcd_alloc(kmem_cache_priv_t *kcp,
+                               kmem_cache_thread_t *kct, int count)
+{
+       kmem_cache_data_t *kcd;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               kcd = kmem_cache_alloc(kcp->kcp_cache, KM_SLEEP);
+               if (kcd == NULL) {
+                       splat_kmem_cache_test_kcd_free(kcp, kct);
+                       return -ENOMEM;
+               }
+
+               spin_lock(&kct->kct_lock);
+               list_add_tail(&kcd->kcd_node, &kct->kct_list);
+               spin_unlock(&kct->kct_lock);
+       }
+
+       return 0;
+}
+
+static void
+splat_kmem_cache_test_debug(struct file *file, char *name,
+                           kmem_cache_priv_t *kcp)
+{
+       int j;
+
+       splat_vprint(file, name, "%s cache objects %d",
+            kcp->kcp_cache->skc_name, kcp->kcp_count);
+
+       if (kcp->kcp_cache->skc_flags & (KMC_KMEM | KMC_VMEM)) {
+               splat_vprint(file, name, ", slabs %u/%u objs %u/%u",
+                    (unsigned)kcp->kcp_cache->skc_slab_alloc,
+                    (unsigned)kcp->kcp_cache->skc_slab_total,
+                    (unsigned)kcp->kcp_cache->skc_obj_alloc,
+                    (unsigned)kcp->kcp_cache->skc_obj_total);
+
+               if (!(kcp->kcp_cache->skc_flags & KMC_NOMAGAZINE)) {
+                       splat_vprint(file, name, "%s", "mags");
+
+                       for_each_online_cpu(j)
+                               splat_print(file, "%u/%u ",
+                                    kcp->kcp_cache->skc_mag[j]->skm_avail,
+                                    kcp->kcp_cache->skc_mag[j]->skm_size);
+               }
+       }
+
+       splat_print(file, "%s\n", "");
+}
+
+static int
+splat_kmem_cache_test_constructor(void *ptr, void *priv, int flags)
+{
+       kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv;
+       kmem_cache_data_t *kcd = (kmem_cache_data_t *)ptr;
+
+       if (kcd && kcp) {
+               kcd->kcd_magic = kcp->kcp_magic;
+               INIT_LIST_HEAD(&kcd->kcd_node);
+               kcd->kcd_flag = 1;
+               memset(kcd->kcd_buf, 0xaa, kcp->kcp_size - (sizeof *kcd));
+               kcp->kcp_count++;
+       }
+
+       return 0;
+}
+
+static void
+splat_kmem_cache_test_destructor(void *ptr, void *priv)
+{
+       kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv;
+       kmem_cache_data_t *kcd = (kmem_cache_data_t *)ptr;
+
+       if (kcd && kcp) {
+               kcd->kcd_magic = 0;
+               kcd->kcd_flag = 0;
+               memset(kcd->kcd_buf, 0xbb, kcp->kcp_size - (sizeof *kcd));
+               kcp->kcp_count--;
+       }
+
+       return;
+}
+
+/*
+ * Generic reclaim function which assumes that all objects may
+ * be reclaimed at any time.  We free a small  percentage of the
+ * objects linked off the kcp or kct[] every time we are called.
+ */
+static void
+splat_kmem_cache_test_reclaim(void *priv)
+{
+       kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv;
+       kmem_cache_thread_t *kct;
+       kmem_cache_data_t *kcd;
+       LIST_HEAD(reclaim);
+       int i, count;
+
+       ASSERT(kcp->kcp_magic == SPLAT_KMEM_TEST_MAGIC);
+
+       /* For each kct thread reclaim some objects */
+       spin_lock(&kcp->kcp_lock);
+       for (i = 0; i < SPLAT_KMEM_THREADS; i++) {
+               kct = kcp->kcp_kct[i];
+               if (!kct)
+                       continue;
+
+               spin_unlock(&kcp->kcp_lock);
+               spin_lock(&kct->kct_lock);
+
+               count = SPLAT_KMEM_OBJ_RECLAIM;
+               while (count > 0 && !list_empty(&kct->kct_list)) {
+                       kcd = list_entry(kct->kct_list.next,
+                                        kmem_cache_data_t, kcd_node);
+                       list_del(&kcd->kcd_node);
+                       list_add(&kcd->kcd_node, &reclaim);
+                       count--;
+               }
+
+               spin_unlock(&kct->kct_lock);
+               spin_lock(&kcp->kcp_lock);
+       }
+       spin_unlock(&kcp->kcp_lock);
+
+       /* Freed outside the spin lock */
+       while (!list_empty(&reclaim)) {
+               kcd = list_entry(reclaim.next, kmem_cache_data_t, kcd_node);
+               list_del(&kcd->kcd_node);
+               kmem_cache_free(kcp->kcp_cache, kcd);
+       }
+
+       return;
+}
+
+static int
+splat_kmem_cache_test_threads(kmem_cache_priv_t *kcp, int threads)
+{
+       int rc;
+
+       spin_lock(&kcp->kcp_lock);
+       rc = (kcp->kcp_kct_count == threads);
+       spin_unlock(&kcp->kcp_lock);
+
+       return rc;
+}
+
+static int
+splat_kmem_cache_test_flags(kmem_cache_priv_t *kcp, int flags)
+{
+       int rc;
+
+       spin_lock(&kcp->kcp_lock);
+       rc = (kcp->kcp_flags & flags);
+       spin_unlock(&kcp->kcp_lock);
+
+       return rc;
+}
+
+static void
+splat_kmem_cache_test_thread(void *arg)
+{
+       kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)arg;
+       kmem_cache_thread_t *kct;
+       int rc = 0, id;
+
+       ASSERT(kcp->kcp_magic == SPLAT_KMEM_TEST_MAGIC);
+
+       /* Assign thread ids */
+       spin_lock(&kcp->kcp_lock);
+       if (kcp->kcp_kct_count == -1)
+               kcp->kcp_kct_count = 0;
+
+       id = kcp->kcp_kct_count;
+       kcp->kcp_kct_count++;
+       spin_unlock(&kcp->kcp_lock);
+
+       kct = splat_kmem_cache_test_kct_alloc(kcp, id);
+       if (!kct) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /* Wait for all threads to have started and report they are ready */
+       if (kcp->kcp_kct_count == SPLAT_KMEM_THREADS)
+               wake_up(&kcp->kcp_ctl_waitq);
+
+       wait_event(kcp->kcp_thr_waitq,
+               splat_kmem_cache_test_flags(kcp, KCP_FLAG_READY));
+
+       /* Create and destroy objects */
+       rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, kcp->kcp_alloc);
+       splat_kmem_cache_test_kcd_free(kcp, kct);
+out:
+       if (kct)
+               splat_kmem_cache_test_kct_free(kcp, kct);
+
+       spin_lock(&kcp->kcp_lock);
+       if (!kcp->kcp_rc)
+               kcp->kcp_rc = rc;
+
+       if ((--kcp->kcp_kct_count) == 0)
+               wake_up(&kcp->kcp_ctl_waitq);
+
+       spin_unlock(&kcp->kcp_lock);
+
+       thread_exit();
+}
+
+static int
+splat_kmem_cache_test(struct file *file, void *arg, char *name,
+    int size, int align, int flags)
+{
+       kmem_cache_priv_t *kcp = NULL;
+       kmem_cache_data_t **kcd = NULL;
+       int i, rc = 0, objs = 0;
+
+       splat_vprint(file, name,
+           "Testing size=%d, align=%d, flags=0x%04x\n",
+           size, align, flags);
+
+       kcp = splat_kmem_cache_test_kcp_alloc(file, name, size, align, 0);
+       if (!kcp) {
+               splat_vprint(file, name, "Unable to create '%s'\n", "kcp");
+               return (-ENOMEM);
+       }
+
+       kcp->kcp_cache = kmem_cache_create(SPLAT_KMEM_CACHE_NAME,
+           kcp->kcp_size, kcp->kcp_align,
+           splat_kmem_cache_test_constructor,
+           splat_kmem_cache_test_destructor,
+           NULL, kcp, NULL, flags);
+       if (kcp->kcp_cache == NULL) {
+               splat_vprint(file, name, "Unable to create "
+                   "name='%s', size=%d, align=%d, flags=0x%x\n",
+                   SPLAT_KMEM_CACHE_NAME, size, align, flags);
+               rc = -ENOMEM;
+               goto out_free;
+       }
+
+       /*
+        * Allocate several slabs worth of objects to verify functionality.
+        * However, on 32-bit systems with limited address space constrain
+        * it to a single slab for the purposes of this test.
+        */
+#ifdef _LP64
+       objs = SPL_KMEM_CACHE_OBJ_PER_SLAB * 4;
+#else
+       objs = 1;
+#endif
+       kcd = kmem_zalloc(sizeof (kmem_cache_data_t *) * objs, KM_SLEEP);
+       if (kcd == NULL) {
+               splat_vprint(file, name, "Unable to allocate pointers "
+                   "for %d objects\n", objs);
+               rc = -ENOMEM;
+               goto out_free;
+       }
+
+       for (i = 0; i < objs; i++) {
+               kcd[i] = kmem_cache_alloc(kcp->kcp_cache, KM_SLEEP);
+               if (kcd[i] == NULL) {
+                       splat_vprint(file, name, "Unable to allocate "
+                           "from '%s'\n", SPLAT_KMEM_CACHE_NAME);
+                       rc = -EINVAL;
+                       goto out_free;
+               }
+
+               if (!kcd[i]->kcd_flag) {
+                       splat_vprint(file, name, "Failed to run constructor "
+                           "for '%s'\n", SPLAT_KMEM_CACHE_NAME);
+                       rc = -EINVAL;
+                       goto out_free;
+               }
+
+               if (kcd[i]->kcd_magic != kcp->kcp_magic) {
+                       splat_vprint(file, name,
+                           "Failed to pass private data to constructor "
+                           "for '%s'\n", SPLAT_KMEM_CACHE_NAME);
+                       rc = -EINVAL;
+                       goto out_free;
+               }
+       }
+
+       for (i = 0; i < objs; i++) {
+               kmem_cache_free(kcp->kcp_cache, kcd[i]);
+
+               /* Destructors are run for every kmem_cache_free() */
+               if (kcd[i]->kcd_flag) {
+                       splat_vprint(file, name,
+                           "Failed to run destructor for '%s'\n",
+                           SPLAT_KMEM_CACHE_NAME);
+                       rc = -EINVAL;
+                       goto out_free;
+               }
+       }
+
+       if (kcp->kcp_count) {
+               splat_vprint(file, name,
+                   "Failed to run destructor on all slab objects for '%s'\n",
+                   SPLAT_KMEM_CACHE_NAME);
+               rc = -EINVAL;
+       }
+
+       kmem_free(kcd, sizeof (kmem_cache_data_t *) * objs);
+       kmem_cache_destroy(kcp->kcp_cache);
+
+       splat_kmem_cache_test_kcp_free(kcp);
+       splat_vprint(file, name,
+           "Success ran alloc'd/free'd %d objects of size %d\n",
+           objs, size);
+
+       return (rc);
+
+out_free:
+       if (kcd) {
+               for (i = 0; i < objs; i++) {
+                       if (kcd[i] != NULL)
+                               kmem_cache_free(kcp->kcp_cache, kcd[i]);
+               }
+
+               kmem_free(kcd, sizeof (kmem_cache_data_t *) * objs);
+       }
+
+       if (kcp->kcp_cache)
+               kmem_cache_destroy(kcp->kcp_cache);
+
+       splat_kmem_cache_test_kcp_free(kcp);
+
+       return (rc);
+}
+
+static int
+splat_kmem_cache_thread_test(struct file *file, void *arg, char *name,
+                            int size, int alloc, int max_time)
+{
+       kmem_cache_priv_t *kcp;
+       kthread_t *thr;
+       struct timespec start, stop, delta;
+       char cache_name[32];
+       int i, rc = 0;
+
+       kcp = splat_kmem_cache_test_kcp_alloc(file, name, size, 0, alloc);
+       if (!kcp) {
+               splat_vprint(file, name, "Unable to create '%s'\n", "kcp");
+               return -ENOMEM;
+       }
+
+       (void)snprintf(cache_name, 32, "%s-%d-%d",
+                      SPLAT_KMEM_CACHE_NAME, size, alloc);
+       kcp->kcp_cache =
+               kmem_cache_create(cache_name, kcp->kcp_size, 0,
+                                 splat_kmem_cache_test_constructor,
+                                 splat_kmem_cache_test_destructor,
+                                 splat_kmem_cache_test_reclaim,
+                                 kcp, NULL, 0);
+       if (!kcp->kcp_cache) {
+               splat_vprint(file, name, "Unable to create '%s'\n", cache_name);
+               rc = -ENOMEM;
+               goto out_kcp;
+       }
+
+       getnstimeofday(&start);
+
+       for (i = 0; i < SPLAT_KMEM_THREADS; i++) {
+               thr = thread_create(NULL, 0,
+                                   splat_kmem_cache_test_thread,
+                                   kcp, 0, &p0, TS_RUN, defclsyspri);
+               if (thr == NULL) {
+                       rc = -ESRCH;
+                       goto out_cache;
+               }
+       }
+
+       /* Sleep until all threads have started, then set the ready
+        * flag and wake them all up for maximum concurrency. */
+       wait_event(kcp->kcp_ctl_waitq,
+                  splat_kmem_cache_test_threads(kcp, SPLAT_KMEM_THREADS));
+
+       spin_lock(&kcp->kcp_lock);
+       kcp->kcp_flags |= KCP_FLAG_READY;
+       spin_unlock(&kcp->kcp_lock);
+       wake_up_all(&kcp->kcp_thr_waitq);
+
+       /* Sleep until all thread have finished */
+       wait_event(kcp->kcp_ctl_waitq, splat_kmem_cache_test_threads(kcp, 0));
+
+       getnstimeofday(&stop);
+       delta = timespec_sub(stop, start);
+
+       splat_vprint(file, name,
+                    "%-22s %2ld.%09ld\t"
+                    "%lu/%lu/%lu\t%lu/%lu/%lu\n",
+                    kcp->kcp_cache->skc_name,
+                    delta.tv_sec, delta.tv_nsec,
+                    (unsigned long)kcp->kcp_cache->skc_slab_total,
+                    (unsigned long)kcp->kcp_cache->skc_slab_max,
+                    (unsigned long)(kcp->kcp_alloc *
+                                   SPLAT_KMEM_THREADS /
+                                   SPL_KMEM_CACHE_OBJ_PER_SLAB),
+                    (unsigned long)kcp->kcp_cache->skc_obj_total,
+                    (unsigned long)kcp->kcp_cache->skc_obj_max,
+                    (unsigned long)(kcp->kcp_alloc *
+                                    SPLAT_KMEM_THREADS));
+
+       if (delta.tv_sec >= max_time)
+               rc = -ETIME;
+
+       if (!rc && kcp->kcp_rc)
+               rc = kcp->kcp_rc;
+
+out_cache:
+       kmem_cache_destroy(kcp->kcp_cache);
+out_kcp:
+       splat_kmem_cache_test_kcp_free(kcp);
+       return rc;
+}
+
+/* Validate small object cache behavior for dynamic/kmem/vmem caches */
+static int
+splat_kmem_test5(struct file *file, void *arg)
+{
+       char *name = SPLAT_KMEM_TEST5_NAME;
+       int i, rc = 0;
+
+       /* Randomly pick small object sizes and alignments. */
+       for (i = 0; i < 100; i++) {
+               int size, align, flags = 0;
+               uint32_t rnd;
+
+               /* Evenly distribute tests over all value cache types */
+               get_random_bytes((void *)&rnd, sizeof (uint32_t));
+               switch (rnd & 0x03) {
+               default:
+               case 0x00:
+                       flags = 0;
+                       break;
+               case 0x01:
+                       flags = KMC_KMEM;
+                       break;
+               case 0x02:
+                       flags = KMC_VMEM;
+                       break;
+               case 0x03:
+                       flags = KMC_SLAB;
+                       break;
+               }
+
+               /* The following flags are set with a 1/10 chance */
+               flags |= ((((rnd >> 8) % 10) == 0) ? KMC_OFFSLAB : 0);
+               flags |= ((((rnd >> 16) % 10) == 0) ? KMC_NOEMERGENCY : 0);
+
+               /* 32b - PAGE_SIZE */
+               get_random_bytes((void *)&rnd, sizeof (uint32_t));
+               size = MAX(rnd % (PAGE_SIZE + 1), 32);
+
+               /* 2^N where (3 <= N <= PAGE_SHIFT) */
+               get_random_bytes((void *)&rnd, sizeof (uint32_t));
+               align = (1 << MAX(3, rnd % (PAGE_SHIFT + 1)));
+
+               rc = splat_kmem_cache_test(file, arg, name, size, align, flags);
+               if (rc)
+                       return (rc);
+       }
+
+       return (rc);
+}
+
+/*
+ * Validate large object cache behavior for dynamic/kmem/vmem caches
+ */
+static int
+splat_kmem_test6(struct file *file, void *arg)
+{
+       char *name = SPLAT_KMEM_TEST6_NAME;
+       int i, max_size, rc = 0;
+
+       /* Randomly pick large object sizes and alignments. */
+       for (i = 0; i < 100; i++) {
+               int size, align, flags = 0;
+               uint32_t rnd;
+
+               /* Evenly distribute tests over all value cache types */
+               get_random_bytes((void *)&rnd, sizeof (uint32_t));
+               switch (rnd & 0x03) {
+               default:
+               case 0x00:
+                       flags = 0;
+                       max_size = (SPL_KMEM_CACHE_MAX_SIZE * 1024 * 1024) / 2;
+                       break;
+               case 0x01:
+                       flags = KMC_KMEM;
+                       max_size = (SPL_MAX_ORDER_NR_PAGES - 2) * PAGE_SIZE;
+                       break;
+               case 0x02:
+                       flags = KMC_VMEM;
+                       max_size = (SPL_KMEM_CACHE_MAX_SIZE * 1024 * 1024) / 2;
+                       break;
+               case 0x03:
+                       flags = KMC_SLAB;
+                       max_size = SPL_MAX_KMEM_ORDER_NR_PAGES * PAGE_SIZE;
+                       break;
+               }
+
+               /* The following flags are set with a 1/10 chance */
+               flags |= ((((rnd >> 8) % 10) == 0) ? KMC_OFFSLAB : 0);
+               flags |= ((((rnd >> 16) % 10) == 0) ? KMC_NOEMERGENCY : 0);
+
+               /* PAGE_SIZE - max_size */
+               get_random_bytes((void *)&rnd, sizeof (uint32_t));
+               size = MAX(rnd % (max_size + 1), PAGE_SIZE),
+
+               /* 2^N where (3 <= N <= PAGE_SHIFT) */
+               get_random_bytes((void *)&rnd, sizeof (uint32_t));
+               align = (1 << MAX(3, rnd % (PAGE_SHIFT + 1)));
+
+               rc = splat_kmem_cache_test(file, arg, name, size, align, flags);
+               if (rc)
+                       return (rc);
+       }
+
+       return (rc);
+}
+
+/*
+ * Validate object alignment cache behavior for caches
+ */
+static int
+splat_kmem_test7(struct file *file, void *arg)
+{
+       char *name = SPLAT_KMEM_TEST7_NAME;
+       int max_size = (SPL_KMEM_CACHE_MAX_SIZE * 1024 * 1024) / 2;
+       int i, rc;
+
+       for (i = SPL_KMEM_CACHE_ALIGN; i <= PAGE_SIZE; i *= 2) {
+               uint32_t size;
+
+               get_random_bytes((void *)&size, sizeof (uint32_t));
+               size = MAX(size % (max_size + 1), 32);
+
+               rc = splat_kmem_cache_test(file, arg, name, size, i, 0);
+               if (rc)
+                       return rc;
+
+               rc = splat_kmem_cache_test(file, arg, name, size, i,
+                   KMC_OFFSLAB);
+               if (rc)
+                       return rc;
+       }
+
+       return rc;
+}
+
+/*
+ * Validate kmem_cache_reap() by requesting the slab cache free any objects
+ * it can.  For a few reasons this may not immediately result in more free
+ * memory even if objects are freed.  First off, due to fragmentation we
+ * may not be able to reclaim any slabs.  Secondly, even if we do we fully
+ * clear some slabs we will not want to immediately reclaim all of them
+ * because we may contend with cache allocations and thrash.  What we want
+ * to see is the slab size decrease more gradually as it becomes clear they
+ * will not be needed.  This should be achievable in less than a minute.
+ * If it takes longer than this something has gone wrong.
+ */
+static int
+splat_kmem_test8(struct file *file, void *arg)
+{
+       kmem_cache_priv_t *kcp;
+       kmem_cache_thread_t *kct;
+       unsigned int spl_kmem_cache_expire_old;
+       int i, rc = 0;
+
+       /* Enable cache aging just for this test if it is disabled */
+       spl_kmem_cache_expire_old = spl_kmem_cache_expire;
+       spl_kmem_cache_expire = KMC_EXPIRE_AGE;
+
+       kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST8_NAME,
+                                             256, 0, 0);
+       if (!kcp) {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME,
+                            "Unable to create '%s'\n", "kcp");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       kcp->kcp_cache =
+               kmem_cache_create(SPLAT_KMEM_CACHE_NAME, kcp->kcp_size, 0,
+                                 splat_kmem_cache_test_constructor,
+                                 splat_kmem_cache_test_destructor,
+                                 splat_kmem_cache_test_reclaim,
+                                 kcp, NULL, 0);
+       if (!kcp->kcp_cache) {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME,
+                          "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME);
+               rc = -ENOMEM;
+               goto out_kcp;
+       }
+
+       kct = splat_kmem_cache_test_kct_alloc(kcp, 0);
+       if (!kct) {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME,
+                            "Unable to create '%s'\n", "kct");
+               rc = -ENOMEM;
+               goto out_cache;
+       }
+
+       rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, SPLAT_KMEM_OBJ_COUNT);
+       if (rc) {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME, "Unable to "
+                            "allocate from '%s'\n", SPLAT_KMEM_CACHE_NAME);
+               goto out_kct;
+       }
+
+       /* Force reclaim every 1/10 a second for 60 seconds. */
+       for (i = 0; i < 600; i++) {
+               kmem_cache_reap_now(kcp->kcp_cache);
+               splat_kmem_cache_test_debug(file, SPLAT_KMEM_TEST8_NAME, kcp);
+
+               if (kcp->kcp_count == 0)
+                       break;
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ / 10);
+       }
+
+       if (kcp->kcp_count == 0) {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME,
+                       "Successfully created %d objects "
+                       "in cache %s and reclaimed them\n",
+                       SPLAT_KMEM_OBJ_COUNT, SPLAT_KMEM_CACHE_NAME);
+       } else {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME,
+                       "Failed to reclaim %u/%d objects from cache %s\n",
+                       (unsigned)kcp->kcp_count,
+                       SPLAT_KMEM_OBJ_COUNT, SPLAT_KMEM_CACHE_NAME);
+               rc = -ENOMEM;
+       }
+
+       /* Cleanup our mess (for failure case of time expiring) */
+       splat_kmem_cache_test_kcd_free(kcp, kct);
+out_kct:
+       splat_kmem_cache_test_kct_free(kcp, kct);
+out_cache:
+       kmem_cache_destroy(kcp->kcp_cache);
+out_kcp:
+       splat_kmem_cache_test_kcp_free(kcp);
+out:
+       spl_kmem_cache_expire = spl_kmem_cache_expire_old;
+
+       return rc;
+}
+
+/* Test cache aging, we have allocated a large number of objects thus
+ * creating a large number of slabs and then free'd them all.  However,
+ * since there should be little memory pressure at the moment those
+ * slabs have not been freed.  What we want to see is the slab size
+ * decrease gradually as it becomes clear they will not be be needed.
+ * This should be achievable in less than minute.  If it takes longer
+ * than this something has gone wrong.
+ */
+static int
+splat_kmem_test9(struct file *file, void *arg)
+{
+       kmem_cache_priv_t *kcp;
+       kmem_cache_thread_t *kct;
+       unsigned int spl_kmem_cache_expire_old;
+       int i, rc = 0, count = SPLAT_KMEM_OBJ_COUNT * 128;
+
+       /* Enable cache aging just for this test if it is disabled */
+       spl_kmem_cache_expire_old = spl_kmem_cache_expire;
+       spl_kmem_cache_expire = KMC_EXPIRE_AGE;
+
+       kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST9_NAME,
+                                             256, 0, 0);
+       if (!kcp) {
+               splat_vprint(file, SPLAT_KMEM_TEST9_NAME,
+                            "Unable to create '%s'\n", "kcp");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       kcp->kcp_cache =
+               kmem_cache_create(SPLAT_KMEM_CACHE_NAME, kcp->kcp_size, 0,
+                                 splat_kmem_cache_test_constructor,
+                                 splat_kmem_cache_test_destructor,
+                                 NULL, kcp, NULL, 0);
+       if (!kcp->kcp_cache) {
+               splat_vprint(file, SPLAT_KMEM_TEST9_NAME,
+                          "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME);
+               rc = -ENOMEM;
+               goto out_kcp;
+       }
+
+       kct = splat_kmem_cache_test_kct_alloc(kcp, 0);
+       if (!kct) {
+               splat_vprint(file, SPLAT_KMEM_TEST8_NAME,
+                            "Unable to create '%s'\n", "kct");
+               rc = -ENOMEM;
+               goto out_cache;
+       }
+
+       rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, count);
+       if (rc) {
+               splat_vprint(file, SPLAT_KMEM_TEST9_NAME, "Unable to "
+                            "allocate from '%s'\n", SPLAT_KMEM_CACHE_NAME);
+               goto out_kct;
+       }
+
+       splat_kmem_cache_test_kcd_free(kcp, kct);
+
+       for (i = 0; i < 60; i++) {
+               splat_kmem_cache_test_debug(file, SPLAT_KMEM_TEST9_NAME, kcp);
+
+               if (kcp->kcp_count == 0)
+                       break;
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ);
+       }
+
+       if (kcp->kcp_count == 0) {
+               splat_vprint(file, SPLAT_KMEM_TEST9_NAME,
+                       "Successfully created %d objects "
+                       "in cache %s and reclaimed them\n",
+                       count, SPLAT_KMEM_CACHE_NAME);
+       } else {
+               splat_vprint(file, SPLAT_KMEM_TEST9_NAME,
+                       "Failed to reclaim %u/%d objects from cache %s\n",
+                       (unsigned)kcp->kcp_count, count,
+                       SPLAT_KMEM_CACHE_NAME);
+               rc = -ENOMEM;
+       }
+
+out_kct:
+       splat_kmem_cache_test_kct_free(kcp, kct);
+out_cache:
+       kmem_cache_destroy(kcp->kcp_cache);
+out_kcp:
+       splat_kmem_cache_test_kcp_free(kcp);
+out:
+       spl_kmem_cache_expire = spl_kmem_cache_expire_old;
+
+       return rc;
+}
+
+/*
+ * This test creates N threads with a shared kmem cache.  They then all
+ * concurrently allocate and free from the cache to stress the locking and
+ * concurrent cache performance.  If any one test takes longer than 5
+ * seconds to complete it is treated as a failure and may indicate a
+ * performance regression.  On my test system no one test takes more
+ * than 1 second to complete so a 5x slowdown likely a problem.
+ */
+static int
+splat_kmem_test10(struct file *file, void *arg)
+{
+       uint64_t size, alloc, rc = 0;
+
+       for (size = 32; size <= 1024*1024; size *= 2) {
+
+               splat_vprint(file, SPLAT_KMEM_TEST10_NAME, "%-22s  %s", "name",
+                            "time (sec)\tslabs       \tobjs    \thash\n");
+               splat_vprint(file, SPLAT_KMEM_TEST10_NAME, "%-22s  %s", "",
+                            "    \ttot/max/calc\ttot/max/calc\n");
+
+               for (alloc = 1; alloc <= 1024; alloc *= 2) {
+
+                       /* Skip tests which exceed 1/2 of physical memory. */
+                       if (size * alloc * SPLAT_KMEM_THREADS > physmem / 2)
+                               continue;
+
+                       rc = splat_kmem_cache_thread_test(file, arg,
+                               SPLAT_KMEM_TEST10_NAME, size, alloc, 5);
+                       if (rc)
+                               break;
+               }
+       }
+
+       return rc;
+}
+
+#if 0
+/*
+ * This test creates N threads with a shared kmem cache which overcommits
+ * memory by 4x.  This makes it impossible for the slab to satify the
+ * thread requirements without having its reclaim hook run which will
+ * free objects back for use.  This behavior is triggered by the linum VM
+ * detecting a low memory condition on the node and invoking the shrinkers.
+ * This should allow all the threads to complete while avoiding deadlock
+ * and for the most part out of memory events.  This is very tough on the
+ * system so it is possible the test app may get oom'ed.  This particular
+ * test has proven troublesome on 32-bit archs with limited virtual
+ * address space so it only run on 64-bit systems.
+ */
+static int
+splat_kmem_test11(struct file *file, void *arg)
+{
+       uint64_t size, alloc, rc;
+
+       size = 8 * 1024;
+       alloc = ((4 * physmem * PAGE_SIZE) / size) / SPLAT_KMEM_THREADS;
+
+       splat_vprint(file, SPLAT_KMEM_TEST11_NAME, "%-22s  %s", "name",
+                    "time (sec)\tslabs       \tobjs    \thash\n");
+       splat_vprint(file, SPLAT_KMEM_TEST11_NAME, "%-22s  %s", "",
+                    "    \ttot/max/calc\ttot/max/calc\n");
+
+       rc = splat_kmem_cache_thread_test(file, arg,
+               SPLAT_KMEM_TEST11_NAME, size, alloc, 60);
+
+       return rc;
+}
+#endif
+
+typedef struct dummy_page {
+       struct list_head dp_list;
+       char             dp_pad[PAGE_SIZE - sizeof(struct list_head)];
+} dummy_page_t;
+
+/*
+ * This test is designed to verify that direct reclaim is functioning as
+ * expected.  We allocate a large number of objects thus creating a large
+ * number of slabs.  We then apply memory pressure and expect that the
+ * direct reclaim path can easily recover those slabs.  The registered
+ * reclaim function will free the objects and the slab shrinker will call
+ * it repeatedly until at least a single slab can be freed.
+ *
+ * Note it may not be possible to reclaim every last slab via direct reclaim
+ * without a failure because the shrinker_rwsem may be contended.  For this
+ * reason, quickly reclaiming 3/4 of the slabs is considered a success.
+ *
+ * This should all be possible within 10 seconds.  For reference, on a
+ * system with 2G of memory this test takes roughly 0.2 seconds to run.
+ * It may take longer on larger memory systems but should still easily
+ * complete in the alloted 10 seconds.
+ */
+static int
+splat_kmem_test13(struct file *file, void *arg)
+{
+       kmem_cache_priv_t *kcp;
+       kmem_cache_thread_t *kct;
+       dummy_page_t *dp;
+       struct list_head list;
+       struct timespec start, stop, delta = { 0, 0 };
+       int size, count, slabs, fails = 0;
+       int i, rc = 0, max_time = 10;
+
+       size = 128 * 1024;
+       count = ((physmem * PAGE_SIZE) / 4 / size);
+
+       kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST13_NAME,
+                                             size, 0, 0);
+       if (!kcp) {
+               splat_vprint(file, SPLAT_KMEM_TEST13_NAME,
+                            "Unable to create '%s'\n", "kcp");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       kcp->kcp_cache =
+               kmem_cache_create(SPLAT_KMEM_CACHE_NAME, kcp->kcp_size, 0,
+                                 splat_kmem_cache_test_constructor,
+                                 splat_kmem_cache_test_destructor,
+                                 splat_kmem_cache_test_reclaim,
+                                 kcp, NULL, 0);
+       if (!kcp->kcp_cache) {
+               splat_vprint(file, SPLAT_KMEM_TEST13_NAME,
+                            "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME);
+               rc = -ENOMEM;
+               goto out_kcp;
+       }
+
+       kct = splat_kmem_cache_test_kct_alloc(kcp, 0);
+       if (!kct) {
+               splat_vprint(file, SPLAT_KMEM_TEST13_NAME,
+                            "Unable to create '%s'\n", "kct");
+               rc = -ENOMEM;
+               goto out_cache;
+       }
+
+       rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, count);
+       if (rc) {
+               splat_vprint(file, SPLAT_KMEM_TEST13_NAME, "Unable to "
+                            "allocate from '%s'\n", SPLAT_KMEM_CACHE_NAME);
+               goto out_kct;
+       }
+
+       i = 0;
+       slabs = kcp->kcp_cache->skc_slab_total;
+       INIT_LIST_HEAD(&list);
+       getnstimeofday(&start);
+
+       /* Apply memory pressure */
+       while (kcp->kcp_cache->skc_slab_total > (slabs >> 2)) {
+
+               if ((i % 10000) == 0)
+                       splat_kmem_cache_test_debug(
+                           file, SPLAT_KMEM_TEST13_NAME, kcp);
+
+               getnstimeofday(&stop);
+               delta = timespec_sub(stop, start);
+               if (delta.tv_sec >= max_time) {
+                       splat_vprint(file, SPLAT_KMEM_TEST13_NAME,
+                                    "Failed to reclaim 3/4 of cache in %ds, "
+                                    "%u/%u slabs remain\n", max_time,
+                                    (unsigned)kcp->kcp_cache->skc_slab_total,
+                                    slabs);
+                       rc = -ETIME;
+                       break;
+               }
+
+               dp = (dummy_page_t *)__get_free_page(GFP_KERNEL);
+               if (!dp) {
+                       fails++;
+                       splat_vprint(file, SPLAT_KMEM_TEST13_NAME,
+                                    "Failed (%d) to allocate page with %u "
+                                    "slabs still in the cache\n", fails,
+                                    (unsigned)kcp->kcp_cache->skc_slab_total);
+                       continue;
+               }
+
+               list_add(&dp->dp_list, &list);
+               i++;
+       }
+
+       if (rc == 0)
+               splat_vprint(file, SPLAT_KMEM_TEST13_NAME,
+                            "Successfully created %u slabs and with %d alloc "
+                            "failures reclaimed 3/4 of them in %d.%03ds\n",
+                            slabs, fails,
+                            (int)delta.tv_sec, (int)delta.tv_nsec / 1000000);
+
+       /* Release memory pressure pages */
+       while (!list_empty(&list)) {
+               dp = list_entry(list.next, dummy_page_t, dp_list);
+               list_del_init(&dp->dp_list);
+               free_page((unsigned long)dp);
+       }
+
+       /* Release remaining kmem cache objects */
+       splat_kmem_cache_test_kcd_free(kcp, kct);
+out_kct:
+       splat_kmem_cache_test_kct_free(kcp, kct);
+out_cache:
+       kmem_cache_destroy(kcp->kcp_cache);
+out_kcp:
+       splat_kmem_cache_test_kcp_free(kcp);
+out:
+       return rc;
+}
+
+splat_subsystem_t *
+splat_kmem_init(void)
+{
+       splat_subsystem_t *sub;
+
+       sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+       if (sub == NULL)
+               return NULL;
+
+       memset(sub, 0, sizeof(*sub));
+       strncpy(sub->desc.name, SPLAT_KMEM_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_KMEM_DESC, SPLAT_DESC_SIZE);
+       INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+       spin_lock_init(&sub->test_lock);
+       sub->desc.id = SPLAT_SUBSYSTEM_KMEM;
+
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST1_NAME, SPLAT_KMEM_TEST1_DESC,
+                       SPLAT_KMEM_TEST1_ID, splat_kmem_test1);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST2_NAME, SPLAT_KMEM_TEST2_DESC,
+                       SPLAT_KMEM_TEST2_ID, splat_kmem_test2);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST3_NAME, SPLAT_KMEM_TEST3_DESC,
+                       SPLAT_KMEM_TEST3_ID, splat_kmem_test3);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST4_NAME, SPLAT_KMEM_TEST4_DESC,
+                       SPLAT_KMEM_TEST4_ID, splat_kmem_test4);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST5_NAME, SPLAT_KMEM_TEST5_DESC,
+                       SPLAT_KMEM_TEST5_ID, splat_kmem_test5);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST6_NAME, SPLAT_KMEM_TEST6_DESC,
+                       SPLAT_KMEM_TEST6_ID, splat_kmem_test6);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST7_NAME, SPLAT_KMEM_TEST7_DESC,
+                       SPLAT_KMEM_TEST7_ID, splat_kmem_test7);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST8_NAME, SPLAT_KMEM_TEST8_DESC,
+                       SPLAT_KMEM_TEST8_ID, splat_kmem_test8);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST9_NAME, SPLAT_KMEM_TEST9_DESC,
+                       SPLAT_KMEM_TEST9_ID, splat_kmem_test9);
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST10_NAME, SPLAT_KMEM_TEST10_DESC,
+                       SPLAT_KMEM_TEST10_ID, splat_kmem_test10);
+#if 0
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST11_NAME, SPLAT_KMEM_TEST11_DESC,
+                       SPLAT_KMEM_TEST11_ID, splat_kmem_test11);
+#endif
+       SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST13_NAME, SPLAT_KMEM_TEST13_DESC,
+                       SPLAT_KMEM_TEST13_ID, splat_kmem_test13);
+
+       return sub;
+}
+
+void
+splat_kmem_fini(splat_subsystem_t *sub)
+{
+       ASSERT(sub);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST13_ID);
+#if 0
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST11_ID);
+#endif
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST10_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST9_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST8_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST7_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST6_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST5_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST4_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST3_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST2_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST1_ID);
+
+       kfree(sub);
+}
+
+int
+splat_kmem_id(void) {
+       return SPLAT_SUBSYSTEM_KMEM;
+}
diff --git a/spl/module/splat/splat-kobj.c b/spl/module/splat/splat-kobj.c
new file mode 100644 (file)
index 0000000..a0d4097
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Kobj Tests.
+\*****************************************************************************/
+
+#include <sys/kobj.h>
+#include "splat-internal.h"
+
+#define SPLAT_KOBJ_NAME                        "kobj"
+#define SPLAT_KOBJ_DESC                        "Kernel Kobj Tests"
+
+#define SPLAT_KOBJ_TEST1_ID            0x0a01
+#define SPLAT_KOBJ_TEST1_NAME          "open"
+#define SPLAT_KOBJ_TEST1_DESC          "Kobj Open/Close Test"
+
+#define SPLAT_KOBJ_TEST2_ID            0x0a02
+#define SPLAT_KOBJ_TEST2_NAME          "size/read"
+#define SPLAT_KOBJ_TEST2_DESC          "Kobj Size/Read Test"
+
+#define SPLAT_KOBJ_TEST_FILE           "/etc/fstab"
+
+static int
+splat_kobj_test1(struct file *file, void *arg)
+{
+       struct _buf *f;
+
+       f = kobj_open_file(SPLAT_KOBJ_TEST_FILE);
+       if (f == (struct _buf *)-1) {
+               splat_vprint(file, SPLAT_KOBJ_TEST1_NAME, "Failed to open "
+                            "test file: %s\n", SPLAT_KOBJ_TEST_FILE);
+               return -ENOENT;
+       }
+
+       kobj_close_file(f);
+       splat_vprint(file, SPLAT_KOBJ_TEST1_NAME, "Successfully opened and "
+                    "closed test file: %s\n", SPLAT_KOBJ_TEST_FILE);
+
+        return 0;
+} /* splat_kobj_test1() */
+
+static int
+splat_kobj_test2(struct file *file, void *arg)
+{
+       struct _buf *f;
+       char *buf;
+       uint64_t size;
+       int rc;
+
+       f = kobj_open_file(SPLAT_KOBJ_TEST_FILE);
+       if (f == (struct _buf *)-1) {
+               splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to open "
+                            "test file: %s\n", SPLAT_KOBJ_TEST_FILE);
+               return -ENOENT;
+       }
+
+       rc = kobj_get_filesize(f, &size);
+       if (rc) {
+               splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed stat of "
+                            "test file: %s (%d)\n", SPLAT_KOBJ_TEST_FILE, rc);
+               goto out;
+       }
+
+       buf = kmalloc(size + 1, GFP_KERNEL);
+       if (!buf) {
+               rc = -ENOMEM;
+               splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to alloc "
+                            "%lld bytes for tmp buffer (%d)\n",
+                            (long long)size, rc);
+               goto out;
+       }
+
+       memset(buf, 0, size + 1);
+       rc = kobj_read_file(f, buf, size, 0);
+       if (rc < 0) {
+               splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed read of "
+                            "test file: %s (%d)\n", SPLAT_KOBJ_TEST_FILE, rc);
+               goto out2;
+       }
+
+       /* Validate we read as many bytes as expected based on the stat.  This
+        * isn't a perfect test since we didn't create the file however it is
+        * pretty unlikely there are garbage characters in your /etc/fstab */
+       if (size != (uint64_t)strlen(buf)) {
+               rc = -EFBIG;
+               splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Stat'ed size "
+                            "(%lld) does not match number of bytes read "
+                            "(%lld)\n", (long long)size,
+                            (long long)strlen(buf));
+               goto out2;
+       }
+
+       rc = 0;
+       splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "\n%s\n", buf);
+       splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Successfully stat'ed "
+                    "and read expected number of bytes (%lld) from test "
+                    "file: %s\n", (long long)size, SPLAT_KOBJ_TEST_FILE);
+out2:
+       kfree(buf);
+out:
+       kobj_close_file(f);
+
+        return rc;
+} /* splat_kobj_test2() */
+
+splat_subsystem_t *
+splat_kobj_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_KOBJ_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_KOBJ_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_KOBJ;
+
+        SPLAT_TEST_INIT(sub, SPLAT_KOBJ_TEST1_NAME, SPLAT_KOBJ_TEST1_DESC,
+                     SPLAT_KOBJ_TEST1_ID, splat_kobj_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_KOBJ_TEST2_NAME, SPLAT_KOBJ_TEST2_DESC,
+                     SPLAT_KOBJ_TEST2_ID, splat_kobj_test2);
+
+        return sub;
+} /* splat_kobj_init() */
+
+void
+splat_kobj_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_KOBJ_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_KOBJ_TEST1_ID);
+
+        kfree(sub);
+} /* splat_kobj_fini() */
+
+int
+splat_kobj_id(void)
+{
+        return SPLAT_SUBSYSTEM_KOBJ;
+} /* splat_kobj_id() */
diff --git a/spl/module/splat/splat-linux.c b/spl/module/splat/splat-linux.c
new file mode 100644 (file)
index 0000000..3652267
--- /dev/null
@@ -0,0 +1,237 @@
+/*****************************************************************************\
+ *  Copyright (C) 2011 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Kernel Compatibility Tests.
+\*****************************************************************************/
+
+#include <sys/kmem.h>
+#include <linux/mm_compat.h>
+#include "splat-internal.h"
+
+#define SPLAT_LINUX_NAME               "linux"
+#define SPLAT_LINUX_DESC               "Kernel Compatibility Tests"
+
+#define SPLAT_LINUX_TEST1_ID           0x1001
+#define SPLAT_LINUX_TEST1_NAME         "shrinker"
+#define SPLAT_LINUX_TEST1_DESC         "Shrinker test"
+
+/*
+ * Wait queue used to eliminate race between dropping of slab
+ * and execution of the shrinker callback
+ */
+DECLARE_WAIT_QUEUE_HEAD(shrinker_wait);
+
+SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn);
+SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1);
+static unsigned long splat_linux_shrinker_size = 0;
+static struct file *splat_linux_shrinker_file = NULL;
+
+static spl_shrinker_t
+__splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
+{
+       static int failsafe = 0;
+       static unsigned long last_splat_linux_shrinker_size = 0;
+       unsigned long size;
+       spl_shrinker_t count;
+
+       /*
+        * shrinker_size can only decrease or stay the same between callbacks
+        * in the same run, so Reset failsafe whenever shrinker increases
+        * as this indicates a new run.
+        */
+       if (last_splat_linux_shrinker_size < splat_linux_shrinker_size)
+               failsafe = 0;
+
+       last_splat_linux_shrinker_size = splat_linux_shrinker_size;
+
+       if (sc->nr_to_scan) {
+               size = MIN(sc->nr_to_scan, splat_linux_shrinker_size);
+               splat_linux_shrinker_size -= size;
+
+               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
+                   "Reclaimed %lu objects, size now %lu\n",
+                   size, splat_linux_shrinker_size);
+
+#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
+               count = size;
+#else
+               count = splat_linux_shrinker_size;
+#endif /* HAVE_SPLIT_SHRINKER_CALLBACK */
+
+       } else {
+               count = splat_linux_shrinker_size;
+               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
+                   "Cache size is %lu\n", splat_linux_shrinker_size);
+       }
+
+       /* Far more calls than expected abort drop_slab as a failsafe */
+       if (failsafe > 100) {
+               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
+                   "Far more calls than expected (%d), size now %lu\n",
+                  failsafe, splat_linux_shrinker_size);
+               return (SHRINK_STOP);
+       } else {
+               /*
+                * We only increment failsafe if it doesn't trigger.  This
+                * makes any failsafe failure persistent until the next test.
+                */
+               failsafe++;
+       }
+
+       /* Shrinker has run, so signal back to test. */
+       wake_up(&shrinker_wait);
+
+       return (count);
+}
+
+SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn);
+
+#define DROP_SLAB_CMD \
+       "exec 0</dev/null " \
+       "     1>/proc/sys/vm/drop_caches " \
+       "     2>/dev/null; " \
+       "echo 2"
+
+static int
+splat_linux_drop_slab(struct file *file)
+{
+       char *argv[] = { "/bin/sh",
+                        "-c",
+                        DROP_SLAB_CMD,
+                        NULL };
+       char *envp[] = { "HOME=/",
+                        "TERM=linux",
+                        "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+                        NULL };
+       int rc;
+
+       rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+       if (rc)
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed user helper '%s %s %s', rc = %d\n",
+                   argv[0], argv[1], argv[2], rc);
+
+       return rc;
+}
+
+/*
+ * Verify correct shrinker functionality by registering a shrinker
+ * with the required compatibility macros.  We then use a simulated
+ * cache and force the systems caches to be dropped.  The shrinker
+ * should be repeatedly called until it reports that the cache is
+ * empty.  It is then cleanly unregistered and correct behavior is
+ * verified.  There are now four slightly different supported shrinker
+ * API and this test ensures the compatibility code is correct.
+ */
+static int
+splat_linux_test1(struct file *file, void *arg)
+{
+       int rc = -EINVAL;
+
+       /*
+        * Globals used by the shrinker, it is not safe to run this
+        * test concurrently this is a safe assumption for SPLAT tests.
+        * Regardless we do some minimal checking a bail if concurrent
+        * use is detected.
+        */
+       if (splat_linux_shrinker_size || splat_linux_shrinker_file) {
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed due to concurrent shrinker test, rc = %d\n", rc);
+               return (rc);
+       }
+
+       splat_linux_shrinker_size = 1024;
+       splat_linux_shrinker_file = file;
+
+       spl_register_shrinker(&splat_linux_shrinker);
+       rc = splat_linux_drop_slab(file);
+       if (rc)
+               goto out;
+
+       /*
+        * By the time we get here, it is possible that the shrinker has not
+        * yet run. splat_linux_drop_slab sends a signal for it to run, but
+        * there is no guarantee of when it will actually run. We wait for it
+        * to run here, terminating when either the shrinker size is now 0 or
+        * we timeout after 1 second, which should be an eternity (error).
+        */
+       rc = wait_event_timeout(shrinker_wait, !splat_linux_shrinker_size, HZ);
+       if (!rc) {
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed cache shrinking timed out, size now %lu",
+                   splat_linux_shrinker_size);
+               rc = -ETIMEDOUT;
+       } else {
+               rc = 0;
+       }
+
+       if (!rc && splat_linux_shrinker_size != 0) {
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed cache was not shrunk to 0, size now %lu",
+                   splat_linux_shrinker_size);
+               rc = -EDOM;
+       }
+out:
+       spl_unregister_shrinker(&splat_linux_shrinker);
+
+       splat_linux_shrinker_size = 0;
+       splat_linux_shrinker_file = NULL;
+
+       return rc;
+}
+
+splat_subsystem_t *
+splat_linux_init(void)
+{
+       splat_subsystem_t *sub;
+
+       sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+       if (sub == NULL)
+               return NULL;
+
+       memset(sub, 0, sizeof(*sub));
+       strncpy(sub->desc.name, SPLAT_LINUX_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_LINUX_DESC, SPLAT_DESC_SIZE);
+       INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+       spin_lock_init(&sub->test_lock);
+       sub->desc.id = SPLAT_SUBSYSTEM_LINUX;
+
+       SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC,
+                       SPLAT_LINUX_TEST1_ID, splat_linux_test1);
+
+       return sub;
+}
+
+void
+splat_linux_fini(splat_subsystem_t *sub)
+{
+       ASSERT(sub);
+       SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST1_ID);
+
+       kfree(sub);
+}
+
+int
+splat_linux_id(void) {
+       return SPLAT_SUBSYSTEM_LINUX;
+}
diff --git a/spl/module/splat/splat-list.c b/spl/module/splat/splat-list.c
new file mode 100644 (file)
index 0000000..f59394c
--- /dev/null
@@ -0,0 +1,475 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) List Tests.
+\*****************************************************************************/
+
+#include <sys/list.h>
+#include <sys/kmem.h>
+#include "splat-internal.h"
+
+#define SPLAT_LIST_NAME                        "list"
+#define SPLAT_LIST_DESC                        "Kernel List Tests"
+
+#define SPLAT_LIST_TEST1_ID            0x0c01
+#define SPLAT_LIST_TEST1_NAME          "create/destroy"
+#define SPLAT_LIST_TEST1_DESC          "Create/destroy Test"
+
+#define SPLAT_LIST_TEST2_ID            0x0c02
+#define SPLAT_LIST_TEST2_NAME          "ins/rm head"
+#define SPLAT_LIST_TEST2_DESC          "Insert/remove head Test"
+
+#define SPLAT_LIST_TEST3_ID            0x0c03
+#define SPLAT_LIST_TEST3_NAME          "ins/rm tail"
+#define SPLAT_LIST_TEST3_DESC          "Insert/remove tail Test"
+
+#define SPLAT_LIST_TEST4_ID            0x0c04
+#define SPLAT_LIST_TEST4_NAME          "insert_after"
+#define SPLAT_LIST_TEST4_DESC          "Insert_after Test"
+
+#define SPLAT_LIST_TEST5_ID            0x0c05
+#define SPLAT_LIST_TEST5_NAME          "insert_before"
+#define SPLAT_LIST_TEST5_DESC          "Insert_before Test"
+
+#define SPLAT_LIST_TEST6_ID            0x0c06
+#define SPLAT_LIST_TEST6_NAME          "remove"
+#define SPLAT_LIST_TEST6_DESC          "Remove Test"
+
+#define SPLAT_LIST_TEST7_ID            0x0c7
+#define SPLAT_LIST_TEST7_NAME          "active"
+#define SPLAT_LIST_TEST7_DESC          "Active Test"
+
+/* It is important that li_node is not the first element, this
+ * ensures the list_d2l/list_object macros are working correctly. */
+typedef struct list_item {
+       int li_data;
+       list_node_t li_node;
+} list_item_t;
+
+#define LIST_ORDER_STACK               0
+#define LIST_ORDER_QUEUE               1
+
+static int
+splat_list_test1(struct file *file, void *arg)
+{
+       list_t list;
+
+       splat_vprint(file, SPLAT_LIST_TEST1_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       if (!list_is_empty(&list)) {
+               splat_vprint(file, SPLAT_LIST_TEST1_NAME,
+                            "New list NOT empty%s\n", "");
+               /* list_destroy() intentionally skipped to avoid assert */
+               return -EEXIST;
+       }
+
+       splat_vprint(file, SPLAT_LIST_TEST1_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+       /* Validate the list has been destroyed */
+       if (list_link_active(&list.list_head)) {
+               splat_vprint(file, SPLAT_LIST_TEST1_NAME,
+                            "Destroyed list still active%s", "");
+               return -EIO;
+       }
+
+        return 0;
+}
+
+static int
+splat_list_validate(list_t *list, int size, int order, int mult)
+{
+       list_item_t *li;
+       int i;
+
+       /* Walk all items in list from head to verify stack or queue
+        * ordering.  We bound the for loop by size+1 to ensure that
+        * we still terminate if there is list corruption.  We also
+        * intentionally make things a little more complex than they
+        * need to be by using list_head/list_next for queues, and
+        * list_tail/list_prev for stacks.  This is simply done for
+        * coverage and to ensure these function are working right.
+        */
+       for (i = 0, li = (order ? list_head(list) : list_tail(list));
+            i < size + 1 && li != NULL;
+            i++, li = (order ? list_next(list, li) : list_prev(list, li)))
+               if (li->li_data != i * mult)
+                       return -EIDRM;
+
+       if (i != size)
+               return -E2BIG;
+
+       return 0;
+}
+
+static int
+splat_list_test2(struct file *file, void *arg)
+{
+       list_t list;
+       list_item_t *li;
+       int i, list_size = 8, rc = 0;
+
+       splat_vprint(file, SPLAT_LIST_TEST2_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       /* Insert all items at the list head to form a stack */
+       splat_vprint(file, SPLAT_LIST_TEST2_NAME,
+                    "Adding %d items to list head\n", list_size);
+       for (i = 0; i < list_size; i++) {
+               li = kmem_alloc(sizeof(list_item_t), KM_SLEEP);
+               if (li == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               list_link_init(&li->li_node);
+               li->li_data = i;
+               list_insert_head(&list, li);
+       }
+
+       splat_vprint(file, SPLAT_LIST_TEST2_NAME,
+                    "Validating %d item list is a stack\n", list_size);
+       rc = splat_list_validate(&list, list_size, LIST_ORDER_STACK, 1);
+       if (rc)
+               splat_vprint(file, SPLAT_LIST_TEST2_NAME,
+                            "List validation failed, %d\n", rc);
+out:
+       /* Remove all items */
+       splat_vprint(file, SPLAT_LIST_TEST2_NAME,
+                    "Removing %d items from list head\n", list_size);
+       while ((li = list_remove_head(&list)))
+               kmem_free(li, sizeof(list_item_t));
+
+       splat_vprint(file, SPLAT_LIST_TEST2_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+        return rc;
+}
+
+static int
+splat_list_test3(struct file *file, void *arg)
+{
+       list_t list;
+       list_item_t *li;
+       int i, list_size = 8, rc = 0;
+
+       splat_vprint(file, SPLAT_LIST_TEST3_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       /* Insert all items at the list tail to form a queue */
+       splat_vprint(file, SPLAT_LIST_TEST3_NAME,
+                    "Adding %d items to list tail\n", list_size);
+       for (i = 0; i < list_size; i++) {
+               li = kmem_alloc(sizeof(list_item_t), KM_SLEEP);
+               if (li == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               list_link_init(&li->li_node);
+               li->li_data = i;
+               list_insert_tail(&list, li);
+       }
+
+       splat_vprint(file, SPLAT_LIST_TEST3_NAME,
+                    "Validating %d item list is a queue\n", list_size);
+       rc = splat_list_validate(&list, list_size, LIST_ORDER_QUEUE, 1);
+       if (rc)
+               splat_vprint(file, SPLAT_LIST_TEST3_NAME,
+                            "List validation failed, %d\n", rc);
+out:
+       /* Remove all items */
+       splat_vprint(file, SPLAT_LIST_TEST3_NAME,
+                    "Removing %d items from list tail\n", list_size);
+       while ((li = list_remove_tail(&list)))
+               kmem_free(li, sizeof(list_item_t));
+
+       splat_vprint(file, SPLAT_LIST_TEST3_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+        return rc;
+}
+
+static int
+splat_list_test4(struct file *file, void *arg)
+{
+       list_t list;
+       list_item_t *li_new, *li_last = NULL;
+       int i, list_size = 8, rc = 0;
+
+       splat_vprint(file, SPLAT_LIST_TEST4_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       /* Insert all items after the last item to form a queue */
+       splat_vprint(file, SPLAT_LIST_TEST4_NAME,
+                    "Adding %d items each after the last item\n", list_size);
+       for (i = 0; i < list_size; i++) {
+               li_new = kmem_alloc(sizeof(list_item_t), KM_SLEEP);
+               if (li_new == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               list_link_init(&li_new->li_node);
+               li_new->li_data = i;
+               list_insert_after(&list, li_last, li_new);
+               li_last = li_new;
+       }
+
+       splat_vprint(file, SPLAT_LIST_TEST4_NAME,
+                    "Validating %d item list is a queue\n", list_size);
+       rc = splat_list_validate(&list, list_size, LIST_ORDER_QUEUE, 1);
+       if (rc)
+               splat_vprint(file, SPLAT_LIST_TEST4_NAME,
+                            "List validation failed, %d\n", rc);
+out:
+       /* Remove all items */
+       splat_vprint(file, SPLAT_LIST_TEST4_NAME,
+                    "Removing %d items from list tail\n", list_size);
+       while ((li_new = list_remove_head(&list)))
+               kmem_free(li_new, sizeof(list_item_t));
+
+       splat_vprint(file, SPLAT_LIST_TEST4_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+        return rc;
+}
+
+static int
+splat_list_test5(struct file *file, void *arg)
+{
+       list_t list;
+       list_item_t *li_new, *li_last = NULL;
+       int i, list_size = 8, rc = 0;
+
+       splat_vprint(file, SPLAT_LIST_TEST5_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       /* Insert all items before the last item to form a stack */
+       splat_vprint(file, SPLAT_LIST_TEST5_NAME,
+                    "Adding %d items each before the last item\n", list_size);
+       for (i = 0; i < list_size; i++) {
+               li_new = kmem_alloc(sizeof(list_item_t), KM_SLEEP);
+               if (li_new == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               list_link_init(&li_new->li_node);
+               li_new->li_data = i;
+               list_insert_before(&list, li_last, li_new);
+               li_last = li_new;
+       }
+
+       splat_vprint(file, SPLAT_LIST_TEST5_NAME,
+                    "Validating %d item list is a queue\n", list_size);
+       rc = splat_list_validate(&list, list_size, LIST_ORDER_STACK, 1);
+       if (rc)
+               splat_vprint(file, SPLAT_LIST_TEST5_NAME,
+                            "List validation failed, %d\n", rc);
+out:
+       /* Remove all items */
+       splat_vprint(file, SPLAT_LIST_TEST5_NAME,
+                    "Removing %d items from list tail\n", list_size);
+       while ((li_new = list_remove_tail(&list)))
+               kmem_free(li_new, sizeof(list_item_t));
+
+       splat_vprint(file, SPLAT_LIST_TEST5_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+        return rc;
+}
+
+static int
+splat_list_test6(struct file *file, void *arg)
+{
+       list_t list;
+       list_item_t *li, *li_prev;
+       int i, list_size = 8, rc = 0;
+
+       splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       /* Insert all items at the list tail to form a queue */
+       splat_vprint(file, SPLAT_LIST_TEST6_NAME,
+                    "Adding %d items to list tail\n", list_size);
+       for (i = 0; i < list_size; i++) {
+               li = kmem_alloc(sizeof(list_item_t), KM_SLEEP);
+               if (li == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               list_link_init(&li->li_node);
+               li->li_data = i;
+               list_insert_tail(&list, li);
+       }
+
+       /* Remove all odd items from the queue */
+       splat_vprint(file, SPLAT_LIST_TEST6_NAME,
+                    "Removing %d odd items from the list\n", list_size >> 1);
+       for (li = list_head(&list); li != NULL; li = list_next(&list, li)) {
+               if (li->li_data % 2 == 1) {
+                       li_prev = list_prev(&list, li);
+                       list_remove(&list, li);
+                       kmem_free(li, sizeof(list_item_t));
+                       li = li_prev;
+               }
+       }
+
+       splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Validating %d item "
+                    "list is a queue of only even elements\n", list_size / 2);
+       rc = splat_list_validate(&list, list_size / 2, LIST_ORDER_QUEUE, 2);
+       if (rc)
+               splat_vprint(file, SPLAT_LIST_TEST6_NAME,
+                            "List validation failed, %d\n", rc);
+out:
+       /* Remove all items */
+       splat_vprint(file, SPLAT_LIST_TEST6_NAME,
+                    "Removing %d items from list tail\n", list_size / 2);
+       while ((li = list_remove_tail(&list)))
+               kmem_free(li, sizeof(list_item_t));
+
+       splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+        return rc;
+}
+
+static int
+splat_list_test7(struct file *file, void *arg)
+{
+       list_t list;
+       list_item_t *li;
+       int rc = 0;
+
+       splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Creating list\n%s", "");
+       list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node));
+
+       li = kmem_alloc(sizeof(list_item_t), KM_SLEEP);
+       if (li == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /* Validate newly initialized node is inactive */
+       splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Init list node\n%s", "");
+       list_link_init(&li->li_node);
+       if (list_link_active(&li->li_node)) {
+               splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Newly initialized "
+                           "list node should inactive %p/%p\n",
+                           li->li_node.prev, li->li_node.next);
+               rc = -EINVAL;
+               goto out_li;
+       }
+
+       /* Validate node is active when linked in to a list */
+       splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Insert list node\n%s", "");
+       list_insert_head(&list, li);
+       if (!list_link_active(&li->li_node)) {
+               splat_vprint(file, SPLAT_LIST_TEST7_NAME, "List node "
+                           "inserted in list should be active %p/%p\n",
+                           li->li_node.prev, li->li_node.next);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       /* Validate node is inactive when removed from list */
+       splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Remove list node\n%s", "");
+       list_remove(&list, li);
+       if (list_link_active(&li->li_node)) {
+               splat_vprint(file, SPLAT_LIST_TEST7_NAME, "List node "
+                           "removed from list should be inactive %p/%p\n",
+                           li->li_node.prev, li->li_node.next);
+               rc = -EINVAL;
+       }
+out_li:
+       kmem_free(li, sizeof(list_item_t));
+out:
+       /* Remove all items */
+       while ((li = list_remove_head(&list)))
+               kmem_free(li, sizeof(list_item_t));
+
+       splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Destroying list\n%s", "");
+       list_destroy(&list);
+
+        return rc;
+}
+
+splat_subsystem_t *
+splat_list_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_LIST_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_LIST_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_LIST;
+
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST1_NAME, SPLAT_LIST_TEST1_DESC,
+                       SPLAT_LIST_TEST1_ID, splat_list_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST2_NAME, SPLAT_LIST_TEST2_DESC,
+                       SPLAT_LIST_TEST2_ID, splat_list_test2);
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST3_NAME, SPLAT_LIST_TEST3_DESC,
+                       SPLAT_LIST_TEST3_ID, splat_list_test3);
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST4_NAME, SPLAT_LIST_TEST4_DESC,
+                       SPLAT_LIST_TEST4_ID, splat_list_test4);
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST5_NAME, SPLAT_LIST_TEST5_DESC,
+                       SPLAT_LIST_TEST5_ID, splat_list_test5);
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST6_NAME, SPLAT_LIST_TEST6_DESC,
+                       SPLAT_LIST_TEST6_ID, splat_list_test6);
+        SPLAT_TEST_INIT(sub, SPLAT_LIST_TEST7_NAME, SPLAT_LIST_TEST7_DESC,
+                       SPLAT_LIST_TEST7_ID, splat_list_test7);
+
+        return sub;
+}
+
+void
+splat_list_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST7_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST6_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST5_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST4_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_LIST_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_list_id(void)
+{
+        return SPLAT_SUBSYSTEM_LIST;
+}
diff --git a/spl/module/splat/splat-mutex.c b/spl/module/splat/splat-mutex.c
new file mode 100644 (file)
index 0000000..86bef8e
--- /dev/null
@@ -0,0 +1,441 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Mutex Tests.
+\*****************************************************************************/
+
+#include <sys/mutex.h>
+#include <sys/taskq.h>
+#include <linux/delay.h>
+#include <linux/mm_compat.h>
+#include "splat-internal.h"
+
+#define SPLAT_MUTEX_NAME                "mutex"
+#define SPLAT_MUTEX_DESC                "Kernel Mutex Tests"
+
+#define SPLAT_MUTEX_TEST1_ID            0x0401
+#define SPLAT_MUTEX_TEST1_NAME          "tryenter"
+#define SPLAT_MUTEX_TEST1_DESC          "Validate mutex_tryenter() correctness"
+
+#define SPLAT_MUTEX_TEST2_ID            0x0402
+#define SPLAT_MUTEX_TEST2_NAME          "race"
+#define SPLAT_MUTEX_TEST2_DESC          "Many threads entering/exiting the mutex"
+
+#define SPLAT_MUTEX_TEST3_ID            0x0403
+#define SPLAT_MUTEX_TEST3_NAME          "owned"
+#define SPLAT_MUTEX_TEST3_DESC          "Validate mutex_owned() correctness"
+
+#define SPLAT_MUTEX_TEST4_ID            0x0404
+#define SPLAT_MUTEX_TEST4_NAME          "owner"
+#define SPLAT_MUTEX_TEST4_DESC          "Validate mutex_owner() correctness"
+
+#define SPLAT_MUTEX_TEST_MAGIC          0x115599DDUL
+#define SPLAT_MUTEX_TEST_NAME           "mutex_test"
+#define SPLAT_MUTEX_TEST_TASKQ          "mutex_taskq"
+#define SPLAT_MUTEX_TEST_COUNT          128
+
+typedef struct mutex_priv {
+        unsigned long mp_magic;
+        struct file *mp_file;
+        kmutex_t mp_mtx;
+        int mp_rc;
+        int mp_rc2;
+} mutex_priv_t;
+
+static void
+splat_mutex_test1_func(void *arg)
+{
+        mutex_priv_t *mp = (mutex_priv_t *)arg;
+        ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
+
+        if (mutex_tryenter(&mp->mp_mtx)) {
+                mp->mp_rc = 0;
+                mutex_exit(&mp->mp_mtx);
+        } else {
+                mp->mp_rc = -EBUSY;
+        }
+}
+
+static int
+splat_mutex_test1(struct file *file, void *arg)
+{
+        mutex_priv_t *mp;
+        taskq_t *tq;
+        int id, rc = 0;
+
+        mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL);
+        if (mp == NULL)
+                return -ENOMEM;
+
+        tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, 1, defclsyspri,
+                          50, INT_MAX, TASKQ_PREPOPULATE);
+        if (tq == NULL) {
+                rc = -ENOMEM;
+                goto out2;
+        }
+
+        mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC;
+        mp->mp_file = file;
+        mutex_init(&mp->mp_mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
+        mutex_enter(&mp->mp_mtx);
+
+        /*
+         * Schedule a task function which will try and acquire the mutex via
+         * mutex_tryenter() while it's held.  This should fail and the task
+         * function will indicate this status in the passed private data.
+         */
+        mp->mp_rc = -EINVAL;
+        id = taskq_dispatch(tq, splat_mutex_test1_func, mp, TQ_SLEEP);
+        if (id == 0) {
+                mutex_exit(&mp->mp_mtx);
+                splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
+                             "taskq_dispatch() failed\n");
+                rc = -EINVAL;
+                goto out;
+        }
+
+        taskq_wait_id(tq, id);
+        mutex_exit(&mp->mp_mtx);
+
+        /* Task function successfully acquired mutex, very bad! */
+        if (mp->mp_rc != -EBUSY) {
+                splat_vprint(file, SPLAT_MUTEX_TEST1_NAME,
+                             "mutex_trylock() incorrectly succeeded when "
+                             "the mutex was held, %d/%d\n", id, mp->mp_rc);
+                rc = -EINVAL;
+                goto out;
+        } else {
+                splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
+                             "mutex_trylock() correctly failed when "
+                             "the mutex was held\n");
+        }
+
+        /*
+         * Schedule a task function which will try and acquire the mutex via
+         * mutex_tryenter() while it is not held.  This should succeed and
+         * can be verified by checking the private data.
+         */
+        mp->mp_rc = -EINVAL;
+        id = taskq_dispatch(tq, splat_mutex_test1_func, mp, TQ_SLEEP);
+        if (id == 0) {
+                splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
+                             "taskq_dispatch() failed\n");
+                rc = -EINVAL;
+                goto out;
+        }
+
+        taskq_wait_id(tq, id);
+
+        /* Task function failed to acquire mutex, very bad! */
+        if (mp->mp_rc != 0) {
+                splat_vprint(file, SPLAT_MUTEX_TEST1_NAME,
+                             "mutex_trylock() incorrectly failed when "
+                             "the mutex was not held, %d/%d\n", id, mp->mp_rc);
+                rc = -EINVAL;
+        } else {
+                splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
+                             "mutex_trylock() correctly succeeded "
+                             "when the mutex was not held\n");
+        }
+out:
+        taskq_destroy(tq);
+        mutex_destroy(&(mp->mp_mtx));
+out2:
+        kfree(mp);
+        return rc;
+}
+
+static void
+splat_mutex_test2_func(void *arg)
+{
+        mutex_priv_t *mp = (mutex_priv_t *)arg;
+        int rc;
+        ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
+
+        /* Read the value before sleeping and write it after we wake up to
+         * maximize the chance of a race if mutexs are not working properly */
+        mutex_enter(&mp->mp_mtx);
+        rc = mp->mp_rc;
+        set_current_state(TASK_INTERRUPTIBLE);
+        schedule_timeout(HZ / 100);  /* 1/100 of a second */
+        VERIFY(mp->mp_rc == rc);
+        mp->mp_rc = rc + 1;
+        mutex_exit(&mp->mp_mtx);
+}
+
+static int
+splat_mutex_test2(struct file *file, void *arg)
+{
+        mutex_priv_t *mp;
+        taskq_t *tq;
+        int i, rc = 0;
+
+        mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL);
+        if (mp == NULL)
+                return -ENOMEM;
+
+        /* Create several threads allowing tasks to race with each other */
+        tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, num_online_cpus(),
+                          defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
+        if (tq == NULL) {
+                rc = -ENOMEM;
+                goto out;
+        }
+
+        mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC;
+        mp->mp_file = file;
+        mutex_init(&(mp->mp_mtx), SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
+        mp->mp_rc = 0;
+
+        /*
+         * Schedule N work items to the work queue each of which enters the
+         * mutex, sleeps briefly, then exits the mutex.  On a multiprocessor
+         * box these work items will be handled by all available CPUs.  The
+         * task function checks to ensure the tracked shared variable is
+         * always only incremented by one.  Additionally, the mutex itself
+         * is instrumented such that if any two processors are in the
+         * critical region at the same time the system will panic.  If the
+         * mutex is implemented right this will never happy, that's a pass.
+         */
+        for (i = 0; i < SPLAT_MUTEX_TEST_COUNT; i++) {
+                if (!taskq_dispatch(tq, splat_mutex_test2_func, mp, TQ_SLEEP)) {
+                        splat_vprint(file, SPLAT_MUTEX_TEST2_NAME,
+                                     "Failed to queue task %d\n", i);
+                        rc = -EINVAL;
+                }
+        }
+
+        taskq_wait(tq);
+
+        if (mp->mp_rc == SPLAT_MUTEX_TEST_COUNT) {
+                splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads "
+                           "correctly entered/exited the mutex %d times\n",
+                           num_online_cpus(), mp->mp_rc);
+        } else {
+                splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads "
+                           "only processed %d/%d mutex work items\n",
+                           num_online_cpus(),mp->mp_rc,SPLAT_MUTEX_TEST_COUNT);
+                rc = -EINVAL;
+        }
+
+        taskq_destroy(tq);
+        mutex_destroy(&(mp->mp_mtx));
+out:
+        kfree(mp);
+        return rc;
+}
+
+static void
+splat_mutex_owned(void *priv)
+{
+        mutex_priv_t *mp = (mutex_priv_t *)priv;
+
+        ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
+        mp->mp_rc = mutex_owned(&mp->mp_mtx);
+        mp->mp_rc2 = MUTEX_HELD(&mp->mp_mtx);
+}
+
+static int
+splat_mutex_test3(struct file *file, void *arg)
+{
+        mutex_priv_t mp;
+        taskq_t *tq;
+        int rc = 0;
+
+        mp.mp_magic = SPLAT_MUTEX_TEST_MAGIC;
+        mp.mp_file = file;
+        mutex_init(&mp.mp_mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
+
+        if ((tq = taskq_create(SPLAT_MUTEX_TEST_NAME, 1, defclsyspri,
+                               50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Taskq '%s' "
+                             "create failed\n", SPLAT_MUTEX_TEST3_NAME);
+                return -EINVAL;
+        }
+
+        mutex_enter(&mp.mp_mtx);
+
+        /* Mutex should be owned by current */
+        if (!mutex_owned(&mp.mp_mtx)) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Unowned mutex "
+                             "should be owned by pid %d\n", current->pid);
+                rc = -EINVAL;
+                goto out_exit;
+        }
+
+        if (taskq_dispatch(tq, splat_mutex_owned, &mp, TQ_SLEEP) == 0) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Failed to "
+                             "dispatch function '%s' to taskq\n",
+                             sym2str(splat_mutex_owned));
+                rc = -EINVAL;
+                goto out_exit;
+        }
+        taskq_wait(tq);
+
+        /* Mutex should not be owned which checked from a different thread */
+        if (mp.mp_rc || mp.mp_rc2) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex owned by "
+                             "pid %d not by taskq\n", current->pid);
+                rc = -EINVAL;
+                goto out_exit;
+        }
+
+        mutex_exit(&mp.mp_mtx);
+
+        /* Mutex should not be owned by current */
+        if (mutex_owned(&mp.mp_mtx)) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex owned by "
+                             "pid %d it should be unowned\b", current->pid);
+                rc = -EINVAL;
+                goto out;
+        }
+
+        if (taskq_dispatch(tq, splat_mutex_owned, &mp, TQ_SLEEP) == 0) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Failed to "
+                             "dispatch function '%s' to taskq\n",
+                             sym2str(splat_mutex_owned));
+                rc = -EINVAL;
+                goto out;
+        }
+        taskq_wait(tq);
+
+        /* Mutex should be owned by no one */
+        if (mp.mp_rc || mp.mp_rc2) {
+                splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex owned by "
+                             "no one, %d/%d disagrees\n", mp.mp_rc, mp.mp_rc2);
+                rc = -EINVAL;
+                goto out;
+        }
+
+        splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s",
+                   "Correct mutex_owned() behavior\n");
+        goto out;
+out_exit:
+        mutex_exit(&mp.mp_mtx);
+out:
+        mutex_destroy(&mp.mp_mtx);
+        taskq_destroy(tq);
+
+        return rc;
+}
+
+static int
+splat_mutex_test4(struct file *file, void *arg)
+{
+        kmutex_t mtx;
+        kthread_t *owner;
+        int rc = 0;
+
+        mutex_init(&mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
+
+        /*
+         * Verify mutex owner is cleared after being dropped.  Depending
+         * on how you build your kernel this behavior changes, ensure the
+         * SPL mutex implementation is properly detecting this.
+         */
+        mutex_enter(&mtx);
+        msleep(100);
+        mutex_exit(&mtx);
+        if (MUTEX_HELD(&mtx)) {
+                splat_vprint(file, SPLAT_MUTEX_TEST4_NAME, "Mutex should "
+                           "not be held, bit is by %p\n", mutex_owner(&mtx));
+                rc = -EINVAL;
+                goto out;
+        }
+
+        mutex_enter(&mtx);
+
+        /* Mutex should be owned by current */
+        owner = mutex_owner(&mtx);
+        if (current != owner) {
+                splat_vprint(file, SPLAT_MUTEX_TEST4_NAME, "Mutex should "
+                           "be owned by pid %d but is owned by pid %d\n",
+                           current->pid, owner ? owner->pid : -1);
+                rc = -EINVAL;
+                goto out;
+        }
+
+        mutex_exit(&mtx);
+
+        /* Mutex should not be owned by any task */
+        owner = mutex_owner(&mtx);
+        if (owner) {
+                splat_vprint(file, SPLAT_MUTEX_TEST4_NAME, "Mutex should not "
+                           "be owned but is owned by pid %d\n", owner->pid);
+                rc = -EINVAL;
+                goto out;
+        }
+
+        splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s",
+                   "Correct mutex_owner() behavior\n");
+out:
+        mutex_destroy(&mtx);
+
+        return rc;
+}
+
+splat_subsystem_t *
+splat_mutex_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_MUTEX_NAME, SPLAT_NAME_SIZE);
+        strncpy(sub->desc.desc, SPLAT_MUTEX_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+        INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_MUTEX;
+
+        SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST1_NAME, SPLAT_MUTEX_TEST1_DESC,
+                      SPLAT_MUTEX_TEST1_ID, splat_mutex_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST2_NAME, SPLAT_MUTEX_TEST2_DESC,
+                      SPLAT_MUTEX_TEST2_ID, splat_mutex_test2);
+        SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST3_NAME, SPLAT_MUTEX_TEST3_DESC,
+                      SPLAT_MUTEX_TEST3_ID, splat_mutex_test3);
+        SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST4_NAME, SPLAT_MUTEX_TEST4_DESC,
+                      SPLAT_MUTEX_TEST4_ID, splat_mutex_test4);
+
+        return sub;
+}
+
+void
+splat_mutex_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+        SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST4_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_mutex_id(void) {
+        return SPLAT_SUBSYSTEM_MUTEX;
+}
diff --git a/spl/module/splat/splat-random.c b/spl/module/splat/splat-random.c
new file mode 100644 (file)
index 0000000..33b799b
--- /dev/null
@@ -0,0 +1,130 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Random Number Generator Tests.
+\*****************************************************************************/
+
+#include <sys/random.h>
+#include <sys/kmem.h>
+#include "splat-internal.h"
+
+#define SPLAT_KRNG_NAME                        "krng"
+#define SPLAT_KRNG_DESC                        "Kernel Random Number Generator Tests"
+
+#define SPLAT_KRNG_TEST1_ID            0x0301
+#define SPLAT_KRNG_TEST1_NAME          "freq"
+#define SPLAT_KRNG_TEST1_DESC          "Frequency Test"
+
+#define KRNG_NUM_BITS                  1048576
+#define KRNG_NUM_BYTES                 (KRNG_NUM_BITS >> 3)
+#define KRNG_NUM_BITS_DIV2             (KRNG_NUM_BITS >> 1)
+#define KRNG_ERROR_RANGE               2097
+
+/* Random Number Generator Tests
+   There can be meny more tests on quality of the
+   random number generator.  For now we are only
+   testing the frequency of particular bits.
+   We could also test consecutive sequences,
+   randomness within a particular block, etc.
+   but is probably not necessary for our purposes */
+
+static int
+splat_krng_test1(struct file *file, void *arg)
+{
+       uint8_t *buf;
+       int i, j, diff, num = 0, rc = 0;
+
+       buf = kmalloc(sizeof(*buf) * KRNG_NUM_BYTES, GFP_KERNEL);
+       if (buf == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       memset(buf, 0, sizeof(*buf) * KRNG_NUM_BYTES);
+
+       /* Always succeeds */
+       random_get_pseudo_bytes(buf, sizeof(uint8_t) * KRNG_NUM_BYTES);
+
+       for (i = 0; i < KRNG_NUM_BYTES; i++) {
+               uint8_t tmp = buf[i];
+               for (j = 0; j < 8; j++) {
+                       uint8_t tmp2 = ((tmp >> j) & 0x01);
+                       if (tmp2 == 1) {
+                               num++;
+                       }
+               }
+       }
+
+       kfree(buf);
+
+       diff = KRNG_NUM_BITS_DIV2 - num;
+       if (diff < 0)
+               diff *= -1;
+
+       splat_print(file, "Test 1 Number of ones: %d\n", num);
+       splat_print(file, "Test 1 Difference from expected: %d Allowed: %d\n",
+                  diff, KRNG_ERROR_RANGE);
+
+       if (diff > KRNG_ERROR_RANGE)
+               rc = -ERANGE;
+out:
+       return rc;
+}
+
+splat_subsystem_t *
+splat_krng_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_KRNG_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_KRNG_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_KRNG;
+
+        SPLAT_TEST_INIT(sub, SPLAT_KRNG_TEST1_NAME, SPLAT_KRNG_TEST1_DESC,
+                     SPLAT_KRNG_TEST1_ID, splat_krng_test1);
+
+        return sub;
+}
+
+void
+splat_krng_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_KRNG_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_krng_id(void) {
+        return SPLAT_SUBSYSTEM_KRNG;
+}
diff --git a/spl/module/splat/splat-rwlock.c b/spl/module/splat/splat-rwlock.c
new file mode 100644 (file)
index 0000000..4576f20
--- /dev/null
@@ -0,0 +1,723 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Read/Writer Lock Tests.
+\*****************************************************************************/
+
+#include <sys/random.h>
+#include <sys/rwlock.h>
+#include <sys/taskq.h>
+#include <linux/delay.h>
+#include <linux/mm_compat.h>
+#include "splat-internal.h"
+
+#define SPLAT_RWLOCK_NAME              "rwlock"
+#define SPLAT_RWLOCK_DESC              "Kernel RW Lock Tests"
+
+#define SPLAT_RWLOCK_TEST1_ID          0x0701
+#define SPLAT_RWLOCK_TEST1_NAME                "N-rd/1-wr"
+#define SPLAT_RWLOCK_TEST1_DESC                "Multiple readers one writer"
+
+#define SPLAT_RWLOCK_TEST2_ID          0x0702
+#define SPLAT_RWLOCK_TEST2_NAME                "0-rd/N-wr"
+#define SPLAT_RWLOCK_TEST2_DESC                "Multiple writers"
+
+#define SPLAT_RWLOCK_TEST3_ID          0x0703
+#define SPLAT_RWLOCK_TEST3_NAME                "held"
+#define SPLAT_RWLOCK_TEST3_DESC                "RW_{LOCK|READ|WRITE}_HELD"
+
+#define SPLAT_RWLOCK_TEST4_ID          0x0704
+#define SPLAT_RWLOCK_TEST4_NAME                "tryenter"
+#define SPLAT_RWLOCK_TEST4_DESC                "Tryenter"
+
+#define SPLAT_RWLOCK_TEST5_ID          0x0705
+#define SPLAT_RWLOCK_TEST5_NAME                "rw_downgrade"
+#define SPLAT_RWLOCK_TEST5_DESC                "Write downgrade"
+
+#define SPLAT_RWLOCK_TEST6_ID          0x0706
+#define SPLAT_RWLOCK_TEST6_NAME                "rw_tryupgrade-1"
+#define SPLAT_RWLOCK_TEST6_DESC                "rwsem->count value"
+
+#define SPLAT_RWLOCK_TEST7_ID          0x0707
+#define SPLAT_RWLOCK_TEST7_NAME                "rw_tryupgrade-2"
+#define SPLAT_RWLOCK_TEST7_DESC                "Read upgrade"
+
+#define SPLAT_RWLOCK_TEST_MAGIC                0x115599DDUL
+#define SPLAT_RWLOCK_TEST_NAME         "rwlock_test"
+#define SPLAT_RWLOCK_TEST_TASKQ                "rwlock_taskq"
+#define SPLAT_RWLOCK_TEST_COUNT                8
+
+#define SPLAT_RWLOCK_RELEASE_INIT      0
+#define SPLAT_RWLOCK_RELEASE_WR                1
+#define SPLAT_RWLOCK_RELEASE_RD                2
+
+typedef struct rw_priv {
+       unsigned long rw_magic;
+       struct file *rw_file;
+       krwlock_t rw_rwlock;
+       spinlock_t rw_lock;
+       wait_queue_head_t rw_waitq;
+       int rw_completed;
+       int rw_holders;
+       int rw_waiters;
+       int rw_release;
+       int rw_rc;
+       krw_t rw_type;
+} rw_priv_t;
+
+typedef struct rw_thr {
+       const char *rwt_name;
+       rw_priv_t *rwt_rwp;
+       struct task_struct *rwt_thread;
+} rw_thr_t;
+
+void splat_init_rw_priv(rw_priv_t *rwp, struct file *file)
+{
+       rwp->rw_magic = SPLAT_RWLOCK_TEST_MAGIC;
+       rwp->rw_file = file;
+       rw_init(&rwp->rw_rwlock, SPLAT_RWLOCK_TEST_NAME, RW_DEFAULT, NULL);
+       spin_lock_init(&rwp->rw_lock);
+       init_waitqueue_head(&rwp->rw_waitq);
+       rwp->rw_completed = 0;
+       rwp->rw_holders = 0;
+       rwp->rw_waiters = 0;
+       rwp->rw_release = SPLAT_RWLOCK_RELEASE_INIT;
+       rwp->rw_rc = 0;
+       rwp->rw_type = 0;
+}
+
+static int
+splat_rwlock_wr_thr(void *arg)
+{
+       rw_thr_t *rwt = (rw_thr_t *)arg;
+       rw_priv_t *rwp = rwt->rwt_rwp;
+       uint8_t rnd;
+
+       ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
+
+       get_random_bytes((void *)&rnd, 1);
+       msleep((unsigned int)rnd);
+
+       splat_vprint(rwp->rw_file, rwt->rwt_name,
+           "%s trying to acquire rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_waiters++;
+       spin_unlock(&rwp->rw_lock);
+       rw_enter(&rwp->rw_rwlock, RW_WRITER);
+
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_waiters--;
+       rwp->rw_holders++;
+       spin_unlock(&rwp->rw_lock);
+       splat_vprint(rwp->rw_file, rwt->rwt_name,
+           "%s acquired rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
+
+       /* Wait for control thread to signal we can release the write lock */
+       wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
+           rwp->rw_release == SPLAT_RWLOCK_RELEASE_WR));
+
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_completed++;
+       rwp->rw_holders--;
+       spin_unlock(&rwp->rw_lock);
+       splat_vprint(rwp->rw_file, rwt->rwt_name,
+           "%s dropped rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
+
+       rw_exit(&rwp->rw_rwlock);
+
+       return 0;
+}
+
+static int
+splat_rwlock_rd_thr(void *arg)
+{
+       rw_thr_t *rwt = (rw_thr_t *)arg;
+       rw_priv_t *rwp = rwt->rwt_rwp;
+       uint8_t rnd;
+
+       ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
+
+       get_random_bytes((void *)&rnd, 1);
+       msleep((unsigned int)rnd);
+
+       /* Don't try and take the semaphore until after someone has it */
+       wait_event_interruptible(rwp->rw_waitq,
+           splat_locked_test(&rwp->rw_lock, rwp->rw_holders > 0));
+
+       splat_vprint(rwp->rw_file, rwt->rwt_name,
+           "%s trying to acquire rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_waiters++;
+       spin_unlock(&rwp->rw_lock);
+       rw_enter(&rwp->rw_rwlock, RW_READER);
+
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_waiters--;
+       rwp->rw_holders++;
+       spin_unlock(&rwp->rw_lock);
+       splat_vprint(rwp->rw_file, rwt->rwt_name,
+           "%s acquired rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
+
+       /* Wait for control thread to signal we can release the read lock */
+       wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
+           rwp->rw_release == SPLAT_RWLOCK_RELEASE_RD));
+
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_completed++;
+       rwp->rw_holders--;
+       spin_unlock(&rwp->rw_lock);
+       splat_vprint(rwp->rw_file, rwt->rwt_name,
+           "%s dropped rwlock (%d holding/%d waiting)\n",
+           rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
+
+       rw_exit(&rwp->rw_rwlock);
+
+       return 0;
+}
+
+static int
+splat_rwlock_test1(struct file *file, void *arg)
+{
+       int i, count = 0, rc = 0;
+       rw_thr_t rwt[SPLAT_RWLOCK_TEST_COUNT];
+       rw_priv_t *rwp;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       /* Create some threads, the exact number isn't important just as
+        * long as we know how many we managed to create and should expect. */
+       for (i = 0; i < SPLAT_RWLOCK_TEST_COUNT; i++) {
+               rwt[i].rwt_rwp = rwp;
+               rwt[i].rwt_name = SPLAT_RWLOCK_TEST1_NAME;
+
+               /* The first thread will be the writer */
+               if (i == 0)
+                       rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_wr_thr,
+                           &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i);
+               else
+                       rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_rd_thr,
+                           &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i);
+
+               if (!IS_ERR(rwt[i].rwt_thread)) {
+                       wake_up_process(rwt[i].rwt_thread);
+                       count++;
+               }
+       }
+
+       /* Wait for the writer */
+       while (splat_locked_test(&rwp->rw_lock, rwp->rw_holders == 0)) {
+               wake_up_interruptible(&rwp->rw_waitq);
+               msleep(100);
+       }
+
+       /* Wait for 'count-1' readers */
+       while (splat_locked_test(&rwp->rw_lock, rwp->rw_waiters < count - 1)) {
+               wake_up_interruptible(&rwp->rw_waitq);
+               msleep(100);
+       }
+
+       /* Verify there is only one lock holder */
+       if (splat_locked_test(&rwp->rw_lock, rwp->rw_holders) != 1) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only 1 holder "
+                            "expected for rwlock (%d holding/%d waiting)\n",
+                            rwp->rw_holders, rwp->rw_waiters);
+               rc = -EINVAL;
+       }
+
+       /* Verify 'count-1' readers */
+       if (splat_locked_test(&rwp->rw_lock, rwp->rw_waiters != count - 1)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only %d waiters "
+                            "expected for rwlock (%d holding/%d waiting)\n",
+                            count - 1, rwp->rw_holders, rwp->rw_waiters);
+               rc = -EINVAL;
+       }
+
+       /* Signal the writer to release, allows readers to acquire */
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_release = SPLAT_RWLOCK_RELEASE_WR;
+       wake_up_interruptible(&rwp->rw_waitq);
+       spin_unlock(&rwp->rw_lock);
+
+       /* Wait for 'count-1' readers to hold the lock */
+       while (splat_locked_test(&rwp->rw_lock, rwp->rw_holders < count - 1)) {
+               wake_up_interruptible(&rwp->rw_waitq);
+               msleep(100);
+       }
+
+       /* Verify there are 'count-1' readers */
+       if (splat_locked_test(&rwp->rw_lock, rwp->rw_holders != count - 1)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only %d holders "
+                            "expected for rwlock (%d holding/%d waiting)\n",
+                            count - 1, rwp->rw_holders, rwp->rw_waiters);
+               rc = -EINVAL;
+       }
+
+       /* Release 'count-1' readers */
+       spin_lock(&rwp->rw_lock);
+       rwp->rw_release = SPLAT_RWLOCK_RELEASE_RD;
+       wake_up_interruptible(&rwp->rw_waitq);
+       spin_unlock(&rwp->rw_lock);
+
+       /* Wait for the test to complete */
+       while (splat_locked_test(&rwp->rw_lock,
+                                rwp->rw_holders>0 || rwp->rw_waiters>0))
+               msleep(100);
+
+       rw_destroy(&(rwp->rw_rwlock));
+       kfree(rwp);
+
+       return rc;
+}
+
+static void
+splat_rwlock_test2_func(void *arg)
+{
+       rw_priv_t *rwp = (rw_priv_t *)arg;
+       int rc;
+       ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
+
+       /* Read the value before sleeping and write it after we wake up to
+        * maximize the chance of a race if rwlocks are not working properly */
+       rw_enter(&rwp->rw_rwlock, RW_WRITER);
+       rc = rwp->rw_rc;
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(HZ / 100);  /* 1/100 of a second */
+       VERIFY(rwp->rw_rc == rc);
+       rwp->rw_rc = rc + 1;
+       rw_exit(&rwp->rw_rwlock);
+}
+
+static int
+splat_rwlock_test2(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       taskq_t *tq;
+       int i, rc = 0, tq_count = 256;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       /* Create several threads allowing tasks to race with each other */
+       tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, num_online_cpus(),
+                         defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
+       if (tq == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * Schedule N work items to the work queue each of which enters the
+        * writer rwlock, sleeps briefly, then exits the writer rwlock.  On a
+        * multiprocessor box these work items will be handled by all available
+        * CPUs.  The task function checks to ensure the tracked shared variable
+        * is always only incremented by one.  Additionally, the rwlock itself
+        * is instrumented such that if any two processors are in the
+        * critical region at the same time the system will panic.  If the
+        * rwlock is implemented right this will never happy, that's a pass.
+        */
+       for (i = 0; i < tq_count; i++) {
+               if (!taskq_dispatch(tq,splat_rwlock_test2_func,rwp,TQ_SLEEP)) {
+                       splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME,
+                                    "Failed to queue task %d\n", i);
+                       rc = -EINVAL;
+               }
+       }
+
+       taskq_wait(tq);
+
+       if (rwp->rw_rc == tq_count) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, "%d racing threads "
+                            "correctly entered/exited the rwlock %d times\n",
+                            num_online_cpus(), rwp->rw_rc);
+       } else {
+               splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, "%d racing threads "
+                            "only processed %d/%d w rwlock work items\n",
+                            num_online_cpus(), rwp->rw_rc, tq_count);
+               rc = -EINVAL;
+       }
+
+       taskq_destroy(tq);
+       rw_destroy(&(rwp->rw_rwlock));
+out:
+       kfree(rwp);
+       return rc;
+}
+
+#define splat_rwlock_test3_helper(rwp,rex1,rex2,wex1,wex2,held_func,rc)        \
+do {                                                                   \
+       int result, _rc1_, _rc2_, _rc3_, _rc4_;                         \
+                                                                       \
+       rc = 0;                                                         \
+       rw_enter(&(rwp)->rw_rwlock, RW_READER);                         \
+       _rc1_ = ((result = held_func(&(rwp)->rw_rwlock)) != rex1);      \
+       splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
+                    " returned %d (expected %d) when RW_READER\n",     \
+                    _rc1_ ? "Fail " : "", result, rex1);               \
+       rw_exit(&(rwp)->rw_rwlock);                                     \
+       _rc2_ = ((result = held_func(&(rwp)->rw_rwlock)) != rex2);      \
+       splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
+                    " returned %d (expected %d) when !RW_READER\n",    \
+                    _rc2_ ? "Fail " : "", result, rex2);               \
+                                                                       \
+       rw_enter(&(rwp)->rw_rwlock, RW_WRITER);                         \
+       _rc3_ = ((result = held_func(&(rwp)->rw_rwlock)) != wex1);      \
+       splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
+                    " returned %d (expected %d) when RW_WRITER\n",     \
+                    _rc3_ ? "Fail " : "", result, wex1);               \
+       rw_exit(&(rwp)->rw_rwlock);                                     \
+       _rc4_ = ((result = held_func(&(rwp)->rw_rwlock)) != wex2);      \
+       splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
+                    " returned %d (expected %d) when !RW_WRITER\n",    \
+                    _rc4_ ? "Fail " : "", result, wex2);               \
+                                                                       \
+       rc = ((_rc1_ ||  _rc2_ || _rc3_ || _rc4_) ? -EINVAL : 0);       \
+} while(0);
+
+static int
+splat_rwlock_test3(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       int rc1, rc2, rc3;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       splat_rwlock_test3_helper(rwp, 1, 0, 1, 0, RW_LOCK_HELD, rc1);
+       splat_rwlock_test3_helper(rwp, 1, 0, 0, 0, RW_READ_HELD, rc2);
+       splat_rwlock_test3_helper(rwp, 0, 0, 1, 0, RW_WRITE_HELD, rc3);
+
+       rw_destroy(&rwp->rw_rwlock);
+       kfree(rwp);
+
+       return ((rc1 || rc2 || rc3) ? -EINVAL : 0);
+}
+
+static void
+splat_rwlock_test4_func(void *arg)
+{
+       rw_priv_t *rwp = (rw_priv_t *)arg;
+       ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
+
+       if (rw_tryenter(&rwp->rw_rwlock, rwp->rw_type)) {
+               rwp->rw_rc = 0;
+               rw_exit(&rwp->rw_rwlock);
+       } else {
+               rwp->rw_rc = -EBUSY;
+       }
+}
+
+static char *
+splat_rwlock_test4_name(krw_t type)
+{
+       switch (type) {
+               case RW_NONE: return "RW_NONE";
+               case RW_WRITER: return "RW_WRITER";
+               case RW_READER: return "RW_READER";
+       }
+
+       return NULL;
+}
+
+static int
+splat_rwlock_test4_type(taskq_t *tq, rw_priv_t *rwp, int expected_rc,
+                       krw_t holder_type, krw_t try_type)
+{
+       int id, rc = 0;
+
+       /* Schedule a task function which will try and acquire the rwlock
+        * using type try_type while the rwlock is being held as holder_type.
+        * The result must match expected_rc for the test to pass */
+       rwp->rw_rc = -EINVAL;
+       rwp->rw_type = try_type;
+
+       if (holder_type == RW_WRITER || holder_type == RW_READER)
+               rw_enter(&rwp->rw_rwlock, holder_type);
+
+       id = taskq_dispatch(tq, splat_rwlock_test4_func, rwp, TQ_SLEEP);
+       if (id == 0) {
+               splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME, "%s",
+                            "taskq_dispatch() failed\n");
+               rc = -EINVAL;
+               goto out;
+       }
+
+       taskq_wait_id(tq, id);
+
+       if (rwp->rw_rc != expected_rc)
+               rc = -EINVAL;
+
+       splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME,
+                    "%srw_tryenter(%s) returned %d (expected %d) when %s\n",
+                    rc ? "Fail " : "", splat_rwlock_test4_name(try_type),
+                    rwp->rw_rc, expected_rc,
+                    splat_rwlock_test4_name(holder_type));
+out:
+       if (holder_type == RW_WRITER || holder_type == RW_READER)
+               rw_exit(&rwp->rw_rwlock);
+
+       return rc;
+}
+
+static int
+splat_rwlock_test4(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       taskq_t *tq;
+       int rc = 0, rc1, rc2, rc3, rc4, rc5, rc6;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, defclsyspri,
+                         50, INT_MAX, TASKQ_PREPOPULATE);
+       if (tq == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       splat_init_rw_priv(rwp, file);
+
+       /* Validate all combinations of rw_tryenter() contention */
+       rc1 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_WRITER, RW_WRITER);
+       rc2 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_WRITER, RW_READER);
+       rc3 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_READER, RW_WRITER);
+       rc4 = splat_rwlock_test4_type(tq, rwp, 0,      RW_READER, RW_READER);
+       rc5 = splat_rwlock_test4_type(tq, rwp, 0,      RW_NONE,   RW_WRITER);
+       rc6 = splat_rwlock_test4_type(tq, rwp, 0,      RW_NONE,   RW_READER);
+
+       if (rc1 || rc2 || rc3 || rc4 || rc5 || rc6)
+               rc = -EINVAL;
+
+       taskq_destroy(tq);
+out:
+       rw_destroy(&(rwp->rw_rwlock));
+       kfree(rwp);
+
+       return rc;
+}
+
+static int
+splat_rwlock_test5(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       int rc = -EINVAL;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       rw_enter(&rwp->rw_rwlock, RW_WRITER);
+       if (!RW_WRITE_HELD(&rwp->rw_rwlock)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME,
+                            "rwlock should be write lock: %d\n",
+                            RW_WRITE_HELD(&rwp->rw_rwlock));
+               goto out;
+       }
+
+       rw_downgrade(&rwp->rw_rwlock);
+       if (!RW_READ_HELD(&rwp->rw_rwlock)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME,
+                            "rwlock should be read lock: %d\n",
+                            RW_READ_HELD(&rwp->rw_rwlock));
+               goto out;
+       }
+
+       rc = 0;
+       splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME, "%s",
+                    "rwlock properly downgraded\n");
+out:
+       rw_exit(&rwp->rw_rwlock);
+       rw_destroy(&rwp->rw_rwlock);
+       kfree(rwp);
+
+       return rc;
+}
+
+static int
+splat_rwlock_test6(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       int rc;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       rw_enter(&rwp->rw_rwlock, RW_READER);
+       if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) !=
+           SPL_RWSEM_SINGLE_READER_VALUE) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
+                   "We assumed single reader rwsem->count "
+                   "should be %ld, but is %ld\n",
+                   (long int)SPL_RWSEM_SINGLE_READER_VALUE,
+                   (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock)));
+               rc = -ENOLCK;
+               goto out;
+       }
+       rw_exit(&rwp->rw_rwlock);
+
+       rw_enter(&rwp->rw_rwlock, RW_WRITER);
+       if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) !=
+           SPL_RWSEM_SINGLE_WRITER_VALUE) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
+                   "We assumed single writer rwsem->count "
+                   "should be %ld, but is %ld\n",
+                   (long int)SPL_RWSEM_SINGLE_WRITER_VALUE,
+                   (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock)));
+               rc = -ENOLCK;
+               goto out;
+       }
+       rc = 0;
+       splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "%s",
+                    "rwsem->count same as we assumed\n");
+out:
+       rw_exit(&rwp->rw_rwlock);
+       rw_destroy(&rwp->rw_rwlock);
+       kfree(rwp);
+
+       return rc;
+}
+
+static int
+splat_rwlock_test7(struct file *file, void *arg)
+{
+       rw_priv_t *rwp;
+       int rc;
+
+       rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
+       if (rwp == NULL)
+               return -ENOMEM;
+
+       splat_init_rw_priv(rwp, file);
+
+       rw_enter(&rwp->rw_rwlock, RW_READER);
+       if (!RW_READ_HELD(&rwp->rw_rwlock)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME,
+                            "rwlock should be read lock: %d\n",
+                            RW_READ_HELD(&rwp->rw_rwlock));
+               rc = -ENOLCK;
+               goto out;
+       }
+
+       /* With one reader upgrade should never fail. */
+       rc = rw_tryupgrade(&rwp->rw_rwlock);
+       if (!rc) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME,
+                            "rwlock failed upgrade from reader: %d\n",
+                            RW_READ_HELD(&rwp->rw_rwlock));
+               rc = -ENOLCK;
+               goto out;
+       }
+
+       if (RW_READ_HELD(&rwp->rw_rwlock) || !RW_WRITE_HELD(&rwp->rw_rwlock)) {
+               splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "rwlock should "
+                          "have 0 (not %d) reader and 1 (not %d) writer\n",
+                          RW_READ_HELD(&rwp->rw_rwlock),
+                          RW_WRITE_HELD(&rwp->rw_rwlock));
+               goto out;
+       }
+
+       rc = 0;
+       splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "%s",
+                    "rwlock properly upgraded\n");
+out:
+       rw_exit(&rwp->rw_rwlock);
+       rw_destroy(&rwp->rw_rwlock);
+       kfree(rwp);
+
+       return rc;
+}
+
+splat_subsystem_t *
+splat_rwlock_init(void)
+{
+       splat_subsystem_t *sub;
+
+       sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+       if (sub == NULL)
+               return NULL;
+
+       memset(sub, 0, sizeof(*sub));
+       strncpy(sub->desc.name, SPLAT_RWLOCK_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_RWLOCK_DESC, SPLAT_DESC_SIZE);
+       INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+       spin_lock_init(&sub->test_lock);
+       sub->desc.id = SPLAT_SUBSYSTEM_RWLOCK;
+
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST1_NAME, SPLAT_RWLOCK_TEST1_DESC,
+                     SPLAT_RWLOCK_TEST1_ID, splat_rwlock_test1);
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST2_NAME, SPLAT_RWLOCK_TEST2_DESC,
+                     SPLAT_RWLOCK_TEST2_ID, splat_rwlock_test2);
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST3_NAME, SPLAT_RWLOCK_TEST3_DESC,
+                     SPLAT_RWLOCK_TEST3_ID, splat_rwlock_test3);
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST4_NAME, SPLAT_RWLOCK_TEST4_DESC,
+                     SPLAT_RWLOCK_TEST4_ID, splat_rwlock_test4);
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST5_NAME, SPLAT_RWLOCK_TEST5_DESC,
+                     SPLAT_RWLOCK_TEST5_ID, splat_rwlock_test5);
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST6_NAME, SPLAT_RWLOCK_TEST6_DESC,
+                     SPLAT_RWLOCK_TEST6_ID, splat_rwlock_test6);
+       SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST7_NAME, SPLAT_RWLOCK_TEST7_DESC,
+                     SPLAT_RWLOCK_TEST7_ID, splat_rwlock_test7);
+
+       return sub;
+}
+
+void
+splat_rwlock_fini(splat_subsystem_t *sub)
+{
+       ASSERT(sub);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST7_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST6_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST5_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST4_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST3_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST2_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST1_ID);
+       kfree(sub);
+}
+
+int
+splat_rwlock_id(void) {
+       return SPLAT_SUBSYSTEM_RWLOCK;
+}
diff --git a/spl/module/splat/splat-taskq.c b/spl/module/splat/splat-taskq.c
new file mode 100644 (file)
index 0000000..8f06f41
--- /dev/null
@@ -0,0 +1,1547 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Task Queue Tests.
+\*****************************************************************************/
+
+#include <sys/kmem.h>
+#include <sys/vmem.h>
+#include <sys/random.h>
+#include <sys/taskq.h>
+#include <sys/time.h>
+#include <sys/timer.h>
+#include <linux/delay.h>
+#include "splat-internal.h"
+
+#define SPLAT_TASKQ_NAME               "taskq"
+#define SPLAT_TASKQ_DESC               "Kernel Task Queue Tests"
+
+#define SPLAT_TASKQ_TEST1_ID           0x0201
+#define SPLAT_TASKQ_TEST1_NAME         "single"
+#define SPLAT_TASKQ_TEST1_DESC         "Single task queue, single task"
+
+#define SPLAT_TASKQ_TEST2_ID           0x0202
+#define SPLAT_TASKQ_TEST2_NAME         "multiple"
+#define SPLAT_TASKQ_TEST2_DESC         "Multiple task queues, multiple tasks"
+
+#define SPLAT_TASKQ_TEST3_ID           0x0203
+#define SPLAT_TASKQ_TEST3_NAME         "system"
+#define SPLAT_TASKQ_TEST3_DESC         "System task queue, multiple tasks"
+
+#define SPLAT_TASKQ_TEST4_ID           0x0204
+#define SPLAT_TASKQ_TEST4_NAME         "wait"
+#define SPLAT_TASKQ_TEST4_DESC         "Multiple task waiting"
+
+#define SPLAT_TASKQ_TEST5_ID           0x0205
+#define SPLAT_TASKQ_TEST5_NAME         "order"
+#define SPLAT_TASKQ_TEST5_DESC         "Correct task ordering"
+
+#define SPLAT_TASKQ_TEST6_ID           0x0206
+#define SPLAT_TASKQ_TEST6_NAME         "front"
+#define SPLAT_TASKQ_TEST6_DESC         "Correct ordering with TQ_FRONT flag"
+
+#define SPLAT_TASKQ_TEST7_ID           0x0207
+#define SPLAT_TASKQ_TEST7_NAME         "recurse"
+#define SPLAT_TASKQ_TEST7_DESC         "Single task queue, recursive dispatch"
+
+#define SPLAT_TASKQ_TEST8_ID           0x0208
+#define SPLAT_TASKQ_TEST8_NAME         "contention"
+#define SPLAT_TASKQ_TEST8_DESC         "1 queue, 100 threads, 131072 tasks"
+
+#define SPLAT_TASKQ_TEST9_ID           0x0209
+#define SPLAT_TASKQ_TEST9_NAME         "delay"
+#define SPLAT_TASKQ_TEST9_DESC         "Delayed task execution"
+
+#define SPLAT_TASKQ_TEST10_ID          0x020a
+#define SPLAT_TASKQ_TEST10_NAME                "cancel"
+#define SPLAT_TASKQ_TEST10_DESC                "Cancel task execution"
+
+#define SPLAT_TASKQ_TEST11_ID          0x020b
+#define SPLAT_TASKQ_TEST11_NAME                "dynamic"
+#define SPLAT_TASKQ_TEST11_DESC                "Dynamic task queue thread creation"
+
+#define SPLAT_TASKQ_ORDER_MAX          8
+#define SPLAT_TASKQ_DEPTH_MAX          16
+
+
+typedef struct splat_taskq_arg {
+       int flag;
+       int id;
+       atomic_t *count;
+       int order[SPLAT_TASKQ_ORDER_MAX];
+       unsigned int depth;
+       clock_t expire;
+       taskq_t *tq;
+       taskq_ent_t *tqe;
+       spinlock_t lock;
+       struct file *file;
+       const char *name;
+} splat_taskq_arg_t;
+
+typedef struct splat_taskq_id {
+       int id;
+       splat_taskq_arg_t *arg;
+} splat_taskq_id_t;
+
+/*
+ * Create a taskq, queue a task, wait until task completes, ensure
+ * task ran properly, cleanup taskq.
+ */
+static void
+splat_taskq_test13_func(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+
+       ASSERT(tq_arg);
+       splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME,
+                  "Taskq '%s' function '%s' setting flag\n",
+                  tq_arg->name, sym2str(splat_taskq_test13_func));
+       tq_arg->flag = 1;
+}
+
+static int
+splat_taskq_test1_impl(struct file *file, void *arg, boolean_t prealloc)
+{
+       taskq_t *tq;
+       taskqid_t id;
+       splat_taskq_arg_t tq_arg;
+       taskq_ent_t *tqe;
+
+       tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP);
+       taskq_init_ent(tqe);
+
+       splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
+                    "Taskq '%s' creating (%s dispatch)\n",
+                    SPLAT_TASKQ_TEST1_NAME,
+                    prealloc ? "prealloc" : "dynamic");
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, defclsyspri,
+                              50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
+                          "Taskq '%s' create failed\n",
+                          SPLAT_TASKQ_TEST1_NAME);
+               kmem_free(tqe, sizeof (taskq_ent_t));
+               return -EINVAL;
+       }
+
+       tq_arg.flag = 0;
+       tq_arg.id   = 0;
+       tq_arg.file = file;
+       tq_arg.name = SPLAT_TASKQ_TEST1_NAME;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
+                  "Taskq '%s' function '%s' dispatching\n",
+                  tq_arg.name, sym2str(splat_taskq_test13_func));
+       if (prealloc) {
+               taskq_dispatch_ent(tq, splat_taskq_test13_func,
+                                  &tq_arg, TQ_SLEEP, tqe);
+               id = tqe->tqent_id;
+       } else {
+               id = taskq_dispatch(tq, splat_taskq_test13_func,
+                                   &tq_arg, TQ_SLEEP);
+       }
+
+       if (id == 0) {
+               splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
+                            "Taskq '%s' function '%s' dispatch failed\n",
+                            tq_arg.name, sym2str(splat_taskq_test13_func));
+               kmem_free(tqe, sizeof (taskq_ent_t));
+               taskq_destroy(tq);
+               return -EINVAL;
+       }
+
+       splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
+                  tq_arg.name);
+       taskq_wait(tq);
+       splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
+                  tq_arg.name);
+
+       kmem_free(tqe, sizeof (taskq_ent_t));
+       taskq_destroy(tq);
+
+       return (tq_arg.flag) ? 0 : -EINVAL;
+}
+
+static int
+splat_taskq_test1(struct file *file, void *arg)
+{
+       int rc;
+
+       rc = splat_taskq_test1_impl(file, arg, B_FALSE);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test1_impl(file, arg, B_TRUE);
+
+       return rc;
+}
+
+/*
+ * Create multiple taskq's, each with multiple tasks, wait until
+ * all tasks complete, ensure all tasks ran properly and in the
+ * correct order.  Run order must be the same as the order submitted
+ * because we only have 1 thread per taskq.  Finally cleanup the taskq.
+ */
+static void
+splat_taskq_test2_func1(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+
+       ASSERT(tq_arg);
+       splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
+                  "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
+                  tq_arg->name, tq_arg->id,
+                  sym2str(splat_taskq_test2_func1),
+                  tq_arg->flag * 2, tq_arg->flag);
+       tq_arg->flag *= 2;
+}
+
+static void
+splat_taskq_test2_func2(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+
+       ASSERT(tq_arg);
+       splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
+                  "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
+                  tq_arg->name, tq_arg->id,
+                  sym2str(splat_taskq_test2_func2),
+                  tq_arg->flag + 1, tq_arg->flag);
+       tq_arg->flag += 1;
+}
+
+#define TEST2_TASKQS                    8
+#define TEST2_THREADS_PER_TASKQ         1
+
+static int
+splat_taskq_test2_impl(struct file *file, void *arg, boolean_t prealloc) {
+       taskq_t *tq[TEST2_TASKQS] = { NULL };
+       taskqid_t id;
+       splat_taskq_arg_t *tq_args[TEST2_TASKQS] = { NULL };
+       taskq_ent_t *func1_tqes = NULL;
+       taskq_ent_t *func2_tqes = NULL;
+       int i, rc = 0;
+
+       func1_tqes = kmalloc(sizeof(*func1_tqes) * TEST2_TASKQS, GFP_KERNEL);
+       if (func1_tqes == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       func2_tqes = kmalloc(sizeof(*func2_tqes) * TEST2_TASKQS, GFP_KERNEL);
+       if (func2_tqes == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < TEST2_TASKQS; i++) {
+               taskq_init_ent(&func1_tqes[i]);
+               taskq_init_ent(&func2_tqes[i]);
+
+               tq_args[i] = kmalloc(sizeof (splat_taskq_arg_t), GFP_KERNEL);
+               if (tq_args[i] == NULL) {
+                       rc = -ENOMEM;
+                       break;
+               }
+
+               splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                            "Taskq '%s/%d' creating (%s dispatch)\n",
+                            SPLAT_TASKQ_TEST2_NAME, i,
+                            prealloc ? "prealloc" : "dynamic");
+               if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
+                                         TEST2_THREADS_PER_TASKQ,
+                                         defclsyspri, 50, INT_MAX,
+                                         TASKQ_PREPOPULATE)) == NULL) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                                  "Taskq '%s/%d' create failed\n",
+                                  SPLAT_TASKQ_TEST2_NAME, i);
+                       rc = -EINVAL;
+                       break;
+               }
+
+               tq_args[i]->flag = i;
+               tq_args[i]->id   = i;
+               tq_args[i]->file = file;
+               tq_args[i]->name = SPLAT_TASKQ_TEST2_NAME;
+
+               splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                          "Taskq '%s/%d' function '%s' dispatching\n",
+                          tq_args[i]->name, tq_args[i]->id,
+                          sym2str(splat_taskq_test2_func1));
+               if (prealloc) {
+                       taskq_dispatch_ent(tq[i], splat_taskq_test2_func1,
+                           tq_args[i], TQ_SLEEP, &func1_tqes[i]);
+                       id = func1_tqes[i].tqent_id;
+               } else {
+                       id = taskq_dispatch(tq[i], splat_taskq_test2_func1,
+                           tq_args[i], TQ_SLEEP);
+               }
+
+               if (id == 0) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                                  "Taskq '%s/%d' function '%s' dispatch "
+                                  "failed\n", tq_args[i]->name, tq_args[i]->id,
+                                  sym2str(splat_taskq_test2_func1));
+                       rc = -EINVAL;
+                       break;
+               }
+
+               splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                          "Taskq '%s/%d' function '%s' dispatching\n",
+                          tq_args[i]->name, tq_args[i]->id,
+                          sym2str(splat_taskq_test2_func2));
+               if (prealloc) {
+                       taskq_dispatch_ent(tq[i], splat_taskq_test2_func2,
+                           tq_args[i], TQ_SLEEP, &func2_tqes[i]);
+                       id = func2_tqes[i].tqent_id;
+               } else {
+                       id = taskq_dispatch(tq[i], splat_taskq_test2_func2,
+                           tq_args[i], TQ_SLEEP);
+               }
+
+               if (id == 0) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq "
+                                    "'%s/%d' function '%s' dispatch failed\n",
+                                    tq_args[i]->name, tq_args[i]->id,
+                                    sym2str(splat_taskq_test2_func2));
+                       rc = -EINVAL;
+                       break;
+               }
+       }
+
+       /* When rc is set we're effectively just doing cleanup here, so
+        * ignore new errors in that case.  They just cause noise. */
+       for (i = 0; i < TEST2_TASKQS; i++) {
+               if (tq_args[i] == NULL)
+                       continue;
+
+               if (tq[i] != NULL) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                                  "Taskq '%s/%d' waiting\n",
+                                  tq_args[i]->name, tq_args[i]->id);
+                       taskq_wait(tq[i]);
+                       splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                                  "Taskq '%s/%d; destroying\n",
+                                 tq_args[i]->name, tq_args[i]->id);
+
+                       taskq_destroy(tq[i]);
+
+                       if (!rc && tq_args[i]->flag != ((i * 2) + 1)) {
+                               splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                                          "Taskq '%s/%d' processed tasks "
+                                          "out of order; %d != %d\n",
+                                          tq_args[i]->name, tq_args[i]->id,
+                                          tq_args[i]->flag, i * 2 + 1);
+                               rc = -EINVAL;
+                       } else {
+                               splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
+                                          "Taskq '%s/%d' processed tasks "
+                                          "in the correct order; %d == %d\n",
+                                          tq_args[i]->name, tq_args[i]->id,
+                                          tq_args[i]->flag, i * 2 + 1);
+                       }
+
+                       kfree(tq_args[i]);
+               }
+       }
+out:
+       if (func1_tqes)
+               kfree(func1_tqes);
+
+       if (func2_tqes)
+               kfree(func2_tqes);
+
+       return rc;
+}
+
+static int
+splat_taskq_test2(struct file *file, void *arg) {
+       int rc;
+
+       rc = splat_taskq_test2_impl(file, arg, B_FALSE);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test2_impl(file, arg, B_TRUE);
+
+       return rc;
+}
+
+/*
+ * Use the global system task queue with a single task, wait until task
+ * completes, ensure task ran properly.
+ */
+static int
+splat_taskq_test3_impl(struct file *file, void *arg, boolean_t prealloc)
+{
+       taskqid_t id;
+       splat_taskq_arg_t *tq_arg;
+       taskq_ent_t *tqe;
+       int error;
+
+       tq_arg = kmem_alloc(sizeof (splat_taskq_arg_t), KM_SLEEP);
+       tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP);
+       taskq_init_ent(tqe);
+
+       tq_arg->flag = 0;
+       tq_arg->id   = 0;
+       tq_arg->file = file;
+       tq_arg->name = SPLAT_TASKQ_TEST3_NAME;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
+                  "Taskq '%s' function '%s' %s dispatch\n",
+                  tq_arg->name, sym2str(splat_taskq_test13_func),
+                  prealloc ? "prealloc" : "dynamic");
+       if (prealloc) {
+               taskq_dispatch_ent(system_taskq, splat_taskq_test13_func,
+                                  tq_arg, TQ_SLEEP, tqe);
+               id = tqe->tqent_id;
+       } else {
+               id = taskq_dispatch(system_taskq, splat_taskq_test13_func,
+                                   tq_arg, TQ_SLEEP);
+       }
+
+       if (id == 0) {
+               splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
+                          "Taskq '%s' function '%s' dispatch failed\n",
+                          tq_arg->name, sym2str(splat_taskq_test13_func));
+               kmem_free(tqe, sizeof (taskq_ent_t));
+               kmem_free(tq_arg, sizeof (splat_taskq_arg_t));
+               return -EINVAL;
+       }
+
+       splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n",
+                  tq_arg->name);
+       taskq_wait(system_taskq);
+
+       error = (tq_arg->flag) ? 0 : -EINVAL;
+
+       kmem_free(tqe, sizeof (taskq_ent_t));
+       kmem_free(tq_arg, sizeof (splat_taskq_arg_t));
+
+       return (error);
+}
+
+static int
+splat_taskq_test3(struct file *file, void *arg)
+{
+       int rc;
+
+       rc = splat_taskq_test3_impl(file, arg, B_FALSE);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test3_impl(file, arg, B_TRUE);
+
+       return rc;
+}
+
+/*
+ * Create a taskq and dispatch a large number of tasks to the queue.
+ * Then use taskq_wait() to block until all the tasks complete, then
+ * cross check that all the tasks ran by checking the shared atomic
+ * counter which is incremented in the task function.
+ *
+ * First we try with a large 'maxalloc' value, then we try with a small one.
+ * We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
+ * if the number of pending tasks is above maxalloc.
+ */
+static void
+splat_taskq_test4_func(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+       ASSERT(tq_arg);
+
+       atomic_inc(tq_arg->count);
+}
+
+static int
+splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
+                         int maxalloc, int nr_tasks, boolean_t prealloc)
+{
+       taskq_t *tq;
+       taskqid_t id;
+       splat_taskq_arg_t tq_arg;
+       taskq_ent_t *tqes;
+       atomic_t count;
+       int i, j, rc = 0;
+
+       tqes = kmalloc(sizeof(*tqes) * nr_tasks, GFP_KERNEL);
+       if (tqes == NULL)
+               return -ENOMEM;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
+                    "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
+                    SPLAT_TASKQ_TEST4_NAME,
+                    prealloc ? "prealloc" : "dynamic",
+                    minalloc, maxalloc, nr_tasks);
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, defclsyspri,
+                              minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
+                            "Taskq '%s' create failed\n",
+                            SPLAT_TASKQ_TEST4_NAME);
+               rc = -EINVAL;
+               goto out_free;
+       }
+
+       tq_arg.file = file;
+       tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
+       tq_arg.count = &count;
+
+       for (i = 1; i <= nr_tasks; i *= 2) {
+               atomic_set(tq_arg.count, 0);
+               splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
+                            "Taskq '%s' function '%s' dispatched %d times\n",
+                            tq_arg.name, sym2str(splat_taskq_test4_func), i);
+
+               for (j = 0; j < i; j++) {
+                       taskq_init_ent(&tqes[j]);
+
+                       if (prealloc) {
+                               taskq_dispatch_ent(tq, splat_taskq_test4_func,
+                                                  &tq_arg, TQ_SLEEP, &tqes[j]);
+                               id = tqes[j].tqent_id;
+                       } else {
+                               id = taskq_dispatch(tq, splat_taskq_test4_func,
+                                                   &tq_arg, TQ_SLEEP);
+                       }
+
+                       if (id == 0) {
+                               splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
+                                       "Taskq '%s' function '%s' dispatch "
+                                       "%d failed\n", tq_arg.name,
+                                       sym2str(splat_taskq_test4_func), j);
+                                       rc = -EINVAL;
+                                       goto out;
+                       }
+               }
+
+               splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
+                            "waiting for %d dispatches\n", tq_arg.name, i);
+               taskq_wait(tq);
+               splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
+                            "%d/%d dispatches finished\n", tq_arg.name,
+                            atomic_read(&count), i);
+               if (atomic_read(&count) != i) {
+                       rc = -ERANGE;
+                       goto out;
+
+               }
+       }
+out:
+       splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' destroying\n",
+                  tq_arg.name);
+       taskq_destroy(tq);
+
+out_free:
+       kfree(tqes);
+
+       return rc;
+}
+
+static int
+splat_taskq_test4_impl(struct file *file, void *arg, boolean_t prealloc)
+{
+       int rc;
+
+       rc = splat_taskq_test4_common(file, arg, 50, INT_MAX, 1024, prealloc);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test4_common(file, arg, 1, 1, 32, prealloc);
+
+       return rc;
+}
+
+static int
+splat_taskq_test4(struct file *file, void *arg)
+{
+       int rc;
+
+       rc = splat_taskq_test4_impl(file, arg, B_FALSE);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test4_impl(file, arg, B_TRUE);
+
+       return rc;
+}
+
+/*
+ * Create a taskq and dispatch a specific sequence of tasks carefully
+ * crafted to validate the order in which tasks are processed.  When
+ * there are multiple worker threads each thread will process the
+ * next pending task as soon as it completes its current task.  This
+ * means that tasks do not strictly complete in order in which they
+ * were dispatched (increasing task id).  This is fine but we need to
+ * verify taskq_wait_outstanding() blocks until the passed task id and
+ * all lower task ids complete.  We do this by dispatching the following
+ * specific sequence of tasks each of which block for N time units.
+ * We then use taskq_wait_outstanding() to unblock at specific task id and
+ * verify the only the expected task ids have completed and in the
+ * correct order.  The two cases of interest are:
+ *
+ * 1) Task ids larger than the waited for task id can run and
+ *    complete as long as there is an available worker thread.
+ * 2) All task ids lower than the waited one must complete before
+ *    unblocking even if the waited task id itself has completed.
+ *
+ * The following table shows each task id and how they will be
+ * scheduled.  Each rows represent one time unit and each column
+ * one of the three worker threads.  The places taskq_wait_outstanding()
+ * must unblock for a specific id are identified as well as the
+ * task ids which must have completed and their order.
+ *
+ *       +-----+       <--- taskq_wait_outstanding(tq, 8) unblocks
+ *       |     |            Required Completion Order: 1,2,4,5,3,8,6,7
+ * +-----+     |
+ * |     |     |
+ * |     |     +-----+
+ * |     |     |  8  |
+ * |     |     +-----+ <--- taskq_wait_outstanding(tq, 3) unblocks
+ * |     |  7  |     |      Required Completion Order: 1,2,4,5,3
+ * |     +-----+     |
+ * |  6  |     |     |
+ * +-----+     |     |
+ * |     |  5  |     |
+ * |     +-----+     |
+ * |  4  |     |     |
+ * +-----+     |     |
+ * |  1  |  2  |  3  |
+ * +-----+-----+-----+
+ *
+ */
+static void
+splat_taskq_test5_func(void *arg)
+{
+       splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
+       splat_taskq_arg_t *tq_arg = tq_id->arg;
+       int factor;
+
+       /* Delays determined by above table */
+       switch (tq_id->id) {
+               default:                factor = 0;     break;
+               case 1: case 8:         factor = 1;     break;
+               case 2: case 4: case 5: factor = 2;     break;
+               case 6: case 7:         factor = 4;     break;
+               case 3:                 factor = 5;     break;
+       }
+
+       msleep(factor * 100);
+       splat_vprint(tq_arg->file, tq_arg->name,
+                    "Taskqid %d complete for taskq '%s'\n",
+                    tq_id->id, tq_arg->name);
+
+       spin_lock(&tq_arg->lock);
+       tq_arg->order[tq_arg->flag] = tq_id->id;
+       tq_arg->flag++;
+       spin_unlock(&tq_arg->lock);
+}
+
+static int
+splat_taskq_test_order(splat_taskq_arg_t *tq_arg, int *order)
+{
+       int i, j;
+
+       for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
+               if (tq_arg->order[i] != order[i]) {
+                       splat_vprint(tq_arg->file, tq_arg->name,
+                                    "Taskq '%s' incorrect completion "
+                                    "order\n", tq_arg->name);
+                       splat_vprint(tq_arg->file, tq_arg->name,
+                                    "%s", "Expected { ");
+
+                       for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
+                               splat_print(tq_arg->file, "%d ", order[j]);
+
+                       splat_print(tq_arg->file, "%s", "}\n");
+                       splat_vprint(tq_arg->file, tq_arg->name,
+                                    "%s", "Got      { ");
+
+                       for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
+                               splat_print(tq_arg->file, "%d ",
+                                           tq_arg->order[j]);
+
+                       splat_print(tq_arg->file, "%s", "}\n");
+                       return -EILSEQ;
+               }
+       }
+
+       splat_vprint(tq_arg->file, tq_arg->name,
+                    "Taskq '%s' validated correct completion order\n",
+                    tq_arg->name);
+
+       return 0;
+}
+
+static int
+splat_taskq_test5_impl(struct file *file, void *arg, boolean_t prealloc)
+{
+       taskq_t *tq;
+       taskqid_t id;
+       splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
+       splat_taskq_arg_t tq_arg;
+       int order1[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,0,0,0 };
+       int order2[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,8,6,7 };
+       taskq_ent_t *tqes;
+       int i, rc = 0;
+
+       tqes = kmem_alloc(sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX, KM_SLEEP);
+       memset(tqes, 0, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX);
+
+       splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
+                    "Taskq '%s' creating (%s dispatch)\n",
+                    SPLAT_TASKQ_TEST5_NAME,
+                    prealloc ? "prealloc" : "dynamic");
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, defclsyspri,
+                              50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
+                            "Taskq '%s' create failed\n",
+                            SPLAT_TASKQ_TEST5_NAME);
+               return -EINVAL;
+       }
+
+       tq_arg.flag = 0;
+       memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
+       spin_lock_init(&tq_arg.lock);
+       tq_arg.file = file;
+       tq_arg.name = SPLAT_TASKQ_TEST5_NAME;
+
+       for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
+               taskq_init_ent(&tqes[i]);
+
+               tq_id[i].id = i + 1;
+               tq_id[i].arg = &tq_arg;
+
+               if (prealloc) {
+                       taskq_dispatch_ent(tq, splat_taskq_test5_func,
+                                      &tq_id[i], TQ_SLEEP, &tqes[i]);
+                       id = tqes[i].tqent_id;
+               } else {
+                       id = taskq_dispatch(tq, splat_taskq_test5_func,
+                                           &tq_id[i], TQ_SLEEP);
+               }
+
+               if (id == 0) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
+                               "Taskq '%s' function '%s' dispatch failed\n",
+                               tq_arg.name, sym2str(splat_taskq_test5_func));
+                               rc = -EINVAL;
+                               goto out;
+               }
+
+               if (tq_id[i].id != id) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
+                               "Taskq '%s' expected taskqid %d got %d\n",
+                               tq_arg.name, (int)tq_id[i].id, (int)id);
+                               rc = -EINVAL;
+                               goto out;
+               }
+       }
+
+       splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
+                    "waiting for taskqid %d completion\n", tq_arg.name, 3);
+       taskq_wait_outstanding(tq, 3);
+       if ((rc = splat_taskq_test_order(&tq_arg, order1)))
+               goto out;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
+                    "waiting for taskqid %d completion\n", tq_arg.name, 8);
+       taskq_wait_outstanding(tq, 8);
+       rc = splat_taskq_test_order(&tq_arg, order2);
+
+out:
+       splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
+                    "Taskq '%s' destroying\n", tq_arg.name);
+       taskq_destroy(tq);
+
+       kmem_free(tqes, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX);
+
+       return rc;
+}
+
+static int
+splat_taskq_test5(struct file *file, void *arg)
+{
+       int rc;
+
+       rc = splat_taskq_test5_impl(file, arg, B_FALSE);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test5_impl(file, arg, B_TRUE);
+
+       return rc;
+}
+
+/*
+ * Create a single task queue with three threads.  Dispatch 8 tasks,
+ * setting TQ_FRONT on only the last three.  Sleep after
+ * dispatching tasks 1-3 to ensure they will run and hold the threads
+ * busy while we dispatch the remaining tasks.  Verify that tasks 6-8
+ * run before task 4-5.
+ *
+ * The following table shows each task id and how they will be
+ * scheduled.  Each rows represent one time unit and each column
+ * one of the three worker threads.
+ *
+ * NB: The Horizontal Line is the LAST Time unit consumed by the Task,
+ *     and must be included in the factor calculation.
+ *  T
+ * 17->       +-----+
+ * 16         | T6  |
+ * 15-> +-----+     |
+ * 14   | T6  |     |
+ * 13-> |     |  5  +-----+
+ * 12   |     |     | T6  |
+ * 11-> |     +-----|     |
+ * 10   |  4  | T6  |     |
+ *  9-> +-----+     |  8  |
+ *  8   | T5  |     |     |
+ *  7-> |     |  7  +-----+
+ *  6   |     |     | T7  |
+ *  5-> |     +-----+     |
+ *  4   |  6  |  T5 |     |
+ *  3-> +-----+     |     |
+ *  2   | T3  |     |     |
+ *  1   |  1  |  2  |  3  |
+ *  0   +-----+-----+-----+
+ *
+ */
+static void
+splat_taskq_test6_func(void *arg)
+{
+        /* Delays determined by above table */
+        static const int factor[SPLAT_TASKQ_ORDER_MAX+1] = {0,3,5,7,6,6,5,6,6};
+
+       splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
+       splat_taskq_arg_t *tq_arg = tq_id->arg;
+
+       splat_vprint(tq_arg->file, tq_arg->name,
+                    "Taskqid %d starting for taskq '%s'\n",
+                    tq_id->id, tq_arg->name);
+
+        if (tq_id->id < SPLAT_TASKQ_ORDER_MAX+1) {
+               msleep(factor[tq_id->id] * 50);
+       }
+
+       spin_lock(&tq_arg->lock);
+       tq_arg->order[tq_arg->flag] = tq_id->id;
+       tq_arg->flag++;
+       spin_unlock(&tq_arg->lock);
+
+       splat_vprint(tq_arg->file, tq_arg->name,
+                    "Taskqid %d complete for taskq '%s'\n",
+                    tq_id->id, tq_arg->name);
+}
+
+static int
+splat_taskq_test6_impl(struct file *file, void *arg, boolean_t prealloc)
+{
+       taskq_t *tq;
+       taskqid_t id;
+       splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
+       splat_taskq_arg_t tq_arg;
+       int order[SPLAT_TASKQ_ORDER_MAX] = { 1,2,3,6,7,8,4,5 };
+       taskq_ent_t *tqes;
+       int i, rc = 0;
+       uint_t tflags;
+
+       tqes = kmem_alloc(sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX, KM_SLEEP);
+       memset(tqes, 0, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX);
+
+       splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
+                    "Taskq '%s' creating (%s dispatch)\n",
+                    SPLAT_TASKQ_TEST6_NAME,
+                    prealloc ? "prealloc" : "dynamic");
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST6_NAME, 3, defclsyspri,
+                              50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
+                            "Taskq '%s' create failed\n",
+                            SPLAT_TASKQ_TEST6_NAME);
+               return -EINVAL;
+       }
+
+       tq_arg.flag = 0;
+       memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
+       spin_lock_init(&tq_arg.lock);
+       tq_arg.file = file;
+       tq_arg.name = SPLAT_TASKQ_TEST6_NAME;
+
+       for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
+               taskq_init_ent(&tqes[i]);
+
+               tq_id[i].id = i + 1;
+               tq_id[i].arg = &tq_arg;
+               tflags = TQ_SLEEP;
+               if (i > 4)
+                       tflags |= TQ_FRONT;
+
+               if (prealloc) {
+                       taskq_dispatch_ent(tq, splat_taskq_test6_func,
+                                          &tq_id[i], tflags, &tqes[i]);
+                       id = tqes[i].tqent_id;
+               } else {
+                       id = taskq_dispatch(tq, splat_taskq_test6_func,
+                                           &tq_id[i], tflags);
+               }
+
+               if (id == 0) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
+                               "Taskq '%s' function '%s' dispatch failed\n",
+                               tq_arg.name, sym2str(splat_taskq_test6_func));
+                               rc = -EINVAL;
+                               goto out;
+               }
+
+               if (tq_id[i].id != id) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
+                               "Taskq '%s' expected taskqid %d got %d\n",
+                               tq_arg.name, (int)tq_id[i].id, (int)id);
+                               rc = -EINVAL;
+                               goto out;
+               }
+               /* Sleep to let tasks 1-3 start executing. */
+               if ( i == 2 )
+                       msleep(100);
+       }
+
+       splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' "
+                    "waiting for taskqid %d completion\n", tq_arg.name,
+                    SPLAT_TASKQ_ORDER_MAX);
+       taskq_wait_outstanding(tq, SPLAT_TASKQ_ORDER_MAX);
+       rc = splat_taskq_test_order(&tq_arg, order);
+
+out:
+       splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
+                    "Taskq '%s' destroying\n", tq_arg.name);
+       taskq_destroy(tq);
+
+       kmem_free(tqes, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX);
+
+       return rc;
+}
+
+static int
+splat_taskq_test6(struct file *file, void *arg)
+{
+       int rc;
+
+       rc = splat_taskq_test6_impl(file, arg, B_FALSE);
+       if (rc)
+               return rc;
+
+       rc = splat_taskq_test6_impl(file, arg, B_TRUE);
+
+       return rc;
+}
+
+static void
+splat_taskq_test7_func(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+       taskqid_t id;
+
+       ASSERT(tq_arg);
+
+       if (tq_arg->depth >= SPLAT_TASKQ_DEPTH_MAX)
+               return;
+
+       tq_arg->depth++;
+
+       splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME,
+                    "Taskq '%s' function '%s' dispatching (depth = %u)\n",
+                    tq_arg->name, sym2str(splat_taskq_test7_func),
+                    tq_arg->depth);
+
+       if (tq_arg->tqe) {
+               VERIFY(taskq_empty_ent(tq_arg->tqe));
+               taskq_dispatch_ent(tq_arg->tq, splat_taskq_test7_func,
+                                  tq_arg, TQ_SLEEP, tq_arg->tqe);
+               id = tq_arg->tqe->tqent_id;
+       } else {
+               id = taskq_dispatch(tq_arg->tq, splat_taskq_test7_func,
+                                   tq_arg, TQ_SLEEP);
+       }
+
+       if (id == 0) {
+               splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME,
+                            "Taskq '%s' function '%s' dispatch failed "
+                            "(depth = %u)\n", tq_arg->name,
+                            sym2str(splat_taskq_test7_func), tq_arg->depth);
+               tq_arg->flag = -EINVAL;
+               return;
+       }
+}
+
+static int
+splat_taskq_test7_impl(struct file *file, void *arg, boolean_t prealloc)
+{
+       taskq_t *tq;
+       splat_taskq_arg_t *tq_arg;
+       taskq_ent_t *tqe;
+       int error;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
+                    "Taskq '%s' creating (%s dispatch)\n",
+                    SPLAT_TASKQ_TEST7_NAME,
+                    prealloc ? "prealloc" :  "dynamic");
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST7_NAME, 1, defclsyspri,
+                              50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
+                            "Taskq '%s' create failed\n",
+                            SPLAT_TASKQ_TEST7_NAME);
+               return -EINVAL;
+       }
+
+       tq_arg = kmem_alloc(sizeof (splat_taskq_arg_t), KM_SLEEP);
+       tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP);
+
+       tq_arg->depth = 0;
+       tq_arg->flag  = 0;
+       tq_arg->id    = 0;
+       tq_arg->file  = file;
+       tq_arg->name  = SPLAT_TASKQ_TEST7_NAME;
+       tq_arg->tq    = tq;
+
+       if (prealloc) {
+               taskq_init_ent(tqe);
+               tq_arg->tqe = tqe;
+       } else {
+               tq_arg->tqe = NULL;
+       }
+
+       splat_taskq_test7_func(tq_arg);
+
+       if (tq_arg->flag == 0) {
+               splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
+                            "Taskq '%s' waiting\n", tq_arg->name);
+               taskq_wait_outstanding(tq, SPLAT_TASKQ_DEPTH_MAX);
+       }
+
+       error = (tq_arg->depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL);
+
+       kmem_free(tqe, sizeof (taskq_ent_t));
+       kmem_free(tq_arg, sizeof (splat_taskq_arg_t));
+
+       splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
+                     "Taskq '%s' destroying\n", tq_arg->name);
+       taskq_destroy(tq);
+
+       return (error);
+}
+
+static int
+splat_taskq_test7(struct file *file, void *arg)
+{
+       int rc;
+
+       rc = splat_taskq_test7_impl(file, arg, B_FALSE);
+       if (rc)
+               return (rc);
+
+       rc = splat_taskq_test7_impl(file, arg, B_TRUE);
+
+       return (rc);
+}
+
+static void
+splat_taskq_throughput_func(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+       ASSERT(tq_arg);
+
+       atomic_inc(tq_arg->count);
+}
+
+static int
+splat_taskq_throughput(struct file *file, void *arg, const char *name,
+    int nthreads, int minalloc, int maxalloc, int flags, int tasks,
+    struct timespec *delta)
+{
+       taskq_t *tq;
+       taskqid_t id;
+       splat_taskq_arg_t tq_arg;
+       taskq_ent_t **tqes;
+       atomic_t count;
+       struct timespec start, stop;
+       int i, j, rc = 0;
+
+       tqes = vmalloc(sizeof (*tqes) * tasks);
+       if (tqes == NULL)
+               return (-ENOMEM);
+
+       memset(tqes, 0, sizeof (*tqes) * tasks);
+
+       splat_vprint(file, name, "Taskq '%s' creating (%d/%d/%d/%d)\n",
+           name, nthreads, minalloc, maxalloc, tasks);
+       if ((tq = taskq_create(name, nthreads, defclsyspri,
+           minalloc, maxalloc, flags)) == NULL) {
+               splat_vprint(file, name, "Taskq '%s' create failed\n", name);
+               rc = -EINVAL;
+               goto out_free;
+       }
+
+       tq_arg.file = file;
+       tq_arg.name = name;
+       tq_arg.count = &count;
+       atomic_set(tq_arg.count, 0);
+
+       getnstimeofday(&start);
+
+       for (i = 0; i < tasks; i++) {
+               tqes[i] = kmalloc(sizeof (taskq_ent_t), GFP_KERNEL);
+               if (tqes[i] == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+
+               taskq_init_ent(tqes[i]);
+               taskq_dispatch_ent(tq, splat_taskq_throughput_func,
+                   &tq_arg, TQ_SLEEP, tqes[i]);
+               id = tqes[i]->tqent_id;
+
+               if (id == 0) {
+                       splat_vprint(file, name, "Taskq '%s' function '%s' "
+                           "dispatch %d failed\n", tq_arg.name,
+                           sym2str(splat_taskq_throughput_func), i);
+                       rc = -EINVAL;
+                       goto out;
+               }
+       }
+
+       splat_vprint(file, name, "Taskq '%s' waiting for %d dispatches\n",
+           tq_arg.name, tasks);
+
+       taskq_wait(tq);
+
+       if (delta != NULL) {
+               getnstimeofday(&stop);
+               *delta = timespec_sub(stop, start);
+       }
+
+       splat_vprint(file, name, "Taskq '%s' %d/%d dispatches finished\n",
+           tq_arg.name, atomic_read(tq_arg.count), tasks);
+
+       if (atomic_read(tq_arg.count) != tasks)
+               rc = -ERANGE;
+
+out:
+       splat_vprint(file, name, "Taskq '%s' destroying\n", tq_arg.name);
+       taskq_destroy(tq);
+out_free:
+       for (j = 0; j < tasks && tqes[j] != NULL; j++)
+               kfree(tqes[j]);
+
+       vfree(tqes);
+
+       return (rc);
+}
+
+/*
+ * Create a taskq with 100 threads and dispatch a huge number of trivial
+ * tasks to generate contention on tq->tq_lock.  This test should always
+ * pass.  The purpose is to provide a benchmark for measuring the
+ * effectiveness of taskq optimizations.
+ */
+#define        TEST8_NUM_TASKS                 0x20000
+#define        TEST8_THREADS_PER_TASKQ         100
+
+static int
+splat_taskq_test8(struct file *file, void *arg)
+{
+       return (splat_taskq_throughput(file, arg,
+           SPLAT_TASKQ_TEST8_NAME, TEST8_THREADS_PER_TASKQ,
+           1, INT_MAX, TASKQ_PREPOPULATE, TEST8_NUM_TASKS, NULL));
+}
+
+/*
+ * Create a taskq and dispatch a number of delayed tasks to the queue.
+ * For each task verify that it was run no early than requested.
+ */
+static void
+splat_taskq_test9_func(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+       ASSERT(tq_arg);
+
+       if (ddi_time_after_eq(ddi_get_lbolt(), tq_arg->expire))
+               atomic_inc(tq_arg->count);
+
+       kmem_free(tq_arg, sizeof(splat_taskq_arg_t));
+}
+
+static int
+splat_taskq_test9(struct file *file, void *arg)
+{
+       taskq_t *tq;
+       atomic_t count;
+       int i, rc = 0;
+       int minalloc = 1;
+       int maxalloc = 10;
+       int nr_tasks = 100;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
+           "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
+           SPLAT_TASKQ_TEST9_NAME, "delay", minalloc, maxalloc, nr_tasks);
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST9_NAME, 3, defclsyspri,
+           minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
+                   "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST9_NAME);
+               return -EINVAL;
+       }
+
+       atomic_set(&count, 0);
+
+       for (i = 1; i <= nr_tasks; i++) {
+               splat_taskq_arg_t *tq_arg;
+               taskqid_t id;
+               uint32_t rnd;
+
+               /* A random timeout in jiffies of at most 5 seconds */
+               get_random_bytes((void *)&rnd, 4);
+               rnd = rnd % (5 * HZ);
+
+               tq_arg = kmem_alloc(sizeof(splat_taskq_arg_t), KM_SLEEP);
+               tq_arg->file = file;
+               tq_arg->name = SPLAT_TASKQ_TEST9_NAME;
+               tq_arg->expire = ddi_get_lbolt() + rnd;
+               tq_arg->count = &count;
+
+               splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
+                   "Taskq '%s' delay dispatch %u jiffies\n",
+                   SPLAT_TASKQ_TEST9_NAME, rnd);
+
+               id = taskq_dispatch_delay(tq, splat_taskq_test9_func,
+                   tq_arg, TQ_SLEEP, ddi_get_lbolt() + rnd);
+
+               if (id == 0) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
+                          "Taskq '%s' delay dispatch failed\n",
+                          SPLAT_TASKQ_TEST9_NAME);
+                       kmem_free(tq_arg, sizeof(splat_taskq_arg_t));
+                       taskq_wait(tq);
+                       rc = -EINVAL;
+                       goto out;
+               }
+       }
+
+       splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' waiting for "
+           "%d delay dispatches\n", SPLAT_TASKQ_TEST9_NAME, nr_tasks);
+
+       taskq_wait(tq);
+       if (atomic_read(&count) != nr_tasks)
+               rc = -ERANGE;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' %d/%d delay "
+           "dispatches finished on time\n", SPLAT_TASKQ_TEST9_NAME,
+           atomic_read(&count), nr_tasks);
+       splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' destroying\n",
+           SPLAT_TASKQ_TEST9_NAME);
+out:
+       taskq_destroy(tq);
+
+       return rc;
+}
+
+/*
+ * Create a taskq and dispatch then cancel tasks in the queue.
+ */
+static void
+splat_taskq_test10_func(void *arg)
+{
+       splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
+       uint8_t rnd;
+
+       if (ddi_time_after_eq(ddi_get_lbolt(), tq_arg->expire))
+               atomic_inc(tq_arg->count);
+
+       /* Randomly sleep to further perturb the system */
+       get_random_bytes((void *)&rnd, 1);
+       msleep(1 + (rnd % 9));
+}
+
+static int
+splat_taskq_test10(struct file *file, void *arg)
+{
+       taskq_t *tq;
+       splat_taskq_arg_t **tqas;
+       atomic_t count;
+       int i, j, rc = 0;
+       int minalloc = 1;
+       int maxalloc = 10;
+       int nr_tasks = 100;
+       int canceled = 0;
+       int completed = 0;
+       int blocked = 0;
+       clock_t start, cancel;
+
+       tqas = vmalloc(sizeof(*tqas) * nr_tasks);
+       if (tqas == NULL)
+               return -ENOMEM;
+        memset(tqas, 0, sizeof(*tqas) * nr_tasks);
+
+       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
+           "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
+           SPLAT_TASKQ_TEST10_NAME, "delay", minalloc, maxalloc, nr_tasks);
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST10_NAME, 3, defclsyspri,
+           minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
+               splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
+                   "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST10_NAME);
+               rc = -EINVAL;
+               goto out_free;
+       }
+
+       atomic_set(&count, 0);
+
+       for (i = 0; i < nr_tasks; i++) {
+               splat_taskq_arg_t *tq_arg;
+               uint32_t rnd;
+
+               /* A random timeout in jiffies of at most 5 seconds */
+               get_random_bytes((void *)&rnd, 4);
+               rnd = rnd % (5 * HZ);
+
+               tq_arg = kmem_alloc(sizeof(splat_taskq_arg_t), KM_SLEEP);
+               tq_arg->file = file;
+               tq_arg->name = SPLAT_TASKQ_TEST10_NAME;
+               tq_arg->count = &count;
+               tqas[i] = tq_arg;
+
+               /*
+                * Dispatch every 1/3 one immediately to mix it up, the cancel
+                * code is inherently racy and we want to try and provoke any
+                * subtle concurrently issues.
+                */
+               if ((i % 3) == 0) {
+                       tq_arg->expire = ddi_get_lbolt();
+                       tq_arg->id = taskq_dispatch(tq, splat_taskq_test10_func,
+                           tq_arg, TQ_SLEEP);
+               } else {
+                       tq_arg->expire = ddi_get_lbolt() + rnd;
+                       tq_arg->id = taskq_dispatch_delay(tq,
+                           splat_taskq_test10_func,
+                           tq_arg, TQ_SLEEP, ddi_get_lbolt() + rnd);
+               }
+
+               if (tq_arg->id == 0) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
+                          "Taskq '%s' dispatch failed\n",
+                          SPLAT_TASKQ_TEST10_NAME);
+                       kmem_free(tq_arg, sizeof(splat_taskq_arg_t));
+                       taskq_wait(tq);
+                       rc = -EINVAL;
+                       goto out;
+               } else {
+                       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
+                           "Taskq '%s' dispatch %lu in %lu jiffies\n",
+                           SPLAT_TASKQ_TEST10_NAME, (unsigned long)tq_arg->id,
+                           !(i % 3) ? 0 : tq_arg->expire - ddi_get_lbolt());
+               }
+       }
+
+       /*
+        * Start randomly canceling tasks for the duration of the test.  We
+        * happen to know the valid task id's will be in the range 1..nr_tasks
+        * because the taskq is private and was just created.  However, we
+        * have no idea of a particular task has already executed or not.
+        */
+       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, "Taskq '%s' randomly "
+           "canceling task ids\n", SPLAT_TASKQ_TEST10_NAME);
+
+       start = ddi_get_lbolt();
+       i = 0;
+
+       while (ddi_time_before(ddi_get_lbolt(), start + 5 * HZ)) {
+               taskqid_t id;
+               uint32_t rnd;
+
+               i++;
+               cancel = ddi_get_lbolt();
+               get_random_bytes((void *)&rnd, 4);
+               id = 1 + (rnd % nr_tasks);
+               rc = taskq_cancel_id(tq, id);
+
+               /*
+                * Keep track of the results of the random cancels.
+                */
+               if (rc == 0) {
+                       canceled++;
+               } else if (rc == ENOENT) {
+                       completed++;
+               } else if (rc == EBUSY) {
+                       blocked++;
+               } else {
+                       rc = -EINVAL;
+                       break;
+               }
+
+               /*
+                * Verify we never get blocked to long in taskq_cancel_id().
+                * The worst case is 10ms if we happen to cancel the task
+                * which is currently executing.  We allow a factor of 2x.
+                */
+               if (ddi_get_lbolt() - cancel > HZ / 50) {
+                       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
+                           "Taskq '%s' cancel for %lu took %lu\n",
+                           SPLAT_TASKQ_TEST10_NAME, (unsigned long)id,
+                           ddi_get_lbolt() - cancel);
+                       rc = -ETIMEDOUT;
+                       break;
+               }
+
+               get_random_bytes((void *)&rnd, 4);
+               msleep(1 + (rnd % 100));
+               rc = 0;
+       }
+
+       taskq_wait(tq);
+
+       /*
+        * Cross check the results of taskq_cancel_id() with the number of
+        * times the dispatched function actually ran successfully.
+        */
+       if ((rc == 0) && (nr_tasks - canceled != atomic_read(&count)))
+               rc = -EDOM;
+
+       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, "Taskq '%s' %d attempts, "
+           "%d canceled, %d completed, %d blocked, %d/%d tasks run\n",
+           SPLAT_TASKQ_TEST10_NAME, i, canceled, completed, blocked,
+           atomic_read(&count), nr_tasks);
+       splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, "Taskq '%s' destroying %d\n",
+           SPLAT_TASKQ_TEST10_NAME, rc);
+out:
+       taskq_destroy(tq);
+out_free:
+       for (j = 0; j < nr_tasks && tqas[j] != NULL; j++)
+               kmem_free(tqas[j], sizeof(splat_taskq_arg_t));
+       vfree(tqas);
+
+       return rc;
+}
+
+/*
+ * Create a dynamic taskq with 100 threads and dispatch a huge number of
+ * trivial tasks.  This will cause the taskq to grow quickly to its max
+ * thread count.  This test should always pass.  The purpose is to provide
+ * a benchmark for measuring the performance of dynamic taskqs.
+ */
+#define        TEST11_NUM_TASKS                        100000
+#define        TEST11_THREADS_PER_TASKQ                100
+
+static int
+splat_taskq_test11(struct file *file, void *arg)
+{
+       struct timespec normal, dynamic;
+       int error;
+
+       error = splat_taskq_throughput(file, arg, SPLAT_TASKQ_TEST11_NAME,
+           TEST11_THREADS_PER_TASKQ, 1, INT_MAX,
+           TASKQ_PREPOPULATE, TEST11_NUM_TASKS, &normal);
+       if (error)
+               return (error);
+
+       error = splat_taskq_throughput(file, arg, SPLAT_TASKQ_TEST11_NAME,
+           TEST11_THREADS_PER_TASKQ, 1, INT_MAX,
+           TASKQ_PREPOPULATE | TASKQ_DYNAMIC, TEST11_NUM_TASKS, &dynamic);
+       if (error)
+               return (error);
+
+       splat_vprint(file, SPLAT_TASKQ_TEST11_NAME,
+           "Timing taskq_wait(): normal=%ld.%09lds, dynamic=%ld.%09lds\n",
+           normal.tv_sec, normal.tv_nsec,
+           dynamic.tv_sec, dynamic.tv_nsec);
+
+       /* A 10x increase in runtime is used to indicate a core problem. */
+       if ((dynamic.tv_sec * NANOSEC + dynamic.tv_nsec) >
+           ((normal.tv_sec * NANOSEC + normal.tv_nsec) * 10))
+               error = -ETIME;
+
+       return (error);
+}
+
+splat_subsystem_t *
+splat_taskq_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE);
+        strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+       spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_TASKQ;
+
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC,
+                     SPLAT_TASKQ_TEST1_ID, splat_taskq_test1);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC,
+                     SPLAT_TASKQ_TEST2_ID, splat_taskq_test2);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC,
+                     SPLAT_TASKQ_TEST3_ID, splat_taskq_test3);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST4_NAME, SPLAT_TASKQ_TEST4_DESC,
+                     SPLAT_TASKQ_TEST4_ID, splat_taskq_test4);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST5_NAME, SPLAT_TASKQ_TEST5_DESC,
+                     SPLAT_TASKQ_TEST5_ID, splat_taskq_test5);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST6_NAME, SPLAT_TASKQ_TEST6_DESC,
+                     SPLAT_TASKQ_TEST6_ID, splat_taskq_test6);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST7_NAME, SPLAT_TASKQ_TEST7_DESC,
+                     SPLAT_TASKQ_TEST7_ID, splat_taskq_test7);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST8_NAME, SPLAT_TASKQ_TEST8_DESC,
+                     SPLAT_TASKQ_TEST8_ID, splat_taskq_test8);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST9_NAME, SPLAT_TASKQ_TEST9_DESC,
+                     SPLAT_TASKQ_TEST9_ID, splat_taskq_test9);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST10_NAME, SPLAT_TASKQ_TEST10_DESC,
+                     SPLAT_TASKQ_TEST10_ID, splat_taskq_test10);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST11_NAME, SPLAT_TASKQ_TEST11_DESC,
+                     SPLAT_TASKQ_TEST11_ID, splat_taskq_test11);
+
+        return sub;
+}
+
+void
+splat_taskq_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST11_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST10_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST9_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST8_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST7_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST6_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST5_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST4_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST3_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_taskq_id(void) {
+        return SPLAT_SUBSYSTEM_TASKQ;
+}
diff --git a/spl/module/splat/splat-thread.c b/spl/module/splat/splat-thread.c
new file mode 100644 (file)
index 0000000..8a44714
--- /dev/null
@@ -0,0 +1,389 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Thread Tests.
+\*****************************************************************************/
+
+#include <sys/thread.h>
+#include <sys/random.h>
+#include <linux/delay.h>
+#include <linux/mm_compat.h>
+#include <linux/slab.h>
+#include "splat-internal.h"
+
+#define SPLAT_THREAD_NAME              "thread"
+#define SPLAT_THREAD_DESC              "Kernel Thread Tests"
+
+#define SPLAT_THREAD_TEST1_ID          0x0601
+#define SPLAT_THREAD_TEST1_NAME                "create"
+#define SPLAT_THREAD_TEST1_DESC                "Validate thread creation"
+
+#define SPLAT_THREAD_TEST2_ID          0x0602
+#define SPLAT_THREAD_TEST2_NAME                "exit"
+#define SPLAT_THREAD_TEST2_DESC                "Validate thread exit"
+
+#define SPLAT_THREAD_TEST3_ID          0x6003
+#define SPLAT_THREAD_TEST3_NAME                "tsd"
+#define SPLAT_THREAD_TEST3_DESC                "Validate thread specific data"
+
+#define SPLAT_THREAD_TEST_MAGIC                0x4488CC00UL
+#define SPLAT_THREAD_TEST_KEYS         32
+#define SPLAT_THREAD_TEST_THREADS      16
+
+typedef struct thread_priv {
+        unsigned long tp_magic;
+        struct file *tp_file;
+        spinlock_t tp_lock;
+        wait_queue_head_t tp_waitq;
+       uint_t tp_keys[SPLAT_THREAD_TEST_KEYS];
+       int tp_rc;
+       int tp_count;
+       int tp_dtor_count;
+} thread_priv_t;
+
+static int
+splat_thread_rc(thread_priv_t *tp, int rc)
+{
+       int ret;
+
+       spin_lock(&tp->tp_lock);
+       ret = (tp->tp_rc == rc);
+       spin_unlock(&tp->tp_lock);
+
+       return ret;
+}
+
+static int
+splat_thread_count(thread_priv_t *tp, int count)
+{
+       int ret;
+
+       spin_lock(&tp->tp_lock);
+       ret = (tp->tp_count == count);
+       spin_unlock(&tp->tp_lock);
+
+       return ret;
+}
+
+static void
+splat_thread_work1(void *priv)
+{
+       thread_priv_t *tp = (thread_priv_t *)priv;
+
+       spin_lock(&tp->tp_lock);
+       ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
+       tp->tp_rc = 1;
+       wake_up(&tp->tp_waitq);
+       spin_unlock(&tp->tp_lock);
+
+       thread_exit();
+}
+
+static int
+splat_thread_test1(struct file *file, void *arg)
+{
+       thread_priv_t tp;
+       kthread_t *thr;
+
+       tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
+       tp.tp_file = file;
+        spin_lock_init(&tp.tp_lock);
+       init_waitqueue_head(&tp.tp_waitq);
+       tp.tp_rc = 0;
+
+       thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work1, &tp, 0,
+                                        &p0, TS_RUN, defclsyspri);
+       /* Must never fail under Solaris, but we check anyway since this
+        * can happen in the linux SPL, we may want to change this behavior */
+       if (thr == NULL)
+               return  -ESRCH;
+
+       /* Sleep until the thread sets tp.tp_rc == 1 */
+       wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1));
+
+        splat_vprint(file, SPLAT_THREAD_TEST1_NAME, "%s",
+                  "Thread successfully started properly\n");
+       return 0;
+}
+
+static void
+splat_thread_work2(void *priv)
+{
+       thread_priv_t *tp = (thread_priv_t *)priv;
+
+       spin_lock(&tp->tp_lock);
+       ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
+       tp->tp_rc = 1;
+       wake_up(&tp->tp_waitq);
+       spin_unlock(&tp->tp_lock);
+
+       thread_exit();
+
+       /* The following code is unreachable when thread_exit() is
+        * working properly, which is exactly what we're testing */
+       spin_lock(&tp->tp_lock);
+       tp->tp_rc = 2;
+       wake_up(&tp->tp_waitq);
+       spin_unlock(&tp->tp_lock);
+}
+
+static int
+splat_thread_test2(struct file *file, void *arg)
+{
+       thread_priv_t tp;
+       kthread_t *thr;
+       int rc = 0;
+
+       tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
+       tp.tp_file = file;
+        spin_lock_init(&tp.tp_lock);
+       init_waitqueue_head(&tp.tp_waitq);
+       tp.tp_rc = 0;
+
+       thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work2, &tp, 0,
+                                        &p0, TS_RUN, defclsyspri);
+       /* Must never fail under Solaris, but we check anyway since this
+        * can happen in the linux SPL, we may want to change this behavior */
+       if (thr == NULL)
+               return -ESRCH;
+
+       /* Sleep until the thread sets tp.tp_rc == 1 */
+       wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1));
+
+       /* Sleep until the thread sets tp.tp_rc == 2, or until we hit
+        * the timeout.  If thread exit is working properly we should
+        * hit the timeout and never see to.tp_rc == 2. */
+       rc = wait_event_timeout(tp.tp_waitq, splat_thread_rc(&tp, 2), HZ / 10);
+       if (rc > 0) {
+               rc = -EINVAL;
+               splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s",
+                          "Thread did not exit properly at thread_exit()\n");
+       } else {
+               splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s",
+                          "Thread successfully exited at thread_exit()\n");
+       }
+
+       return rc;
+}
+
+static void
+splat_thread_work3_common(thread_priv_t *tp)
+{
+       ulong_t rnd;
+       int i, rc = 0;
+
+       /* set a unique value for each key using a random value */
+       get_random_bytes((void *)&rnd, 4);
+       for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++)
+               tsd_set(tp->tp_keys[i], (void *)(i + rnd));
+
+       /* verify the unique value for each key */
+       for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++)
+               if (tsd_get(tp->tp_keys[i]) !=  (void *)(i + rnd))
+                       rc = -EINVAL;
+
+       /* set the value to thread_priv_t for use by the destructor */
+       for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++)
+               tsd_set(tp->tp_keys[i], (void *)tp);
+
+       spin_lock(&tp->tp_lock);
+       if (rc && !tp->tp_rc)
+               tp->tp_rc = rc;
+
+       tp->tp_count++;
+       wake_up_all(&tp->tp_waitq);
+       spin_unlock(&tp->tp_lock);
+}
+
+static void
+splat_thread_work3_wait(void *priv)
+{
+       thread_priv_t *tp = (thread_priv_t *)priv;
+
+       ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
+       splat_thread_work3_common(tp);
+       wait_event(tp->tp_waitq, splat_thread_count(tp, 0));
+       thread_exit();
+}
+
+static void
+splat_thread_work3_exit(void *priv)
+{
+       thread_priv_t *tp = (thread_priv_t *)priv;
+
+       ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
+       splat_thread_work3_common(tp);
+       thread_exit();
+}
+
+static void
+splat_thread_dtor3(void *priv)
+{
+       thread_priv_t *tp = (thread_priv_t *)priv;
+
+       ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC);
+       spin_lock(&tp->tp_lock);
+       tp->tp_dtor_count++;
+       spin_unlock(&tp->tp_lock);
+}
+
+/*
+ * Create threads which set and verify SPLAT_THREAD_TEST_KEYS number of
+ * keys.  These threads may then exit by calling thread_exit() which calls
+ * tsd_exit() resulting in all their thread specific data being reclaimed.
+ * Alternately, the thread may block in which case the thread specific
+ * data will be reclaimed as part of tsd_destroy().  In either case all
+ * thread specific data must be reclaimed, this is verified by ensuring
+ * the registered destructor is called the correct number of times.
+ */
+static int
+splat_thread_test3(struct file *file, void *arg)
+{
+       int i, rc = 0, expected, wait_count = 0, exit_count = 0;
+       thread_priv_t tp;
+
+       tp.tp_magic = SPLAT_THREAD_TEST_MAGIC;
+       tp.tp_file = file;
+        spin_lock_init(&tp.tp_lock);
+       init_waitqueue_head(&tp.tp_waitq);
+       tp.tp_rc = 0;
+       tp.tp_count = 0;
+       tp.tp_dtor_count = 0;
+
+       for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++) {
+               tp.tp_keys[i] = 0;
+               tsd_create(&tp.tp_keys[i], splat_thread_dtor3);
+       }
+
+       /* Start tsd wait threads */
+       for (i = 0; i < SPLAT_THREAD_TEST_THREADS; i++) {
+               if (thread_create(NULL, 0, splat_thread_work3_wait,
+                                 &tp, 0, &p0, TS_RUN, defclsyspri))
+                       wait_count++;
+       }
+
+       /* All wait threads have setup their tsd and are blocking. */
+       wait_event(tp.tp_waitq, splat_thread_count(&tp, wait_count));
+
+       if (tp.tp_dtor_count != 0) {
+               splat_vprint(file, SPLAT_THREAD_TEST3_NAME,
+                   "Prematurely ran %d tsd destructors\n", tp.tp_dtor_count);
+               if (!rc)
+                       rc = -ERANGE;
+       }
+
+       /* Start tsd exit threads */
+       for (i = 0; i < SPLAT_THREAD_TEST_THREADS; i++) {
+               if (thread_create(NULL, 0, splat_thread_work3_exit,
+                                 &tp, 0, &p0, TS_RUN, defclsyspri))
+                       exit_count++;
+       }
+
+       /* All exit threads verified tsd and are in the process of exiting */
+       wait_event(tp.tp_waitq,splat_thread_count(&tp, wait_count+exit_count));
+       msleep(500);
+
+       expected = (SPLAT_THREAD_TEST_KEYS * exit_count);
+       if (tp.tp_dtor_count != expected) {
+               splat_vprint(file, SPLAT_THREAD_TEST3_NAME,
+                   "Expected %d exit tsd destructors but saw %d\n",
+                   expected, tp.tp_dtor_count);
+               if (!rc)
+                       rc = -ERANGE;
+       }
+
+       /* Destroy all keys and associated tsd in blocked threads */
+       for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++)
+               tsd_destroy(&tp.tp_keys[i]);
+
+       expected = (SPLAT_THREAD_TEST_KEYS * (exit_count + wait_count));
+       if (tp.tp_dtor_count != expected) {
+               splat_vprint(file, SPLAT_THREAD_TEST3_NAME,
+                   "Expected %d wait+exit tsd destructors but saw %d\n",
+                   expected, tp.tp_dtor_count);
+               if (!rc)
+                       rc = -ERANGE;
+       }
+
+       /* Release the remaining wait threads, sleep briefly while they exit */
+       spin_lock(&tp.tp_lock);
+       tp.tp_count = 0;
+       wake_up_all(&tp.tp_waitq);
+       spin_unlock(&tp.tp_lock);
+       msleep(500);
+
+       if (tp.tp_rc) {
+               splat_vprint(file, SPLAT_THREAD_TEST3_NAME,
+                   "Thread tsd_get()/tsd_set() error %d\n", tp.tp_rc);
+               if (!rc)
+                       rc = tp.tp_rc;
+       } else if (!rc) {
+               splat_vprint(file, SPLAT_THREAD_TEST3_NAME, "%s",
+                   "Thread specific data verified\n");
+       }
+
+       return rc;
+}
+
+splat_subsystem_t *
+splat_thread_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_THREAD_NAME, SPLAT_NAME_SIZE);
+        strncpy(sub->desc.desc, SPLAT_THREAD_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+        INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_THREAD;
+
+        SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST1_NAME, SPLAT_THREAD_TEST1_DESC,
+                      SPLAT_THREAD_TEST1_ID, splat_thread_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST2_NAME, SPLAT_THREAD_TEST2_DESC,
+                      SPLAT_THREAD_TEST2_ID, splat_thread_test2);
+        SPLAT_TEST_INIT(sub, SPLAT_THREAD_TEST3_NAME, SPLAT_THREAD_TEST3_DESC,
+                      SPLAT_THREAD_TEST3_ID, splat_thread_test3);
+
+        return sub;
+}
+
+void
+splat_thread_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+        SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_THREAD_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_thread_id(void) {
+        return SPLAT_SUBSYSTEM_THREAD;
+}
diff --git a/spl/module/splat/splat-time.c b/spl/module/splat/splat-time.c
new file mode 100644 (file)
index 0000000..b4e94c8
--- /dev/null
@@ -0,0 +1,119 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Time Tests.
+\*****************************************************************************/
+
+#include <sys/time.h>
+#include <linux/mm_compat.h>
+#include <linux/slab.h>
+#include "splat-internal.h"
+
+#define SPLAT_TIME_NAME                        "time"
+#define SPLAT_TIME_DESC                        "Kernel Time Tests"
+
+#define SPLAT_TIME_TEST1_ID            0x0801
+#define SPLAT_TIME_TEST1_NAME          "time1"
+#define SPLAT_TIME_TEST1_DESC          "HZ Test"
+
+#define SPLAT_TIME_TEST2_ID            0x0802
+#define SPLAT_TIME_TEST2_NAME          "time2"
+#define SPLAT_TIME_TEST2_DESC          "Monotonic Test"
+
+static int
+splat_time_test1(struct file *file, void *arg)
+{
+       int myhz = hz;
+       splat_vprint(file, SPLAT_TIME_TEST1_NAME, "hz is %d\n", myhz);
+        return 0;
+}
+
+static int
+splat_time_test2(struct file *file, void *arg)
+{
+        hrtime_t tm1, tm2;
+       int i;
+
+        tm1 = gethrtime();
+        splat_vprint(file, SPLAT_TIME_TEST2_NAME, "time is %lld\n", tm1);
+
+        for(i = 0; i < 100; i++) {
+                tm2 = gethrtime();
+                splat_vprint(file, SPLAT_TIME_TEST2_NAME, "time is %lld\n", tm2);
+
+                if(tm1 > tm2) {
+                        splat_print(file, "%s: gethrtime() is not giving "
+                                   "monotonically increasing values\n",
+                                   SPLAT_TIME_TEST2_NAME);
+                        return 1;
+                }
+                tm1 = tm2;
+
+                set_current_state(TASK_INTERRUPTIBLE);
+                schedule_timeout(10);
+        }
+
+        return 0;
+}
+
+splat_subsystem_t *
+splat_time_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_TIME_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_TIME_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_TIME;
+
+        SPLAT_TEST_INIT(sub, SPLAT_TIME_TEST1_NAME, SPLAT_TIME_TEST1_DESC,
+                     SPLAT_TIME_TEST1_ID, splat_time_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_TIME_TEST2_NAME, SPLAT_TIME_TEST2_DESC,
+                     SPLAT_TIME_TEST2_ID, splat_time_test2);
+
+        return sub;
+}
+
+void
+splat_time_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_TIME_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_TIME_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_time_id(void)
+{
+        return SPLAT_SUBSYSTEM_TIME;
+}
diff --git a/spl/module/splat/splat-vnode.c b/spl/module/splat/splat-vnode.c
new file mode 100644 (file)
index 0000000..bffcf49
--- /dev/null
@@ -0,0 +1,451 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Vnode Tests.
+\*****************************************************************************/
+
+#include <sys/vnode.h>
+#include "splat-internal.h"
+
+#define SPLAT_VNODE_NAME               "vnode"
+#define SPLAT_VNODE_DESC               "Kernel Vnode Tests"
+
+#define SPLAT_VNODE_TEST1_ID           0x0901
+#define SPLAT_VNODE_TEST1_NAME         "vn_open"
+#define SPLAT_VNODE_TEST1_DESC         "Vn_open Test"
+
+#define SPLAT_VNODE_TEST2_ID           0x0902
+#define SPLAT_VNODE_TEST2_NAME         "vn_openat"
+#define SPLAT_VNODE_TEST2_DESC         "Vn_openat Test"
+
+#define SPLAT_VNODE_TEST3_ID           0x0903
+#define SPLAT_VNODE_TEST3_NAME         "vn_rdwr"
+#define SPLAT_VNODE_TEST3_DESC         "Vn_rdwrt Test"
+
+#define SPLAT_VNODE_TEST4_ID           0x0904
+#define SPLAT_VNODE_TEST4_NAME         "vn_rename"
+#define SPLAT_VNODE_TEST4_DESC         "Vn_rename Test"
+
+#define SPLAT_VNODE_TEST5_ID           0x0905
+#define SPLAT_VNODE_TEST5_NAME         "vn_getattr"
+#define SPLAT_VNODE_TEST5_DESC         "Vn_getattr Test"
+
+#define SPLAT_VNODE_TEST6_ID           0x0906
+#define SPLAT_VNODE_TEST6_NAME         "vn_sync"
+#define SPLAT_VNODE_TEST6_DESC         "Vn_sync Test"
+
+#define SPLAT_VNODE_TEST_FILE          "/etc/fstab"
+#define SPLAT_VNODE_TEST_FILE_AT       "etc/fstab"
+#define SPLAT_VNODE_TEST_FILE_RW       "/tmp/spl.vnode.tmp"
+#define SPLAT_VNODE_TEST_FILE_RW1      "/tmp/spl.vnode.tmp.1"
+#define SPLAT_VNODE_TEST_FILE_RW2      "/tmp/spl.vnode.tmp.2"
+
+static int
+splat_vnode_user_cmd(struct file *file, void *arg,
+                     char *name, char *cmd)
+{
+       char sh_path[] = "/bin/sh";
+       char *argv[] = { sh_path,
+                        "-c",
+                        cmd,
+                        NULL };
+       char *envp[] = { "HOME=/",
+                        "TERM=linux",
+                        "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+                        NULL };
+       int rc;
+
+       rc = call_usermodehelper(sh_path, argv, envp, UMH_WAIT_PROC);
+       if (rc) {
+               splat_vprint(file, name,
+                            "Failed command: %s %s %s (%d)\n",
+                            argv[0], argv[1], cmd, rc);
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+static int
+splat_vnode_unlink_all(struct file *file, void *arg, char *name)
+{
+       char *cmds[] = { "rm -f " SPLAT_VNODE_TEST_FILE_RW,
+                        "rm -f " SPLAT_VNODE_TEST_FILE_RW1,
+                        "rm -f " SPLAT_VNODE_TEST_FILE_RW2,
+                        NULL };
+       int i = 0, rc = 0;
+
+       while (cmds[i] != NULL) {
+               if ((rc = splat_vnode_user_cmd(file, arg, name, cmds[i])))
+                       return rc;
+
+               i++;
+       }
+
+       return rc;
+}
+
+static int
+splat_vnode_test1(struct file *file, void *arg)
+{
+       vnode_t *vp;
+       int rc;
+
+       if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE,
+                         FREAD, 0644, &vp, 0, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST1_NAME,
+                            "Failed to vn_open test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE, rc);
+               return -rc;
+       }
+
+        rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST1_NAME,
+                            "Failed to vn_close test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE, rc);
+               return -rc;
+       }
+
+       splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully vn_open'ed "
+                    "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE);
+
+        return -rc;
+} /* splat_vnode_test1() */
+
+static int
+splat_vnode_test2(struct file *file, void *arg)
+{
+       vnode_t *vp;
+       int rc;
+
+       if ((rc = vn_openat(SPLAT_VNODE_TEST_FILE_AT, UIO_SYSSPACE,
+                           FREAD, 0644, &vp, 0, 0, rootdir, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST2_NAME,
+                            "Failed to vn_openat test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE, rc);
+               return -rc;
+       }
+
+        rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST2_NAME,
+                            "Failed to vn_close test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE, rc);
+               return -rc;
+       }
+
+       splat_vprint(file, SPLAT_VNODE_TEST2_NAME, "Successfully vn_openat'ed "
+                    "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE);
+
+        return -rc;
+} /* splat_vnode_test2() */
+
+static int
+splat_vnode_test3(struct file *file, void *arg)
+{
+       vnode_t *vp;
+       char buf1[32] = "SPL VNode Interface Test File\n";
+       char buf2[32] = "";
+       int rc;
+
+       if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST3_NAME)))
+               return rc;
+
+       if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE,
+                         FWRITE | FREAD | FCREAT | FEXCL,
+                         0644, &vp, 0, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+                            "Failed to vn_open test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW, rc);
+               return -rc;
+       }
+
+        rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0,
+                     UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+                            "Failed vn_rdwr write of test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW, rc);
+               goto out;
+       }
+
+        rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0,
+                     UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+                            "Failed vn_rdwr read of test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW, rc);
+               goto out;
+       }
+
+       if (strncmp(buf1, buf2, strlen(buf1))) {
+               rc = EINVAL;
+               splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+                            "Failed strncmp data written does not match "
+                            "data read\nWrote: %sRead:  %s\n", buf1, buf2);
+               goto out;
+       }
+
+       rc = 0;
+       splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Wrote: %s", buf1);
+       splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Read:  %s", buf2);
+       splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Successfully wrote and "
+                    "read expected data pattern to test file: %s\n",
+                    SPLAT_VNODE_TEST_FILE_RW);
+
+out:
+        VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+       vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE);
+
+        return -rc;
+} /* splat_vnode_test3() */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,1,0)
+static int
+splat_vnode_test4(struct file *file, void *arg)
+{
+       vnode_t *vp;
+       char buf1[32] = "SPL VNode Interface Test File\n";
+       char buf2[32] = "";
+       int rc;
+
+       if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST4_NAME)))
+               return rc;
+
+       if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW1, UIO_SYSSPACE,
+                         FWRITE | FREAD | FCREAT | FEXCL, 0644, &vp, 0, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+                            "Failed to vn_open test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW1, rc);
+               goto out;
+       }
+
+        rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0,
+                     UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+                            "Failed vn_rdwr write of test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW1, rc);
+               goto out2;
+       }
+
+        VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+
+       rc = vn_rename(SPLAT_VNODE_TEST_FILE_RW1,SPLAT_VNODE_TEST_FILE_RW2,0);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed vn_rename "
+                            "%s -> %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW1,
+                            SPLAT_VNODE_TEST_FILE_RW2, rc);
+               goto out;
+       }
+
+       if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW2, UIO_SYSSPACE,
+                         FREAD | FEXCL, 0644, &vp, 0, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+                            "Failed to vn_open test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW2, rc);
+               goto out;
+       }
+
+        rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0,
+                     UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+                            "Failed vn_rdwr read of test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW2, rc);
+               goto out2;
+       }
+
+       if (strncmp(buf1, buf2, strlen(buf1))) {
+               rc = EINVAL;
+               splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+                            "Failed strncmp data written does not match "
+                            "data read\nWrote: %sRead:  %s\n", buf1, buf2);
+               goto out2;
+       }
+
+       rc = 0;
+       splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Wrote to %s:  %s",
+                    SPLAT_VNODE_TEST_FILE_RW1, buf1);
+       splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Read from %s: %s",
+                    SPLAT_VNODE_TEST_FILE_RW2, buf2);
+       splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Successfully renamed "
+                    "test file %s -> %s and verified data pattern\n",
+                    SPLAT_VNODE_TEST_FILE_RW1, SPLAT_VNODE_TEST_FILE_RW2);
+out2:
+        VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+out:
+       vn_remove(SPLAT_VNODE_TEST_FILE_RW1, UIO_SYSSPACE, RMFILE);
+       vn_remove(SPLAT_VNODE_TEST_FILE_RW2, UIO_SYSSPACE, RMFILE);
+
+        return -rc;
+} /* splat_vnode_test4() */
+#endif
+
+static int
+splat_vnode_test5(struct file *file, void *arg)
+{
+       vnode_t *vp;
+       vattr_t vap;
+       int rc;
+
+       if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE,
+                         FREAD, 0644, &vp, 0, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
+                            "Failed to vn_open test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE, rc);
+               return -rc;
+       }
+
+       rc = VOP_GETATTR(vp, &vap, 0, 0, NULL);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
+                            "Failed to vn_getattr test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE, rc);
+               goto out;
+       }
+
+       if (vap.va_type != VREG) {
+               rc = EINVAL;
+               splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
+                            "Failed expected regular file type "
+                            "(%d != VREG): %s (%d)\n", vap.va_type,
+                            SPLAT_VNODE_TEST_FILE, rc);
+               goto out;
+       }
+
+       splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully "
+                    "vn_getattr'ed test file: %s\n", SPLAT_VNODE_TEST_FILE);
+
+out:
+        VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+
+        return -rc;
+} /* splat_vnode_test5() */
+
+static int
+splat_vnode_test6(struct file *file, void *arg)
+{
+       vnode_t *vp;
+       char buf[32] = "SPL VNode Interface Test File\n";
+       int rc;
+
+       if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST6_NAME)))
+               return rc;
+
+       if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE,
+                         FWRITE | FCREAT | FEXCL, 0644, &vp, 0, 0))) {
+               splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
+                            "Failed to vn_open test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW, rc);
+               return -rc;
+       }
+
+        rc = vn_rdwr(UIO_WRITE, vp, buf, strlen(buf), 0,
+                     UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
+                            "Failed vn_rdwr write of test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW, rc);
+               goto out;
+       }
+
+       rc = vn_fsync(vp, 0, 0, 0);
+       if (rc) {
+               splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
+                            "Failed vn_fsync of test file: %s (%d)\n",
+                            SPLAT_VNODE_TEST_FILE_RW, rc);
+               goto out;
+       }
+
+       rc = 0;
+       splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Successfully "
+                    "fsync'ed test file %s\n", SPLAT_VNODE_TEST_FILE_RW);
+out:
+        VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+       vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE);
+
+        return -rc;
+} /* splat_vnode_test6() */
+
+splat_subsystem_t *
+splat_vnode_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_VNODE_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_VNODE_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_VNODE;
+
+        SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST1_NAME, SPLAT_VNODE_TEST1_DESC,
+                       SPLAT_VNODE_TEST1_ID, splat_vnode_test1);
+        SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST2_NAME, SPLAT_VNODE_TEST2_DESC,
+                       SPLAT_VNODE_TEST2_ID, splat_vnode_test2);
+        SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST3_NAME, SPLAT_VNODE_TEST3_DESC,
+                       SPLAT_VNODE_TEST3_ID, splat_vnode_test3);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,1,0)
+        SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST4_NAME, SPLAT_VNODE_TEST4_DESC,
+                       SPLAT_VNODE_TEST4_ID, splat_vnode_test4);
+#endif
+        SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST5_NAME, SPLAT_VNODE_TEST5_DESC,
+                       SPLAT_VNODE_TEST5_ID, splat_vnode_test5);
+        SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST6_NAME, SPLAT_VNODE_TEST6_DESC,
+                       SPLAT_VNODE_TEST6_ID, splat_vnode_test6);
+
+        return sub;
+} /* splat_vnode_init() */
+
+void
+splat_vnode_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST6_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST5_ID);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,1,0)
+        SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST4_ID);
+#endif
+        SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST1_ID);
+
+        kfree(sub);
+} /* splat_vnode_fini() */
+
+int
+splat_vnode_id(void)
+{
+        return SPLAT_SUBSYSTEM_VNODE;
+} /* splat_vnode_id() */
diff --git a/spl/module/splat/splat-zlib.c b/spl/module/splat/splat-zlib.c
new file mode 100644 (file)
index 0000000..eaa4836
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL 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.
+ *
+ *  The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) Zlib Compression Tests.
+\*****************************************************************************/
+
+#include <sys/zmod.h>
+#include <sys/random.h>
+#include <sys/kmem.h>
+#include <sys/vmem.h>
+#include "splat-internal.h"
+
+#define SPLAT_ZLIB_NAME                        "zlib"
+#define SPLAT_ZLIB_DESC                        "Zlib Compression Tests"
+
+#define SPLAT_ZLIB_TEST1_ID            0x0f01
+#define SPLAT_ZLIB_TEST1_NAME          "compress/uncompress"
+#define SPLAT_ZLIB_TEST1_DESC          "Compress/Uncompress Test"
+
+#define BUFFER_SIZE                    (128 * 1024)
+
+static int
+splat_zlib_test1_check(struct file *file, void *src, void *dst, void *chk,
+    int level)
+{
+       size_t dst_len = BUFFER_SIZE;
+       size_t chk_len = BUFFER_SIZE;
+       int rc;
+
+       memset(dst, 0, BUFFER_SIZE);
+       memset(chk, 0, BUFFER_SIZE);
+
+       rc = z_compress_level(dst, &dst_len, src, BUFFER_SIZE, level);
+       if (rc != Z_OK) {
+               splat_vprint(file, SPLAT_ZLIB_TEST1_NAME,
+                   "Failed level %d z_compress_level(), %d\n", level, rc);
+               return -EINVAL;
+       }
+
+       rc = z_uncompress(chk, &chk_len, dst, dst_len);
+       if (rc != Z_OK) {
+               splat_vprint(file, SPLAT_ZLIB_TEST1_NAME,
+                   "Failed level %d z_uncompress(), %d\n", level, rc);
+               return -EINVAL;
+       }
+
+       rc = memcmp(src, chk, BUFFER_SIZE);
+       if (rc) {
+               splat_vprint(file, SPLAT_ZLIB_TEST1_NAME,
+                   "Failed level %d memcmp()), %d\n", level, rc);
+               return -EINVAL;
+       }
+
+       splat_vprint(file, SPLAT_ZLIB_TEST1_NAME,
+           "Passed level %d, compressed %d bytes to %d bytes\n",
+           level, BUFFER_SIZE, (int)dst_len);
+
+       return 0;
+}
+
+/*
+ * Compress a buffer, uncompress the newly compressed buffer, then
+ * compare it to the original.  Do this for all 9 compression levels.
+ */
+static int
+splat_zlib_test1(struct file *file, void *arg)
+{
+       void *src = NULL, *dst = NULL, *chk = NULL;
+       int i, rc, level;
+
+       src = vmalloc(BUFFER_SIZE);
+       if (src == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       dst = vmalloc(BUFFER_SIZE);
+       if (dst == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       chk = vmalloc(BUFFER_SIZE);
+       if (chk == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /* Source buffer is a repeating 1024 byte random pattern. */
+       random_get_pseudo_bytes(src, sizeof(uint8_t) * 1024);
+       for (i = 1; i < 128; i++)
+               memcpy(src + (i * 1024), src, 1024);
+
+       for (level = 1; level <= 9; level++)
+               if ((rc = splat_zlib_test1_check(file, src, dst, chk, level)))
+                       break;
+out:
+       if (src)
+               vfree(src);
+
+       if (dst)
+               vfree(dst);
+
+       if (chk)
+               vfree(chk);
+
+       return rc;
+}
+
+splat_subsystem_t *
+splat_zlib_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_ZLIB_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_ZLIB_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_ZLIB;
+
+        SPLAT_TEST_INIT(sub, SPLAT_ZLIB_TEST1_NAME, SPLAT_ZLIB_TEST1_DESC,
+                     SPLAT_ZLIB_TEST1_ID, splat_zlib_test1);
+
+        return sub;
+}
+
+void
+splat_zlib_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_ZLIB_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_zlib_id(void) {
+        return SPLAT_SUBSYSTEM_ZLIB;
+}
diff --git a/spl/rpm/Makefile.am b/spl/rpm/Makefile.am
new file mode 100644 (file)
index 0000000..f2cf72c
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = generic redhat
diff --git a/spl/rpm/Makefile.in b/spl/rpm/Makefile.in
new file mode 100644 (file)
index 0000000..28c3448
--- /dev/null
@@ -0,0 +1,673 @@
+# 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 = rpm
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+SUBDIRS = generic redhat
+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 rpm/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu rpm/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/spl/rpm/generic/Makefile.am b/spl/rpm/generic/Makefile.am
new file mode 100644 (file)
index 0000000..da6c4ab
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST = spl.spec.in spl-kmod.spec.in spl-dkms.spec.in
diff --git a/spl/rpm/generic/Makefile.in b/spl/rpm/generic/Makefile.in
new file mode 100644 (file)
index 0000000..7de9fed
--- /dev/null
@@ -0,0 +1,500 @@
+# 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 = rpm/generic
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_config.h
+CONFIG_CLEAN_FILES = spl.spec spl-kmod.spec spl-dkms.spec
+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__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/spl-dkms.spec.in \
+       $(srcdir)/spl-kmod.spec.in $(srcdir)/spl.spec.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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+EXTRA_DIST = spl.spec.in spl-kmod.spec.in spl-dkms.spec.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 rpm/generic/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu rpm/generic/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):
+spl.spec: $(top_builddir)/config.status $(srcdir)/spl.spec.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+spl-kmod.spec: $(top_builddir)/config.status $(srcdir)/spl-kmod.spec.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+spl-dkms.spec: $(top_builddir)/config.status $(srcdir)/spl-dkms.spec.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+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
+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/spl/rpm/generic/spl-dkms.spec.in b/spl/rpm/generic/spl-dkms.spec.in
new file mode 100644 (file)
index 0000000..949660e
--- /dev/null
@@ -0,0 +1,71 @@
+%{?!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:        GPLv2+
+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.2
+Requires:       gcc, make, perl
+Requires:       kernel-devel
+Provides:       %{module}-kmod = %{version}
+
+%description
+This package contains the dkms kernel modules required to emulate
+several interfaces provided by the Solaris kernel.
+
+%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
+echo -e "Uninstall of %{module} module (version %{version}) beginning:"
+dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
+exit 0
+
+%changelog
+* %(date "+%a %b %d %Y") %packager %{version}-%{release}
+- Automatic build by DKMS
diff --git a/spl/rpm/generic/spl-kmod.spec.in b/spl/rpm/generic/spl-kmod.spec.in
new file mode 100644 (file)
index 0000000..eb2dc04
--- /dev/null
@@ -0,0 +1,223 @@
+%define module  @PACKAGE@
+#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_log
+%bcond_with     debug_kmem
+%bcond_with     debug_kmem_tracking
+%bcond_with     atomic_spinlocks
+
+
+Name:           %{module}-kmod
+
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+Summary:        Kernel module(s)
+
+Group:          System Environment/Kernel
+License:        GPLv2+
+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%{?fedora} >= 17
+%define prefix  /usr
+%endif
+
+# Kmodtool does its magic here.  A patched version of kmodtool is shipped
+# because the latest versions may not be available for your distribution.
+# 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 kernel modules required to emulate
+several interfaces provided by the Solaris kernel.
+
+%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_log}
+    %define debug_log --enable-debug-log
+%else
+    %define debug_log --disable-debug-log
+%endif
+
+%if %{with debug_kmem}
+    %define debug_kmem --enable-debug-kmem
+%else
+    %define debug_kmem --disable-debug-kmem
+%endif
+
+%if %{with debug_kmem_tracking}
+    %define debug_kmem_tracking --enable-debug-kmem-tracking
+%else
+    %define debug_kmem_tracking --disable-debug-kmem-tracking
+%endif
+
+%if %{with atomic_spinlocks}
+    %define atomic_spinlocks --enable-atomic-spinlocks
+%else
+    %define atomic_spinlocks --disable-atomic-spinlocks
+%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 \
+%if 0%{?rhel}%{?fedora}
+        --with-linux="${kernel_version##*___}" \
+        --with-linux-obj="${kernel_version##*___}" \
+%else
+        --with-linux="$( \
+        if [ -e "/lib/modules/${kernel_version%%___*}/source" ]; then \
+            echo "/lib/modules/${kernel_version%%___*}/source"; \
+        else \
+            echo "/lib/modules/${kernel_version%%___*}/build"; \
+        fi)" \
+        --with-linux-obj="/lib/modules/${kernel_version%%___*}/build" \
+%endif
+        %{debug} \
+        %{debug_log} \
+        %{debug_kmem} \
+        %{debug_kmem_tracking} \
+        %{atomic_spinlocks}
+    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 Feb 3 2017 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5.9-1
+- Use kernel slab for vn_cache and vn_file_cache zfsonlinux/spl#599
+- Fix splat-cred.c cred usage zfsonlinux/spl#556
+- Fix splat memleak zfsonlinux/spl#590
+- Fix p0 initializer zfsonlinux/spl#576
+- Fix aarch64 type warning zfsonlinux/spl#574
+- Linux 4.8 compat: Fix RW_READ_HELD zfsonlinux/zfs#5233
+- Linux 4.9 compat: group_info changes zfsonlinux/spl#581
+- Fix crgetgroups out-of-bound and misc cred fix zfsonlinux/spl#556
+* Fri Sep 9 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.8-1
+- Fix HAVE_MUTEX_OWNER test for kernels prior to 4.6 zfsonlinux/spl#566
+- Add handling for kernel 4.7's CONFIG_TRIM_UNUSED_KSYMS zfsonlinux/spl#565
+- Linux 4.8 compat: rw_semaphore atomic_long_t count zfsonlinux/spl#563
+- Implement a proper rw_tryupgrade zfsonlinux/spl#554
+- Add rw_tryupgrade() zfsonlinux/spl#534 zfsonlinux/zfs#4388
+- Fix taskq_wait_outstanding re-evaluate tq_next_id zfsonlinux/spl#553
+- Fix race between taskq_destroy and dynamic spawning thread zfsonlinux/spl#553 zfsonlinux/spl#550
+- Use kernel provided mutex owner zfsonlinux/spl#553 zfsonlinux/spl#550
+- Add isa_defs for MIPS zfsonlinux/spl#558
+- Linux 4.7 compat: inode_lock() and friends zfsonlinux/spl#549
+- Fix: handle NULL case in spl_kmem_free_track() zfsonlinux/spl#567
+* Thu May 12 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.7-1
+- Fix PPC build failure zfsonlinux/spl#516
+* Tue Mar 22 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.6-1
+- Remove artificial architecture restrictions in packaging
+- Add support for s390[x] zfsonlinux/spl#537
+* Wed Mar 9 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.5-1
+- Linux 4.5 compatibility zfsonlinux/spl#524
+- Create working debuginfo packages on Red Hat zfsonlinux/zfs#4224
+- Allow copy-builtin to run multiple times zfsonlinux/spl#526
+- Use safer flags for in-kernel memory allocations zfsonlinux/spl#523
+- Fix potential deadlock in cv_wait() zfsonlinux/zfs#4106
+- Fix livelock in shrinker zfsonlinux/zfs#3936
+* Fri Jan  8 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.4-1
+- Build fixes on SPARC and some kernels
+- Fix taskq dynamic spawning deadlock
+- Fix builtin kernel builds
+- Fix crash due to overflow in P2ROUNDUP macro
+- Fix deadlock during direct memory reclaim
+* Tue Oct 13 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.3-1
+- Fix CPU hotplug zfsonlinux/spl#482
+- Disable dynamic taskqs by default to avoid deadlock zfsonlinux/spl#484
+* Tue Sep 29 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.2-1
+- Released 0.6.5.2-1
+- Fix PAX Patch/Grsec SLAB_USERCOPY panic zfsonlinux/zfs#3796
+- Always remove during dkms uninstall/update zfsonlinux/spl#476
+* Thu Sep 19 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.1-1
+- Released 0.6.5.1-1, no changes from spl-0.6.5
+* Thu Sep 10 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/spl/rpm/generic/spl.spec.in b/spl/rpm/generic/spl.spec.in
new file mode 100644 (file)
index 0000000..f95519c
--- /dev/null
@@ -0,0 +1,94 @@
+Name:           @PACKAGE@
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+Summary:        Commands to control the kernel modules
+
+Group:          System Environment/Kernel
+License:        GPLv2+
+URL:            http://zfsonlinux.org/
+Source0:        %{name}-%{version}.tar.gz
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Requires:       %{name}-kmod = %{version}
+Provides:       %{name}-kmod-common = %{version}
+
+%description
+This package contains the commands to verify the SPL
+kernel modules are functioning properly.
+
+%prep
+%setup -q
+
+%build
+%configure --with-config=user
+make %{?_smp_mflags}
+
+%install
+%{__rm} -rf $RPM_BUILD_ROOT
+make install DESTDIR=%{?buildroot}
+
+%files
+%doc AUTHORS COPYING DISCLAIMER
+%{_sbindir}/*
+%{_mandir}/man1/*
+%{_mandir}/man5/*
+
+%changelog
+* Fri Feb 3 2017 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5.9-1
+- Use kernel slab for vn_cache and vn_file_cache zfsonlinux/spl#599
+- Fix splat-cred.c cred usage zfsonlinux/spl#556
+- Fix splat memleak zfsonlinux/spl#590
+- Fix p0 initializer zfsonlinux/spl#576
+- Fix aarch64 type warning zfsonlinux/spl#574
+- Linux 4.8 compat: Fix RW_READ_HELD zfsonlinux/zfs#5233
+- Linux 4.9 compat: group_info changes zfsonlinux/spl#581
+- Fix crgetgroups out-of-bound and misc cred fix zfsonlinux/spl#556
+* Fri Sep 9 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.8-1
+- Fix HAVE_MUTEX_OWNER test for kernels prior to 4.6 zfsonlinux/spl#566
+- Add handling for kernel 4.7's CONFIG_TRIM_UNUSED_KSYMS zfsonlinux/spl#565
+- Linux 4.8 compat: rw_semaphore atomic_long_t count zfsonlinux/spl#563
+- Implement a proper rw_tryupgrade zfsonlinux/spl#554
+- Add rw_tryupgrade() zfsonlinux/spl#534 zfsonlinux/zfs#4388
+- Fix taskq_wait_outstanding re-evaluate tq_next_id zfsonlinux/spl#553
+- Fix race between taskq_destroy and dynamic spawning thread zfsonlinux/spl#553 zfsonlinux/spl#550
+- Use kernel provided mutex owner zfsonlinux/spl#553 zfsonlinux/spl#550
+- Add isa_defs for MIPS zfsonlinux/spl#558
+- Linux 4.7 compat: inode_lock() and friends zfsonlinux/spl#549
+- Fix: handle NULL case in spl_kmem_free_track() zfsonlinux/spl#567
+* Thu May 12 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.7-1
+- Fix PPC build failure zfsonlinux/spl#516
+* Tue Mar 22 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.6-1
+- Remove artificial architecture restrictions in packaging
+- Add support for s390[x] zfsonlinux/spl#537
+* Wed Mar 9 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.5-1
+- Linux 4.5 compatibility zfsonlinux/spl#524
+- Create working debuginfo packages on Red Hat zfsonlinux/zfs#4224
+- Allow copy-builtin to run multiple times zfsonlinux/spl#526
+- Use safer flags for in-kernel memory allocations zfsonlinux/spl#523
+- Fix potential deadlock in cv_wait() zfsonlinux/zfs#4106
+- Fix livelock in shrinker zfsonlinux/zfs#3936
+* Fri Jan  8 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.4-1
+- Build fixes on SPARC and some kernels
+- Fix taskq dynamic spawning deadlock
+- Fix builtin kernel builds
+- Fix crash due to overflow in P2ROUNDUP macro
+- Fix deadlock during direct memory reclaim
+* Tue Oct 13 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.3-1
+- Fix CPU hotplug zfsonlinux/spl#482
+- Disable dynamic taskqs by default to avoid deadlock zfsonlinux/spl#484
+* Tue Sep 29 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.2-1
+- Released 0.6.5.2-1
+- Fix PAX Patch/Grsec SLAB_USERCOPY panic zfsonlinux/zfs#3796
+- Always remove during dkms uninstall/update zfsonlinux/spl#476
+* Thu Sep 19 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.1-1
+- Released 0.6.5.1-1, no changes from spl-0.6.5
+* Thu Sep 10 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/spl/rpm/redhat/Makefile.am b/spl/rpm/redhat/Makefile.am
new file mode 100644 (file)
index 0000000..da6c4ab
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST = spl.spec.in spl-kmod.spec.in spl-dkms.spec.in
diff --git a/spl/rpm/redhat/Makefile.in b/spl/rpm/redhat/Makefile.in
new file mode 100644 (file)
index 0000000..96fb468
--- /dev/null
@@ -0,0 +1,500 @@
+# 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 = rpm/redhat
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_config.h
+CONFIG_CLEAN_FILES = spl.spec spl-kmod.spec spl-dkms.spec
+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__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/spl-dkms.spec.in \
+       $(srcdir)/spl-kmod.spec.in $(srcdir)/spl.spec.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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+EXTRA_DIST = spl.spec.in spl-kmod.spec.in spl-dkms.spec.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 rpm/redhat/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu rpm/redhat/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):
+spl.spec: $(top_builddir)/config.status $(srcdir)/spl.spec.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+spl-kmod.spec: $(top_builddir)/config.status $(srcdir)/spl-kmod.spec.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+spl-dkms.spec: $(top_builddir)/config.status $(srcdir)/spl-dkms.spec.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+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
+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/spl/rpm/redhat/spl-dkms.spec.in b/spl/rpm/redhat/spl-dkms.spec.in
new file mode 100644 (file)
index 0000000..949660e
--- /dev/null
@@ -0,0 +1,71 @@
+%{?!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:        GPLv2+
+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.2
+Requires:       gcc, make, perl
+Requires:       kernel-devel
+Provides:       %{module}-kmod = %{version}
+
+%description
+This package contains the dkms kernel modules required to emulate
+several interfaces provided by the Solaris kernel.
+
+%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
+echo -e "Uninstall of %{module} module (version %{version}) beginning:"
+dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
+exit 0
+
+%changelog
+* %(date "+%a %b %d %Y") %packager %{version}-%{release}
+- Automatic build by DKMS
diff --git a/spl/rpm/redhat/spl-kmod.spec.in b/spl/rpm/redhat/spl-kmod.spec.in
new file mode 100644 (file)
index 0000000..6fcc4a8
--- /dev/null
@@ -0,0 +1,105 @@
+%bcond_with     debug
+%bcond_with     debug_log
+%bcond_with     debug_kmem
+%bcond_with     debug_kmem_tracking
+%bcond_with     atomic_spinlocks
+
+Name:           @PACKAGE@-kmod
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+
+Summary:        Kernel module(s)
+Group:          System Environment/Kernel
+License:        GPLv2+
+URL:            http://zfsonlinux.org/
+BuildRequires:  %kernel_module_package_buildreqs
+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:       @PACKAGE@ = %{version}\n\
+Conflicts:      @PACKAGE@-dkms\n\n" > %{_sourcedir}/kmod-preamble)
+
+%description
+This package contains the kernel modules required to emulate
+several interfaces provided by the Solaris kernel.
+
+%define kmod_name spl
+
+%kernel_module_package -n %{kmod_name} -p %{_sourcedir}/kmod-preamble
+
+%define ksrc %{_usrsrc}/kernels/%{kverrel}
+%define kobj %{ksrc}
+
+%package -n kmod-%{kmod_name}-devel
+Summary:        SPL kernel module(s) devel common
+Group:          System Environment/Kernel
+
+%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_log}
+%define debug_log --enable-debug-log
+%else
+%define debug_log --disable-debug-log
+%endif
+
+%if %{with debug_kmem}
+%define debug_kmem --enable-debug-kmem
+%else
+%define debug_kmem --disable-debug-kmem
+%endif
+
+%if %{with debug_kmem_tracking}
+%define debug_kmem_tracking --enable-debug-kmem-tracking
+%else
+%define debug_kmem_tracking --disable-debug-kmem-tracking
+%endif
+
+%if %{with atomic_spinlocks}
+%define atomic_spinlocks --enable-atomic-spinlocks
+%else
+%define atomic_spinlocks --disable-atomic-spinlocks
+%endif
+
+%setup -n %{kmod_name}-%{version}
+%build
+%configure \
+        --with-config=kernel \
+        --with-linux=%{ksrc} \
+        --with-linux-obj=%{kobj} \
+        %{debug} \
+        %{debug_log} \
+        %{debug_kmem} \
+        %{debug_kmem_tracking} \
+        %{atomic_spinlocks}
+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}
diff --git a/spl/rpm/redhat/spl.spec.in b/spl/rpm/redhat/spl.spec.in
new file mode 100644 (file)
index 0000000..f95519c
--- /dev/null
@@ -0,0 +1,94 @@
+Name:           @PACKAGE@
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+Summary:        Commands to control the kernel modules
+
+Group:          System Environment/Kernel
+License:        GPLv2+
+URL:            http://zfsonlinux.org/
+Source0:        %{name}-%{version}.tar.gz
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Requires:       %{name}-kmod = %{version}
+Provides:       %{name}-kmod-common = %{version}
+
+%description
+This package contains the commands to verify the SPL
+kernel modules are functioning properly.
+
+%prep
+%setup -q
+
+%build
+%configure --with-config=user
+make %{?_smp_mflags}
+
+%install
+%{__rm} -rf $RPM_BUILD_ROOT
+make install DESTDIR=%{?buildroot}
+
+%files
+%doc AUTHORS COPYING DISCLAIMER
+%{_sbindir}/*
+%{_mandir}/man1/*
+%{_mandir}/man5/*
+
+%changelog
+* Fri Feb 3 2017 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5.9-1
+- Use kernel slab for vn_cache and vn_file_cache zfsonlinux/spl#599
+- Fix splat-cred.c cred usage zfsonlinux/spl#556
+- Fix splat memleak zfsonlinux/spl#590
+- Fix p0 initializer zfsonlinux/spl#576
+- Fix aarch64 type warning zfsonlinux/spl#574
+- Linux 4.8 compat: Fix RW_READ_HELD zfsonlinux/zfs#5233
+- Linux 4.9 compat: group_info changes zfsonlinux/spl#581
+- Fix crgetgroups out-of-bound and misc cred fix zfsonlinux/spl#556
+* Fri Sep 9 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.8-1
+- Fix HAVE_MUTEX_OWNER test for kernels prior to 4.6 zfsonlinux/spl#566
+- Add handling for kernel 4.7's CONFIG_TRIM_UNUSED_KSYMS zfsonlinux/spl#565
+- Linux 4.8 compat: rw_semaphore atomic_long_t count zfsonlinux/spl#563
+- Implement a proper rw_tryupgrade zfsonlinux/spl#554
+- Add rw_tryupgrade() zfsonlinux/spl#534 zfsonlinux/zfs#4388
+- Fix taskq_wait_outstanding re-evaluate tq_next_id zfsonlinux/spl#553
+- Fix race between taskq_destroy and dynamic spawning thread zfsonlinux/spl#553 zfsonlinux/spl#550
+- Use kernel provided mutex owner zfsonlinux/spl#553 zfsonlinux/spl#550
+- Add isa_defs for MIPS zfsonlinux/spl#558
+- Linux 4.7 compat: inode_lock() and friends zfsonlinux/spl#549
+- Fix: handle NULL case in spl_kmem_free_track() zfsonlinux/spl#567
+* Thu May 12 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.7-1
+- Fix PPC build failure zfsonlinux/spl#516
+* Tue Mar 22 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.6-1
+- Remove artificial architecture restrictions in packaging
+- Add support for s390[x] zfsonlinux/spl#537
+* Wed Mar 9 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.5-1
+- Linux 4.5 compatibility zfsonlinux/spl#524
+- Create working debuginfo packages on Red Hat zfsonlinux/zfs#4224
+- Allow copy-builtin to run multiple times zfsonlinux/spl#526
+- Use safer flags for in-kernel memory allocations zfsonlinux/spl#523
+- Fix potential deadlock in cv_wait() zfsonlinux/zfs#4106
+- Fix livelock in shrinker zfsonlinux/zfs#3936
+* Fri Jan  8 2016 Ned Bass <bass6@llnl.gov> - 0.6.5.4-1
+- Build fixes on SPARC and some kernels
+- Fix taskq dynamic spawning deadlock
+- Fix builtin kernel builds
+- Fix crash due to overflow in P2ROUNDUP macro
+- Fix deadlock during direct memory reclaim
+* Tue Oct 13 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.3-1
+- Fix CPU hotplug zfsonlinux/spl#482
+- Disable dynamic taskqs by default to avoid deadlock zfsonlinux/spl#484
+* Tue Sep 29 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.2-1
+- Released 0.6.5.2-1
+- Fix PAX Patch/Grsec SLAB_USERCOPY panic zfsonlinux/zfs#3796
+- Always remove during dkms uninstall/update zfsonlinux/spl#476
+* Thu Sep 19 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.1-1
+- Released 0.6.5.1-1, no changes from spl-0.6.5
+* Thu Sep 10 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/spl/scripts/Makefile.am b/spl/scripts/Makefile.am
new file mode 100644 (file)
index 0000000..a718c4b
--- /dev/null
@@ -0,0 +1,4 @@
+EXTRA_DIST = check.sh dkms.mkconf dkms.postbuild kmodtool
+
+check:
+       scripts/check.sh
diff --git a/spl/scripts/Makefile.in b/spl/scripts/Makefile.in
new file mode 100644 (file)
index 0000000..7f13dcc
--- /dev/null
@@ -0,0 +1,496 @@
+# 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 = scripts
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(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/spl-build.m4 \
+       $(top_srcdir)/config/spl-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)/spl_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__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@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEBUG_KMEM = @DEBUG_KMEM@
+DEBUG_KMEM_TRACKING = @DEBUG_KMEM_TRACKING@
+DEBUG_SPL = @DEBUG_SPL@
+DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
+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@
+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@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+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@
+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_CONFIG = @SPL_CONFIG@
+SPL_META_ALIAS = @SPL_META_ALIAS@
+SPL_META_AUTHOR = @SPL_META_AUTHOR@
+SPL_META_DATA = @SPL_META_DATA@
+SPL_META_LICENSE = @SPL_META_LICENSE@
+SPL_META_LT_AGE = @SPL_META_LT_AGE@
+SPL_META_LT_CURRENT = @SPL_META_LT_CURRENT@
+SPL_META_LT_REVISION = @SPL_META_LT_REVISION@
+SPL_META_NAME = @SPL_META_NAME@
+SPL_META_RELEASE = @SPL_META_RELEASE@
+SPL_META_VERSION = @SPL_META_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@
+VENDOR = @VENDOR@
+VERSION = @VERSION@
+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@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+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@
+EXTRA_DIST = check.sh dkms.mkconf dkms.postbuild kmodtool
+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 scripts/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu scripts/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
+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
+
+
+check:
+       scripts/check.sh
+
+# 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/spl/scripts/check.sh b/spl/scripts/check.sh
new file mode 100755 (executable)
index 0000000..fc97cec
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/bash
+###############################################################################
+# Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+# Copyright (C) 2007 The Regents of the University of California.
+# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+# UCRL-CODE-235197
+#
+# This file is part of the SPL, Solaris Porting Layer.
+# For details, see <http://zfsonlinux.org/>.
+#
+# The SPL 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.
+#
+# The SPL 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 the SPL.  If not, see <http://www.gnu.org/licenses/>.
+###############################################################################
+# This script runs the full set of regression tests.
+###############################################################################
+
+prog=check.sh
+spl_module=../module/spl/spl.ko
+splat_module=../module/splat/splat.ko
+splat_cmd=../cmd/splat
+verbose=
+
+die() {
+       echo "${prog}: $1" >&2
+       exit 1
+}
+
+warn() {
+       echo "${prog}: $1" >&2
+}
+
+if [ -n "$V" ]; then
+       verbose="-v"
+fi
+
+if [ -n "$TESTS" ]; then
+       tests="$TESTS"
+else
+       tests="-a"
+fi
+
+if [ $(id -u) != 0 ]; then
+       die "Must run as root"
+fi
+
+if /sbin/lsmod | egrep -q "^spl|^splat"; then
+       die "Must start with spl modules unloaded"
+fi
+
+if [ ! -f ${spl_module} ] || [ ! -f ${splat_module} ]; then
+       die "Source tree must be built, run 'make'"
+fi
+
+/sbin/modprobe zlib_inflate &>/dev/null
+/sbin/modprobe zlib_deflate &>/dev/null
+
+echo "Loading ${spl_module}"
+/sbin/insmod ${spl_module} || die "Failed to load ${spl_module}"
+
+echo "Loading ${splat_module}"
+/sbin/insmod ${splat_module} || die "Unable to load ${splat_module}"
+
+# Wait a maximum of 3 seconds for udev to detect the new splatctl 
+# device, if we do not see the character device file created assume
+# udev is not running and manually create the character device.
+for i in `seq 1 50`; do
+       sleep 0.1
+
+       if [ -c /dev/splatctl ]; then
+               break
+       fi
+
+       if [ $i -eq 50 ]; then
+               mknod /dev/splatctl c 229 0
+       fi
+done
+
+$splat_cmd $tests $verbose
+
+echo "Unloading ${splat_module}"
+/sbin/rmmod ${splat_module} || die "Failed to unload ${splat_module}"
+
+echo "Unloading ${spl_module}"
+/sbin/rmmod ${spl_module} || die "Unable to unload ${spl_module}"
+
+exit 0
diff --git a/spl/scripts/dkms.mkconf b/spl/scripts/dkms.mkconf
new file mode 100755 (executable)
index 0000000..67b9dad
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+PROG=$0
+
+pkgcfg=/etc/sysconfig/spl
+
+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}
+  \$(
+    [[ -r \${PACKAGE_CONFIG} ]] \\
+    && source \${PACKAGE_CONFIG} \\
+    && shopt -q -s extglob \\
+    && \\
+    {
+      if [[ \${SPL_DKMS_ENABLE_DEBUG,,} == @(y|yes) ]]
+      then
+        echo --enable-debug
+      fi
+      if [[ \${SPL_DKMS_ENABLE_DEBUG_KMEM,,} == @(y|yes) ]]
+      then
+        echo --enable-debug-kmem
+      fi
+      if [[ \${SPL_DKMS_ENABLE_DEBUG_KMEM_TRACKING,,} == @(y|yes) ]]
+      then
+        echo --enable-debug-kmem-tracking
+      fi
+      if [[ \${SPL_DKMS_ENABLE_ATOMIC_SPINLOCKS,,} == @(y|yes) ]]
+      then
+        echo --enable-atomic-spinlocks
+      fi
+    }
+  )
+"
+POST_BUILD="scripts/dkms.postbuild
+  -n \${PACKAGE_NAME}
+  -v \${PACKAGE_VERSION}
+  -a \${arch}
+  -k \${kernelver}
+  -t \${dkms_tree}
+"
+AUTOINSTALL="yes"
+REMAKE_INITRD="no"
+MAKE[0]="make"
+STRIP[0]="\$(
+  [[ -r \${PACKAGE_CONFIG} ]] \\
+  && source \${PACKAGE_CONFIG} \\
+  && shopt -q -s extglob \\
+  && [[ \${SPL_DKMS_DISABLE_STRIP,,} == @(y|yes) ]] \\
+  && echo -n no
+)"
+STRIP[1]="\${STRIP[0]}"
+BUILT_MODULE_NAME[0]="spl"
+BUILT_MODULE_LOCATION[0]="module/spl/"
+DEST_MODULE_LOCATION[0]="/extra/spl/spl"
+BUILT_MODULE_NAME[1]="splat"
+BUILT_MODULE_LOCATION[1]="module/splat/"
+DEST_MODULE_LOCATION[1]="/extra/splat/splat"
+EOF
diff --git a/spl/scripts/dkms.postbuild b/spl/scripts/dkms.postbuild
new file mode 100755 (executable)
index 0000000..a23bbda
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+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/spl_config.h          \
+   ${tree}/${pkgname}/${pkgver}/build/module/Module.symvers \
+   ${tree}/${pkgname}/${pkgver}/${kver}/${arch}/
diff --git a/spl/scripts/kmodtool b/spl/scripts/kmodtool
new file mode 100644 (file)
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/spl/spl.release.in b/spl/spl.release.in
new file mode 100644 (file)
index 0000000..fd7c84c
--- /dev/null
@@ -0,0 +1 @@
+@SPL_META_VERSION@-@SPL_META_RELEASE@
diff --git a/spl/spl_config.h.in b/spl/spl_config.h.in
new file mode 100644 (file)
index 0000000..463c5f9
--- /dev/null
@@ -0,0 +1,205 @@
+/* spl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Atomic types use spinlocks */
+#undef ATOMIC_SPINLOCK
+
+/* Define to 1 to enable basic kmem accounting */
+#undef DEBUG_KMEM
+
+/* Define to 1 to enable detailed kmem tracking */
+#undef DEBUG_KMEM_TRACKING
+
+/* new shrinker callback wants 2 args */
+#undef HAVE_2ARGS_NEW_SHRINKER_CALLBACK
+
+/* old shrinker callback wants 2 args */
+#undef HAVE_2ARGS_OLD_SHRINKER_CALLBACK
+
+/* vfs_fsync() wants 2 args */
+#undef HAVE_2ARGS_VFS_FSYNC
+
+/* vfs_getattr wants 2 args */
+#undef HAVE_2ARGS_VFS_GETATTR
+
+/* vfs_unlink() wants 2 args */
+#undef HAVE_2ARGS_VFS_UNLINK
+
+/* zlib_deflate_workspacesize() wants 2 args */
+#undef HAVE_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
+
+/* old shrinker callback wants 3 args */
+#undef HAVE_3ARGS_SHRINKER_CALLBACK
+
+/* vfs_unlink() wants 3 args */
+#undef HAVE_3ARGS_VFS_UNLINK
+
+/* vfs_rename() wants 4 args */
+#undef HAVE_4ARGS_VFS_RENAME
+
+/* vfs_rename() wants 5 args */
+#undef HAVE_5ARGS_VFS_RENAME
+
+/* vfs_rename() wants 6 args */
+#undef HAVE_6ARGS_VFS_RENAME
+
+/* kernel defines atomic64_t */
+#undef HAVE_ATOMIC64_T
+
+/* struct ctl_table has ctl_name */
+#undef HAVE_CTL_NAME
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* fops->fallocate() exists */
+#undef HAVE_FILE_FALLOCATE
+
+/* struct fs_struct uses spinlock_t */
+#undef HAVE_FS_STRUCT_SPINLOCK
+
+/* group_info->gid exists */
+#undef HAVE_GROUP_INFO_GID
+
+/* fops->fallocate() exists */
+#undef HAVE_INODE_FALLOCATE
+
+/* yes */
+#undef HAVE_INODE_LOCK_SHARED
+
+/* truncate_range() inode operation is available */
+#undef HAVE_INODE_TRUNCATE_RANGE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* struct kmem_cache has allocflags */
+#undef HAVE_KMEM_CACHE_ALLOCFLAGS
+
+/* struct kmem_cache has gfpflags */
+#undef HAVE_KMEM_CACHE_GFPFLAGS
+
+/* kuid_t/kgid_t in use */
+#undef HAVE_KUIDGID_T
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* yes */
+#undef HAVE_MUTEX_OWNER
+
+/* yes */
+#undef HAVE_PDE_DATA
+
+/* __put_task_struct() is available */
+#undef HAVE_PUT_TASK_STRUCT
+
+/* struct rw_semaphore has member activity */
+#undef HAVE_RWSEM_ACTIVITY
+
+/* struct rw_semaphore has atomic_long_t member count */
+#undef HAVE_RWSEM_ATOMIC_LONG_COUNT
+
+/* linux/sched/rt.h exists */
+#undef HAVE_SCHED_RT_HEADER
+
+/* set_fs_pwd() needs const path * */
+#undef HAVE_SET_FS_PWD_WITH_CONST
+
+/* struct shrink_control exists */
+#undef HAVE_SHRINK_CONTROL_STRUCT
+
+/* ->count_objects exists */
+#undef HAVE_SPLIT_SHRINKER_CALLBACK
+
+/* 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
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* usleep_range is available */
+#undef HAVE_USLEEP_RANGE
+
+/* yes */
+#undef HAVE_WAIT_ON_BIT_ACTION
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* 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 rw_semaphore member wait_lock is raw_spinlock_t */
+#undef RWSEM_SPINLOCK_IS_RAW
+
+/* Define to 1 if GPL-only symbols can be used */
+#undef SPL_IS_GPL_COMPATIBLE
+
+/* Define the project alias string. */
+#undef SPL_META_ALIAS
+
+/* Define the project author. */
+#undef SPL_META_AUTHOR
+
+/* Define the project release date. */
+#undef SPL_META_DATA
+
+/* Define the project license. */
+#undef SPL_META_LICENSE
+
+/* Define the libtool library 'age' version information. */
+#undef SPL_META_LT_AGE
+
+/* Define the libtool library 'current' version information. */
+#undef SPL_META_LT_CURRENT
+
+/* Define the libtool library 'revision' version information. */
+#undef SPL_META_LT_REVISION
+
+/* Define the project name. */
+#undef SPL_META_NAME
+
+/* Define the project release. */
+#undef SPL_META_RELEASE
+
+/* Define the project version. */
+#undef SPL_META_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
diff --git a/zfs/AUTHORS b/zfs/AUTHORS
new file mode 100644 (file)
index 0000000..cf5c808
--- /dev/null
@@ -0,0 +1,95 @@
+Brian Behlendorf is the principal developer of the ZFS on Linux port.
+He works full time as a computer scientist at Lawrence Livermore
+National Laboratory on the ZFS and Lustre filesystems.  However,
+this port would not have been possible without the help of many
+others who have contributed their time, effort, and insight.
+
+  Brian Behlendorf <behlendorf1@llnl.gov>
+
+First and foremost the hard working ZFS developers at Sun/Oracle.
+They are responsible for the bulk of the code in this project and
+without their efforts there never would have been a ZFS filesystem.
+
+  The ZFS Development Team at Sun/Oracle
+
+Next all the developers at KQ Infotech who implemented a prototype
+ZFS Posix Layer (ZPL).  Their implementation provided an excellent
+reference for adding the ZPL functionality.
+
+  Anand Mitra <mitra@kqinfotech.com>
+  Anurag Agarwal <anurag@kqinfotech.com>
+  Neependra Khare <neependra@kqinfotech.com>
+  Prasad Joshi <prasad@kqinfotech.com>
+  Rohan Puri <rohan@kqinfotech.com>
+  Sandip Divekar <sandipd@kqinfotech.com>
+  Shoaib <shoaib@kqinfotech.com>
+  Shrirang <shrirang@kqinfotech.com>
+
+Additionally the following individuals have all made contributions
+to the project and deserve to be acknowledged.
+
+  Albert Lee <trisk@nexenta.com>
+  Alejandro R. Sedeño <asedeno@mit.edu>
+  Alex Zhuravlev <bzzz@whamcloud.com>
+  Alexander Eremin <a.eremin@nexenta.com>
+  Alexander Stetsenko <ams@nexenta.com>
+  Alexey Shvetsov <alexxy@gentoo.org>
+  Andreas Dilger <adilger@whamcloud.com>
+  Andrew Reid <ColdCanuck@nailedtotheperch.com>
+  Andrew Stormont <andrew.stormont@nexenta.com>
+  Andrew Tselischev <andrewtselischev@gmail.com>
+  Andriy Gapon <avg@FreeBSD.org>
+  Aniruddha Shankar <k@191a.net>
+  Bill Pijewski <wdp@joyent.com>
+  Chris Dunlap <cdunlap@llnl.gov>
+  Chris Dunlop <chris@onthe.net.au>
+  Chris Siden <chris.siden@delphix.com>
+  Chris Wedgwood <cw@f00f.org>
+  Christian Kohlschütter <christian@kohlschutter.com>
+  Christopher Siden <chris.siden@delphix.com>
+  Craig Sanders <github@taz.net.au>
+  Cyril Plisko <cyril.plisko@mountall.com>
+  Dan McDonald <danmcd@nexenta.com>
+  Daniel Verite <daniel@verite.pro>
+  Darik Horn <dajhorn@vanadac.com>
+  Eric Schrock <Eric.Schrock@delphix.com>
+  Etienne Dechamps <etienne.dechamps@ovh.net>
+  Fajar A. Nugraha <github@fajar.net>
+  Frederik Wessels <wessels147@gmail.com>
+  Garrett D'Amore <garrett@nexenta.com>
+  George Wilson <george.wilson@delphix.com>
+  Gordon Ross <gwr@nexenta.com>
+  Gregor Kopka <mailfrom-github.com@kopka.net>
+  Gunnar Beutner <gunnar@beutner.name>
+  James H <james@kagisoft.co.uk>
+  Javen Wu <wu.javen@gmail.com>
+  Jeremy Gill <jgill@parallax-innovations.com>
+  Jorgen Lundman <lundman@lundman.net>
+  KORN Andras <korn@elan.rulez.org>
+  Kyle Fuller <inbox@kylefuller.co.uk>
+  Manuel Amador (Rudd-O) <rudd-o@rudd-o.com>
+  Martin Matuska <mm@FreeBSD.org>
+  Massimo Maggi <massimo@mmmm.it>
+  Matthew Ahrens <mahrens@delphix.com>
+  Michael Martin <mgmartin.mgm@gmail.com>
+  Mike Harsch <mike@harschsystems.com>
+  Ned Bass <bass6@llnl.gov>
+  Oleg Stepura <oleg@stepura.com>
+  P.SCH <p88@yahoo.com>
+  Pawel Jakub Dawidek <pawel@dawidek.net>
+  Prakash Surya <surya1@llnl.gov>
+  Prasad Joshi <pjoshi@stec-inc.com>
+  Ricardo M. Correia <Ricardo.M.Correia@Sun.COM>
+  Richard Laager <rlaager@wiktel.com>
+  Richard Lowe <richlowe@richlowe.net>
+  Richard Yao <ryao@cs.stonybrook.edu>
+  Rohan Puri <rohan.puri15@gmail.com>
+  Shampavman <sham.pavman@nexenta.com>
+  Simon Klinkert <klinkert@webgods.de>
+  Suman Chakravartula <suman@gogrid.com>
+  Tim Haley <Tim.Haley@Sun.COM>
+  Turbo Fredriksson <turbo@bayour.com>
+  Xin Li <delphij@FreeBSD.org>
+  Yuxuan Shui <yshuiv7@gmail.com>
+  Zachary Bedell <zac@thebedells.org>
+  nordaux <nordaux@gmail.com>
diff --git a/zfs/COPYRIGHT b/zfs/COPYRIGHT
new file mode 100644 (file)
index 0000000..759a484
--- /dev/null
@@ -0,0 +1,33 @@
+The majority of the code in the ZFS on Linux port comes from OpenSolaris
+which has been released under the terms of the CDDL open source license.
+This includes the core ZFS code, libavl, libnvpair, libefi, libunicode,
+and libutil.  The original OpenSolaris source can be downloaded from:
+
+http://dlc.sun.com/osol/on/downloads/b121/on-src.tar.bz2
+
+Files which do not originate from OpenSolaris are noted in the file header
+and attributed properly.  These exceptions include, but are not limited
+to, the vdev_disk.c and zvol.c implementation which are licensed under
+the CDDL.
+
+The zpios test code is originally derived from the Lustre pios test code
+which is licensed under the GPLv2.  As such the heavily modified zpios
+kernel test code also remains licensed under the GPLv2.
+
+The latest stable and development versions of this port can be downloaded
+from the official ZFS on Linux site located at:
+
+http://zfsonlinux.org/
+
+This ZFS on Linux port was produced at the Lawrence Livermore National
+Laboratory (LLNL) under Contract No. DE-AC52-07NA27344 (Contract 44)
+between the U.S. Department of Energy (DOE) and Lawrence Livermore
+National Security, LLC (LLNS) for the operation of LLNL.  It has been
+approved for release under LLNL-CODE-403049.
+
+Unless otherwise noted, all files in this distribution are released
+under the Common Development and Distribution License (CDDL).
+Exceptions are noted within the associated source files.  See the file
+OPENSOLARIS.LICENSE for more information.
+
+Refer to the git commit log for authoritative copyright attribution.
diff --git a/zfs/DISCLAIMER b/zfs/DISCLAIMER
new file mode 100644 (file)
index 0000000..a0af1ef
--- /dev/null
@@ -0,0 +1,24 @@
+This work was produced at the Lawrence Livermore National Laboratory
+(LLNL) under Contract No. DE-AC52-07NA27344 (Contract 44) between
+the U.S. Department of Energy (DOE) and Lawrence Livermore National
+Security, LLC (LLNS) for the operation of LLNL.
+
+This work was prepared as an account of work sponsored by an agency of
+the United States Government.  Neither the United States Government nor
+Lawrence Livermore National Security, LLC nor any of their employees,
+makes any warranty, express or implied, or assumes any liability or
+responsibility for the accuracy, completeness, or usefulness of any
+information, apparatus, product, or process disclosed, or represents
+that its use would not infringe privately-owned rights.
+
+Reference herein to any specific commercial products, process, or
+services by trade name, trademark, manufacturer or otherwise does
+not necessarily constitute or imply its endorsement, recommendation,
+or favoring by the United States Government or Lawrence Livermore
+National Security, LLC.  The views and opinions of authors expressed
+herein do not necessarily state or reflect those of the United States
+Government or Lawrence Livermore National Security, LLC, and shall
+not be used for advertising or product endorsement purposes.
+
+The precise terms and conditions for copying, distribution, and
+modification are specified in the file OPENSOLARIS.LICENSE.
diff --git a/zfs/META b/zfs/META
new file mode 100644 (file)
index 0000000..e5c8688
--- /dev/null
+++ b/zfs/META
@@ -0,0 +1,8 @@
+Meta:         1
+Name:         zfs
+Branch:       1.0
+Version:      0.6.5.9
+Release:      2
+Release-Tags: relext
+License:      CDDL
+Author:       OpenZFS on Linux
diff --git a/zfs/Makefile.am b/zfs/Makefile.am
new file mode 100644 (file)
index 0000000..f69feb7
--- /dev/null
@@ -0,0 +1,77 @@
+ACLOCAL_AMFLAGS = -I config
+
+include config/rpm.am
+include config/deb.am
+include config/tgz.am
+
+
+if CONFIG_USER
+
+endif
+if CONFIG_KERNEL
+SUBDIRS = module include
+
+extradir = @prefix@/src/zfs-$(VERSION)
+extra_HEADERS = zfs.release.in zfs_config.h.in
+
+kerneldir = @prefix@/src/zfs-$(VERSION)/$(LINUX_VERSION)
+nodist_kernel_HEADERS = zfs.release zfs_config.h module/$(LINUX_SYMBOLS)
+endif
+
+AUTOMAKE_OPTIONS = foreign
+EXTRA_DIST  = autogen.sh copy-builtin
+EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
+EXTRA_DIST += META DISCLAIMER COPYRIGHT README.markdown OPENSOLARIS.LICENSE
+
+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
diff --git a/zfs/Makefile.in b/zfs/Makefile.in
new file mode 100644 (file)
index 0000000..3147144
--- /dev/null
@@ -0,0 +1,1314 @@
+# 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@
+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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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.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 = module include
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config/deb.am \
+       $(srcdir)/config/rpm.am $(srcdir)/config/tgz.am \
+       $(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
+@CONFIG_KERNEL_TRUE@SUBDIRS = module include
+@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.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/OPENSOLARIS.LICENSE b/zfs/OPENSOLARIS.LICENSE
new file mode 100644 (file)
index 0000000..da23621
--- /dev/null
@@ -0,0 +1,384 @@
+Unless otherwise noted, all files in this distribution are released
+under the Common Development and Distribution License (CDDL).
+Exceptions are noted within the associated source files.
+
+--------------------------------------------------------------------
+
+
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/zfs/README.markdown b/zfs/README.markdown
new file mode 100644 (file)
index 0000000..3fc88a0
--- /dev/null
@@ -0,0 +1,10 @@
+Native ZFS for Linux!
+
+ZFS is an advanced file system and volume manager which was originally
+developed for Solaris and is now maintained by the Illumos community.
+
+ZFS on Linux, which is also known as ZoL, is currently feature complete.  It
+includes fully functional and stable SPA, DMU, ZVOL, and ZPL layers.
+
+Full documentation for installing ZoL on your favorite Linux distribution can
+be found at: <http://zfsonlinux.org>
diff --git a/zfs/aclocal.m4 b/zfs/aclocal.m4
new file mode 100644 (file)
index 0000000..51a5d6f
--- /dev/null
@@ -0,0 +1,1302 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4])
+m4_include([config/kernel-security-inode-init.m4])
+m4_include([config/kernel-set-nlink.m4])
+m4_include([config/kernel-setattr-prepare.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/autogen.sh b/zfs/autogen.sh
new file mode 100755 (executable)
index 0000000..427394a
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+autoreconf -fiv
+rm -Rf autom4te.cache
diff --git a/zfs/config/Rules.am b/zfs/config/Rules.am
new file mode 100644 (file)
index 0000000..20a21e9
--- /dev/null
@@ -0,0 +1,15 @@
+DEFAULT_INCLUDES = -include ${top_builddir}/zfs_config.h
+
+AM_LIBTOOLFLAGS = --silent
+AM_CFLAGS  = ${DEBUG_CFLAGS} -Wall -Wstrict-prototypes
+AM_CFLAGS += ${NO_UNUSED_BUT_SET_VARIABLE}
+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 -DHAVE_LARGE_STACKS=1
+AM_CPPFLAGS += -DTEXT_DOMAIN=\"zfs-linux-user\"
+AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\"
+AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\"
+AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\"
+AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\"
diff --git a/zfs/config/always-no-bool-compare.m4 b/zfs/config/always-no-bool-compare.m4
new file mode 100644 (file)
index 0000000..316b04b
--- /dev/null
@@ -0,0 +1,27 @@
+dnl #
+dnl # Check if gcc supports -Wno-bool-compare option.
+dnl #
+dnl # We actually invoke gcc with the -Wbool-compare option
+dnl # and infer the 'no-' version does or doesn't exist based upon
+dnl # the results.  This is required because when checking any of
+dnl # no- prefixed options gcc always returns success.
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_NO_BOOL_COMPARE], [
+       AC_MSG_CHECKING([for -Wno-bool-compare support])
+
+       saved_flags="$CFLAGS"
+       CFLAGS="$CFLAGS -Wbool-compare"
+
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
+       [
+               NO_BOOL_COMPARE=-Wno-bool-compare
+               AC_MSG_RESULT([yes])
+       ],
+       [
+               NO_BOOL_COMPARE=
+               AC_MSG_RESULT([no])
+       ])
+
+       CFLAGS="$saved_flags"
+       AC_SUBST([NO_BOOL_COMPARE])
+])
diff --git a/zfs/config/always-no-unused-but-set-variable.m4 b/zfs/config/always-no-unused-but-set-variable.m4
new file mode 100644 (file)
index 0000000..863c90a
--- /dev/null
@@ -0,0 +1,27 @@
+dnl #
+dnl # Check if gcc supports -Wno-unused-but-set-variable option.
+dnl #
+dnl # We actually invoke gcc with the -Wunused-but-set-variable option
+dnl # and infer the 'no-' version does or doesn't exist based upon
+dnl # the results.  This is required because when checking any of
+dnl # no- prefixed options gcc always returns success.
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_NO_UNUSED_BUT_SET_VARIABLE], [
+       AC_MSG_CHECKING([for -Wno-unused-but-set-variable support])
+
+       saved_flags="$CFLAGS"
+       CFLAGS="$CFLAGS -Wunused-but-set-variable"
+
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
+       [
+               NO_UNUSED_BUT_SET_VARIABLE=-Wno-unused-but-set-variable
+               AC_MSG_RESULT([yes])
+       ],
+       [
+               NO_UNUSED_BUT_SET_VARIABLE=
+               AC_MSG_RESULT([no])
+       ])
+
+       CFLAGS="$saved_flags"
+       AC_SUBST([NO_UNUSED_BUT_SET_VARIABLE])
+])
diff --git a/zfs/config/compile b/zfs/config/compile
new file mode 100755 (executable)
index 0000000..a85b723
--- /dev/null
@@ -0,0 +1,347 @@
+#! /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.awk b/zfs/config/config.awk
new file mode 100644 (file)
index 0000000..cc4b7cc
--- /dev/null
@@ -0,0 +1,15 @@
+# Remove default preprocessor define's from config.h
+#   PACKAGE
+#   PACKAGE_BUGREPORT
+#   PACKAGE_NAME
+#   PACKAGE_STRING
+#   PACKAGE_TARNAME
+#   PACKAGE_VERSION
+#   STDC_HEADERS
+#   VERSION
+
+BEGIN { RS = "" ; FS = "\n" }     \
+       !/.#define PACKAGE./ &&   \
+       !/.#define VERSION./ &&   \
+       !/.#define STDC_HEADERS./ \
+       { print $0"\n" }
diff --git a/zfs/config/config.guess b/zfs/config/config.guess
new file mode 100755 (executable)
index 0000000..2e9ad7f
--- /dev/null
@@ -0,0 +1,1462 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-10-02'
+
+# 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
+#
+# 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-2016 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) and ABI.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               os=netbsdelf
+               ;;
+           arm*|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 ;;
+    *:LibertyBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${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 "[:upper:]" "[:lower:]"``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 ;;
+    k1om: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; }
+       ;;
+    mips64el:Linux:*:*)
+       echo ${UNAME_MACHINE}-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 ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+       echo ${UNAME_MACHINE}-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 configure 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 ;;
+    SX-ACE:SUPER-UX:*:*)
+       echo sxace-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 ;;
+    amd64:Isilon\ OneFS:*:*)
+       echo x86_64-unknown-onefs
+       exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary 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
new file mode 100755 (executable)
index 0000000..dd2ca93
--- /dev/null
@@ -0,0 +1,1825 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-11-04'
+
+# 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
+
+# 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 or 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-2016 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* | cloudabi*-eabi* | \
+  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 \
+       | pru \
+       | 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-* \
+       | pru-* \
+       | 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
+               ;;
+       e500v[12])
+               basic_machine=powerpc-unknown
+               os=$os"spe"
+               ;;
+       e500v[12]-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=$os"spe"
+               ;;
+       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)
+               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)
+               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* | -libertybsd* \
+             | -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* \
+             | -midipix* | -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* \
+             | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
+       # 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*)
+               ;;
+       -ios)
+               ;;
+       -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/deb.am b/zfs/config/deb.am
new file mode 100644 (file)
index 0000000..648417b
--- /dev/null
@@ -0,0 +1,48 @@
+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
+if CONFIG_KERNEL
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --bump=0 --scripts --to-deb $$pkg1; \
+       $(RM) $$pkg1
+endif
+
+deb-utils: deb-local rpm-utils
+if CONFIG_USER
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=$${name}-$${version}.$${arch}.rpm; \
+       pkg2=libnvpair1-$${version}.$${arch}.rpm; \
+       pkg3=libuutil1-$${version}.$${arch}.rpm; \
+       pkg4=libzfs2-$${version}.$${arch}.rpm; \
+       pkg5=libzpool2-$${version}.$${arch}.rpm; \
+       pkg6=libzfs2-devel-$${version}.$${arch}.rpm; \
+       pkg7=$${name}-test-$${version}.$${arch}.rpm; \
+       pkg8=$${name}-dracut-$${version}.$${arch}.rpm; \
+       pkg9=$${name}-initramfs-$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --bump=0 --scripts --to-deb \
+           $$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
+           $$pkg8 $$pkg9;
+       $(RM) $$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
+           $$pkg8 $$pkg9;
+endif
+
+deb: deb-kmod deb-utils
diff --git a/zfs/config/dkms.m4 b/zfs/config/dkms.m4
new file mode 100644 (file)
index 0000000..cfa1152
--- /dev/null
@@ -0,0 +1,14 @@
+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
new file mode 100755 (executable)
index 0000000..59990a1
--- /dev/null
@@ -0,0 +1,508 @@
+#!/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:
diff --git a/zfs/config/kernel-acl.m4 b/zfs/config/kernel-acl.m4
new file mode 100644 (file)
index 0000000..b2c33f1
--- /dev/null
@@ -0,0 +1,324 @@
+dnl #
+dnl # Check if posix_acl_release can be used from a ZFS_META_LICENSED
+dnl # module.  The is_owner_or_cap macro was replaced by
+dnl # inode_owner_or_capable
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_POSIX_ACL_RELEASE], [
+       AC_MSG_CHECKING([whether posix_acl_release() is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/cred.h>
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+       ],[
+               struct posix_acl* tmp = posix_acl_alloc(1, 0);
+               posix_acl_release(tmp);
+       ],[
+               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>
+
+               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])
+       ])
+])
+
+dnl #
+dnl # 3.14 API change,
+dnl # set_cached_acl() and forget_cached_acl() changed from inline to
+dnl # EXPORT_SYMBOL. In the former case, they may not be usable because of
+dnl # posix_acl_release. In the latter case, we can always use them.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SET_CACHED_ACL_USABLE], [
+       AC_MSG_CHECKING([whether set_cached_acl() is usable])
+       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 inode *ip = NULL;
+               struct posix_acl *acl = posix_acl_alloc(1, 0);
+               set_cached_acl(ip, ACL_TYPE_ACCESS, acl);
+               forget_cached_acl(ip, ACL_TYPE_ACCESS);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SET_CACHED_ACL_USABLE, 1,
+                   [posix_acl_release() is usable])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.1 API change,
+dnl # posix_acl_chmod_masq() is not exported anymore and posix_acl_chmod()
+dnl # was introduced to replace it.
+dnl #
+dnl # 3.14 API change,
+dnl # posix_acl_chmod() is changed to __posix_acl_chmod()
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_POSIX_ACL_CHMOD], [
+       AC_MSG_CHECKING([whether posix_acl_chmod exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+       ],[
+               posix_acl_chmod(NULL, 0, 0)
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_POSIX_ACL_CHMOD, 1, [posix_acl_chmod() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+
+       AC_MSG_CHECKING([whether __posix_acl_chmod exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+       ],[
+               __posix_acl_chmod(NULL, 0, 0)
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE___POSIX_ACL_CHMOD, 1, [__posix_acl_chmod() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.1 API change,
+dnl # posix_acl_equiv_mode now wants an umode_t* instead of a mode_t*
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_POSIX_ACL_EQUIV_MODE_WANTS_UMODE_T], [
+       AC_MSG_CHECKING([whether posix_acl_equiv_mode() wants umode_t])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+       ],[
+               umode_t tmp;
+               posix_acl_equiv_mode(NULL,&tmp);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_POSIX_ACL_EQUIV_MODE_UMODE_T, 1,
+                   [ posix_acl_equiv_mode wants umode_t*])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 4.8 API change,
+dnl # The function posix_acl_valid now must be passed a namespace.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_POSIX_ACL_VALID_WITH_NS], [
+       AC_MSG_CHECKING([whether posix_acl_valid() wants user namespace])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+       ],[
+               struct user_namespace *user_ns = NULL;
+               const struct posix_acl *acl = NULL;
+               int error;
+
+               error = posix_acl_valid(user_ns, acl);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_POSIX_ACL_VALID_WITH_NS, 1,
+                   [posix_acl_valid() wants user namespace])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.27 API change,
+dnl # Check if inode_operations contains the function permission
+dnl # and expects the nameidata structure to have been removed.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_PERMISSION], [
+       AC_MSG_CHECKING([whether iops->permission() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_PERMISSION, 1, [iops->permission() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.26 API change,
+dnl # Check if inode_operations contains the function permission
+dnl # and expects the nameidata structure to be passed.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_PERMISSION_WITH_NAMEIDATA], [
+       AC_MSG_CHECKING([whether iops->permission() wants nameidata])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_PERMISSION, 1, [iops->permission() exists])
+               AC_DEFINE(HAVE_PERMISSION_WITH_NAMEIDATA, 1,
+                   [iops->permission() with nameidata exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.32 API change,
+dnl # Check if inode_operations contains the function check_acl
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL], [
+       AC_MSG_CHECKING([whether iops->check_acl() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CHECK_ACL, 1, [iops->check_acl() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.38 API change,
+dnl # The function check_acl gained a new parameter: flags
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL_WITH_FLAGS], [
+       AC_MSG_CHECKING([whether iops->check_acl() wants flags])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CHECK_ACL, 1, [iops->check_acl() exists])
+               AC_DEFINE(HAVE_CHECK_ACL_WITH_FLAGS, 1,
+                   [iops->check_acl() wants flags])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.1 API change,
+dnl # Check if inode_operations contains the function get_acl
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL], [
+       AC_MSG_CHECKING([whether iops->get_acl() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GET_ACL, 1, [iops->get_acl() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.14 API change,
+dnl # Check if inode_operations contains the function set_acl
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL], [
+       AC_MSG_CHECKING([whether iops->set_acl() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+
+               int set_acl_fn(struct inode *inode, struct posix_acl *acl, int type)
+                   { return 0; }
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .set_acl = set_acl_fn,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 4.7 API change,
+dnl # The kernel get_acl will now check cache before calling i_op->get_acl and
+dnl # do set_cached_acl after that, so i_op->get_acl don't need to do that
+dnl # anymore.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_GET_ACL_HANDLE_CACHE], [
+       AC_MSG_CHECKING([whether uncached_acl_sentinel() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               void *sentinel __attribute__ ((unused)) = uncached_acl_sentinel(NULL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_KERNEL_GET_ACL_HANDLE_CACHE, 1, [uncached_acl_sentinel() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-aio-fsync.m4 b/zfs/config/kernel-aio-fsync.m4
new file mode 100644 (file)
index 0000000..41b7a98
--- /dev/null
@@ -0,0 +1,21 @@
+dnl #
+dnl # Linux 4.9-rc5+ ABI, removal of the .aio_fsync field
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_AIO_FSYNC], [
+       AC_MSG_CHECKING([whether fops->aio_fsync() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+
+               static const struct file_operations
+                   fops __attribute__ ((unused)) = {
+                       .aio_fsync = NULL,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FILE_AIO_FSYNC, 1, [fops->aio_fsync() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
diff --git a/zfs/config/kernel-automount.m4 b/zfs/config/kernel-automount.m4
new file mode 100644 (file)
index 0000000..1ee4c16
--- /dev/null
@@ -0,0 +1,23 @@
+dnl #
+dnl # 2.6.37 API change
+dnl # The dops->d_automount() dentry operation was added as a clean
+dnl # solution to handling automounts.  Prior to this cifs/nfs clients
+dnl # which required automount support would abuse the follow_link()
+dnl # operation on directories for this purpose.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_AUTOMOUNT], [
+       AC_MSG_CHECKING([whether dops->d_automount() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/dcache.h>
+               struct vfsmount *d_automount(struct path *p) { return NULL; }
+               struct dentry_operations dops __attribute__ ((unused)) = {
+                       .d_automount = d_automount,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_AUTOMOUNT, 1, [dops->automount() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-bdev-block-device-operations.m4 b/zfs/config/kernel-bdev-block-device-operations.m4
new file mode 100644 (file)
index 0000000..faacc19
--- /dev/null
@@ -0,0 +1,34 @@
+dnl #
+dnl # 2.6.x API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS], [
+       AC_MSG_CHECKING([block device operation prototypes])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(struct block_device)
+               AC_DEFINE(HAVE_BDEV_BLOCK_DEVICE_OPERATIONS, 1,
+                         [struct block_device_operations use bdevs])
+       ],[
+               AC_MSG_RESULT(struct inode)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-bdev-logical-size.m4 b/zfs/config/kernel-bdev-logical-size.m4
new file mode 100644 (file)
index 0000000..a619457
--- /dev/null
@@ -0,0 +1,25 @@
+dnl #
+dnl # 2.6.30 API change
+dnl # bdev_hardsect_size() replaced with bdev_logical_block_size().  While
+dnl # it has been true for a while that there was no strict 1:1 mapping
+dnl # between physical sector size and logical block size this change makes
+dnl # it explicit.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BDEV_LOGICAL_BLOCK_SIZE], [
+       AC_MSG_CHECKING([whether bdev_logical_block_size() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct block_device *bdev = NULL;
+               bdev_logical_block_size(bdev);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BDEV_LOGICAL_BLOCK_SIZE, 1,
+                         [bdev_logical_block_size() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-bdev-physical-size.m4 b/zfs/config/kernel-bdev-physical-size.m4
new file mode 100644 (file)
index 0000000..77746ee
--- /dev/null
@@ -0,0 +1,39 @@
+dnl #
+dnl # 2.6.30 API change
+dnl #
+dnl # The bdev_physical_block_size() interface was added to provide a way
+dnl # to determine the smallest write which can be performed without a
+dnl # read-modify-write operation.  From the kernel documentation:
+dnl #
+dnl # What:          /sys/block/<disk>/queue/physical_block_size
+dnl # Date:          May 2009
+dnl # Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+dnl # Description:
+dnl #                This is the smallest unit the storage device can write
+dnl #                without resorting to read-modify-write operation.  It is
+dnl #                usually the same as the logical block size but may be
+dnl #                bigger.  One example is SATA drives with 4KB sectors
+dnl #                that expose a 512-byte logical block size to the
+dnl #                operating system.
+dnl #
+dnl # Unfortunately, this interface isn't entirely reliable because
+dnl # drives are sometimes known to misreport this value.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BDEV_PHYSICAL_BLOCK_SIZE], [
+       AC_MSG_CHECKING([whether bdev_physical_block_size() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct block_device *bdev = NULL;
+               bdev_physical_block_size(bdev);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BDEV_PHYSICAL_BLOCK_SIZE, 1,
+                         [bdev_physical_block_size() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-bdi-setup-and-register.m4 b/zfs/config/kernel-bdi-setup-and-register.m4
new file mode 100644 (file)
index 0000000..d1062e1
--- /dev/null
@@ -0,0 +1,38 @@
+dnl #
+dnl # 2.6.32 - 2.6.33, bdi_setup_and_register() is not exported.
+dnl # 2.6.34 - 3.19, bdi_setup_and_register() takes 3 arguments.
+dnl # 4.0 - x.y, bdi_setup_and_register() takes 2 arguments.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BDI_SETUP_AND_REGISTER], [
+       AC_MSG_CHECKING([whether bdi_setup_and_register() wants 2 args])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/backing-dev.h>
+               struct backing_dev_info bdi;
+       ], [
+               char *name = "bdi";
+               int error __attribute__((unused)) =
+                   bdi_setup_and_register(&bdi, name);
+       ], [bdi_setup_and_register], [mm/backing-dev.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_2ARGS_BDI_SETUP_AND_REGISTER, 1,
+                   [bdi_setup_and_register() wants 2 args])
+       ], [
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([whether bdi_setup_and_register() wants 3 args])
+               ZFS_LINUX_TRY_COMPILE_SYMBOL([
+                       #include <linux/backing-dev.h>
+                       struct backing_dev_info bdi;
+               ], [
+                       char *name = "bdi";
+                       unsigned int cap = BDI_CAP_MAP_COPY;
+                       int error __attribute__((unused)) =
+                           bdi_setup_and_register(&bdi, name, cap);
+               ], [bdi_setup_and_register], [mm/backing-dev.c], [
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_3ARGS_BDI_SETUP_AND_REGISTER, 1,
+                           [bdi_setup_and_register() wants 3 args])
+               ], [
+                       AC_MSG_RESULT(no)
+               ])
+       ])
+])
diff --git a/zfs/config/kernel-bio-bvec-iter.m4 b/zfs/config/kernel-bio-bvec-iter.m4
new file mode 100644 (file)
index 0000000..64c9893
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 3.14 API change,
+dnl # Immutable biovecs. A number of fields of struct bio are moved to
+dnl # struct bvec_iter.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BIO_BVEC_ITER], [
+       AC_MSG_CHECKING([whether bio has bi_iter])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               struct bio bio;
+               bio.bi_iter.bi_sector = 0;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BIO_BVEC_ITER, 1, [bio has bi_iter])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
diff --git a/zfs/config/kernel-bio-end-io-t-args.m4 b/zfs/config/kernel-bio-end-io-t-args.m4
new file mode 100644 (file)
index 0000000..c8c520f
--- /dev/null
@@ -0,0 +1,24 @@
+dnl #
+dnl # 4.3 API change
+dnl # Error argument dropped from bio_endio in favor of newly introduced
+dnl # bio->bi_error. This also replaces bio->bi_flags value BIO_UPTODATE.
+dnl # Introduced by torvalds/linux@4246a0b63bd8f56a1469b12eafeb875b1041a451
+dnl # ("block: add a bi_error field to struct bio").
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BIO_END_IO_T_ARGS], [
+       AC_MSG_CHECKING([whether bio_end_io_t wants 1 arg])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+
+               void wanted_end_io(struct bio *bio) { return; }
+
+               bio_end_io_t *end_io __attribute__ ((unused)) = wanted_end_io;
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_1ARG_BIO_END_IO_T, 1,
+                         [bio_end_io_t wants 1 arg])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-bio-failfast.m4 b/zfs/config/kernel-bio-failfast.m4
new file mode 100644 (file)
index 0000000..cfbec05
--- /dev/null
@@ -0,0 +1,39 @@
+dnl #
+dnl # Preferred interface for setting FAILFAST on a bio:
+dnl #   2.6.28-2.6.35: BIO_RW_FAILFAST_{DEV|TRANSPORT|DRIVER}
+dnl #       >= 2.6.36: REQ_FAILFAST_{DEV|TRANSPORT|DRIVER}
+dnl #
+
+AC_DEFUN([ZFS_AC_KERNEL_BIO_FAILFAST_DTD], [
+       AC_MSG_CHECKING([whether BIO_RW_FAILFAST_* are defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               int flags __attribute__ ((unused));
+               flags = ((1 << BIO_RW_FAILFAST_DEV) |
+                        (1 << BIO_RW_FAILFAST_TRANSPORT) |
+                        (1 << BIO_RW_FAILFAST_DRIVER));
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BIO_RW_FAILFAST_DTD, 1,
+                         [BIO_RW_FAILFAST_* are defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_REQ_FAILFAST_MASK], [
+       AC_MSG_CHECKING([whether REQ_FAILFAST_MASK is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               int flags __attribute__ ((unused));
+               flags = REQ_FAILFAST_MASK;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_REQ_FAILFAST_MASK, 1,
+                         [REQ_FAILFAST_MASK is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-bio-op.m4 b/zfs/config/kernel-bio-op.m4
new file mode 100644 (file)
index 0000000..5559d6c
--- /dev/null
@@ -0,0 +1,84 @@
+dnl #
+dnl # Linux 4.8 API,
+dnl #
+dnl # The bio_op() helper was introduced as a replacement for explicitly
+dnl # checking the bio->bi_rw flags.  The following checks are used to
+dnl # detect if a specific operation is supported.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_REQ_OP_DISCARD], [
+       AC_MSG_CHECKING([whether REQ_OP_DISCARD is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blk_types.h>
+       ],[
+               int op __attribute__ ((unused)) = REQ_OP_DISCARD;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_REQ_OP_DISCARD, 1,
+                   [REQ_OP_DISCARD is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_REQ_OP_SECURE_ERASE], [
+       AC_MSG_CHECKING([whether REQ_OP_SECURE_ERASE is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blk_types.h>
+       ],[
+               int op __attribute__ ((unused)) = REQ_OP_SECURE_ERASE;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_REQ_OP_SECURE_ERASE, 1,
+                   [REQ_OP_SECURE_ERASE is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+
+AC_DEFUN([ZFS_AC_KERNEL_REQ_OP_FLUSH], [
+       AC_MSG_CHECKING([whether REQ_OP_FLUSH is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blk_types.h>
+       ],[
+               int op __attribute__ ((unused)) = REQ_OP_FLUSH;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_REQ_OP_FLUSH, 1,
+                   [REQ_OP_FLUSH is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BIO_BI_OPF], [
+       AC_MSG_CHECKING([whether bio->bi_opf is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               struct bio bio __attribute__ ((unused));
+               bio.bi_opf = 0;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BIO_BI_OPF, 1, [bio->bi_opf is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_HAVE_BIO_SET_OP_ATTRS], [
+       AC_MSG_CHECKING([whether bio_set_op_attrs is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blk_types.h>
+       ],[
+               struct bio *bio __attribute__ ((unused)) = NULL;
+
+               bio_set_op_attrs(bio, 0, 0);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BIO_SET_OP_ATTRS, 1,
+                   [bio_set_op_attrs is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-bio-rw-barrier.m4 b/zfs/config/kernel-bio-rw-barrier.m4
new file mode 100644 (file)
index 0000000..bcf0f7e
--- /dev/null
@@ -0,0 +1,25 @@
+dnl #
+dnl # Interface for issuing a discard bio:
+dnl # 2.6.28-2.6.35: BIO_RW_BARRIER
+dnl # 2.6.36-3.x:    REQ_BARRIER
+dnl #
+
+dnl # Since REQ_BARRIER is a preprocessor definition, there is no need for an
+dnl # autotools check for it. Also, REQ_BARRIER existed in the request layer
+dnl # until torvalds/linux@7b6d91daee5cac6402186ff224c3af39d79f4a0e unified the
+dnl # request layer and bio layer flags, so it would be wrong to assume that
+dnl # the APIs are mutually exclusive contrary to the typical case.
+AC_DEFUN([ZFS_AC_KERNEL_BIO_RW_BARRIER], [
+       AC_MSG_CHECKING([whether BIO_RW_BARRIER is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               int flags __attribute__ ((unused));
+               flags = BIO_RW_BARRIER;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BIO_RW_BARRIER, 1, [BIO_RW_BARRIER is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-bio-rw-discard.m4 b/zfs/config/kernel-bio-rw-discard.m4
new file mode 100644 (file)
index 0000000..0554b9a
--- /dev/null
@@ -0,0 +1,25 @@
+dnl #
+dnl # Interface for issuing a discard bio:
+dnl # 2.6.28-2.6.35: BIO_RW_DISCARD
+dnl # 2.6.36-3.x:    REQ_DISCARD
+dnl #
+
+dnl # Since REQ_DISCARD is a preprocessor definition, there is no need for an
+dnl # autotools check for it. Also, REQ_DISCARD existed in the request layer
+dnl # until torvalds/linux@7b6d91daee5cac6402186ff224c3af39d79f4a0e unified the
+dnl # request layer and bio layer flags, so it would be wrong to assume that
+dnl # the APIs are mutually exclusive contrary to the typical case.
+AC_DEFUN([ZFS_AC_KERNEL_BIO_RW_DISCARD], [
+       AC_MSG_CHECKING([whether BIO_RW_DISCARD is defined])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               int flags __attribute__ ((unused));
+               flags = BIO_RW_DISCARD;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BIO_RW_DISCARD, 1, [BIO_RW_DISCARD is defined])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-blk-queue-flush.m4 b/zfs/config/kernel-blk-queue-flush.m4
new file mode 100644 (file)
index 0000000..1baab83
--- /dev/null
@@ -0,0 +1,85 @@
+dnl #
+dnl # 2.6.36 API change
+dnl # In 2.6.36 kernels the blk_queue_ordered() interface has been
+dnl # replaced by the simpler blk_queue_flush().  However, while the
+dnl # old interface was available to all the new one is GPL-only.
+dnl # Thus in addition to detecting if this function is available
+dnl # we determine if it is GPL-only.  If the GPL-only interface is
+dnl # there we implement our own compatibility function, otherwise
+dnl # we use the function.  The hope is that long term this function
+dnl # will be opened up.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_FLUSH], [
+       AC_MSG_CHECKING([whether blk_queue_flush() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct request_queue *q = NULL;
+               (void) blk_queue_flush(q, REQ_FLUSH);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLK_QUEUE_FLUSH, 1,
+                         [blk_queue_flush() is available])
+
+               AC_MSG_CHECKING([whether blk_queue_flush() is GPL-only])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/module.h>
+                       #include <linux/blkdev.h>
+
+                       MODULE_LICENSE("$ZFS_META_LICENSE");
+               ],[
+                       struct request_queue *q = NULL;
+                       (void) blk_queue_flush(q, REQ_FLUSH);
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_BLK_QUEUE_FLUSH_GPL_ONLY, 1,
+                                 [blk_queue_flush() is GPL-only])
+               ])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+
+       dnl #
+       dnl # 4.7 API change
+       dnl # Replace blk_queue_flush with blk_queue_write_cache
+       dnl #
+       AC_MSG_CHECKING([whether blk_queue_write_cache() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/kernel.h>
+               #include <linux/blkdev.h>
+
+       ],[
+               struct request_queue *q = NULL;
+               blk_queue_write_cache(q, true, true);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLK_QUEUE_WRITE_CACHE, 1,
+                       [blk_queue_write_cache() exists])
+
+               AC_MSG_CHECKING([whether blk_queue_write_cache() is GPL-only])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/kernel.h>
+                       #include <linux/module.h>
+                       #include <linux/blkdev.h>
+
+                       MODULE_LICENSE("$ZFS_META_LICENSE");
+               ],[
+                       struct request_queue *q = NULL;
+                       blk_queue_write_cache(q, true, true);
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_BLK_QUEUE_WRITE_CACHE_GPL_ONLY, 1,
+                                 [blk_queue_write_cache() is GPL-only])
+               ])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-blk-queue-max-hw-sectors.m4 b/zfs/config/kernel-blk-queue-max-hw-sectors.m4
new file mode 100644 (file)
index 0000000..2f5515d
--- /dev/null
@@ -0,0 +1,22 @@
+dnl #
+dnl # 2.6.34 API change
+dnl # blk_queue_max_hw_sectors() replaces blk_queue_max_sectors().
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_MAX_HW_SECTORS], [
+       AC_MSG_CHECKING([whether blk_queue_max_hw_sectors() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct request_queue *q = NULL;
+               (void) blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLK_QUEUE_MAX_HW_SECTORS, 1,
+                         [blk_queue_max_hw_sectors() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-blk-queue-max-segments.m4 b/zfs/config/kernel-blk-queue-max-segments.m4
new file mode 100644 (file)
index 0000000..b2a4042
--- /dev/null
@@ -0,0 +1,23 @@
+dnl #
+dnl # 2.6.34 API change
+dnl # blk_queue_max_segments() consolidates blk_queue_max_hw_segments()
+dnl # and blk_queue_max_phys_segments().
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_MAX_SEGMENTS], [
+       AC_MSG_CHECKING([whether blk_queue_max_segments() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct request_queue *q = NULL;
+               (void) blk_queue_max_segments(q, BLK_MAX_SEGMENTS);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLK_QUEUE_MAX_SEGMENTS, 1,
+                         [blk_queue_max_segments() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
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-blkdev-get-by-path.m4 b/zfs/config/kernel-blkdev-get-by-path.m4
new file mode 100644 (file)
index 0000000..40ecc06
--- /dev/null
@@ -0,0 +1,19 @@
+dnl #
+dnl # 2.6.38 API change
+dnl # open_bdev_exclusive() changed to blkdev_get_by_path()
+dnl # close_bdev_exclusive() changed to blkdev_put()
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH],
+       [AC_MSG_CHECKING([whether blkdev_get_by_path() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               blkdev_get_by_path(NULL, 0, NULL);
+       ], [blkdev_get_by_path], [fs/block_dev.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLKDEV_GET_BY_PATH, 1,
+                         [blkdev_get_by_path() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-blkdev-get.m4 b/zfs/config/kernel-blkdev-get.m4
new file mode 100644 (file)
index 0000000..e31d717
--- /dev/null
@@ -0,0 +1,19 @@
+dnl #
+dnl # 2.6.37 API change
+dnl # Added 3rd argument for the active holder, previously this was
+dnl # hardcoded to NULL.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_3ARG_BLKDEV_GET], [
+       AC_MSG_CHECKING([whether blkdev_get() wants 3 args])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct block_device *bdev = NULL;
+               (void) blkdev_get(bdev, 0, NULL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_3ARG_BLKDEV_GET, 1, [blkdev_get() wants 3 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-block-device-operations-release-void.m4 b/zfs/config/kernel-block-device-operations-release-void.m4
new file mode 100644 (file)
index 0000000..a73f858
--- /dev/null
@@ -0,0 +1,29 @@
+dnl #
+dnl # 3.10.x API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
+       AC_MSG_CHECKING([whether block_device_operations.release is void])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(void)
+               AC_DEFINE(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID, 1,
+                         [struct block_device_operations.release returns void])
+       ],[
+               AC_MSG_RESULT(int)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-check-disk-size-change.m4 b/zfs/config/kernel-check-disk-size-change.m4
new file mode 100644 (file)
index 0000000..ea5c75f
--- /dev/null
@@ -0,0 +1,18 @@
+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-clear-inode.m4 b/zfs/config/kernel-clear-inode.m4
new file mode 100644 (file)
index 0000000..8d880fc
--- /dev/null
@@ -0,0 +1,34 @@
+dnl #
+dnl # 3.5.0 API change
+dnl # torvalds/linux@dbd5768f87ff6fb0a4fe09c4d7b6c4a24de99430 and
+dnl # torvalds/linux@7994e6f7254354e03028a11f98a27bd67dace9f1 reworked
+dnl # where inode_sync_wait() is called.
+dnl #
+dnl # Prior to these changes it would occur in end_writeback() but due
+dnl # to various issues (described in the above commits) it has been
+dnl # moved to evict().   This changes the ordering is which sync occurs
+dnl # but otherwise doesn't impact the zpl implementation.
+dnl #
+dnl # The major impact here is the renaming of end_writeback() to
+dnl # clear_inode().  However, care must be taken when detecting this
+dnl # API change because as recently as 2.6.35 there was a clear_inode()
+dnl # function.  However, it was made obsolete by the evict_inode() API
+dnl # change at the same time.
+dnl #
+dnl # Therefore, to ensure we have the correct API we only allow the
+dnl # clear_inode() compatibility code to be defined iff the evict_inode()
+dnl # functionality is also detected.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CLEAR_INODE],
+       [AC_MSG_CHECKING([whether clear_inode() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               clear_inode(NULL);
+       ], [clear_inode], [fs/inode.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CLEAR_INODE, 1, [clear_inode() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-commit-metadata.m4 b/zfs/config/kernel-commit-metadata.m4
new file mode 100644 (file)
index 0000000..b66a16f
--- /dev/null
@@ -0,0 +1,23 @@
+dnl #
+dnl # 2.6.33 API change
+dnl # Added eops->commit_metadata() callback to allow the underlying
+dnl # filesystem to determine the most efficient way to commit the inode.
+dnl # Prior to this the nfs server would issue an explicit fsync().
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_COMMIT_METADATA], [
+       AC_MSG_CHECKING([whether eops->commit_metadata() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/exportfs.h>
+               int commit_metadata(struct inode *inode) { return 0; }
+               static struct export_operations eops __attribute__ ((unused))={
+                       .commit_metadata = commit_metadata,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_COMMIT_METADATA, 1,
+                         [eops->commit_metadata() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-create-nameidata.m4 b/zfs/config/kernel-create-nameidata.m4
new file mode 100644 (file)
index 0000000..a71490a
--- /dev/null
@@ -0,0 +1,29 @@
+dnl #
+dnl # 3.6 API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CREATE_NAMEIDATA], [
+       AC_MSG_CHECKING([whether iops->create() passes nameidata])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CREATE_NAMEIDATA, 1,
+                         [iops->create() passes nameidata])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-current_bio_tail.m4 b/zfs/config/kernel-current_bio_tail.m4
new file mode 100644 (file)
index 0000000..b72f21e
--- /dev/null
@@ -0,0 +1,33 @@
+dnl #
+dnl # 2.6.34 API change
+dnl # current->bio_tail and current->bio_list were struct bio pointers prior to
+dnl # Linux 2.6.34. They were refactored into a struct bio_list pointer called
+dnl # current->bio_list in Linux 2.6.34.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CURRENT_BIO_TAIL], [
+       AC_MSG_CHECKING([whether current->bio_tail exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/sched.h>
+       ],[
+               current->bio_tail = (struct bio **) NULL;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CURRENT_BIO_TAIL, 1,
+                   [current->bio_tail exists])
+       ],[
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([whether current->bio_list exists])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/sched.h>
+               ],[
+                       current->bio_list = (struct bio_list *) NULL;
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_CURRENT_BIO_LIST, 1,
+                           [current->bio_list exists])
+               ],[
+                       AC_MSG_ERROR(no - Please file a bug report at
+                           https://github.com/zfsonlinux/zfs/issues/new)
+               ])
+       ])
+])
diff --git a/zfs/config/kernel-d-make-root.m4 b/zfs/config/kernel-d-make-root.m4
new file mode 100644 (file)
index 0000000..9c2b73d
--- /dev/null
@@ -0,0 +1,17 @@
+dnl #
+dnl # 3.4.0 API change
+dnl # Added d_make_root() to replace previous d_alloc_root() function.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_D_MAKE_ROOT],
+       [AC_MSG_CHECKING([whether d_make_root() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/dcache.h>
+       ], [
+               d_make_root(NULL);
+       ], [d_make_root], [fs/dcache.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_D_MAKE_ROOT, 1, [d_make_root() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-d-obtain-alias.m4 b/zfs/config/kernel-d-obtain-alias.m4
new file mode 100644 (file)
index 0000000..2b4b11e
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # 2.6.28 API change
+dnl # Added d_obtain_alias() helper function.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_D_OBTAIN_ALIAS],
+       [AC_MSG_CHECKING([whether d_obtain_alias() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/dcache.h>
+       ], [
+               d_obtain_alias(NULL);
+       ], [d_obtain_alias], [fs/dcache.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_D_OBTAIN_ALIAS, 1,
+                         [d_obtain_alias() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-d-prune-aliases.m4 b/zfs/config/kernel-d-prune-aliases.m4
new file mode 100644 (file)
index 0000000..d9c521b
--- /dev/null
@@ -0,0 +1,19 @@
+dnl #
+dnl # 2.6.12 API change
+dnl # d_prune_aliases() helper function available.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_D_PRUNE_ALIASES],
+       [AC_MSG_CHECKING([whether d_prune_aliases() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/dcache.h>
+       ], [
+               struct inode *ip = NULL;
+               d_prune_aliases(ip);
+       ], [d_prune_aliases], [fs/dcache.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_D_PRUNE_ALIASES, 1,
+                         [d_prune_aliases() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-declare-event-class.m4 b/zfs/config/kernel-declare-event-class.m4
new file mode 100644 (file)
index 0000000..7867d75
--- /dev/null
@@ -0,0 +1,59 @@
+dnl #
+dnl # Ensure the DECLARE_EVENT_CLASS macro is available to non-GPL modules.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_DECLARE_EVENT_CLASS], [
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="-I\$(src)"
+
+       AC_MSG_CHECKING([whether DECLARE_EVENT_CLASS() is available])
+       ZFS_LINUX_TRY_COMPILE_HEADER([
+               #include <linux/module.h>
+               MODULE_LICENSE(ZFS_META_LICENSE);
+
+               #define CREATE_TRACE_POINTS
+               #include "conftest.h"
+       ],[
+               trace_zfs_autoconf_event_one(1UL);
+               trace_zfs_autoconf_event_two(2UL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_DECLARE_EVENT_CLASS, 1,
+                         [DECLARE_EVENT_CLASS() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ],[
+               #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>
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-dentry-operations.m4 b/zfs/config/kernel-dentry-operations.m4
new file mode 100644 (file)
index 0000000..3182490
--- /dev/null
@@ -0,0 +1,87 @@
+dnl #
+dnl # 3.6 API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_D_REVALIDATE_NAMEIDATA], [
+       AC_MSG_CHECKING([whether dops->d_revalidate() takes struct nameidata])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_D_REVALIDATE_NAMEIDATA, 1,
+                         [dops->d_revalidate() operation takes nameidata])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.30 API change
+dnl # The 'struct dentry_operations' was constified in the dentry structure.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CONST_DENTRY_OPERATIONS], [
+       AC_MSG_CHECKING([whether dentry uses const struct dentry_operations])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/dcache.h>
+
+               const struct dentry_operations test_d_op = {
+                       .d_revalidate = NULL,
+               };
+       ],[
+               struct dentry d __attribute__ ((unused));
+
+               d.d_op = &test_d_op;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CONST_DENTRY_OPERATIONS, 1,
+                         [dentry uses const struct dentry_operations])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.38 API change
+dnl # Added d_set_d_op() helper function.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_D_SET_D_OP],
+       [AC_MSG_CHECKING([whether d_set_d_op() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/dcache.h>
+       ], [
+               d_set_d_op(NULL, NULL);
+       ], [d_set_d_op], [fs/dcache.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_D_SET_D_OP, 1,
+                         [d_set_d_op() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 2.6.38 API chage
+dnl # Added sb->s_d_op default dentry_operations member
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_S_D_OP],
+       [AC_MSG_CHECKING([whether super_block has s_d_op])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct super_block sb __attribute__ ((unused));
+               sb.s_d_op = NULL;
+       ], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_S_D_OP, 1, [struct super_block has s_d_op])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-dirty-inode.m4 b/zfs/config/kernel-dirty-inode.m4
new file mode 100644 (file)
index 0000000..ffd87bb
--- /dev/null
@@ -0,0 +1,26 @@
+dnl #
+dnl # 3.0 API change
+dnl # The sops->dirty_inode() callbacks were updated to take a flags
+dnl # argument.  This allows the greater control over whether the
+dnl # filesystem needs to push out a transaction or not.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_DIRTY_INODE_WITH_FLAGS], [
+       AC_MSG_CHECKING([whether sops->dirty_inode() wants flags])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_DIRTY_INODE_WITH_FLAGS, 1,
+                       [sops->dirty_inode() wants flags])
+       ],[
+               AC_MSG_RESULT([no])
+       ])
+])
diff --git a/zfs/config/kernel-discard-granularity.m4 b/zfs/config/kernel-discard-granularity.m4
new file mode 100644 (file)
index 0000000..2c677c9
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 2.6.33 API change
+dnl # Discard granularity and alignment restrictions may now be set.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_DISCARD_GRANULARITY], [
+       AC_MSG_CHECKING([whether ql->discard_granularity is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct queue_limits ql __attribute__ ((unused));
+
+               ql.discard_granularity = 0;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_DISCARD_GRANULARITY, 1,
+                         [ql->discard_granularity is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-elevator-change.m4 b/zfs/config/kernel-elevator-change.m4
new file mode 100644 (file)
index 0000000..ace5aa8
--- /dev/null
@@ -0,0 +1,25 @@
+dnl #
+dnl # 2.6.36 API change
+dnl # Verify the elevator_change() symbol is available.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_ELEVATOR_CHANGE], [
+       AC_MSG_CHECKING([whether elevator_change() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+               #include <linux/elevator.h>
+       ],[
+               int ret;
+               struct request_queue *q = NULL;
+               char *elevator = NULL;
+               ret = elevator_change(q, elevator);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_ELEVATOR_CHANGE, 1,
+                         [elevator_change() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-encode-fh-inode.m4 b/zfs/config/kernel-encode-fh-inode.m4
new file mode 100644 (file)
index 0000000..287f62a
--- /dev/null
@@ -0,0 +1,24 @@
+dnl #
+dnl # 3.5.0 API change
+dnl # torvalds/linux@b0b0382bb4904965a9e9fca77ad87514dfda0d1c changed the
+dnl # ->encode_fh() callback to pass the child inode and its parents inode
+dnl # rather than a dentry and a boolean saying whether we want the parent.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_ENCODE_FH_WITH_INODE], [
+       AC_MSG_CHECKING([whether eops->encode_fh() wants inode])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_ENCODE_FH_WITH_INODE, 1,
+                         [eops->encode_fh() wants child and parent inodes])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-evict-inode.m4 b/zfs/config/kernel-evict-inode.m4
new file mode 100644 (file)
index 0000000..683cedb
--- /dev/null
@@ -0,0 +1,21 @@
+dnl #
+dnl # 2.6.36 API change
+dnl # The sops->delete_inode() and sops->clear_inode() callbacks have
+dnl # replaced by a single sops->evict_inode() callback.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_EVICT_INODE], [
+       AC_MSG_CHECKING([whether sops->evict_inode() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               void evict_inode (struct inode * t) { return; }
+               static struct super_operations sops __attribute__ ((unused)) = {
+                       .evict_inode = evict_inode,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_EVICT_INODE, 1, [sops->evict_inode() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-fallocate.m4 b/zfs/config/kernel-fallocate.m4
new file mode 100644 (file)
index 0000000..5509064
--- /dev/null
@@ -0,0 +1,56 @@
+dnl #
+dnl # Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FILE_FALLOCATE], [
+       AC_MSG_CHECKING([whether fops->fallocate() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # Linux 2.6.x - 2.6.37 API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_FALLOCATE], [
+       AC_MSG_CHECKING([whether iops->fallocate() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INODE_FALLOCATE, 1, [fops->fallocate() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # The fallocate callback was moved from the inode_operations
+dnl # structure to the file_operations structure.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FALLOCATE], [
+       ZFS_AC_KERNEL_FILE_FALLOCATE
+       ZFS_AC_KERNEL_INODE_FALLOCATE
+])
diff --git a/zfs/config/kernel-file-inode.m4 b/zfs/config/kernel-file-inode.m4
new file mode 100644 (file)
index 0000000..300188f
--- /dev/null
@@ -0,0 +1,19 @@
+dnl #
+dnl # 3.19 API change
+dnl # struct access f->f_dentry->d_inode was replaced by accessor function
+dnl # file_inode(f)
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FILE_INODE], [
+       AC_MSG_CHECKING([whether file_inode() is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct file *f = NULL;
+               file_inode(f);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FILE_INODE, 1, [file_inode() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-fmode-t.m4 b/zfs/config/kernel-fmode-t.m4
new file mode 100644 (file)
index 0000000..4a23c39
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # 2.6.28 API change,
+dnl # check if fmode_t typedef is defined
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_TYPE_FMODE_T],
+       [AC_MSG_CHECKING([whether kernel defines fmode_t])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/types.h>
+       ],[
+               fmode_t *ptr __attribute__ ((unused));
+       ],[
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_FMODE_T, 1,
+                         [kernel defines fmode_t])
+       ],[
+               AC_MSG_RESULT([no])
+       ])
+])
diff --git a/zfs/config/kernel-follow-down-one.m4 b/zfs/config/kernel-follow-down-one.m4
new file mode 100644 (file)
index 0000000..63fa779
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 2.6.38 API change
+dnl # follow_down() renamed follow_down_one().  The original follow_down()
+dnl # symbol still exists but will traverse down all the layers.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FOLLOW_DOWN_ONE], [
+       AC_MSG_CHECKING([whether follow_down_one() is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/namei.h>
+       ],[
+               struct path *p = NULL;
+               follow_down_one(p);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FOLLOW_DOWN_ONE, 1,
+                   [follow_down_one() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-fsync.m4 b/zfs/config/kernel-fsync.m4
new file mode 100644 (file)
index 0000000..e1f2d68
--- /dev/null
@@ -0,0 +1,74 @@
+dnl #
+dnl # Linux 2.6.x - 2.6.34 API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FSYNC_WITH_DENTRY], [
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT([dentry])
+               AC_DEFINE(HAVE_FSYNC_WITH_DENTRY, 1,
+                       [fops->fsync() with dentry])
+       ],[
+       ])
+])
+
+dnl #
+dnl # Linux 2.6.35 - Linux 3.0 API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FSYNC_WITHOUT_DENTRY], [
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT([no dentry])
+               AC_DEFINE(HAVE_FSYNC_WITHOUT_DENTRY, 1,
+                       [fops->fsync() without dentry])
+       ],[
+       ])
+])
+
+dnl #
+dnl # Linux 3.1 - 3.x API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FSYNC_RANGE], [
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT([range])
+               AC_DEFINE(HAVE_FSYNC_RANGE, 1,
+                       [fops->fsync() with range])
+       ],[
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_FSYNC], [
+       AC_MSG_CHECKING([whether fops->fsync() wants])
+       ZFS_AC_KERNEL_FSYNC_WITH_DENTRY
+       ZFS_AC_KERNEL_FSYNC_WITHOUT_DENTRY
+       ZFS_AC_KERNEL_FSYNC_RANGE
+])
diff --git a/zfs/config/kernel-generic_io_acct.m4 b/zfs/config/kernel-generic_io_acct.m4
new file mode 100644 (file)
index 0000000..25bfa38
--- /dev/null
@@ -0,0 +1,26 @@
+dnl #
+dnl # 3.19 API addition
+dnl #
+dnl # torvalds/linux@394ffa503bc40e32d7f54a9b817264e81ce131b4 allows us to
+dnl # increment iostat counters without generic_make_request().
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_GENERIC_IO_ACCT], [
+       AC_MSG_CHECKING([whether generic IO accounting symbols are avaliable])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #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;
+       ], [
+               generic_start_io_acct(0, 0, NULL);
+               generic_end_io_acct(0, NULL, 0);
+       ], [generic_start_io_acct], [block/bio.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GENERIC_IO_ACCT, 1,
+                   [generic_start_io_acct()/generic_end_io_acct() avaliable])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-generic_readlink.m4 b/zfs/config/kernel-generic_readlink.m4
new file mode 100644 (file)
index 0000000..914431d
--- /dev/null
@@ -0,0 +1,22 @@
+dnl #
+dnl # 4.10 API
+dnl #
+dnl # NULL inode_operations.readlink implies generic_readlink(), which
+dnl # has been made static.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_GENERIC_READLINK_GLOBAL], [
+       AC_MSG_CHECKING([whether generic_readlink is global])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               int i __attribute__ ((unused));
+
+               i = generic_readlink(NULL, NULL, 0);
+       ],[
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_GENERIC_READLINK, 1,
+                         [generic_readlink is global])
+       ],[
+               AC_MSG_RESULT([no])
+       ])
+])
diff --git a/zfs/config/kernel-get-disk-ro.m4 b/zfs/config/kernel-get-disk-ro.m4
new file mode 100644 (file)
index 0000000..13ed812
--- /dev/null
@@ -0,0 +1,21 @@
+dnl #
+dnl # 2.6.x API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_GET_DISK_RO], [
+       AC_MSG_CHECKING([whether get_disk_ro() is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct gendisk *disk = NULL;
+               (void) get_disk_ro(disk);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GET_DISK_RO, 1,
+                         [blk_disk_ro() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-get-gendisk.m4 b/zfs/config/kernel-get-gendisk.m4
new file mode 100644 (file)
index 0000000..b091377
--- /dev/null
@@ -0,0 +1,17 @@
+dnl #
+dnl # 2.6.34 API change
+dnl # Verify the get_gendisk() symbol is available.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_GET_GENDISK],
+       [AC_MSG_CHECKING([whether get_gendisk() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/genhd.h>
+       ], [
+               get_gendisk(0, NULL);
+       ], [get_gendisk], [block/genhd.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GET_GENDISK, 1, [get_gendisk() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-get-link.m4 b/zfs/config/kernel-get-link.m4
new file mode 100644 (file)
index 0000000..022c49c
--- /dev/null
@@ -0,0 +1,100 @@
+dnl #
+dnl # Supported get_link() interfaces checked newest to oldest.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FOLLOW_LINK], [
+       dnl #
+       dnl # 4.2 API change
+       dnl # - This kernel retired the nameidata structure.
+       dnl #
+       AC_MSG_CHECKING([whether iops->follow_link() passes cookie])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FOLLOW_LINK_COOKIE, 1,
+                   [iops->follow_link() cookie])
+       ],[
+               dnl #
+               dnl # 2.6.32 API
+               dnl #
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING(
+                  [whether iops->follow_link() passes nameidata])
+               ZFS_LINUX_TRY_COMPILE([
+               #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,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_FOLLOW_LINK_NAMEIDATA, 1,
+                                 [iops->follow_link() nameidata])
+               ],[
+                        AC_MSG_ERROR(no; please file a bug report)
+               ])
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_GET_LINK], [
+       dnl #
+       dnl # 4.5 API change
+       dnl # The get_link interface has added a delayed done call and
+       dnl # used it to retire the put_link() interface.
+       dnl #
+       AC_MSG_CHECKING([whether iops->get_link() passes delayed])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GET_LINK_DELAYED, 1,
+                   [iops->get_link() delayed])
+       ],[
+               dnl #
+               dnl # 4.5 API change
+               dnl # The follow_link() interface has been replaced by
+               dnl # get_link() which behaves the same as before except:
+               dnl # - An inode is passed as a separate argument
+               dnl # - When called in RCU mode a NULL dentry is passed.
+               dnl #
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([whether iops->get_link() passes cookie])
+               ZFS_LINUX_TRY_COMPILE([
+                       #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,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_GET_LINK_COOKIE, 1,
+                           [iops->get_link() cookie])
+               ],[
+                       dnl #
+                       dnl # Check for the follow_link APIs.
+                       dnl #
+                       AC_MSG_RESULT(no)
+                       ZFS_AC_KERNEL_FOLLOW_LINK
+               ])
+       ])
+])
diff --git a/zfs/config/kernel-insert-inode-locked.m4 b/zfs/config/kernel-insert-inode-locked.m4
new file mode 100644 (file)
index 0000000..da141d1
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # 2.6.28 API change
+dnl # Added insert_inode_locked() helper function.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INSERT_INODE_LOCKED],
+       [AC_MSG_CHECKING([whether insert_inode_locked() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               insert_inode_locked(NULL);
+       ], [insert_inode_locked], [fs/inode.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INSERT_INODE_LOCKED, 1,
+                         [insert_inode_locked() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-invalidate-bdev-args.m4 b/zfs/config/kernel-invalidate-bdev-args.m4
new file mode 100644 (file)
index 0000000..09c2ebf
--- /dev/null
@@ -0,0 +1,19 @@
+dnl #
+dnl # 2.6.22 API change
+dnl # Unused destroy_dirty_buffers arg removed from prototype.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INVALIDATE_BDEV_ARGS], [
+       AC_MSG_CHECKING([whether invalidate_bdev() wants 1 arg])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/buffer_head.h>
+       ],[
+               struct block_device *bdev = NULL;
+               invalidate_bdev(bdev);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_1ARG_INVALIDATE_BDEV, 1,
+                         [invalidate_bdev() wants 1 arg])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-is_owner_or_cap.m4 b/zfs/config/kernel-is_owner_or_cap.m4
new file mode 100644 (file)
index 0000000..da07e58
--- /dev/null
@@ -0,0 +1,36 @@
+dnl #
+dnl # 2.6.39 API change,
+dnl # The is_owner_or_cap() macro was renamed to inode_owner_or_capable(),
+dnl # This is used for permission checks in the xattr and file attribute call
+dnl # paths.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [
+       AC_MSG_CHECKING([whether inode_owner_or_capable() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct inode *ip = NULL;
+               (void) inode_owner_or_capable(ip);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE, 1,
+                   [inode_owner_or_capable() exists])
+       ],[
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([whether is_owner_or_cap() exists])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/fs.h>
+                       #include <linux/sched.h>
+               ],[
+                       struct inode *ip = NULL;
+                       (void) is_owner_or_cap(ip);
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_IS_OWNER_OR_CAP, 1,
+                           [is_owner_or_cap() exists])
+               ],[
+                       AC_MSG_ERROR(no - Please file a bug report at
+                           https://github.com/zfsonlinux/zfs/issues/new)
+               ])
+       ])
+])
diff --git a/zfs/config/kernel-kmap-atomic-args.m4 b/zfs/config/kernel-kmap-atomic-args.m4
new file mode 100644 (file)
index 0000000..beb1692
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 2.6.37 API change
+dnl # kmap_atomic changed from assigning hard-coded named slot to using
+dnl # push/pop based dynamical allocation.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_KMAP_ATOMIC_ARGS], [
+       AC_MSG_CHECKING([whether kmap_atomic wants 1 args])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/pagemap.h>
+       ],[
+               struct page page;
+               kmap_atomic(&page);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_1ARG_KMAP_ATOMIC, 1,
+                         [kmap_atomic wants 1 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-kobj-name-len.m4 b/zfs/config/kernel-kobj-name-len.m4
new file mode 100644 (file)
index 0000000..37999fa
--- /dev/null
@@ -0,0 +1,21 @@
+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-lookup-bdev.m4 b/zfs/config/kernel-lookup-bdev.m4
new file mode 100644 (file)
index 0000000..abbf55d
--- /dev/null
@@ -0,0 +1,29 @@
+dnl #
+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() 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_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-lookup-nameidata.m4 b/zfs/config/kernel-lookup-nameidata.m4
new file mode 100644 (file)
index 0000000..43f5fb4
--- /dev/null
@@ -0,0 +1,25 @@
+dnl #
+dnl # 3.6 API change
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_LOOKUP_NAMEIDATA], [
+       AC_MSG_CHECKING([whether iops->lookup() passes nameidata])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_LOOKUP_NAMEIDATA, 1,
+                         [iops->lookup() passes nameidata])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-lseek-execute.m4 b/zfs/config/kernel-lseek-execute.m4
new file mode 100644 (file)
index 0000000..8c4032b
--- /dev/null
@@ -0,0 +1,23 @@
+dnl #
+dnl # 3.11 API change
+dnl # lseek_execute helper exported
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_LSEEK_EXECUTE],
+       [AC_MSG_CHECKING([whether lseek_execute() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               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);
+       ], [lseek_exclusive], [fs/read_write.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_LSEEK_EXECUTE, 1,
+                         [lseek_execute() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-mk-request-fn.m4 b/zfs/config/kernel-mk-request-fn.m4
new file mode 100644 (file)
index 0000000..57eebe2
--- /dev/null
@@ -0,0 +1,65 @@
+dnl #
+dnl # Linux 3.2 API Change
+dnl # make_request_fn returns void instead of int.
+dnl #
+dnl # Linux 4.4 API Change
+dnl # make_request_fn returns blk_qc_t.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_MAKE_REQUEST_FN], [
+       AC_MSG_CHECKING([whether make_request_fn() returns int])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+
+               int make_request(struct request_queue *q, struct bio *bio)
+               {
+                       return (0);
+               }
+       ],[
+               blk_queue_make_request(NULL, &make_request);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(MAKE_REQUEST_FN_RET, int,
+                   [make_request_fn() returns int])
+               AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_INT, 1,
+                   [Noting that make_request_fn() returns int])
+       ],[
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([whether make_request_fn() returns void])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/blkdev.h>
+
+                       void make_request(struct request_queue *q, struct bio *bio)
+                       {
+                               return;
+                       }
+               ],[
+                       blk_queue_make_request(NULL, &make_request);
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(MAKE_REQUEST_FN_RET, void,
+                           [make_request_fn() returns void])
+               ],[
+                       AC_MSG_RESULT(no)
+                       AC_MSG_CHECKING([whether make_request_fn() returns blk_qc_t])
+                       ZFS_LINUX_TRY_COMPILE([
+                               #include <linux/blkdev.h>
+
+                               blk_qc_t make_request(struct request_queue *q, struct bio *bio)
+                               {
+                                       return (BLK_QC_T_NONE);
+                               }
+                       ],[
+                               blk_queue_make_request(NULL, &make_request);
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(MAKE_REQUEST_FN_RET, blk_qc_t,
+                                   [make_request_fn() returns blk_qc_t])
+                               AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_QC, 1,
+                                   [Noting that make_request_fn() returns blk_qc_t])
+                       ],[
+                               AC_MSG_ERROR(no - Please file a bug report at
+                                   https://github.com/zfsonlinux/zfs/issues/new)
+                       ])
+               ])
+       ])
+])
diff --git a/zfs/config/kernel-mkdir-umode-t.m4 b/zfs/config/kernel-mkdir-umode-t.m4
new file mode 100644 (file)
index 0000000..634260b
--- /dev/null
@@ -0,0 +1,29 @@
+dnl #
+dnl # 3.3 API change
+dnl # The VFS .create, .mkdir and .mknod callbacks were updated to take a
+dnl # umode_t type rather than an int.  The expectation is that any backport
+dnl # would also change all three prototypes.  However, if it turns out that
+dnl # some distribution doesn't backport the whole thing this could be
+dnl # broken apart in to three seperate checks.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_MKDIR_UMODE_T], [
+       AC_MSG_CHECKING([whether iops->create()/mkdir()/mknod() take umode_t])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_MKDIR_UMODE_T, 1,
+                   [iops->create()/mkdir()/mknod() take umode_t])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-mount-nodev.m4 b/zfs/config/kernel-mount-nodev.m4
new file mode 100644 (file)
index 0000000..28a4515
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 2.6.39 API change
+dnl # The .get_sb callback has been replaced by a .mount callback
+dnl # in the file_system_type structure.  When using the new
+dnl # interface the caller must now use the mount_nodev() helper.
+dnl # This updated callback and helper no longer pass the vfsmount.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_MOUNT_NODEV],
+       [AC_MSG_CHECKING([whether mount_nodev() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               mount_nodev(NULL, 0, NULL, NULL);
+       ], [mount_nodev], [fs/super.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_MOUNT_NODEV, 1, [mount_nodev() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-open-bdev-exclusive.m4 b/zfs/config/kernel-open-bdev-exclusive.m4
new file mode 100644 (file)
index 0000000..0661315
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # 2.6.28 API change
+dnl # open/close_bdev_excl() renamed to open/close_bdev_exclusive()
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_OPEN_BDEV_EXCLUSIVE],
+       [AC_MSG_CHECKING([whether open_bdev_exclusive() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               open_bdev_exclusive(NULL, 0, NULL);
+       ], [open_bdev_exclusive], [fs/block_dev.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_OPEN_BDEV_EXCLUSIVE, 1,
+                         [open_bdev_exclusive() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-put-link.m4 b/zfs/config/kernel-put-link.m4
new file mode 100644 (file)
index 0000000..a0bb36e
--- /dev/null
@@ -0,0 +1,60 @@
+dnl #
+dnl # Supported symlink APIs
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_PUT_LINK], [
+       dnl #
+       dnl # 4.5 API change
+       dnl # get_link() uses delayed done, there is no put_link() interface.
+       dnl #
+       ZFS_LINUX_TRY_COMPILE([
+               #if !defined(HAVE_GET_LINK_DELAYED)
+               #error "Expecting get_link() delayed done"
+               #endif
+       ],[
+       ],[
+               AC_DEFINE(HAVE_PUT_LINK_DELAYED, 1, [iops->put_link() delayed])
+       ],[
+               dnl #
+               dnl # 4.2 API change
+               dnl # This kernel retired the nameidata structure.
+               dnl #
+               AC_MSG_CHECKING([whether iops->put_link() passes cookie])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/fs.h>
+                       void put_link(struct inode *ip, void *cookie)
+                           { return; }
+                       static struct inode_operations
+                           iops __attribute__ ((unused)) = {
+                               .put_link = put_link,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_PUT_LINK_COOKIE, 1,
+                           [iops->put_link() cookie])
+               ],[
+                       dnl #
+                       dnl # 2.6.32 API
+                       dnl #
+                       AC_MSG_RESULT(no)
+                       AC_MSG_CHECKING(
+                           [whether iops->put_link() passes nameidata])
+                       ZFS_LINUX_TRY_COMPILE([
+                               #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,
+                               };
+                       ],[
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_PUT_LINK_NAMEIDATA, 1,
+                                   [iops->put_link() nameidata])
+                       ],[
+                               AC_MSG_ERROR(no; please file a bug report)
+                       ])
+               ])
+       ])
+])
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-security-inode-init.m4 b/zfs/config/kernel-security-inode-init.m4
new file mode 100644 (file)
index 0000000..a62176d
--- /dev/null
@@ -0,0 +1,55 @@
+dnl #
+dnl # 2.6.39 API change
+dnl # The security_inode_init_security() function now takes an additional
+dnl # qstr argument which must be passed in from the dentry if available.
+dnl # Passing a NULL is safe when no qstr is available the relevant
+dnl # security checks will just be skipped.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_6ARGS_SECURITY_INODE_INIT_SECURITY], [
+       AC_MSG_CHECKING([whether security_inode_init_security wants 6 args])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/security.h>
+       ],[
+               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);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY, 1,
+                         [security_inode_init_security wants 6 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.2 API change
+dnl # The security_inode_init_security() API has been changed to include
+dnl # a filesystem specific callback to write security extended attributes.
+dnl # This was done to support the initialization of multiple LSM xattrs
+dnl # and the EVM xattr.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CALLBACK_SECURITY_INODE_INIT_SECURITY], [
+       AC_MSG_CHECKING([whether security_inode_init_security wants callback])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/security.h>
+       ],[
+               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);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY, 1,
+                         [security_inode_init_security wants callback])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-set-nlink.m4 b/zfs/config/kernel-set-nlink.m4
new file mode 100644 (file)
index 0000000..f7ffc0d
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # Linux v3.2-rc1 API change
+dnl # SHA: bfe8684869601dacfcb2cd69ef8cfd9045f62170
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SET_NLINK], [
+       AC_MSG_CHECKING([whether set_nlink() is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct inode node;
+               unsigned int link = 0;
+               (void) set_nlink(&node, link);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SET_NLINK, 1,
+                         [set_nlink() is available])
+       ],[
+               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-sget-args.m4 b/zfs/config/kernel-sget-args.m4
new file mode 100644 (file)
index 0000000..9d17459
--- /dev/null
@@ -0,0 +1,23 @@
+dnl #
+dnl # 3.6 API change,
+dnl # 'sget' now takes the mount flags as an argument.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_5ARG_SGET],
+       [AC_MSG_CHECKING([whether sget() wants 5 args])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               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);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_5ARG_SGET, 1, [sget() wants 5 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
diff --git a/zfs/config/kernel-show-options.m4 b/zfs/config/kernel-show-options.m4
new file mode 100644 (file)
index 0000000..67d683c
--- /dev/null
@@ -0,0 +1,22 @@
+dnl #
+dnl # Linux 3.3 API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SHOW_OPTIONS], [
+       AC_MSG_CHECKING([whether sops->show_options() wants dentry])
+
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_SHOW_OPTIONS_WITH_DENTRY, 1,
+                       [sops->show_options() with dentry])
+       ],[
+               AC_MSG_RESULT([no])
+       ])
+])
diff --git a/zfs/config/kernel-shrink.m4 b/zfs/config/kernel-shrink.m4
new file mode 100644 (file)
index 0000000..a57c2af
--- /dev/null
@@ -0,0 +1,133 @@
+dnl #
+dnl # 3.1 API change
+dnl # The super_block structure now stores a per-filesystem shrinker.
+dnl # This interface is preferable because it can be used to specifically
+dnl # target only the zfs filesystem for pruning.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SHRINK], [
+       AC_MSG_CHECKING([whether super_block has s_shrink])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SHRINK, 1, [struct super_block has s_shrink])
+
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.3 API change
+dnl # The super_block structure was changed to use an hlist_node instead
+dnl # of a list_head for the .s_instance linkage.
+dnl #
+dnl # This was done in part to resolve a race in the iterate_supers_type()
+dnl # function which was introduced in Linux 3.0 kernel.  The iterator
+dnl # was supposed to provide a safe way to call an arbitrary function on
+dnl # all super blocks of a specific type.  Unfortunately, because a
+dnl # list_head was used it was possible for iterate_supers_type() to
+dnl # get stuck spinning a super block which was just deactivated.
+dnl #
+dnl # This can occur because when the list head is removed from the
+dnl # fs_supers list it is reinitialized to point to itself.  If the
+dnl # iterate_supers_type() function happened to be processing the
+dnl # removed list_head it will get stuck spinning on that list_head.
+dnl #
+dnl # To resolve the issue for existing 3.0 - 3.2 kernels we detect when
+dnl # a list_head is used.  Then to prevent the spinning from occurring
+dnl # the .next pointer is set to the fs_supers list_head which ensures
+dnl # the iterate_supers_type() function will always terminate.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_S_INSTANCES_LIST_HEAD], [
+       AC_MSG_CHECKING([whether super_block has s_instances list_head])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct super_block sb __attribute__ ((unused));
+
+               INIT_LIST_HEAD(&sb.s_instances);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_S_INSTANCES_LIST_HEAD, 1,
+                   [struct super_block has s_instances list_head])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_NR_CACHED_OBJECTS], [
+       AC_MSG_CHECKING([whether sops->nr_cached_objects() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_NR_CACHED_OBJECTS, 1,
+                       [sops->nr_cached_objects() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_FREE_CACHED_OBJECTS], [
+       AC_MSG_CHECKING([whether sops->free_cached_objects() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FREE_CACHED_OBJECTS, 1,
+                       [sops->free_cached_objects() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # 3.12 API change
+dnl # The nid member was added to struct shrink_control to support
+dnl # NUMA-aware shrinkers.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SHRINK_CONTROL_HAS_NID], [
+       AC_MSG_CHECKING([whether shrink_control has nid])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct shrink_control sc __attribute__ ((unused));
+               unsigned long scnidsize __attribute__ ((unused)) =
+                   sizeof(sc.nid);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(SHRINK_CONTROL_HAS_NID, 1,
+                   [struct shrink_control has nid])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-submit_bio.m4 b/zfs/config/kernel-submit_bio.m4
new file mode 100644 (file)
index 0000000..da5f85c
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 4.8 API change
+dnl # The rw argument has been removed from submit_bio/submit_bio_wait.
+dnl # Callers are now expected to set bio->bi_rw instead of passing it in.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SUBMIT_BIO], [
+       AC_MSG_CHECKING([whether submit_bio() wants 1 arg])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/bio.h>
+       ],[
+               blk_qc_t blk_qc;
+               struct bio *bio = NULL;
+               blk_qc = submit_bio(bio);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_1ARG_SUBMIT_BIO, 1, [submit_bio() wants 1 arg])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-truncate-range.m4 b/zfs/config/kernel-truncate-range.m4
new file mode 100644 (file)
index 0000000..da2cb50
--- /dev/null
@@ -0,0 +1,24 @@
+dnl #
+dnl # 3.5.0 API change
+dnl # torvalds/linux@17cf28afea2a1112f240a3a2da8af883be024811 removed
+dnl # truncate_range(). The file hole punching functionality is now
+dnl # provided by fallocate()
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_TRUNCATE_RANGE], [
+       AC_MSG_CHECKING([whether iops->truncate_range() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_INODE_TRUNCATE_RANGE, 1,
+                         [iops->truncate_range() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-truncate-setsize.m4 b/zfs/config/kernel-truncate-setsize.m4
new file mode 100644 (file)
index 0000000..7e4aff4
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # 2.6.35 API change
+dnl # Added truncate_setsize() helper function.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_TRUNCATE_SETSIZE],
+       [AC_MSG_CHECKING([whether truncate_setsize() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/mm.h>
+       ], [
+               truncate_setsize(NULL, 0);
+       ], [truncate_setsize], [mm/truncate.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_TRUNCATE_SETSIZE, 1,
+                         [truncate_setsize() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-vfs-iterate.m4 b/zfs/config/kernel-vfs-iterate.m4
new file mode 100644 (file)
index 0000000..7b1599e
--- /dev/null
@@ -0,0 +1,64 @@
+AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
+       dnl #
+       dnl # 4.7 API change
+       dnl #
+       AC_MSG_CHECKING([whether fops->iterate_shared() is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_VFS_ITERATE_SHARED, 1,
+                         [fops->iterate_shared() is available])
+       ],[
+               AC_MSG_RESULT(no)
+
+               dnl #
+               dnl # 3.11 API change
+               dnl #
+               AC_MSG_CHECKING([whether fops->iterate() is available])
+               ZFS_LINUX_TRY_COMPILE([
+                       #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,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_VFS_ITERATE, 1,
+                                 [fops->iterate() is available])
+               ],[
+                       AC_MSG_RESULT(no)
+
+                       AC_MSG_CHECKING([whether fops->readdir() is available])
+                       ZFS_LINUX_TRY_COMPILE([
+                               #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,
+                               };
+                       ],[
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_VFS_READDIR, 1,
+                                         [fops->readdir() is available])
+                       ],[
+                               AC_MSG_ERROR(no; file a bug report with ZFSOnLinux)
+                       ])
+               ])
+       ])
+])
diff --git a/zfs/config/kernel-vfs-rw-iterate.m4 b/zfs/config/kernel-vfs-rw-iterate.m4
new file mode 100644 (file)
index 0000000..af44beb
--- /dev/null
@@ -0,0 +1,48 @@
+dnl #
+dnl # Linux 4.1.x API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_VFS_RW_ITERATE],
+       [AC_MSG_CHECKING([whether fops->read/write_iter() are available])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_VFS_RW_ITERATE, 1,
+                       [fops->read/write_iter() are available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+dnl #
+dnl # Linux 4.1.x API
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_GENERIC_WRITE_CHECKS],
+       [AC_MSG_CHECKING([whether generic_write_checks() takes kiocb])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+
+       ],[
+               struct kiocb *iocb = NULL;
+               struct iov_iter *iov = NULL;
+               generic_write_checks(iocb, iov);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GENERIC_WRITE_CHECKS_KIOCB, 1,
+                       [generic_write_checks() takes kiocb])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-xattr-handler.m4 b/zfs/config/kernel-xattr-handler.m4
new file mode 100644 (file)
index 0000000..4ac08d8
--- /dev/null
@@ -0,0 +1,415 @@
+dnl #
+dnl # 2.6.35 API change,
+dnl # The 'struct xattr_handler' was constified in the generic
+dnl # super_block structure.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CONST_XATTR_HANDLER], [
+       AC_MSG_CHECKING([whether super_block uses const struct xattr_handler])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_CONST_XATTR_HANDLER, 1,
+                         [super_block uses const struct xattr_handler])
+       ],[
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # 4.5 API change,
+dnl # struct xattr_handler added new member "name".
+dnl # xattr_handler which matches to whole name rather than prefix should use
+dnl # "name" instead of "prefix", e.g. "system.posix_acl_access"
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_NAME], [
+       AC_MSG_CHECKING([whether xattr_handler has name])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/xattr.h>
+
+               static const struct xattr_handler
+                   xops __attribute__ ((unused)) = {
+                       .name = XATTR_NAME_POSIX_ACL_ACCESS,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_XATTR_HANDLER_NAME, 1,
+                   [xattr_handler has name])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
+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 #
+AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_GET], [
+       dnl #
+       dnl # 4.7 API change,
+       dnl # The xattr_handler->get() callback was changed to take both
+       dnl # dentry and inode.
+       dnl #
+       AC_MSG_CHECKING([whether xattr_handler->get() wants both dentry and inode])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_XATTR_GET_DENTRY_INODE, 1,
+                   [xattr_handler->get() wants both dentry and inode])
+       ],[
+               dnl #
+               dnl # 4.4 API change,
+               dnl # The xattr_handler->get() callback was changed to take a
+               dnl # attr_handler, and handler_flags argument was removed and
+               dnl # should be accessed by handler->flags.
+               dnl #
+               AC_MSG_CHECKING([whether xattr_handler->get() wants xattr_handler])
+               ZFS_LINUX_TRY_COMPILE([
+                       #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,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_XATTR_GET_HANDLER, 1,
+                           [xattr_handler->get() wants xattr_handler])
+               ],[
+                       dnl #
+                       dnl # 2.6.33 API change,
+                       dnl # The xattr_handler->get() callback was changed to take
+                       dnl # a dentry instead of an inode, and a handler_flags
+                       dnl # argument was added.
+                       dnl #
+                       AC_MSG_RESULT(no)
+                       AC_MSG_CHECKING([whether xattr_handler->get() wants dentry])
+                       ZFS_LINUX_TRY_COMPILE([
+                               #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,
+                               };
+                       ],[
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_XATTR_GET_DENTRY, 1,
+                                   [xattr_handler->get() wants dentry])
+                       ],[
+                               dnl #
+                               dnl # 2.6.32 API
+                               dnl #
+                               AC_MSG_RESULT(no)
+                               AC_MSG_CHECKING(
+                                   [whether xattr_handler->get() wants inode])
+                               ZFS_LINUX_TRY_COMPILE([
+                                       #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,
+                                       };
+                               ],[
+                               ],[
+                                       AC_MSG_RESULT(yes)
+                                       AC_DEFINE(HAVE_XATTR_GET_INODE, 1,
+                                           [xattr_handler->get() wants inode])
+                               ],[
+                                       AC_MSG_ERROR([no; please file a bug report])
+                               ])
+                       ])
+               ])
+       ])
+])
+
+dnl #
+dnl # Supported xattr handler set() interfaces checked newest to oldest.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [
+       dnl #
+       dnl # 4.7 API change,
+       dnl # The xattr_handler->set() callback was changed to take both
+       dnl # dentry and inode.
+       dnl #
+       AC_MSG_CHECKING([whether xattr_handler->set() wants both dentry and inode])
+       ZFS_LINUX_TRY_COMPILE([
+               #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,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1,
+                   [xattr_handler->set() wants both dentry and inode])
+       ],[
+               dnl #
+               dnl # 4.4 API change,
+               dnl # The xattr_handler->set() callback was changed to take a
+               dnl # xattr_handler, and handler_flags argument was removed and
+               dnl # should be accessed by handler->flags.
+               dnl #
+               AC_MSG_CHECKING([whether xattr_handler->set() wants xattr_handler])
+               ZFS_LINUX_TRY_COMPILE([
+                       #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,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1,
+                           [xattr_handler->set() wants xattr_handler])
+               ],[
+                       dnl #
+                       dnl # 2.6.33 API change,
+                       dnl # The xattr_handler->set() callback was changed to take a
+                       dnl # dentry instead of an inode, and a handler_flags
+                       dnl # argument was added.
+                       dnl #
+                       AC_MSG_RESULT(no)
+                       AC_MSG_CHECKING([whether xattr_handler->set() wants dentry])
+                       ZFS_LINUX_TRY_COMPILE([
+                               #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,
+                               };
+                       ],[
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1,
+                                   [xattr_handler->set() wants dentry])
+                       ],[
+                               dnl #
+                               dnl # 2.6.32 API
+                               dnl #
+                               AC_MSG_RESULT(no)
+                               AC_MSG_CHECKING(
+                                   [whether xattr_handler->set() wants inode])
+                               ZFS_LINUX_TRY_COMPILE([
+                                       #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,
+                                       };
+                               ],[
+                               ],[
+                                       AC_MSG_RESULT(yes)
+                                       AC_DEFINE(HAVE_XATTR_SET_INODE, 1,
+                                           [xattr_handler->set() wants inode])
+                               ],[
+                                       AC_MSG_ERROR([no; please file a bug report])
+                               ])
+                       ])
+               ])
+       ])
+])
+
+dnl #
+dnl # Supported xattr handler list() interfaces checked newest to oldest.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_LIST], [
+       dnl # 4.5 API change,
+       dnl # The xattr_handler->list() callback was changed to take only a
+       dnl # dentry and it only needs to return if it's accessable.
+       AC_MSG_CHECKING([whether xattr_handler->list() wants simple])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/xattr.h>
+
+               bool list(struct dentry *dentry) { return 0; }
+               static const struct xattr_handler
+                   xops __attribute__ ((unused)) = {
+                       .list = list,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_XATTR_LIST_SIMPLE, 1,
+                   [xattr_handler->list() wants simple])
+       ],[
+               dnl #
+               dnl # 4.4 API change,
+               dnl # The xattr_handler->list() callback was changed to take a
+               dnl # xattr_handler, and handler_flags argument was removed
+               dnl # and should be accessed by handler->flags.
+               dnl #
+               AC_MSG_RESULT(no)
+               AC_MSG_CHECKING(
+                   [whether xattr_handler->list() wants xattr_handler])
+               ZFS_LINUX_TRY_COMPILE([
+                       #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,
+                       };
+               ],[
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_XATTR_LIST_HANDLER, 1,
+                           [xattr_handler->list() wants xattr_handler])
+               ],[
+                       dnl #
+                       dnl # 2.6.33 API change,
+                       dnl # The xattr_handler->list() callback was changed
+                       dnl # to take a dentry instead of an inode, and a
+                       dnl # handler_flags argument was added.
+                       dnl #
+                       AC_MSG_RESULT(no)
+                       AC_MSG_CHECKING(
+                           [whether xattr_handler->list() wants dentry])
+                       ZFS_LINUX_TRY_COMPILE([
+                               #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,
+                               };
+                       ],[
+                       ],[
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(HAVE_XATTR_LIST_DENTRY, 1,
+                                   [xattr_handler->list() wants dentry])
+                       ],[
+                               dnl #
+                               dnl # 2.6.32 API
+                               dnl #
+                               AC_MSG_RESULT(no)
+                               AC_MSG_CHECKING(
+                                   [whether xattr_handler->list() wants inode])
+                               ZFS_LINUX_TRY_COMPILE([
+                                       #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,
+                                       };
+                               ],[
+                               ],[
+                                       AC_MSG_RESULT(yes)
+                                       AC_DEFINE(HAVE_XATTR_LIST_INODE, 1,
+                                           [xattr_handler->list() wants inode])
+                               ],[
+                                       AC_MSG_ERROR(
+                                           [no; please file a bug report])
+                               ])
+                       ])
+               ])
+       ])
+])
+
+dnl #
+dnl # 3.7 API change,
+dnl # The posix_acl_{from,to}_xattr functions gained a new
+dnl # parameter: user_ns
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_POSIX_ACL_FROM_XATTR_USERNS], [
+       AC_MSG_CHECKING([whether posix_acl_from_xattr() needs user_ns])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/cred.h>
+               #include <linux/fs.h>
+               #include <linux/posix_acl_xattr.h>
+       ],[
+               posix_acl_from_xattr(&init_user_ns, NULL, 0);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_POSIX_ACL_FROM_XATTR_USERNS, 1,
+                   [posix_acl_from_xattr() needs user_ns])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
diff --git a/zfs/config/kernel.m4 b/zfs/config/kernel.m4
new file mode 100644 (file)
index 0000000..5b8abf7
--- /dev/null
@@ -0,0 +1,697 @@
+dnl #
+dnl # Default ZFS kernel configuration 
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
+       ZFS_AC_KERNEL
+       ZFS_AC_SPL
+       ZFS_AC_TEST_MODULE
+       ZFS_AC_KERNEL_CONFIG
+       ZFS_AC_KERNEL_DECLARE_EVENT_CLASS
+       ZFS_AC_KERNEL_CURRENT_BIO_TAIL
+       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
+       ZFS_AC_KERNEL_LOOKUP_BDEV
+       ZFS_AC_KERNEL_INVALIDATE_BDEV_ARGS
+       ZFS_AC_KERNEL_BDEV_LOGICAL_BLOCK_SIZE
+       ZFS_AC_KERNEL_BDEV_PHYSICAL_BLOCK_SIZE
+       ZFS_AC_KERNEL_BIO_BVEC_ITER
+       ZFS_AC_KERNEL_BIO_FAILFAST_DTD
+       ZFS_AC_KERNEL_REQ_FAILFAST_MASK
+       ZFS_AC_KERNEL_REQ_OP_DISCARD
+       ZFS_AC_KERNEL_REQ_OP_SECURE_ERASE
+       ZFS_AC_KERNEL_REQ_OP_FLUSH
+       ZFS_AC_KERNEL_BIO_BI_OPF
+       ZFS_AC_KERNEL_BIO_END_IO_T_ARGS
+       ZFS_AC_KERNEL_BIO_RW_BARRIER
+       ZFS_AC_KERNEL_BIO_RW_DISCARD
+       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_HAVE_BIO_SET_OP_ATTRS
+       ZFS_AC_KERNEL_GENERIC_READLINK_GLOBAL
+       ZFS_AC_KERNEL_DISCARD_GRANULARITY
+       ZFS_AC_KERNEL_CONST_XATTR_HANDLER
+       ZFS_AC_KERNEL_XATTR_HANDLER_NAME
+       ZFS_AC_KERNEL_XATTR_HANDLER_GET
+       ZFS_AC_KERNEL_XATTR_HANDLER_SET
+       ZFS_AC_KERNEL_XATTR_HANDLER_LIST
+       ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE
+       ZFS_AC_KERNEL_POSIX_ACL_FROM_XATTR_USERNS
+       ZFS_AC_KERNEL_POSIX_ACL_RELEASE
+       ZFS_AC_KERNEL_SET_CACHED_ACL_USABLE
+       ZFS_AC_KERNEL_POSIX_ACL_CHMOD
+       ZFS_AC_KERNEL_POSIX_ACL_EQUIV_MODE_WANTS_UMODE_T
+       ZFS_AC_KERNEL_POSIX_ACL_VALID_WITH_NS
+       ZFS_AC_KERNEL_INODE_OPERATIONS_PERMISSION
+       ZFS_AC_KERNEL_INODE_OPERATIONS_PERMISSION_WITH_NAMEIDATA
+       ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL
+       ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL_WITH_FLAGS
+       ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL
+       ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL
+       ZFS_AC_KERNEL_GET_ACL_HANDLE_CACHE
+       ZFS_AC_KERNEL_SHOW_OPTIONS
+       ZFS_AC_KERNEL_FILE_INODE
+       ZFS_AC_KERNEL_FSYNC
+       ZFS_AC_KERNEL_EVICT_INODE
+       ZFS_AC_KERNEL_DIRTY_INODE_WITH_FLAGS
+       ZFS_AC_KERNEL_NR_CACHED_OBJECTS
+       ZFS_AC_KERNEL_FREE_CACHED_OBJECTS
+       ZFS_AC_KERNEL_FALLOCATE
+       ZFS_AC_KERNEL_AIO_FSYNC
+       ZFS_AC_KERNEL_MKDIR_UMODE_T
+       ZFS_AC_KERNEL_LOOKUP_NAMEIDATA
+       ZFS_AC_KERNEL_CREATE_NAMEIDATA
+       ZFS_AC_KERNEL_GET_LINK
+       ZFS_AC_KERNEL_PUT_LINK
+       ZFS_AC_KERNEL_TRUNCATE_RANGE
+       ZFS_AC_KERNEL_AUTOMOUNT
+       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
+       ZFS_AC_KERNEL_D_PRUNE_ALIASES
+       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
+       ZFS_AC_KERNEL_MOUNT_NODEV
+       ZFS_AC_KERNEL_SHRINK
+       ZFS_AC_KERNEL_SHRINK_CONTROL_HAS_NID
+       ZFS_AC_KERNEL_S_INSTANCES_LIST_HEAD
+       ZFS_AC_KERNEL_S_D_OP
+       ZFS_AC_KERNEL_BDI_SETUP_AND_REGISTER
+       ZFS_AC_KERNEL_SET_NLINK
+       ZFS_AC_KERNEL_ELEVATOR_CHANGE
+       ZFS_AC_KERNEL_5ARG_SGET
+       ZFS_AC_KERNEL_LSEEK_EXECUTE
+       ZFS_AC_KERNEL_VFS_ITERATE
+       ZFS_AC_KERNEL_VFS_RW_ITERATE
+       ZFS_AC_KERNEL_GENERIC_WRITE_CHECKS
+       ZFS_AC_KERNEL_KMAP_ATOMIC_ARGS
+       ZFS_AC_KERNEL_FOLLOW_DOWN_ONE
+       ZFS_AC_KERNEL_MAKE_REQUEST_FN
+       ZFS_AC_KERNEL_GENERIC_IO_ACCT
+       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"
+       ])
+       AC_SUBST(KERNELMAKE_PARAMS)
+
+
+       dnl # -Wall -fno-strict-aliasing -Wstrict-prototypes and other
+       dnl # compiler options are added by the kernel build system.
+       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\\\""
+
+       AC_SUBST(KERNELCPPFLAGS)
+])
+
+dnl #
+dnl # Detect name used for Module.symvers file in kernel
+dnl #
+AC_DEFUN([ZFS_AC_MODULE_SYMVERS], [
+       modpost=$LINUX/scripts/Makefile.modpost
+       AC_MSG_CHECKING([kernel file name for module symbols])
+       AS_IF([test "x$enable_linux_builtin" != xyes -a -f "$modpost"], [
+               AS_IF([grep -q Modules.symvers $modpost], [
+                       LINUX_SYMBOLS=Modules.symvers
+               ], [
+                       LINUX_SYMBOLS=Module.symvers
+               ])
+
+               AS_IF([test ! -f "$LINUX_OBJ/$LINUX_SYMBOLS"], [
+                       AC_MSG_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.])
+               ])
+       ], [
+               LINUX_SYMBOLS=NONE
+       ])
+       AC_MSG_RESULT($LINUX_SYMBOLS)
+       AC_SUBST(LINUX_SYMBOLS)
+])
+
+dnl #
+dnl # Detect the kernel to be built against
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL], [
+       AC_ARG_WITH([linux],
+               AS_HELP_STRING([--with-linux=PATH],
+               [Path to kernel source]),
+               [kernelsrc="$withval"])
+
+       AC_ARG_WITH(linux-obj,
+               AS_HELP_STRING([--with-linux-obj=PATH],
+               [Path to kernel build objects]),
+               [kernelbuild="$withval"])
+
+       AC_MSG_CHECKING([kernel source directory])
+       AS_IF([test -z "$kernelsrc"], [
+               AS_IF([test -e "/lib/modules/$(uname -r)/source"], [
+                       headersdir="/lib/modules/$(uname -r)/source"
+                       sourcelink=$(readlink -f "$headersdir")
+               ], [test -e "/lib/modules/$(uname -r)/build"], [
+                       headersdir="/lib/modules/$(uname -r)/build"
+                       sourcelink=$(readlink -f "$headersdir")
+               ], [
+                       sourcelink=$(ls -1d /usr/src/kernels/* \
+                                    /usr/src/linux-* \
+                                    2>/dev/null | grep -v obj | tail -1)
+               ])
+
+               AS_IF([test -n "$sourcelink" && test -e ${sourcelink}], [
+                       kernelsrc=`readlink -f ${sourcelink}`
+               ], [
+                       kernelsrc="[Not found]"
+               ])
+       ], [
+               AS_IF([test "$kernelsrc" = "NONE"], [
+                       kernsrcver=NONE
+               ])
+       ])
+
+       AC_MSG_RESULT([$kernelsrc])
+       AS_IF([test ! -d "$kernelsrc"], [
+               AC_MSG_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.])
+       ])
+
+       AC_MSG_CHECKING([kernel build directory])
+       AS_IF([test -z "$kernelbuild"], [
+               AS_IF([test -e "/lib/modules/$(uname -r)/build"], [
+                       kernelbuild=`readlink -f /lib/modules/$(uname -r)/build`
+               ], [test -d ${kernelsrc}-obj/${target_cpu}/${target_cpu}], [
+                       kernelbuild=${kernelsrc}-obj/${target_cpu}/${target_cpu}
+               ], [test -d ${kernelsrc}-obj/${target_cpu}/default], [
+                       kernelbuild=${kernelsrc}-obj/${target_cpu}/default
+               ], [test -d `dirname ${kernelsrc}`/build-${target_cpu}], [
+                       kernelbuild=`dirname ${kernelsrc}`/build-${target_cpu}
+               ], [
+                       kernelbuild=${kernelsrc}
+               ])
+       ])
+       AC_MSG_RESULT([$kernelbuild])
+
+       AC_MSG_CHECKING([kernel source version])
+       utsrelease1=$kernelbuild/include/linux/version.h
+       utsrelease2=$kernelbuild/include/linux/utsrelease.h
+       utsrelease3=$kernelbuild/include/generated/utsrelease.h
+       AS_IF([test -r $utsrelease1 && fgrep -q UTS_RELEASE $utsrelease1], [
+               utsrelease=linux/version.h
+       ], [test -r $utsrelease2 && fgrep -q UTS_RELEASE $utsrelease2], [
+               utsrelease=linux/utsrelease.h
+       ], [test -r $utsrelease3 && fgrep -q UTS_RELEASE $utsrelease3], [
+               utsrelease=generated/utsrelease.h
+       ])
+
+       AS_IF([test "$utsrelease"], [
+               kernsrcver=`(echo "#include <$utsrelease>";
+                            echo "kernsrcver=UTS_RELEASE") |
+                            cpp -I $kernelbuild/include |
+                            grep "^kernsrcver=" | cut -d \" -f 2`
+
+               AS_IF([test -z "$kernsrcver"], [
+                       AC_MSG_RESULT([Not found])
+                       AC_MSG_ERROR([*** Cannot determine kernel version.])
+               ])
+       ], [
+               AC_MSG_RESULT([Not found])
+               if test "x$enable_linux_builtin" != xyes; then
+                       AC_MSG_ERROR([*** Cannot find UTS_RELEASE definition.])
+               else
+                       AC_MSG_ERROR([
+       *** Cannot find UTS_RELEASE definition.
+       *** Please run 'make prepare' inside the kernel source tree.])
+               fi
+       ])
+
+       AC_MSG_RESULT([$kernsrcver])
+
+       LINUX=${kernelsrc}
+       LINUX_OBJ=${kernelbuild}
+       LINUX_VERSION=${kernsrcver}
+
+       AC_SUBST(LINUX)
+       AC_SUBST(LINUX_OBJ)
+       AC_SUBST(LINUX_VERSION)
+
+       ZFS_AC_MODULE_SYMVERS
+])
+
+
+dnl #
+dnl # Detect the SPL module to be built against
+dnl #
+AC_DEFUN([ZFS_AC_SPL], [
+       AC_ARG_WITH([spl],
+               AS_HELP_STRING([--with-spl=PATH],
+               [Path to spl source]),
+               [splsrc="$withval"])
+
+       AC_ARG_WITH([spl-obj],
+               AS_HELP_STRING([--with-spl-obj=PATH],
+               [Path to spl build objects]),
+               [splbuild="$withval"])
+
+       AC_ARG_WITH([spl-timeout],
+               AS_HELP_STRING([--with-spl-timeout=SECS],
+               [Wait SECS for SPL header and symver file @<:@default=0@:>@]),
+               [timeout="$withval"], [timeout=0])
+
+       dnl #
+       dnl # The existence of spl.release.in is used to identify a valid
+       dnl # source directory.  In order of preference:
+       dnl #
+       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"
+
+       AC_MSG_CHECKING([spl source directory])
+       AS_IF([test -z "${splsrc}"], [
+               AS_IF([ test -e "${splsrc0}/spl.release.in"], [
+                       splsrc=${splsrc0}
+               ], [ test -e "${splsrc1}/spl.release.in"], [
+                       splsrc=${splsrc1}
+               ], [ test -e "${splsrc2}/spl.release.in"], [
+                       splsrc=${splsrc2}
+               ], [ test -e "${splsrc3}/spl.release.in"], [
+                       splsrc=$(readlink -f "${splsrc3}")
+               ], [ test -e "${splsrc4}/spl.release.in" ], [
+                       splsrc=${splsrc4}
+               ], [ test -e "${splsrc5}/spl.release.in"], [
+                       splsrc=$(readlink -f "${splsrc5}")
+               ], [ test -e "${splsrc6}/spl.release.in" ], [
+                       splsrc=${splsrc6}
+               ], [
+                       splsrc="[Not found]"
+               ])
+       ], [
+               AS_IF([test "$splsrc" = "NONE"], [
+                       splbuild=NONE
+                       splsrcver=NONE
+               ])
+       ])
+
+       AC_MSG_RESULT([$splsrc])
+       AS_IF([ test ! -e "$splsrc/spl.release.in"], [
+               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.])
+       ])
+
+       dnl #
+       dnl # The existence of the spl_config.h is used to identify a valid
+       dnl # spl object directory.  In many cases the object and source
+       dnl # directory are the same, however the objects may also reside
+       dnl # is a subdirectory named after the kernel version.
+       dnl #
+       dnl # This file is supposed to be available after DKMS finishes
+       dnl # building the SPL kernel module for the target kernel.  The
+       dnl # '--with-spl-timeout' option can be passed to pause here,
+       dnl # waiting for the file to appear from a concurrently building
+       dnl # SPL package.
+       dnl #
+       AC_MSG_CHECKING([spl build directory])
+       while true; do
+               AS_IF([test -z "$splbuild"], [
+                       AS_IF([ test -e "${splsrc}/${LINUX_VERSION}/spl_config.h" ], [
+                               splbuild="${splsrc}/${LINUX_VERSION}"
+                       ], [ test -e "${splsrc}/spl_config.h" ], [
+                               splbuild="${splsrc}"
+                       ], [ find -L "${splsrc}" -name spl_config.h 2> /dev/null | grep -wq spl_config.h ], [
+                               splbuild=$(find -L "${splsrc}" -name spl_config.h | sed 's,/spl_config.h,,')
+                       ], [
+                               splbuild="[Not found]"
+                       ])
+               ])
+               AS_IF([test -e "$splbuild/spl_config.h" -o $timeout -le 0], [
+                       break;
+               ], [
+                       sleep 1
+                       timeout=$((timeout-1))
+               ])
+       done
+
+       AC_MSG_RESULT([$splbuild])
+       AS_IF([ ! test -e "$splbuild/spl_config.h"], [
+               AC_MSG_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.])
+       ])
+
+       AC_MSG_CHECKING([spl source version])
+       AS_IF([test -r $splbuild/spl_config.h &&
+               fgrep -q SPL_META_VERSION $splbuild/spl_config.h], [
+
+               splsrcver=`(echo "#include <spl_config.h>";
+                           echo "splsrcver=SPL_META_VERSION-SPL_META_RELEASE") |
+                           cpp -I $splbuild |
+                           grep "^splsrcver=" | tr -d \" | cut -d= -f2`
+       ])
+
+       AS_IF([test -z "$splsrcver"], [
+               AC_MSG_RESULT([Not found])
+               AC_MSG_ERROR([
+       *** Cannot determine the version of the spl source.
+       *** Please prepare the spl source before running this script])
+       ])
+
+       AC_MSG_RESULT([$splsrcver])
+
+       SPL=${splsrc}
+       SPL_OBJ=${splbuild}
+       SPL_VERSION=${splsrcver}
+
+       AC_SUBST(SPL)
+       AC_SUBST(SPL_OBJ)
+       AC_SUBST(SPL_VERSION)
+
+       dnl #
+       dnl # Detect the name used for the SPL Module.symvers file.  If one
+       dnl # does not exist this is likely because the SPL has been configured
+       dnl # but not built.  The '--with-spl-timeout' option can be passed
+       dnl # to pause here, waiting for the file to appear from a concurrently
+       dnl # building SPL package.  If the file does not appear in time, a good
+       dnl # guess is made as to what this file will be named based on what it
+       dnl # is named in the kernel build products.  This file will first be
+       dnl # used at link time so if the guess is wrong the build will fail
+       dnl # then.  This unfortunately means the ZFS package does not contain a
+       dnl # reliable mechanism to detect symbols exported by the SPL at
+       dnl # configure time.
+       dnl #
+       AC_MSG_CHECKING([spl file name for module symbols])
+       SPL_SYMBOLS=NONE
+
+       while true; do
+               AS_IF([test -r $SPL_OBJ/Module.symvers], [
+                       SPL_SYMBOLS=Module.symvers
+               ], [test -r $SPL_OBJ/Modules.symvers], [
+                       SPL_SYMBOLS=Modules.symvers
+               ], [test -r $SPL_OBJ/module/Module.symvers], [
+                       SPL_SYMBOLS=Module.symvers
+               ], [test -r $SPL_OBJ/module/Modules.symvers], [
+                       SPL_SYMBOLS=Modules.symvers
+               ])
+
+               AS_IF([test $SPL_SYMBOLS != NONE -o $timeout -le 0], [
+                       break;
+               ], [
+                       sleep 1
+                       timeout=$((timeout-1))
+               ])
+       done
+
+       AS_IF([test "$SPL_SYMBOLS" = NONE], [
+               SPL_SYMBOLS=$LINUX_SYMBOLS
+       ])
+
+       AC_MSG_RESULT([$SPL_SYMBOLS])
+       AC_SUBST(SPL_SYMBOLS)
+])
+
+dnl #
+dnl # Basic toolchain sanity check.
+dnl #
+AC_DEFUN([ZFS_AC_TEST_MODULE], [
+       AC_MSG_CHECKING([whether modules can be built])
+       ZFS_LINUX_TRY_COMPILE([],[],[
+               AC_MSG_RESULT([yes])
+       ],[
+               AC_MSG_RESULT([no])
+               if test "x$enable_linux_builtin" != xyes; then
+                       AC_MSG_ERROR([*** Unable to build an empty module.])
+               else
+                       AC_MSG_ERROR([
+       *** Unable to build an empty module.
+       *** Please run 'make scripts' inside the kernel source tree.])
+               fi
+       ])
+])
+
+dnl #
+dnl # Certain kernel build options are not supported.  These must be
+dnl # detected at configure time and cause a build failure.  Otherwise
+dnl # modules may be successfully built that behave incorrectly.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CONFIG], [
+       AS_IF([test "x$cross_compiling" != xyes], [
+               AC_RUN_IFELSE([
+                       AC_LANG_PROGRAM([
+                               #include "$LINUX/include/linux/license.h"
+                       ], [
+                               return !license_is_gpl_compatible("$ZFS_META_LICENSE");
+                       ])
+               ], [
+                       AC_DEFINE([ZFS_IS_GPL_COMPATIBLE], [1],
+                           [Define to 1 if GPL-only symbols can be used])
+               ], [
+               ])
+       ])
+
+       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 #
+dnl # This is typically only set for debug kernels because it comes with
+dnl # a performance penalty.  However, when it is set it maps the non-GPL
+dnl # symbol mutex_lock() to the GPL-only mutex_lock_nested() symbol.
+dnl # This will cause a failure at link time which we'd rather know about
+dnl # at compile time.
+dnl #
+dnl # Since we plan to pursue making mutex_lock_nested() a non-GPL symbol
+dnl # with the upstream community we add a check to detect this case.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC], [
+
+       ZFS_LINUX_CONFIG([DEBUG_LOCK_ALLOC], [
+               AC_MSG_CHECKING([whether mutex_lock() is GPL-only])
+               tmp_flags="$EXTRA_KCFLAGS"
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/module.h>
+                       #include <linux/mutex.h>
+
+                       MODULE_LICENSE("$ZFS_META_LICENSE");
+               ],[
+                       struct mutex lock;
+
+                       mutex_init(&lock);
+                       mutex_lock(&lock);
+                       mutex_unlock(&lock);
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_MSG_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.])
+               ])
+               EXTRA_KCFLAGS="$tmp_flags"
+       ], [])
+])
+
+dnl #
+dnl # ZFS_LINUX_CONFTEST_H
+dnl #
+AC_DEFUN([ZFS_LINUX_CONFTEST_H], [
+cat - <<_ACEOF >conftest.h
+$1
+_ACEOF
+])
+
+dnl #
+dnl # ZFS_LINUX_CONFTEST_C
+dnl #
+AC_DEFUN([ZFS_LINUX_CONFTEST_C], [
+cat confdefs.h - <<_ACEOF >conftest.c
+$1
+_ACEOF
+])
+
+dnl #
+dnl # ZFS_LANG_PROGRAM(C)([PROLOGUE], [BODY])
+dnl #
+m4_define([ZFS_LANG_PROGRAM], [
+$1
+int
+main (void)
+{
+dnl Do *not* indent the following line: there may be CPP directives.
+dnl Don't move the `;' right after for the same reason.
+$2
+  ;
+  return 0;
+}
+])
+
+dnl #
+dnl # ZFS_LINUX_COMPILE_IFELSE / like AC_COMPILE_IFELSE
+dnl #
+AC_DEFUN([ZFS_LINUX_COMPILE_IFELSE], [
+       m4_ifvaln([$1], [ZFS_LINUX_CONFTEST_C([$1])])
+       m4_ifvaln([$6], [ZFS_LINUX_CONFTEST_H([$6])], [ZFS_LINUX_CONFTEST_H([])])
+       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
+       AS_IF(
+               [AC_TRY_COMMAND(cp conftest.c conftest.h build && make [$2] -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag) >/dev/null && AC_TRY_COMMAND([$3])],
+               [$4],
+               [_AC_MSG_LOG_CONFTEST m4_ifvaln([$5],[$5])]
+       )
+       rm -Rf build
+])
+
+dnl #
+dnl # ZFS_LINUX_TRY_COMPILE like AC_TRY_COMPILE
+dnl #
+AC_DEFUN([ZFS_LINUX_TRY_COMPILE],
+       [ZFS_LINUX_COMPILE_IFELSE(
+       [AC_LANG_SOURCE([ZFS_LANG_PROGRAM([[$1]], [[$2]])])],
+       [modules],
+       [test -s build/conftest.o],
+       [$3], [$4])
+])
+
+dnl #
+dnl # ZFS_LINUX_CONFIG
+dnl #
+AC_DEFUN([ZFS_LINUX_CONFIG],
+       [AC_MSG_CHECKING([whether kernel was built with CONFIG_$1])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/module.h>
+       ],[
+               #ifndef CONFIG_$1
+               #error CONFIG_$1 not #defined
+               #endif
+       ],[
+               AC_MSG_RESULT([yes])
+               $2
+       ],[
+               AC_MSG_RESULT([no])
+               $3
+       ])
+])
+
+dnl #
+dnl # ZFS_CHECK_SYMBOL_EXPORT
+dnl # check symbol exported or not
+dnl #
+AC_DEFUN([ZFS_CHECK_SYMBOL_EXPORT], [
+       grep -q -E '[[[:space:]]]$1[[[:space:]]]' \
+               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in $2; do
+                       grep -q -E "EXPORT_SYMBOL.*($1)" \
+                               "$LINUX/$file" 2>/dev/null
+                       rc=$?
+                       if test $rc -eq 0; then
+                               export=1
+                               break;
+                       fi
+               done
+               if test $export -eq 0; then :
+                       $4
+               else :
+                       $3
+               fi
+       else :
+               $3
+       fi
+])
+
+dnl #
+dnl # ZFS_LINUX_TRY_COMPILE_SYMBOL
+dnl # like ZFS_LINUX_TRY_COMPILE, except ZFS_CHECK_SYMBOL_EXPORT
+dnl # is called if not compiling for builtin
+dnl #
+AC_DEFUN([ZFS_LINUX_TRY_COMPILE_SYMBOL], [
+       ZFS_LINUX_TRY_COMPILE([$1], [$2], [rc=0], [rc=1])
+       if test $rc -ne 0; then :
+               $6
+       else
+               if test "x$enable_linux_builtin" != xyes; then
+                       ZFS_CHECK_SYMBOL_EXPORT([$3], [$4], [rc=0], [rc=1])
+               fi
+               if test $rc -ne 0; then :
+                       $6
+               else :
+                       $5
+               fi
+       fi
+])
+
+dnl #
+dnl # ZFS_LINUX_TRY_COMPILE_HEADER
+dnl # like ZFS_LINUX_TRY_COMPILE, except the contents conftest.h are
+dnl # provided via the fifth parameter
+dnl #
+AC_DEFUN([ZFS_LINUX_TRY_COMPILE_HEADER],
+       [ZFS_LINUX_COMPILE_IFELSE(
+       [AC_LANG_SOURCE([ZFS_LANG_PROGRAM([[$1]], [[$2]])])],
+       [modules],
+       [test -s build/conftest.o],
+       [$3], [$4], [$5])
+])
diff --git a/zfs/config/libtool.m4 b/zfs/config/libtool.m4
new file mode 100644 (file)
index 0000000..ee80844
--- /dev/null
@@ -0,0 +1,8387 @@
+# 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
new file mode 100644 (file)
index 0000000..a736cf9
--- /dev/null
@@ -0,0 +1,11156 @@
+#! /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-2"
+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'
+
+
+# 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 Debian-2.4.6-2
+       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
new file mode 100644 (file)
index 0000000..94b0829
--- /dev/null
@@ -0,0 +1,437 @@
+# 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
new file mode 100644 (file)
index 0000000..48bc934
--- /dev/null
@@ -0,0 +1,124 @@
+# 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
new file mode 100644 (file)
index 0000000..fa04b52
--- /dev/null
@@ -0,0 +1,23 @@
+# 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
new file mode 100644 (file)
index 0000000..c6b26f8
--- /dev/null
@@ -0,0 +1,99 @@
+# 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
new file mode 100755 (executable)
index 0000000..f62bbae
--- /dev/null
@@ -0,0 +1,215 @@
+#! /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/mount-helper.m4 b/zfs/config/mount-helper.m4
new file mode 100644 (file)
index 0000000..0a6c767
--- /dev/null
@@ -0,0 +1,8 @@
+AC_DEFUN([ZFS_AC_CONFIG_USER_MOUNT_HELPER], [
+       AC_ARG_WITH(mounthelperdir,
+               AC_HELP_STRING([--with-mounthelperdir=DIR],
+               [install mount.zfs in dir [[/sbin]]]),
+               mounthelperdir=$withval,mounthelperdir=/sbin)
+
+       AC_SUBST(mounthelperdir)
+])
diff --git a/zfs/config/rpm.am b/zfs/config/rpm.am
new file mode 100644 (file)
index 0000000..51a20b3
--- /dev/null
@@ -0,0 +1,87 @@
+###############################################################################
+# 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.
+###############################################################################
+
+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)
diff --git a/zfs/config/tgz.am b/zfs/config/tgz.am
new file mode 100644 (file)
index 0000000..2997b1d
--- /dev/null
@@ -0,0 +1,32 @@
+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
+if CONFIG_KERNEL
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --scripts --to-tgz $$pkg1; \
+       $(RM) $$pkg1
+endif
+
+tgz-utils: tgz-local rpm-utils
+if CONFIG_USER
+       name=${PACKAGE}; \
+       version=${VERSION}-${RELEASE}; \
+       arch=`$(RPM) -qp $${name}-$${version}.src.rpm --qf %{arch} | tail -1`; \
+       pkg1=$${name}-$${version}.$${arch}.rpm; \
+       pkg2=$${name}-devel-$${version}.$${arch}.rpm; \
+       pkg3=$${name}-test-$${version}.$${arch}.rpm; \
+       fakeroot $(ALIEN) --scripts --to-tgz $$pkg1 $$pkg2 $$pkg3; \
+       $(RM) $$pkg1 $$pkg2 $$pkg3
+endif
+
+tgz: tgz-kmod tgz-utils
diff --git a/zfs/config/user-arch.m4 b/zfs/config/user-arch.m4
new file mode 100644 (file)
index 0000000..fcc566f
--- /dev/null
@@ -0,0 +1,19 @@
+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-dracut.m4 b/zfs/config/user-dracut.m4
new file mode 100644 (file)
index 0000000..95f800b
--- /dev/null
@@ -0,0 +1,22 @@
+AC_DEFUN([ZFS_AC_CONFIG_USER_DRACUT], [
+       AC_MSG_CHECKING(for dracut directory)
+       AC_ARG_WITH([dracutdir],
+               AC_HELP_STRING([--with-dracutdir=DIR],
+               [install dracut helpers @<:@default=check@:>@]),
+               [dracutdir=$withval],
+               [dracutdir=check])
+
+       AS_IF([test "x$dracutdir" = xcheck], [
+               path1=/usr/share/dracut
+               path2=/usr/lib/dracut
+               default=$path2
+
+               AS_IF([test -d "$path1"], [dracutdir="$path1"], [
+                       AS_IF([test -d "$path2"], [dracutdir="$path2"],
+                               [dracutdir="$default"])
+               ])
+       ])
+
+       AC_SUBST(dracutdir)
+       AC_MSG_RESULT([$dracutdir])
+])
diff --git a/zfs/config/user-frame-larger-than.m4 b/zfs/config/user-frame-larger-than.m4
new file mode 100644 (file)
index 0000000..e0828ec
--- /dev/null
@@ -0,0 +1,22 @@
+dnl #
+dnl # Check if gcc supports -Wframe-larger-than=<size> option.
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN], [
+       AC_MSG_CHECKING([for -Wframe-larger-than=<size> support])
+
+       saved_flags="$CFLAGS"
+       CFLAGS="$CFLAGS -Wframe-larger-than=1024"
+
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])],
+       [
+               FRAME_LARGER_THAN=-Wframe-larger-than=1024
+               AC_MSG_RESULT([yes])
+       ],
+       [
+               FRAME_LARGER_THAN=
+               AC_MSG_RESULT([no])
+       ])
+
+       CFLAGS="$saved_flags"
+        AC_SUBST([FRAME_LARGER_THAN])
+])
diff --git a/zfs/config/user-libblkid.m4 b/zfs/config/user-libblkid.m4
new file mode 100644 (file)
index 0000000..2dd2623
--- /dev/null
@@ -0,0 +1,113 @@
+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 #
+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])])
+                       ])
+
+                       LIBS="$saved_LIBS"
+               ],
+               [
+                       AS_IF([test "x$with_blkid" != xcheck],
+                               [AC_MSG_FAILURE(
+                               [--with-blkid given but unavailable])])
+               ]
+               [])
+       ])
+])
diff --git a/zfs/config/user-libuuid.m4 b/zfs/config/user-libuuid.m4
new file mode 100644 (file)
index 0000000..aba375a
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # Check for libuuid
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_LIBUUID], [
+       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([
+       *** uuid_generate() missing, libuuid-devel package required])])
+
+       AC_CHECK_LIB([uuid], [uuid_is_null], [], [AC_MSG_FAILURE([
+       *** uuid_is_null() missing, libuuid-devel package required])])
+
+       AC_SUBST([LIBUUID], ["-luuid"])
+       AC_DEFINE([HAVE_LIBUUID], 1, [Define if you have libuuid])
+])
diff --git a/zfs/config/user-runstatedir.m4 b/zfs/config/user-runstatedir.m4
new file mode 100644 (file)
index 0000000..ded1362
--- /dev/null
@@ -0,0 +1,6 @@
+dnl For backwards compatibility; runstatedir added in autoconf 2.70.
+AC_DEFUN([ZFS_AC_CONFIG_USER_RUNSTATEDIR], [
+       if test "x$runstatedir" = x; then
+               AC_SUBST([runstatedir], ['${localstatedir}/run'])
+       fi
+])
diff --git a/zfs/config/user-systemd.m4 b/zfs/config/user-systemd.m4
new file mode 100644 (file)
index 0000000..c2105ab
--- /dev/null
@@ -0,0 +1,35 @@
+AC_DEFUN([ZFS_AC_CONFIG_USER_SYSTEMD], [
+       AC_ARG_ENABLE(systemd,
+               AC_HELP_STRING([--enable-systemd],
+               [install systemd unit/preset files [[default: yes]]]),
+               [],enable_systemd=yes)
+
+       AC_ARG_WITH(systemdunitdir,
+               AC_HELP_STRING([--with-systemdunitdir=DIR],
+               [install systemd unit files in dir [[/usr/lib/systemd/system]]]),
+               systemdunitdir=$withval,systemdunitdir=/usr/lib/systemd/system)
+
+       AC_ARG_WITH(systemdpresetdir,
+               AC_HELP_STRING([--with-systemdpresetdir=DIR],
+               [install systemd preset files in dir [[/usr/lib/systemd/system-preset]]]),
+               systemdpresetdir=$withval,systemdpresetdir=/usr/lib/systemd/system-preset)
+
+       AC_ARG_WITH(systemdmodulesloaddir,
+               AC_HELP_STRING([--with-systemdmodulesloaddir=DIR],
+               [install systemd module load files into dir [[/usr/lib/modules-load.d]]]),
+               systemdmoduleloaddir=$withval,systemdmodulesloaddir=/usr/lib/modules-load.d)
+
+
+       AS_IF([test "x$enable_systemd" = xyes],
+               [
+               ZFS_INIT_SYSTEMD=systemd
+               ZFS_MODULE_LOAD=modules-load.d
+               modulesloaddir=$systemdmodulesloaddir
+               ])
+
+       AC_SUBST(ZFS_INIT_SYSTEMD)
+       AC_SUBST(ZFS_MODULE_LOAD)
+       AC_SUBST(systemdunitdir)
+       AC_SUBST(systemdpresetdir)
+       AC_SUBST(modulesloaddir)
+])
diff --git a/zfs/config/user-sysvinit.m4 b/zfs/config/user-sysvinit.m4
new file mode 100644 (file)
index 0000000..65dcc38
--- /dev/null
@@ -0,0 +1,11 @@
+AC_DEFUN([ZFS_AC_CONFIG_USER_SYSVINIT], [
+       AC_ARG_ENABLE(sysvinit,
+               AC_HELP_STRING([--enable-sysvinit],
+               [install SysV init scripts [default: yes]]),
+               [],enable_sysvinit=yes)
+
+       AS_IF([test "x$enable_sysvinit" = xyes],
+               [ZFS_INIT_SYSV=init.d])
+
+       AC_SUBST(ZFS_INIT_SYSV)
+])
diff --git a/zfs/config/user-udev.m4 b/zfs/config/user-udev.m4
new file mode 100644 (file)
index 0000000..65dc79f
--- /dev/null
@@ -0,0 +1,29 @@
+AC_DEFUN([ZFS_AC_CONFIG_USER_UDEV], [
+       AC_MSG_CHECKING(for udev directories)
+       AC_ARG_WITH(udevdir,
+               AC_HELP_STRING([--with-udevdir=DIR],
+               [install udev helpers @<:@default=check@:>@]),
+               [udevdir=$withval],
+               [udevdir=check])
+
+       AS_IF([test "x$udevdir" = xcheck], [
+               path1=/lib/udev
+               path2=/usr/lib/udev
+               default=$path2
+
+               AS_IF([test -d "$path1"], [udevdir="$path1"], [
+                       AS_IF([test -d "$path2"], [udevdir="$path2"],
+                               [udevdir="$default"])
+               ])
+       ])
+
+       AC_ARG_WITH(udevruledir,
+               AC_HELP_STRING([--with-udevruledir=DIR],
+               [install udev rules [[UDEVDIR/rules.d]]]),
+               [udevruledir=$withval],
+               [udevruledir="${udevdir}/rules.d"])
+
+       AC_SUBST(udevdir)
+       AC_SUBST(udevruledir)
+       AC_MSG_RESULT([$udevdir;$udevruledir])
+])
diff --git a/zfs/config/user-zlib.m4 b/zfs/config/user-zlib.m4
new file mode 100644 (file)
index 0000000..a483616
--- /dev/null
@@ -0,0 +1,21 @@
+dnl #
+dnl # Check for zlib
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_ZLIB], [
+       ZLIB=
+
+       AC_CHECK_HEADER([zlib.h], [], [AC_MSG_FAILURE([
+       *** zlib.h missing, zlib-devel package required])])
+
+       AC_CHECK_LIB([z], [compress2], [], [AC_MSG_FAILURE([
+       *** compress2() missing, zlib-devel package required])])
+
+       AC_CHECK_LIB([z], [uncompress], [], [AC_MSG_FAILURE([
+       *** uncompress() missing, zlib-devel package required])])
+
+       AC_CHECK_LIB([z], [crc32], [], [AC_MSG_FAILURE([
+       *** crc32() missing, zlib-devel package required])])
+
+       AC_SUBST([ZLIB], ["-lz"])
+       AC_DEFINE([HAVE_ZLIB], 1, [Define if you have zlib])
+])
diff --git a/zfs/config/user.m4 b/zfs/config/user.m4
new file mode 100644 (file)
index 0000000..a86b552
--- /dev/null
@@ -0,0 +1,20 @@
+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_LIBBLKID
+       ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN
+       ZFS_AC_CONFIG_USER_RUNSTATEDIR
+dnl #
+dnl #  Checks for library functions
+       AC_CHECK_FUNCS([mlockall])
+])
diff --git a/zfs/config/zfs-build.m4 b/zfs/config/zfs-build.m4
new file mode 100644 (file)
index 0000000..facd302
--- /dev/null
@@ -0,0 +1,347 @@
+AC_DEFUN([ZFS_AC_LICENSE], [
+       AC_MSG_CHECKING([zfs author])
+       AC_MSG_RESULT([$ZFS_META_AUTHOR])
+
+       AC_MSG_CHECKING([zfs license])
+       AC_MSG_RESULT([$ZFS_META_LICENSE])
+])
+
+AC_DEFUN([ZFS_AC_DEBUG], [
+       AC_MSG_CHECKING([whether debugging is enabled])
+       AC_ARG_ENABLE([debug],
+               [AS_HELP_STRING([--enable-debug],
+               [Enable generic debug support @<:@default=no@:>@])],
+               [],
+               [enable_debug=no])
+
+       AS_IF([test "x$enable_debug" = xyes],
+       [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG -Werror"
+               HOSTCFLAGS="${HOSTCFLAGS} -DDEBUG -Werror"
+               DEBUG_CFLAGS="-DDEBUG -Werror"
+               DEBUG_STACKFLAGS="-fstack-check"
+               DEBUG_ZFS="_with_debug"
+               AC_DEFINE(ZFS_DEBUG, 1, [zfs debugging enabled])
+       ],
+       [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DNDEBUG "
+               HOSTCFLAGS="${HOSTCFLAGS} -DNDEBUG "
+               DEBUG_CFLAGS="-DNDEBUG"
+               DEBUG_STACKFLAGS=""
+               DEBUG_ZFS="_without_debug"
+       ])
+
+       AC_SUBST(DEBUG_CFLAGS)
+       AC_SUBST(DEBUG_STACKFLAGS)
+       AC_SUBST(DEBUG_ZFS)
+       AC_MSG_RESULT([$enable_debug])
+])
+
+AC_DEFUN([ZFS_AC_DEBUG_DMU_TX], [
+       AC_ARG_ENABLE([debug-dmu-tx],
+               [AS_HELP_STRING([--enable-debug-dmu-tx],
+               [Enable dmu tx validation @<:@default=no@:>@])],
+               [],
+               [enable_debug_dmu_tx=no])
+
+       AS_IF([test "x$enable_debug_dmu_tx" = xyes],
+       [
+               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_DMU_TX"
+               DEBUG_DMU_TX="_with_debug_dmu_tx"
+               AC_DEFINE([DEBUG_DMU_TX], [1],
+               [Define to 1 to enabled dmu tx validation])
+       ],
+       [
+               DEBUG_DMU_TX="_without_debug_dmu_tx"
+       ])
+
+       AC_SUBST(DEBUG_DMU_TX)
+       AC_MSG_CHECKING([whether dmu tx validation is enabled])
+       AC_MSG_RESULT([$enable_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
+])
+
+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],
+               [Config file 'kernel|user|all|srpm']),
+               [ZFS_CONFIG="$withval"])
+       AC_ARG_ENABLE([linux-builtin],
+               [AC_HELP_STRING([--enable-linux-builtin],
+               [Configure for builtin in-tree kernel modules @<:@default=no@:>@])],
+               [],
+               [enable_linux_builtin=no])
+
+       AC_MSG_CHECKING([zfs config])
+       AC_MSG_RESULT([$ZFS_CONFIG]);
+       AC_SUBST(ZFS_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   ;;
+               srpm)                        ;;
+               *)
+               AC_MSG_RESULT([Error!])
+               AC_MSG_ERROR([Bad value "$ZFS_CONFIG" for --with-config,
+                             user kernel|user|all|srpm]) ;;
+       esac
+
+       AM_CONDITIONAL([CONFIG_USER],
+                      [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 ])
+])
+
+dnl #
+dnl # Check for rpm+rpmbuild to build RPM packages.  If these tools
+dnl # are missing it is non-fatal but you will not be able to build
+dnl # RPM packages and will be warned if you try too.
+dnl #
+dnl # By default the generic spec file will be used because it requires
+dnl # minimal dependencies.  Distribution specific spec files can be
+dnl # placed under the 'rpm/<distribution>' directory and enabled using
+dnl # the --with-spec=<distribution> configure option.
+dnl #
+AC_DEFUN([ZFS_AC_RPM], [
+       RPM=rpm
+       RPMBUILD=rpmbuild
+
+       AC_MSG_CHECKING([whether $RPM is available])
+       AS_IF([tmp=$($RPM --version 2>/dev/null)], [
+               RPM_VERSION=$(echo $tmp | $AWK '/RPM/ { print $[3] }')
+               HAVE_RPM=yes
+               AC_MSG_RESULT([$HAVE_RPM ($RPM_VERSION)])
+       ],[
+               HAVE_RPM=no
+               AC_MSG_RESULT([$HAVE_RPM])
+       ])
+
+       AC_MSG_CHECKING([whether $RPMBUILD is available])
+       AS_IF([tmp=$($RPMBUILD --version 2>/dev/null)], [
+               RPMBUILD_VERSION=$(echo $tmp | $AWK '/RPM/ { print $[3] }')
+               HAVE_RPMBUILD=yes
+               AC_MSG_RESULT([$HAVE_RPMBUILD ($RPMBUILD_VERSION)])
+       ],[
+               HAVE_RPMBUILD=no
+               AC_MSG_RESULT([$HAVE_RPMBUILD])
+       ])
+
+       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"
+       AC_ARG_WITH([spec],
+               AS_HELP_STRING([--with-spec=SPEC],
+               [Spec files 'generic|redhat']),
+               [RPM_SPEC_DIR="rpm/$withval"])
+
+       AC_MSG_CHECKING([whether spec files are available])
+       AC_MSG_RESULT([yes ($RPM_SPEC_DIR/*.spec.in)])
+
+       AC_SUBST(HAVE_RPM)
+       AC_SUBST(RPM)
+       AC_SUBST(RPM_VERSION)
+
+       AC_SUBST(HAVE_RPMBUILD)
+       AC_SUBST(RPMBUILD)
+       AC_SUBST(RPMBUILD_VERSION)
+
+       AC_SUBST(RPM_SPEC_DIR)
+       AC_SUBST(RPM_DEFINE_UTIL)
+       AC_SUBST(RPM_DEFINE_KMOD)
+       AC_SUBST(RPM_DEFINE_DKMS)
+       AC_SUBST(RPM_DEFINE_COMMON)
+       AC_SUBST(SRPM_DEFINE_UTIL)
+       AC_SUBST(SRPM_DEFINE_KMOD)
+       AC_SUBST(SRPM_DEFINE_DKMS)
+       AC_SUBST(SRPM_DEFINE_COMMON)
+])
+
+dnl #
+dnl # Check for dpkg+dpkg-buildpackage to build DEB packages.  If these
+dnl # tools are missing it is non-fatal but you will not be able to build
+dnl # DEB packages and will be warned if you try too.
+dnl #
+AC_DEFUN([ZFS_AC_DPKG], [
+       DPKG=dpkg
+       DPKGBUILD=dpkg-buildpackage
+
+       AC_MSG_CHECKING([whether $DPKG is available])
+       AS_IF([tmp=$($DPKG --version 2>/dev/null)], [
+               DPKG_VERSION=$(echo $tmp | $AWK '/Debian/ { print $[7] }')
+               HAVE_DPKG=yes
+               AC_MSG_RESULT([$HAVE_DPKG ($DPKG_VERSION)])
+       ],[
+               HAVE_DPKG=no
+               AC_MSG_RESULT([$HAVE_DPKG])
+       ])
+
+       AC_MSG_CHECKING([whether $DPKGBUILD is available])
+       AS_IF([tmp=$($DPKGBUILD --version 2>/dev/null)], [
+               DPKGBUILD_VERSION=$(echo $tmp | \
+                   $AWK '/Debian/ { print $[4] }' | cut -f-4 -d'.')
+               HAVE_DPKGBUILD=yes
+               AC_MSG_RESULT([$HAVE_DPKGBUILD ($DPKGBUILD_VERSION)])
+       ],[
+               HAVE_DPKGBUILD=no
+               AC_MSG_RESULT([$HAVE_DPKGBUILD])
+       ])
+
+       AC_SUBST(HAVE_DPKG)
+       AC_SUBST(DPKG)
+       AC_SUBST(DPKG_VERSION)
+
+       AC_SUBST(HAVE_DPKGBUILD)
+       AC_SUBST(DPKGBUILD)
+       AC_SUBST(DPKGBUILD_VERSION)
+])
+
+dnl #
+dnl # Until native packaging for various different packing systems
+dnl # can be added the least we can do is attempt to use alien to
+dnl # convert the RPM packages to the needed package type.  This is
+dnl # a hack but so far it has worked reasonable well.
+dnl #
+AC_DEFUN([ZFS_AC_ALIEN], [
+       ALIEN=alien
+
+       AC_MSG_CHECKING([whether $ALIEN is available])
+       AS_IF([tmp=$($ALIEN --version 2>/dev/null)], [
+               ALIEN_VERSION=$(echo $tmp | $AWK '{ print $[3] }')
+               HAVE_ALIEN=yes
+               AC_MSG_RESULT([$HAVE_ALIEN ($ALIEN_VERSION)])
+       ],[
+               HAVE_ALIEN=no
+               AC_MSG_RESULT([$HAVE_ALIEN])
+       ])
+
+       AC_SUBST(HAVE_ALIEN)
+       AC_SUBST(ALIEN)
+       AC_SUBST(ALIEN_VERSION)
+])
+
+dnl #
+dnl # Using the VENDOR tag from config.guess set the default
+dnl # package type for 'make pkg': (rpm | deb | tgz)
+dnl #
+AC_DEFUN([ZFS_AC_DEFAULT_PACKAGE], [
+       AC_MSG_CHECKING([linux distribution])
+       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
+       AC_MSG_RESULT([$VENDOR])
+       AC_SUBST(VENDOR)
+
+       AC_MSG_CHECKING([default package type])
+       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
+       AC_MSG_RESULT([$DEFAULT_PACKAGE])
+       AC_SUBST(DEFAULT_PACKAGE)
+
+       DEFAULT_INIT_DIR=$sysconfdir/init.d
+       AC_MSG_CHECKING([default init directory])
+       AC_MSG_RESULT([$DEFAULT_INIT_DIR])
+       AC_SUBST(DEFAULT_INIT_DIR)
+
+       AC_MSG_CHECKING([default init script type])
+       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
+       AC_MSG_RESULT([$DEFAULT_INIT_SCRIPT])
+       AC_SUBST(DEFAULT_INIT_SCRIPT)
+
+       AC_MSG_CHECKING([default init config direectory])
+       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
+       AC_MSG_RESULT([$DEFAULT_INITCONF_DIR])
+       AC_SUBST(DEFAULT_INITCONF_DIR)
+
+       AC_MSG_CHECKING([whether initramfs-tools is available])
+       if test -d /usr/share/initramfs-tools ; then
+               DEFINE_INITRAMFS='--define "_initramfs 1"'
+               AC_MSG_RESULT([yes])
+       else
+               DEFINE_INITRAMFS=''
+               AC_MSG_RESULT([no])
+       fi
+       AC_SUBST(DEFINE_INITRAMFS)
+])
+
+dnl #
+dnl # Default ZFS package configuration
+dnl #
+AC_DEFUN([ZFS_AC_PACKAGE], [
+       ZFS_AC_DEFAULT_PACKAGE
+       ZFS_AC_RPM
+       ZFS_AC_DPKG
+       ZFS_AC_ALIEN
+])
diff --git a/zfs/config/zfs-meta.m4 b/zfs/config/zfs-meta.m4
new file mode 100644 (file)
index 0000000..d174ccc
--- /dev/null
@@ -0,0 +1,197 @@
+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 #
+dnl #    The META file format is as follows:
+dnl #      ^[ ]*KEY:[ \t]+VALUE$
+dnl #
+dnl #    In other words:
+dnl #    - KEY is separated from VALUE by a colon and one or more spaces/tabs.
+dnl #    - KEY and VALUE are case sensitive.
+dnl #    - Leading spaces are ignored.
+dnl #    - First match wins for duplicate keys.
+dnl #
+dnl #    A line can be commented out by preceding it with a '#' (or technically
+dnl #    any non-space character since that will prevent the regex from
+dnl #    matching).
+dnl #
+dnl # WARNING:
+dnl #   Placing a colon followed by a space or tab (ie, ":[ \t]+") within the
+dnl #   VALUE will prematurely terminate the string since that sequence is
+dnl #   used as the awk field separator.
+dnl #
+dnl # KEYS:
+dnl #   The following META keys are recognized:
+dnl #     Name, Version, Release, Date, Author, LT_Current, LT_Revision, LT_Age
+dnl #
+dnl # Written by Chris Dunlap <cdunlap@llnl.gov>.
+dnl # Modified by Brian Behlendorf <behlendorf1@llnl.gov>.
+dnl #
+AC_DEFUN([ZFS_AC_META], [
+
+       AH_BOTTOM([
+#undef PACKAGE
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef STDC_HEADERS
+#undef VERSION])
+
+       AC_PROG_AWK
+       AC_MSG_CHECKING([metadata])
+
+       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=_ZFS_AC_META_GETVAL([(Name|Project|Package)]);
+               if test -n "$ZFS_META_NAME"; then
+                       AC_DEFINE_UNQUOTED([ZFS_META_NAME], ["$ZFS_META_NAME"],
+                               [Define the project name.]
+                       )
+                       AC_SUBST([ZFS_META_NAME])
+               fi
+
+               ZFS_META_VERSION=_ZFS_AC_META_GETVAL([Version]);
+               if test -n "$ZFS_META_VERSION"; then
+                       AC_DEFINE_UNQUOTED([ZFS_META_VERSION], ["$ZFS_META_VERSION"],
+                               [Define the project version.]
+                       )
+                       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
+                       _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
+                       AC_DEFINE_UNQUOTED([ZFS_META_RELEASE], ["$ZFS_META_RELEASE"],
+                               [Define the project release.]
+                       )
+                       AC_SUBST([ZFS_META_RELEASE])
+
+                       RELEASE="$ZFS_META_RELEASE"
+                       AC_SUBST([RELEASE])
+               fi
+
+               ZFS_META_LICENSE=_ZFS_AC_META_GETVAL([License]);
+               if test -n "$ZFS_META_LICENSE"; then
+                       AC_DEFINE_UNQUOTED([ZFS_META_LICENSE], ["$ZFS_META_LICENSE"],
+                               [Define the project license.]
+                       )
+                       AC_SUBST([ZFS_META_LICENSE])
+               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"
+                               AC_DEFINE_UNQUOTED([ZFS_META_ALIAS],
+                                       ["$ZFS_META_ALIAS"],
+                                       [Define the project alias string.] 
+                               )
+                               AC_SUBST([ZFS_META_ALIAS])
+               fi
+
+               ZFS_META_DATA=_ZFS_AC_META_GETVAL([Date]);
+               if test -n "$ZFS_META_DATA"; then
+                       AC_DEFINE_UNQUOTED([ZFS_META_DATA], ["$ZFS_META_DATA"],
+                               [Define the project release date.] 
+                       )
+                       AC_SUBST([ZFS_META_DATA])
+               fi
+
+               ZFS_META_AUTHOR=_ZFS_AC_META_GETVAL([Author]);
+               if test -n "$ZFS_META_AUTHOR"; then
+                       AC_DEFINE_UNQUOTED([ZFS_META_AUTHOR], ["$ZFS_META_AUTHOR"],
+                               [Define the project author.]
+                       )
+                       AC_SUBST([ZFS_META_AUTHOR])
+               fi
+
+               m4_pattern_allow([^LT_(CURRENT|REVISION|AGE)$])
+               ZFS_META_LT_CURRENT=_ZFS_AC_META_GETVAL([LT_Current]);
+               ZFS_META_LT_REVISION=_ZFS_AC_META_GETVAL([LT_Revision]);
+               ZFS_META_LT_AGE=_ZFS_AC_META_GETVAL([LT_Age]);
+               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"
+                       AC_DEFINE_UNQUOTED([ZFS_META_LT_CURRENT],
+                               ["$ZFS_META_LT_CURRENT"],
+                               [Define the libtool library 'current'
+                                version information.]
+                       )
+                       AC_DEFINE_UNQUOTED([ZFS_META_LT_REVISION],
+                               ["$ZFS_META_LT_REVISION"],
+                               [Define the libtool library 'revision'
+                                version information.]
+                       )
+                       AC_DEFINE_UNQUOTED([ZFS_META_LT_AGE], ["$ZFS_META_LT_AGE"],
+                               [Define the libtool library 'age' 
+                                version information.]
+                       )
+                       AC_SUBST([ZFS_META_LT_CURRENT])
+                       AC_SUBST([ZFS_META_LT_REVISION])
+                       AC_SUBST([ZFS_META_LT_AGE])
+               fi
+       fi
+
+       AC_MSG_RESULT([$_zfs_ac_meta_type])
+       ]
+)
+
+dnl # _ZFS_AC_META_GETVAL (KEY_NAME_OR_REGEX)
+dnl #
+dnl # Returns the META VALUE associated with the given KEY_NAME_OR_REGEX expr.
+dnl #
+dnl # Despite their resemblance to line noise,
+dnl #   the "@<:@" and "@:>@" constructs are quadrigraphs for "[" and "]".
+dnl #   <www.gnu.org/software/autoconf/manual/autoconf.html#Quadrigraphs>
+dnl #
+dnl # The "$[]1" and "$[]2" constructs prevent M4 parameter expansion
+dnl #   so a literal $1 and $2 will be passed to the resulting awk script,
+dnl #   whereas the "$1" will undergo M4 parameter expansion for the META key.
+dnl #
+AC_DEFUN([_ZFS_AC_META_GETVAL],
+       [`$AWK -F ':@<:@ \t@:>@+' '$[]1 ~ /^ *$1$/ { print $[]2; exit }' $META`]dnl
+)
diff --git a/zfs/configure b/zfs/configure
new file mode 100755 (executable)
index 0000000..984208c
--- /dev/null
@@ -0,0 +1,38442 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for zfs 0.6.5.9.
+#
+#
+# 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.9'
+PACKAGE_STRING='zfs 0.6.5.9'
+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.9 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.9:";;
+   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.9
+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.9, 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.9'
+
+
+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 kernel was built with 16K or larger stacks" >&5
+$as_echo_n "checking whether kernel was built with 16K or larger stacks... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/module.h>
+
+int
+main (void)
+{
+
+               #if (THREAD_SIZE < 16384)
+               #error "THREAD_SIZE is less than 16K"
+               #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 "#define HAVE_LARGE_STACKS 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 was built with CONFIG_DEBUG_LOCK_ALLOC" >&5
+$as_echo_n "checking whether kernel 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() wants 1 arg" >&5
+$as_echo_n "checking whether lookup_bdev() wants 1 arg... " >&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; }
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lookup_bdev() wants 2 args" >&5
+$as_echo_n "checking whether lookup_bdev() wants 2 args... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       lookup_bdev(NULL, FMODE_READ);
+
+  ;
+  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_2ARGS_LOOKUP_BDEV 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+       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; }
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lookup_bdev() wants 2 args" >&5
+$as_echo_n "checking whether lookup_bdev() wants 2 args... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       lookup_bdev(NULL, FMODE_READ);
+
+  ;
+  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_2ARGS_LOOKUP_BDEV 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+               else :
+
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_1ARG_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)
+{
+
+               int 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)
+{
+
+               int 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_ERASE 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)
+{
+
+               int 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 the BIO_RW_UNPLUG enum is available" >&5
+$as_echo_n "checking whether the BIO_RW_UNPLUG enum 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)
+{
+
+               extern enum bio_rw_flags rw;
+
+               rw = BIO_RW_UNPLUG;
+
+  ;
+  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_HAVE_BIO_RW_UNPLUG 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 struct blk_plug is available" >&5
+$as_echo_n "checking whether struct blk_plug 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 blk_plug plug;
+
+               blk_start_plug(&plug);
+               blk_finish_plug(&plug);
+
+  ;
+  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_HAVE_BLK_PLUG 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 bio_set_op_attrs is available" >&5
+$as_echo_n "checking whether bio_set_op_attrs is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/blk_types.h>
+
+int
+main (void)
+{
+
+               struct bio *bio __attribute__ ((unused)) = NULL;
+
+               bio_set_op_attrs(bio, 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_BIO_SET_OP_ATTRS 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 generic_readlink is global" >&5
+$as_echo_n "checking whether generic_readlink is global... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               int i __attribute__ ((unused));
+
+               i = generic_readlink(NULL, 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_GENERIC_READLINK 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 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 set_cached_acl() is usable" >&5
+$as_echo_n "checking whether set_cached_acl() is usable... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/module.h>
+               #include <linux/cred.h>
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+
+               MODULE_LICENSE("$ZFS_META_LICENSE");
+
+int
+main (void)
+{
+
+               struct inode *ip = NULL;
+               struct posix_acl *acl = posix_acl_alloc(1, 0);
+               set_cached_acl(ip, ACL_TYPE_ACCESS, acl);
+               forget_cached_acl(ip, ACL_TYPE_ACCESS);
+
+  ;
+  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_CACHED_ACL_USABLE 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_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 iops->set_acl() exists" >&5
+$as_echo_n "checking whether iops->set_acl() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+               int set_acl_fn(struct inode *inode, struct posix_acl *acl, int type)
+                   { return 0; }
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .set_acl = set_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_SET_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 fops->aio_fsync() exists" >&5
+$as_echo_n "checking whether fops->aio_fsync() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+               static const struct file_operations
+                   fops __attribute__ ((unused)) = {
+                       .aio_fsync = 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: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_FILE_AIO_FSYNC 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 setattr_prepare() is available" >&5
+$as_echo_n "checking whether setattr_prepare() is available... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               struct dentry *dentry = NULL;
+               struct iattr *attr = NULL;
+               int error;
+
+               error = setattr_prepare(dentry, attr);
+
+  ;
+  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:]]setattr_prepare[[:space:]]' \
+               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in fs/attr.c; do
+                       grep -q -E "EXPORT_SYMBOL.*(setattr_prepare)" \
+                               "$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_SETATTR_PREPARE 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 generic_write_checks() takes kiocb" >&5
+$as_echo_n "checking whether generic_write_checks() takes kiocb... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+
+int
+main (void)
+{
+
+               struct kiocb *iocb = NULL;
+               struct iov_iter *iov = NULL;
+               generic_write_checks(iocb, iov);
+
+  ;
+  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_GENERIC_WRITE_CHECKS_KIOCB 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
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->rename() wants flags" >&5
+$as_echo_n "checking whether iops->rename() wants flags... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #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,
+               };
+
+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_RENAME_WANTS_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 generic_setxattr() exists" >&5
+$as_echo_n "checking whether generic_setxattr() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+               #include <linux/xattr.h>
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .setxattr = generic_setxattr
+               };
+
+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_GENERIC_SETXATTR 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
+
+
+
+
+       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 kernel was built with 16K or larger stacks" >&5
+$as_echo_n "checking whether kernel was built with 16K or larger stacks... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/module.h>
+
+int
+main (void)
+{
+
+               #if (THREAD_SIZE < 16384)
+               #error "THREAD_SIZE is less than 16K"
+               #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 "#define HAVE_LARGE_STACKS 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 was built with CONFIG_DEBUG_LOCK_ALLOC" >&5
+$as_echo_n "checking whether kernel 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() wants 1 arg" >&5
+$as_echo_n "checking whether lookup_bdev() wants 1 arg... " >&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; }
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lookup_bdev() wants 2 args" >&5
+$as_echo_n "checking whether lookup_bdev() wants 2 args... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       lookup_bdev(NULL, FMODE_READ);
+
+  ;
+  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_2ARGS_LOOKUP_BDEV 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+       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; }
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lookup_bdev() wants 2 args" >&5
+$as_echo_n "checking whether lookup_bdev() wants 2 args... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+                       #include <linux/fs.h>
+
+int
+main (void)
+{
+
+                       lookup_bdev(NULL, FMODE_READ);
+
+  ;
+  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_2ARGS_LOOKUP_BDEV 1" >>confdefs.h
+
+
+               fi
+       fi
+
+
+               else :
+
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_1ARG_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)
+{
+
+               int 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)
+{
+
+               int 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_ERASE 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)
+{
+
+               int 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 the BIO_RW_UNPLUG enum is available" >&5
+$as_echo_n "checking whether the BIO_RW_UNPLUG enum 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)
+{
+
+               extern enum bio_rw_flags rw;
+
+               rw = BIO_RW_UNPLUG;
+
+  ;
+  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_HAVE_BIO_RW_UNPLUG 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 struct blk_plug is available" >&5
+$as_echo_n "checking whether struct blk_plug 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 blk_plug plug;
+
+               blk_start_plug(&plug);
+               blk_finish_plug(&plug);
+
+  ;
+  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_HAVE_BLK_PLUG 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 bio_set_op_attrs is available" >&5
+$as_echo_n "checking whether bio_set_op_attrs is available... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/blk_types.h>
+
+int
+main (void)
+{
+
+               struct bio *bio __attribute__ ((unused)) = NULL;
+
+               bio_set_op_attrs(bio, 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_BIO_SET_OP_ATTRS 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 generic_readlink is global" >&5
+$as_echo_n "checking whether generic_readlink is global... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               int i __attribute__ ((unused));
+
+               i = generic_readlink(NULL, 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_GENERIC_READLINK 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 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 set_cached_acl() is usable" >&5
+$as_echo_n "checking whether set_cached_acl() is usable... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/module.h>
+               #include <linux/cred.h>
+               #include <linux/fs.h>
+               #include <linux/posix_acl.h>
+
+               MODULE_LICENSE("$ZFS_META_LICENSE");
+
+int
+main (void)
+{
+
+               struct inode *ip = NULL;
+               struct posix_acl *acl = posix_acl_alloc(1, 0);
+               set_cached_acl(ip, ACL_TYPE_ACCESS, acl);
+               forget_cached_acl(ip, ACL_TYPE_ACCESS);
+
+  ;
+  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_CACHED_ACL_USABLE 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_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 iops->set_acl() exists" >&5
+$as_echo_n "checking whether iops->set_acl() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+               int set_acl_fn(struct inode *inode, struct posix_acl *acl, int type)
+                   { return 0; }
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .set_acl = set_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_SET_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 fops->aio_fsync() exists" >&5
+$as_echo_n "checking whether fops->aio_fsync() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+               static const struct file_operations
+                   fops __attribute__ ((unused)) = {
+                       .aio_fsync = 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: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_FILE_AIO_FSYNC 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 setattr_prepare() is available" >&5
+$as_echo_n "checking whether setattr_prepare() is available... " >&6; }
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+int
+main (void)
+{
+
+               struct dentry *dentry = NULL;
+               struct iattr *attr = NULL;
+               int error;
+
+               error = setattr_prepare(dentry, attr);
+
+  ;
+  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:]]setattr_prepare[[:space:]]' \
+               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in fs/attr.c; do
+                       grep -q -E "EXPORT_SYMBOL.*(setattr_prepare)" \
+                               "$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_SETATTR_PREPARE 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 generic_write_checks() takes kiocb" >&5
+$as_echo_n "checking whether generic_write_checks() takes kiocb... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+
+
+int
+main (void)
+{
+
+               struct kiocb *iocb = NULL;
+               struct iov_iter *iov = NULL;
+               generic_write_checks(iocb, iov);
+
+  ;
+  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_GENERIC_WRITE_CHECKS_KIOCB 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
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->rename() wants flags" >&5
+$as_echo_n "checking whether iops->rename() wants flags... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #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,
+               };
+
+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_RENAME_WANTS_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 generic_setxattr() exists" >&5
+$as_echo_n "checking whether generic_setxattr() exists... " >&6; }
+
+
+cat confdefs.h - <<_ACEOF >conftest.c
+
+
+               #include <linux/fs.h>
+               #include <linux/xattr.h>
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .setxattr = generic_setxattr
+               };
+
+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_GENERIC_SETXATTR 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
+
+
+
+
+       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 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 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.9, 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.9
+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" ;;
+    "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" ;;
+    "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
+
diff --git a/zfs/configure.ac b/zfs/configure.ac
new file mode 100644 (file)
index 0000000..8bf4f64
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the ZFS Linux port.
+ *
+ * Copyright (c) 2009 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory
+ * Written by:
+ *         Brian Behlendorf <behlendorf1@llnl.gov>,
+ *         Herb Wartens <wartens2@llnl.gov>,
+ *         Jim Garlick <garlick@llnl.gov>
+ * LLNL-CODE-403049
+ *
+ * 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
+ */
+
+AC_INIT(m4_esyscmd(grep Name META | cut -d ':' -f 2 | tr -d ' \n'),
+       m4_esyscmd(grep Version META | cut -d ':' -f 2 | tr -d ' \n'))
+AC_LANG(C)
+ZFS_AC_META
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_MACRO_DIR([config])
+AC_CANONICAL_SYSTEM
+AM_MAINTAINER_MODE
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AM_INIT_AUTOMAKE
+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 &&
+       rm zfs_config.h.tmp) || exit 1])
+
+AC_PROG_INSTALL
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AM_PROG_AS
+
+ZFS_AC_LICENSE
+ZFS_AC_PACKAGE
+ZFS_AC_CONFIG
+ZFS_AC_DEBUG
+ZFS_AC_DEBUG_DMU_TX
+
+AC_CONFIG_FILES([ 
+       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
+       zfs.release
+])
+
+AC_OUTPUT
diff --git a/zfs/cp b/zfs/cp
new file mode 100755 (executable)
index 0000000..46ff2c9
--- /dev/null
+++ b/zfs/cp
@@ -0,0 +1,2 @@
+#!/bin/sh
+cp "$@"
diff --git a/zfs/dkms.conf b/zfs/dkms.conf
new file mode 100644 (file)
index 0000000..a0d084e
--- /dev/null
@@ -0,0 +1,89 @@
+BUILD_DEPENDS[0]="spl"
+AUTOINSTALL="yes"
+PACKAGE_NAME="zfs"
+PACKAGE_VERSION="0.6.5.9"
+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
+    }
+  )
+  --with-spl-timeout=600
+"
+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/include/Makefile.am b/zfs/include/Makefile.am
new file mode 100644 (file)
index 0000000..a94cad5
--- /dev/null
@@ -0,0 +1,34 @@
+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)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/Makefile.in b/zfs/include/Makefile.in
new file mode 100644 (file)
index 0000000..b0e96d4
--- /dev/null
@@ -0,0 +1,912 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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:
diff --git a/zfs/include/libnvpair.h b/zfs/include/libnvpair.h
new file mode 100644 (file)
index 0000000..4c2615d
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef        _LIBNVPAIR_H
+#define        _LIBNVPAIR_H
+
+#include <sys/nvpair.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <regex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * All interfaces described in this file are private to Solaris, and
+ * are subject to change at any time and without notice.  The public
+ * nvlist/nvpair interfaces, as documented in manpage sections 3NVPAIR,
+ * are all imported from <sys/nvpair.h> included above.
+ */
+
+extern int nvpair_value_match(nvpair_t *, int, char *, char **);
+extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *,
+    char **);
+
+extern void nvlist_print(FILE *, nvlist_t *);
+extern void dump_nvlist(nvlist_t *, int);
+
+/*
+ * Private nvlist printing interface that allows the caller some control
+ * over output rendering (as opposed to nvlist_print and dump_nvlist).
+ *
+ * Obtain an opaque nvlist_prtctl_t cookie using nvlist_prtctl_alloc
+ * (NULL on failure);  on return the cookie is set up for default formatting
+ * and rendering.  Quote the cookie in subsequent customisation functions and
+ * then pass the cookie to nvlist_prt to render the nvlist.  Finally,
+ * use nvlist_prtctl_free to release the cookie.
+ *
+ * For all nvlist_lookup_xxx and nvlist_lookup_xxx_array functions
+ * we have a corresponding brace of functions that appoint replacement
+ * rendering functions:
+ *
+ *     extern void nvlist_prtctl_xxx(nvlist_prtctl_t,
+ *         void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
+ *         xxxtype value))
+ *
+ *     and
+ *
+ *     extern void nvlist_prtctl_xxx_array(nvlist_prtctl_t,
+ *         void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
+ *         xxxtype value, uint_t count))
+ *
+ * where xxxtype is the C datatype corresponding to xxx, eg int8_t for "int8"
+ * and char * for "string".  The function that is appointed to render the
+ * specified datatype receives as arguments the cookie, the nvlist
+ * member name, the value of that member (or a pointer for array function),
+ * and (for array rendering functions) a count of the number of elements.
+ */
+
+typedef struct nvlist_prtctl *nvlist_prtctl_t; /* opaque */
+
+enum nvlist_indent_mode {
+       NVLIST_INDENT_ABS,      /* Absolute indentation */
+       NVLIST_INDENT_TABBED    /* Indent with tabstops */
+};
+
+extern nvlist_prtctl_t nvlist_prtctl_alloc(void);
+extern void nvlist_prtctl_free(nvlist_prtctl_t);
+extern void nvlist_prt(nvlist_t *, nvlist_prtctl_t);
+
+/* Output stream */
+extern void nvlist_prtctl_setdest(nvlist_prtctl_t, FILE *);
+extern FILE *nvlist_prtctl_getdest(nvlist_prtctl_t);
+
+/* Indentation mode, start indent, indent increment; default tabbed/0/1 */
+extern void nvlist_prtctl_setindent(nvlist_prtctl_t, enum nvlist_indent_mode,
+    int, int);
+extern void nvlist_prtctl_doindent(nvlist_prtctl_t, int);
+
+enum nvlist_prtctl_fmt {
+       NVLIST_FMT_MEMBER_NAME,         /* name fmt; default "%s = " */
+       NVLIST_FMT_MEMBER_POSTAMBLE,    /* after nvlist member; default "\n" */
+       NVLIST_FMT_BTWN_ARRAY           /* between array members; default " " */
+};
+
+extern void nvlist_prtctl_setfmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt,
+    const char *);
+extern void nvlist_prtctl_dofmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt, ...);
+
+/*
+ * Function prototypes for interfaces that appoint a new rendering function
+ * for single-valued nvlist members.
+ *
+ * A replacement function receives arguments as follows:
+ *
+ *     nvlist_prtctl_t Print control structure; do not change preferences
+ *                     for this object from a print callback function.
+ *
+ *     void *          The function-private cookie argument registered
+ *                     when the replacement function was appointed.
+ *
+ *     nvlist_t *      The full nvlist that is being processed.  The
+ *                     rendering function is called to render a single
+ *                     member (name and value passed as below) but it may
+ *                     want to reference or incorporate other aspects of
+ *                     the full nvlist.
+ *
+ *     const char *    Member name to render
+ *
+ *     valtype         Value of the member to render
+ *
+ * The function must return non-zero if it has rendered output for this
+ * member, or 0 if it wants to default to standard rendering for this
+ * one member.
+ */
+
+#define        NVLIST_PRINTCTL_SVDECL(funcname, valtype) \
+    extern void funcname(nvlist_prtctl_t, \
+    int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, valtype), \
+    void *)
+
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean, int);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean_value, boolean_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_byte, uchar_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int8, int8_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint8, uint8_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int16, int16_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint16, uint16_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int32, int32_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint32, uint32_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int64, int64_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint64, uint64_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_double, double);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_string, char *);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_hrtime, hrtime_t);
+NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_nvlist, nvlist_t *);
+
+#undef NVLIST_PRINTCTL_SVDECL  /* was just for "clarity" above */
+
+/*
+ * Function prototypes for interfaces that appoint a new rendering function
+ * for array-valued nvlist members.
+ *
+ * One additional argument is taken: uint_t for the number of array elements
+ *
+ * Return values as above.
+ */
+#define        NVLIST_PRINTCTL_AVDECL(funcname, vtype) \
+    extern void funcname(nvlist_prtctl_t, \
+    int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, uint_t), \
+    void *)
+
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_boolean_array, boolean_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_byte_array, uchar_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int8_array, int8_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint8_array, uint8_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int16_array, int16_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint16_array, uint16_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int32_array, int32_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint32_array, uint32_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int64_array, int64_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint64_array, uint64_t *);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_string_array, char **);
+NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_nvlist_array, nvlist_t **);
+
+#undef NVLIST_PRINTCTL_AVDECL  /* was just for "clarity" above */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBNVPAIR_H */
diff --git a/zfs/include/libuutil.h b/zfs/include/libuutil.h
new file mode 100644 (file)
index 0000000..6675424
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef        _LIBUUTIL_H
+#define        _LIBUUTIL_H
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Standard flags codes.
+ */
+#define        UU_DEFAULT              0
+
+/*
+ * Standard error codes.
+ */
+#define        UU_ERROR_NONE           0       /* no error */
+#define        UU_ERROR_INVALID_ARGUMENT 1     /* invalid argument */
+#define        UU_ERROR_UNKNOWN_FLAG   2       /* passed flag invalid */
+#define        UU_ERROR_NO_MEMORY      3       /* out of memory */
+#define        UU_ERROR_CALLBACK_FAILED 4      /* callback-initiated error */
+#define        UU_ERROR_NOT_SUPPORTED  5       /* operation not supported */
+#define        UU_ERROR_EMPTY          6       /* no value provided */
+#define        UU_ERROR_UNDERFLOW      7       /* value is too small */
+#define        UU_ERROR_OVERFLOW       8       /* value is too value */
+#define        UU_ERROR_INVALID_CHAR   9       /* value contains unexpected char */
+#define        UU_ERROR_INVALID_DIGIT  10      /* value contains digit not in base */
+
+#define        UU_ERROR_SYSTEM         99      /* underlying system error */
+#define        UU_ERROR_UNKNOWN        100     /* error status not known */
+
+/*
+ * Standard program exit codes.
+ */
+#define        UU_EXIT_OK      (*(uu_exit_ok()))
+#define        UU_EXIT_FATAL   (*(uu_exit_fatal()))
+#define        UU_EXIT_USAGE   (*(uu_exit_usage()))
+
+/*
+ * Exit status profiles.
+ */
+#define        UU_PROFILE_DEFAULT      0
+#define        UU_PROFILE_LAUNCHER     1
+
+/*
+ * Error reporting functions.
+ */
+uint32_t uu_error(void);
+const char *uu_strerror(uint32_t);
+
+/*
+ * Program notification functions.
+ */
+extern void uu_alt_exit(int);
+extern const char *uu_setpname(char *);
+extern const char *uu_getpname(void);
+/*PRINTFLIKE1*/
+extern void uu_warn(const char *, ...);
+extern void uu_vwarn(const char *, va_list);
+/*PRINTFLIKE1*/
+extern void uu_die(const char *, ...) __NORETURN;
+extern void uu_vdie(const char *, va_list) __NORETURN;
+/*PRINTFLIKE2*/
+extern void uu_xdie(int, const char *, ...) __NORETURN;
+extern void uu_vxdie(int, const char *, va_list) __NORETURN;
+
+/*
+ * Exit status functions (not to be used directly)
+ */
+extern int *uu_exit_ok(void);
+extern int *uu_exit_fatal(void);
+extern int *uu_exit_usage(void);
+
+/*
+ * string->number conversions
+ */
+extern int uu_strtoint(const char *, void *, size_t, int, int64_t, int64_t);
+extern int uu_strtouint(const char *, void *, size_t, int, uint64_t, uint64_t);
+
+/*
+ * Debug print facility functions.
+ */
+typedef struct uu_dprintf uu_dprintf_t;
+
+typedef enum {
+       UU_DPRINTF_SILENT,
+       UU_DPRINTF_FATAL,
+       UU_DPRINTF_WARNING,
+       UU_DPRINTF_NOTICE,
+       UU_DPRINTF_INFO,
+       UU_DPRINTF_DEBUG
+} uu_dprintf_severity_t;
+
+extern uu_dprintf_t *uu_dprintf_create(const char *, uu_dprintf_severity_t,
+    uint_t);
+/*PRINTFLIKE3*/
+extern void uu_dprintf(uu_dprintf_t *, uu_dprintf_severity_t,
+    const char *, ...);
+extern void uu_dprintf_destroy(uu_dprintf_t *);
+extern const char *uu_dprintf_getname(uu_dprintf_t *);
+
+/*
+ * Identifier test flags and function.
+ */
+#define        UU_NAME_DOMAIN          0x1     /* allow SUNW, or com.sun, prefix */
+#define        UU_NAME_PATH            0x2     /* allow '/'-delimited paths */
+
+int uu_check_name(const char *, uint_t);
+
+/*
+ * File creation functions.
+ */
+extern int uu_open_tmp(const char *dir, uint_t uflags);
+
+/*
+ * Convenience functions.
+ */
+#define        UU_NELEM(a)     (sizeof (a) / sizeof ((a)[0]))
+
+/*PRINTFLIKE1*/
+extern char *uu_msprintf(const char *format, ...);
+extern void *uu_zalloc(size_t);
+extern char *uu_strdup(const char *);
+extern void uu_free(void *);
+
+extern boolean_t uu_strcaseeq(const char *a, const char *b);
+extern boolean_t uu_streq(const char *a, const char *b);
+extern char *uu_strndup(const char *s, size_t n);
+extern boolean_t uu_strbw(const char *a, const char *b);
+extern void *uu_memdup(const void *buf, size_t sz);
+extern void uu_dump(FILE *out, const char *prefix, const void *buf, size_t len);
+
+/*
+ * Comparison function type definition.
+ *   Developers should be careful in their use of the _private argument. If you
+ *   break interface guarantees, you get undefined behavior.
+ */
+typedef int uu_compare_fn_t(const void *__left, const void *__right,
+    void *__private);
+
+/*
+ * Walk variant flags.
+ *   A data structure need not provide support for all variants and
+ *   combinations.  Refer to the appropriate documentation.
+ */
+#define        UU_WALK_ROBUST          0x00000001      /* walk can survive removes */
+#define        UU_WALK_REVERSE         0x00000002      /* reverse walk order */
+
+#define        UU_WALK_PREORDER        0x00000010      /* walk tree in pre-order */
+#define        UU_WALK_POSTORDER       0x00000020      /* walk tree in post-order */
+
+/*
+ * Walk callback function return codes.
+ */
+#define        UU_WALK_ERROR           -1
+#define        UU_WALK_NEXT            0
+#define        UU_WALK_DONE            1
+
+/*
+ * Walk callback function type definition.
+ */
+typedef int uu_walk_fn_t(void *_elem, void *_private);
+
+/*
+ * lists: opaque structures
+ */
+typedef struct uu_list_pool uu_list_pool_t;
+typedef struct uu_list uu_list_t;
+
+typedef struct uu_list_node {
+       uintptr_t uln_opaque[2];
+} uu_list_node_t;
+
+typedef struct uu_list_walk uu_list_walk_t;
+
+typedef uintptr_t uu_list_index_t;
+
+/*
+ * lists: interface
+ *
+ * basic usage:
+ *     typedef struct foo {
+ *             ...
+ *             uu_list_node_t foo_node;
+ *             ...
+ *     } foo_t;
+ *
+ *     static int
+ *     foo_compare(void *l_arg, void *r_arg, void *private)
+ *     {
+ *             foo_t *l = l_arg;
+ *             foo_t *r = r_arg;
+ *
+ *             if (... l greater than r ...)
+ *                     return (1);
+ *             if (... l less than r ...)
+ *                     return (-1);
+ *             return (0);
+ *     }
+ *
+ *     ...
+ *             // at initialization time
+ *             foo_pool = uu_list_pool_create("foo_pool",
+ *                 sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
+ *                 debugging? 0 : UU_AVL_POOL_DEBUG);
+ *     ...
+ */
+uu_list_pool_t *uu_list_pool_create(const char *, size_t, size_t,
+    uu_compare_fn_t *, uint32_t);
+#define        UU_LIST_POOL_DEBUG      0x00000001
+
+void uu_list_pool_destroy(uu_list_pool_t *);
+
+/*
+ * usage:
+ *
+ *     foo_t *a;
+ *     a = malloc(sizeof(*a));
+ *     uu_list_node_init(a, &a->foo_list, pool);
+ *     ...
+ *     uu_list_node_fini(a, &a->foo_list, pool);
+ *     free(a);
+ */
+void uu_list_node_init(void *, uu_list_node_t *, uu_list_pool_t *);
+void uu_list_node_fini(void *, uu_list_node_t *, uu_list_pool_t *);
+
+uu_list_t *uu_list_create(uu_list_pool_t *, void *_parent, uint32_t);
+#define        UU_LIST_DEBUG   0x00000001
+#define        UU_LIST_SORTED  0x00000002      /* list is sorted */
+
+void uu_list_destroy(uu_list_t *);     /* list must be empty */
+
+size_t uu_list_numnodes(uu_list_t *);
+
+void *uu_list_first(uu_list_t *);
+void *uu_list_last(uu_list_t *);
+
+void *uu_list_next(uu_list_t *, void *);
+void *uu_list_prev(uu_list_t *, void *);
+
+int uu_list_walk(uu_list_t *, uu_walk_fn_t *, void *, uint32_t);
+
+uu_list_walk_t *uu_list_walk_start(uu_list_t *, uint32_t);
+void *uu_list_walk_next(uu_list_walk_t *);
+void uu_list_walk_end(uu_list_walk_t *);
+
+void *uu_list_find(uu_list_t *, void *, void *, uu_list_index_t *);
+void uu_list_insert(uu_list_t *, void *, uu_list_index_t);
+
+void *uu_list_nearest_next(uu_list_t *, uu_list_index_t);
+void *uu_list_nearest_prev(uu_list_t *, uu_list_index_t);
+
+void *uu_list_teardown(uu_list_t *, void **);
+
+void uu_list_remove(uu_list_t *, void *);
+
+/*
+ * lists: interfaces for non-sorted lists only
+ */
+int uu_list_insert_before(uu_list_t *, void *_target, void *_elem);
+int uu_list_insert_after(uu_list_t *, void *_target, void *_elem);
+
+/*
+ * avl trees: opaque structures
+ */
+typedef struct uu_avl_pool uu_avl_pool_t;
+typedef struct uu_avl uu_avl_t;
+
+typedef struct uu_avl_node {
+#ifdef _LP64
+       uintptr_t uan_opaque[3];
+#else
+       uintptr_t uan_opaque[4];
+#endif
+} uu_avl_node_t;
+
+typedef struct uu_avl_walk uu_avl_walk_t;
+
+typedef uintptr_t uu_avl_index_t;
+
+/*
+ * avl trees: interface
+ *
+ * basic usage:
+ *     typedef struct foo {
+ *             ...
+ *             uu_avl_node_t foo_node;
+ *             ...
+ *     } foo_t;
+ *
+ *     static int
+ *     foo_compare(void *l_arg, void *r_arg, void *private)
+ *     {
+ *             foo_t *l = l_arg;
+ *             foo_t *r = r_arg;
+ *
+ *             if (... l greater than r ...)
+ *                     return (1);
+ *             if (... l less than r ...)
+ *                     return (-1);
+ *             return (0);
+ *     }
+ *
+ *     ...
+ *             // at initialization time
+ *             foo_pool = uu_avl_pool_create("foo_pool",
+ *                 sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
+ *                 debugging? 0 : UU_AVL_POOL_DEBUG);
+ *     ...
+ */
+uu_avl_pool_t *uu_avl_pool_create(const char *, size_t, size_t,
+    uu_compare_fn_t *, uint32_t);
+#define        UU_AVL_POOL_DEBUG       0x00000001
+
+void uu_avl_pool_destroy(uu_avl_pool_t *);
+
+/*
+ * usage:
+ *
+ *     foo_t *a;
+ *     a = malloc(sizeof(*a));
+ *     uu_avl_node_init(a, &a->foo_avl, pool);
+ *     ...
+ *     uu_avl_node_fini(a, &a->foo_avl, pool);
+ *     free(a);
+ */
+void uu_avl_node_init(void *, uu_avl_node_t *, uu_avl_pool_t *);
+void uu_avl_node_fini(void *, uu_avl_node_t *, uu_avl_pool_t *);
+
+uu_avl_t *uu_avl_create(uu_avl_pool_t *, void *_parent, uint32_t);
+#define        UU_AVL_DEBUG    0x00000001
+
+void uu_avl_destroy(uu_avl_t *);       /* list must be empty */
+
+size_t uu_avl_numnodes(uu_avl_t *);
+
+void *uu_avl_first(uu_avl_t *);
+void *uu_avl_last(uu_avl_t *);
+
+void *uu_avl_next(uu_avl_t *, void *);
+void *uu_avl_prev(uu_avl_t *, void *);
+
+int uu_avl_walk(uu_avl_t *, uu_walk_fn_t *, void *, uint32_t);
+
+uu_avl_walk_t *uu_avl_walk_start(uu_avl_t *, uint32_t);
+void *uu_avl_walk_next(uu_avl_walk_t *);
+void uu_avl_walk_end(uu_avl_walk_t *);
+
+void *uu_avl_find(uu_avl_t *, void *, void *, uu_avl_index_t *);
+void uu_avl_insert(uu_avl_t *, void *, uu_avl_index_t);
+
+void *uu_avl_nearest_next(uu_avl_t *, uu_avl_index_t);
+void *uu_avl_nearest_prev(uu_avl_t *, uu_avl_index_t);
+
+void *uu_avl_teardown(uu_avl_t *, void **);
+
+void uu_avl_remove(uu_avl_t *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBUUTIL_H */
diff --git a/zfs/include/libuutil_common.h b/zfs/include/libuutil_common.h
new file mode 100644 (file)
index 0000000..52ac488
--- /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.
+ */
+
+#ifndef        _LIBUUTIL_COMMON_H
+#define        _LIBUUTIL_COMMON_H
+
+
+
+#include <libuutil.h>
+#include <libuutil_impl.h>
+
+#endif /* _LIBUUTIL_COMMON_H */
diff --git a/zfs/include/libuutil_impl.h b/zfs/include/libuutil_impl.h
new file mode 100644 (file)
index 0000000..f978b47
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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        _LIBUUTIL_IMPL_H
+#define        _LIBUUTIL_IMPL_H
+
+
+
+#include <libuutil.h>
+#include <pthread.h>
+
+#include <sys/avl_impl.h>
+#include <sys/byteorder.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void uu_set_error(uint_t);
+
+
+/*PRINTFLIKE1*/
+void uu_panic(const char *format, ...);
+
+
+struct uu_dprintf {
+       char    *uud_name;
+       uu_dprintf_severity_t uud_severity;
+       uint_t  uud_flags;
+};
+
+/*
+ * For debugging purposes, libuutil keeps around linked lists of all uu_lists
+ * and uu_avls, along with pointers to their parents.  These can cause false
+ * negatives when looking for memory leaks, so we encode the pointers by
+ * storing them with swapped endianness;  this is not perfect, but it's about
+ * the best we can do without wasting a lot of space.
+ */
+#ifdef _LP64
+#define        UU_PTR_ENCODE(ptr)              BSWAP_64((uintptr_t)(void *)(ptr))
+#else
+#define        UU_PTR_ENCODE(ptr)              BSWAP_32((uintptr_t)(void *)(ptr))
+#endif
+
+#define        UU_PTR_DECODE(ptr)              ((void *)UU_PTR_ENCODE(ptr))
+
+/*
+ * uu_list structures
+ */
+typedef struct uu_list_node_impl {
+       struct uu_list_node_impl *uln_next;
+       struct uu_list_node_impl *uln_prev;
+} uu_list_node_impl_t;
+
+struct uu_list_walk {
+       uu_list_walk_t  *ulw_next;
+       uu_list_walk_t  *ulw_prev;
+
+       uu_list_t       *ulw_list;
+       int8_t          ulw_dir;
+       uint8_t         ulw_robust;
+       uu_list_node_impl_t *ulw_next_result;
+};
+
+struct uu_list {
+       uintptr_t       ul_next_enc;
+       uintptr_t       ul_prev_enc;
+
+       uu_list_pool_t  *ul_pool;
+       uintptr_t       ul_parent_enc;  /* encoded parent pointer */
+       size_t          ul_offset;
+       size_t          ul_numnodes;
+       uint8_t         ul_debug;
+       uint8_t         ul_sorted;
+       uint8_t         ul_index;       /* mark for uu_list_index_ts */
+
+       uu_list_node_impl_t ul_null_node;
+       uu_list_walk_t  ul_null_walk;   /* for robust walkers */
+};
+
+#define        UU_LIST_PTR(ptr)                ((uu_list_t *)UU_PTR_DECODE(ptr))
+
+#define        UU_LIST_POOL_MAXNAME    64
+
+struct uu_list_pool {
+       uu_list_pool_t  *ulp_next;
+       uu_list_pool_t  *ulp_prev;
+
+       char            ulp_name[UU_LIST_POOL_MAXNAME];
+       size_t          ulp_nodeoffset;
+       size_t          ulp_objsize;
+       uu_compare_fn_t *ulp_cmp;
+       uint8_t         ulp_debug;
+       uint8_t         ulp_last_index;
+       pthread_mutex_t ulp_lock;               /* protects null_list */
+       uu_list_t       ulp_null_list;
+};
+
+/*
+ * uu_avl structures
+ */
+typedef struct avl_node                uu_avl_node_impl_t;
+
+struct uu_avl_walk {
+       uu_avl_walk_t   *uaw_next;
+       uu_avl_walk_t   *uaw_prev;
+
+       uu_avl_t        *uaw_avl;
+       void            *uaw_next_result;
+       int8_t          uaw_dir;
+       uint8_t         uaw_robust;
+};
+
+struct uu_avl {
+       uintptr_t       ua_next_enc;
+       uintptr_t       ua_prev_enc;
+
+       uu_avl_pool_t   *ua_pool;
+       uintptr_t       ua_parent_enc;
+       uint8_t         ua_debug;
+       uint8_t         ua_index;       /* mark for uu_avl_index_ts */
+
+       struct avl_tree ua_tree;
+       uu_avl_walk_t   ua_null_walk;
+};
+
+#define        UU_AVL_PTR(x)           ((uu_avl_t *)UU_PTR_DECODE(x))
+
+#define        UU_AVL_POOL_MAXNAME     64
+
+struct uu_avl_pool {
+       uu_avl_pool_t   *uap_next;
+       uu_avl_pool_t   *uap_prev;
+
+       char            uap_name[UU_AVL_POOL_MAXNAME];
+       size_t          uap_nodeoffset;
+       size_t          uap_objsize;
+       uu_compare_fn_t *uap_cmp;
+       uint8_t         uap_debug;
+       uint8_t         uap_last_index;
+       pthread_mutex_t uap_lock;               /* protects null_avl */
+       uu_avl_t        uap_null_avl;
+};
+
+/*
+ * atfork() handlers
+ */
+void uu_avl_lockup(void);
+void uu_avl_release(void);
+
+void uu_list_lockup(void);
+void uu_list_release(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBUUTIL_IMPL_H */
diff --git a/zfs/include/libzfs.h b/zfs/include/libzfs.h
new file mode 100644 (file)
index 0000000..26847e0
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef        _LIBZFS_H
+#define        _LIBZFS_H
+
+#include <assert.h>
+#include <libnvpair.h>
+#include <sys/mnttab.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <sys/fs/zfs.h>
+#include <sys/avl.h>
+#include <ucred.h>
+#include <libzfs_core.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Miscellaneous ZFS constants
+ */
+#define        ZFS_MAXNAMELEN          MAXNAMELEN
+#define        ZPOOL_MAXNAMELEN        MAXNAMELEN
+#define        ZFS_MAXPROPLEN          MAXPATHLEN
+#define        ZPOOL_MAXPROPLEN        MAXPATHLEN
+
+/*
+ * Default device paths
+ */
+#define        DISK_ROOT               "/dev"
+#define        UDISK_ROOT              "/dev/disk"
+
+/*
+ * Default wait time for a device name to be created.
+ */
+#define        DISK_LABEL_WAIT         (30 * 1000)  /* 30 seconds */
+
+#define        DEFAULT_IMPORT_PATH_SIZE        7
+extern char *zpool_default_import_path[DEFAULT_IMPORT_PATH_SIZE];
+
+/*
+ * libzfs errors
+ */
+typedef enum zfs_error {
+       EZFS_SUCCESS = 0,       /* no error -- success */
+       EZFS_NOMEM = 2000,      /* out of memory */
+       EZFS_BADPROP,           /* invalid property value */
+       EZFS_PROPREADONLY,      /* cannot set readonly property */
+       EZFS_PROPTYPE,          /* property does not apply to dataset type */
+       EZFS_PROPNONINHERIT,    /* property is not inheritable */
+       EZFS_PROPSPACE,         /* bad quota or reservation */
+       EZFS_BADTYPE,           /* dataset is not of appropriate type */
+       EZFS_BUSY,              /* pool or dataset is busy */
+       EZFS_EXISTS,            /* pool or dataset already exists */
+       EZFS_NOENT,             /* no such pool or dataset */
+       EZFS_BADSTREAM,         /* bad backup stream */
+       EZFS_DSREADONLY,        /* dataset is readonly */
+       EZFS_VOLTOOBIG,         /* volume is too large for 32-bit system */
+       EZFS_INVALIDNAME,       /* invalid dataset name */
+       EZFS_BADRESTORE,        /* unable to restore to destination */
+       EZFS_BADBACKUP,         /* backup failed */
+       EZFS_BADTARGET,         /* bad attach/detach/replace target */
+       EZFS_NODEVICE,          /* no such device in pool */
+       EZFS_BADDEV,            /* invalid device to add */
+       EZFS_NOREPLICAS,        /* no valid replicas */
+       EZFS_RESILVERING,       /* currently resilvering */
+       EZFS_BADVERSION,        /* unsupported version */
+       EZFS_POOLUNAVAIL,       /* pool is currently unavailable */
+       EZFS_DEVOVERFLOW,       /* too many devices in one vdev */
+       EZFS_BADPATH,           /* must be an absolute path */
+       EZFS_CROSSTARGET,       /* rename or clone across pool or dataset */
+       EZFS_ZONED,             /* used improperly in local zone */
+       EZFS_MOUNTFAILED,       /* failed to mount dataset */
+       EZFS_UMOUNTFAILED,      /* failed to unmount dataset */
+       EZFS_UNSHARENFSFAILED,  /* unshare(1M) failed */
+       EZFS_SHARENFSFAILED,    /* share(1M) failed */
+       EZFS_PERM,              /* permission denied */
+       EZFS_NOSPC,             /* out of space */
+       EZFS_FAULT,             /* bad address */
+       EZFS_IO,                /* I/O error */
+       EZFS_INTR,              /* signal received */
+       EZFS_ISSPARE,           /* device is a hot spare */
+       EZFS_INVALCONFIG,       /* invalid vdev configuration */
+       EZFS_RECURSIVE,         /* recursive dependency */
+       EZFS_NOHISTORY,         /* no history object */
+       EZFS_POOLPROPS,         /* couldn't retrieve pool props */
+       EZFS_POOL_NOTSUP,       /* ops not supported for this type of pool */
+       EZFS_POOL_INVALARG,     /* invalid argument for this pool operation */
+       EZFS_NAMETOOLONG,       /* dataset name is too long */
+       EZFS_OPENFAILED,        /* open of device failed */
+       EZFS_NOCAP,             /* couldn't get capacity */
+       EZFS_LABELFAILED,       /* write of label failed */
+       EZFS_BADWHO,            /* invalid permission who */
+       EZFS_BADPERM,           /* invalid permission */
+       EZFS_BADPERMSET,        /* invalid permission set name */
+       EZFS_NODELEGATION,      /* delegated administration is disabled */
+       EZFS_UNSHARESMBFAILED,  /* failed to unshare over smb */
+       EZFS_SHARESMBFAILED,    /* failed to share over smb */
+       EZFS_BADCACHE,          /* bad cache file */
+       EZFS_ISL2CACHE,         /* device is for the level 2 ARC */
+       EZFS_VDEVNOTSUP,        /* unsupported vdev type */
+       EZFS_NOTSUP,            /* ops not supported on this dataset */
+       EZFS_ACTIVE_SPARE,      /* pool has active shared spare devices */
+       EZFS_UNPLAYED_LOGS,     /* log device has unplayed logs */
+       EZFS_REFTAG_RELE,       /* snapshot release: tag not found */
+       EZFS_REFTAG_HOLD,       /* snapshot hold: tag already exists */
+       EZFS_TAGTOOLONG,        /* snapshot hold/rele: tag too long */
+       EZFS_PIPEFAILED,        /* pipe create failed */
+       EZFS_THREADCREATEFAILED, /* thread create failed */
+       EZFS_POSTSPLIT_ONLINE,  /* onlining a disk after splitting it */
+       EZFS_SCRUBBING,         /* currently scrubbing */
+       EZFS_NO_SCRUB,          /* no active scrub */
+       EZFS_DIFF,              /* general failure of zfs diff */
+       EZFS_DIFFDATA,          /* bad zfs diff data */
+       EZFS_POOLREADONLY,      /* pool is in read-only mode */
+       EZFS_UNKNOWN
+} zfs_error_t;
+
+/*
+ * The following data structures are all part
+ * of the zfs_allow_t data structure which is
+ * used for printing 'allow' permissions.
+ * It is a linked list of zfs_allow_t's which
+ * then contain avl tree's for user/group/sets/...
+ * and each one of the entries in those trees have
+ * avl tree's for the permissions they belong to and
+ * whether they are local,descendent or local+descendent
+ * permissions.  The AVL trees are used primarily for
+ * sorting purposes, but also so that we can quickly find
+ * a given user and or permission.
+ */
+typedef struct zfs_perm_node {
+       avl_node_t z_node;
+       char z_pname[MAXPATHLEN];
+} zfs_perm_node_t;
+
+typedef struct zfs_allow_node {
+       avl_node_t z_node;
+       char z_key[MAXPATHLEN];         /* name, such as joe */
+       avl_tree_t z_localdescend;      /* local+descendent perms */
+       avl_tree_t z_local;             /* local permissions */
+       avl_tree_t z_descend;           /* descendent permissions */
+} zfs_allow_node_t;
+
+typedef struct zfs_allow {
+       struct zfs_allow *z_next;
+       char z_setpoint[MAXPATHLEN];
+       avl_tree_t z_sets;
+       avl_tree_t z_crperms;
+       avl_tree_t z_user;
+       avl_tree_t z_group;
+       avl_tree_t z_everyone;
+} zfs_allow_t;
+
+/*
+ * Basic handle types
+ */
+typedef struct zfs_handle zfs_handle_t;
+typedef struct zpool_handle zpool_handle_t;
+typedef struct libzfs_handle libzfs_handle_t;
+
+/*
+ * Library initialization
+ */
+extern libzfs_handle_t *libzfs_init(void);
+extern void libzfs_fini(libzfs_handle_t *);
+
+extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
+extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
+
+extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
+
+extern void zfs_save_arguments(int argc, char **, char *, int);
+extern int zpool_log_history(libzfs_handle_t *, const char *);
+
+extern int libzfs_errno(libzfs_handle_t *);
+extern const char *libzfs_error_init(int);
+extern const char *libzfs_error_action(libzfs_handle_t *);
+extern const char *libzfs_error_description(libzfs_handle_t *);
+extern int zfs_standard_error(libzfs_handle_t *, int, const char *);
+extern void libzfs_mnttab_init(libzfs_handle_t *);
+extern void libzfs_mnttab_fini(libzfs_handle_t *);
+extern void libzfs_mnttab_cache(libzfs_handle_t *, boolean_t);
+extern int libzfs_mnttab_find(libzfs_handle_t *, const char *,
+    struct mnttab *);
+extern void libzfs_mnttab_add(libzfs_handle_t *, const char *,
+    const char *, const char *);
+extern void libzfs_mnttab_remove(libzfs_handle_t *, const char *);
+
+/*
+ * Basic handle functions
+ */
+extern zpool_handle_t *zpool_open(libzfs_handle_t *, const char *);
+extern zpool_handle_t *zpool_open_canfail(libzfs_handle_t *, const char *);
+extern void zpool_close(zpool_handle_t *);
+extern const char *zpool_get_name(zpool_handle_t *);
+extern int zpool_get_state(zpool_handle_t *);
+extern char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
+extern const char *zpool_pool_state_to_name(pool_state_t);
+extern void zpool_free_handles(libzfs_handle_t *);
+
+/*
+ * Iterate over all active pools in the system.
+ */
+typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
+extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
+
+/*
+ * Functions to create and destroy pools
+ */
+extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
+    nvlist_t *, nvlist_t *);
+extern int zpool_destroy(zpool_handle_t *, const char *);
+extern int zpool_add(zpool_handle_t *, nvlist_t *);
+
+typedef struct splitflags {
+       /* do not split, but return the config that would be split off */
+       int dryrun : 1;
+
+       /* after splitting, import the pool */
+       int import : 1;
+       int name_flags;
+} splitflags_t;
+
+/*
+ * Functions to manipulate pool and vdev state
+ */
+extern int zpool_scan(zpool_handle_t *, pool_scan_func_t);
+extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
+extern int zpool_reguid(zpool_handle_t *);
+extern int zpool_reopen(zpool_handle_t *);
+
+extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
+    vdev_state_t *);
+extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);
+extern int zpool_vdev_attach(zpool_handle_t *, const char *,
+    const char *, nvlist_t *, int);
+extern int zpool_vdev_detach(zpool_handle_t *, const char *);
+extern int zpool_vdev_remove(zpool_handle_t *, const char *);
+extern int zpool_vdev_split(zpool_handle_t *, char *, nvlist_t **, nvlist_t *,
+    splitflags_t);
+
+extern int zpool_vdev_fault(zpool_handle_t *, uint64_t, vdev_aux_t);
+extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t, vdev_aux_t);
+extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
+
+extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
+    boolean_t *, boolean_t *);
+extern nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
+    boolean_t *, boolean_t *, boolean_t *);
+extern int zpool_label_disk_wait(char *, int);
+extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *);
+
+/*
+ * 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 *);
+
+extern const char *zpool_prop_to_name(zpool_prop_t);
+extern const char *zpool_prop_values(zpool_prop_t);
+
+/*
+ * Pool health statistics.
+ */
+typedef enum {
+       /*
+        * The following correspond to faults as defined in the (fault.fs.zfs.*)
+        * event namespace.  Each is associated with a corresponding message ID.
+        */
+       ZPOOL_STATUS_CORRUPT_CACHE,     /* corrupt /kernel/drv/zpool.cache */
+       ZPOOL_STATUS_MISSING_DEV_R,     /* missing device with replicas */
+       ZPOOL_STATUS_MISSING_DEV_NR,    /* missing device with no replicas */
+       ZPOOL_STATUS_CORRUPT_LABEL_R,   /* bad device label with replicas */
+       ZPOOL_STATUS_CORRUPT_LABEL_NR,  /* bad device label with no replicas */
+       ZPOOL_STATUS_BAD_GUID_SUM,      /* sum of device guids didn't match */
+       ZPOOL_STATUS_CORRUPT_POOL,      /* pool metadata is corrupted */
+       ZPOOL_STATUS_CORRUPT_DATA,      /* data errors in user (meta)data */
+       ZPOOL_STATUS_FAILING_DEV,       /* device experiencing errors */
+       ZPOOL_STATUS_VERSION_NEWER,     /* newer on-disk version */
+       ZPOOL_STATUS_HOSTID_MISMATCH,   /* last accessed by another system */
+       ZPOOL_STATUS_IO_FAILURE_WAIT,   /* failed I/O, failmode 'wait' */
+       ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */
+       ZPOOL_STATUS_BAD_LOG,           /* cannot read log chain(s) */
+       ZPOOL_STATUS_ERRATA,            /* informational errata available */
+
+       /*
+        * If the pool has unsupported features but can still be opened in
+        * read-only mode, its status is ZPOOL_STATUS_UNSUP_FEAT_WRITE. If the
+        * pool has unsupported features but cannot be opened at all, its
+        * status is ZPOOL_STATUS_UNSUP_FEAT_READ.
+        */
+       ZPOOL_STATUS_UNSUP_FEAT_READ,   /* unsupported features for read */
+       ZPOOL_STATUS_UNSUP_FEAT_WRITE,  /* unsupported features for write */
+
+       /*
+        * These faults have no corresponding message ID.  At the time we are
+        * checking the status, the original reason for the FMA fault (I/O or
+        * checksum errors) has been lost.
+        */
+       ZPOOL_STATUS_FAULTED_DEV_R,     /* faulted device with replicas */
+       ZPOOL_STATUS_FAULTED_DEV_NR,    /* faulted device with no replicas */
+
+       /*
+        * The following are not faults per se, but still an error possibly
+        * requiring administrative attention.  There is no corresponding
+        * message ID.
+        */
+       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_REMOVED_DEV,       /* removed device */
+
+       /*
+        * Finally, the following indicates a healthy pool.
+        */
+       ZPOOL_STATUS_OK
+} zpool_status_t;
+
+extern unsigned long get_system_hostid(void);
+extern zpool_status_t zpool_get_status(zpool_handle_t *, char **,
+    zpool_errata_t *);
+extern zpool_status_t zpool_import_status(nvlist_t *, char **,
+    zpool_errata_t *);
+extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh);
+
+/*
+ * Statistics and configuration functions.
+ */
+extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
+extern nvlist_t *zpool_get_features(zpool_handle_t *);
+extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
+extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
+
+/*
+ * Import and export functions
+ */
+extern int zpool_export(zpool_handle_t *, boolean_t, const char *);
+extern int zpool_export_force(zpool_handle_t *, const char *);
+extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
+    char *altroot);
+extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
+    nvlist_t *, int);
+extern void zpool_print_unsup_feat(nvlist_t *config);
+
+/*
+ * Search for pools to import
+ */
+
+typedef struct importargs {
+       char **path;            /* a list of paths to search            */
+       int paths;              /* number of paths to search            */
+       char *poolname;         /* name of a pool to find               */
+       uint64_t guid;          /* guid of a pool to find               */
+       char *cachefile;        /* cachefile to use for import          */
+       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 */
+} importargs_t;
+
+extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
+
+/* legacy pool search routines */
+extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
+extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
+    char *, uint64_t);
+
+/*
+ * Miscellaneous pool functions
+ */
+struct zfs_cmd;
+
+extern const char *zfs_history_event_names[];
+
+typedef enum {
+       VDEV_NAME_PATH          = 1 << 0,
+       VDEV_NAME_GUID          = 1 << 1,
+       VDEV_NAME_FOLLOW_LINKS  = 1 << 2,
+       VDEV_NAME_TYPE_ID       = 1 << 3,
+} vdev_name_t;
+
+extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
+    int name_flags);
+extern int zpool_upgrade(zpool_handle_t *, uint64_t);
+extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
+extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
+    nvlist_t ***, uint_t *);
+extern int zpool_events_next(libzfs_handle_t *, nvlist_t **, int *, unsigned,
+    int);
+extern int zpool_events_clear(libzfs_handle_t *, int *);
+extern int zpool_events_seek(libzfs_handle_t *, uint64_t, int);
+extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
+    size_t len);
+extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
+extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
+extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
+    nvlist_t *);
+
+/*
+ * Basic handle manipulations.  These functions do not create or destroy the
+ * underlying datasets, only the references to them.
+ */
+extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
+extern zfs_handle_t *zfs_handle_dup(zfs_handle_t *);
+extern void zfs_close(zfs_handle_t *);
+extern zfs_type_t zfs_get_type(const zfs_handle_t *);
+extern const char *zfs_get_name(const zfs_handle_t *);
+extern zpool_handle_t *zfs_get_pool_handle(const zfs_handle_t *);
+
+/*
+ * Property management functions.  Some functions are shared with the kernel,
+ * and are found in sys/fs/zfs.h.
+ */
+
+/*
+ * zfs dataset property management
+ */
+extern const char *zfs_prop_default_string(zfs_prop_t);
+extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
+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 *);
+
+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_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,
+    boolean_t);
+extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
+    zprop_source_t *, char *, size_t);
+extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
+    uint64_t *propvalue);
+extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
+    char *propbuf, int proplen, boolean_t literal);
+extern int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
+    uint64_t *propvalue);
+extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
+    char *propbuf, int proplen, boolean_t literal);
+extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
+    char *buf, size_t len);
+extern uint64_t getprop_uint64(zfs_handle_t *, zfs_prop_t, char **);
+extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
+extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
+extern const char *zfs_prop_values(zfs_prop_t);
+extern int zfs_prop_is_string(zfs_prop_t prop);
+extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
+extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
+extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *);
+
+typedef struct zprop_list {
+       int             pl_prop;
+       char            *pl_user_prop;
+       struct zprop_list *pl_next;
+       boolean_t       pl_all;
+       size_t          pl_width;
+       size_t          pl_recvd_width;
+       boolean_t       pl_fixed;
+} zprop_list_t;
+
+extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t,
+    boolean_t);
+extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
+
+#define        ZFS_MOUNTPOINT_NONE     "none"
+#define        ZFS_MOUNTPOINT_LEGACY   "legacy"
+
+#define        ZFS_FEATURE_DISABLED    "disabled"
+#define        ZFS_FEATURE_ENABLED     "enabled"
+#define        ZFS_FEATURE_ACTIVE      "active"
+
+#define        ZFS_UNSUPPORTED_INACTIVE        "inactive"
+#define        ZFS_UNSUPPORTED_READONLY        "readonly"
+
+/*
+ * zpool property management
+ */
+extern int zpool_expand_proplist(zpool_handle_t *, zprop_list_t **);
+extern int zpool_prop_get_feature(zpool_handle_t *, const char *, char *,
+    size_t);
+extern const char *zpool_prop_default_string(zpool_prop_t);
+extern uint64_t zpool_prop_default_numeric(zpool_prop_t);
+extern const char *zpool_prop_column_name(zpool_prop_t);
+extern boolean_t zpool_prop_align_right(zpool_prop_t);
+
+/*
+ * Functions shared by zfs and zpool property management.
+ */
+extern int zprop_iter(zprop_func func, void *cb, boolean_t show_all,
+    boolean_t ordered, zfs_type_t type);
+extern int zprop_get_list(libzfs_handle_t *, char *, zprop_list_t **,
+    zfs_type_t);
+extern void zprop_free_list(zprop_list_t *);
+
+#define        ZFS_GET_NCOLS   5
+
+typedef enum {
+       GET_COL_NONE,
+       GET_COL_NAME,
+       GET_COL_PROPERTY,
+       GET_COL_VALUE,
+       GET_COL_RECVD,
+       GET_COL_SOURCE
+} zfs_get_column_t;
+
+/*
+ * Functions for printing zfs or zpool properties
+ */
+typedef struct zprop_get_cbdata {
+       int cb_sources;
+       zfs_get_column_t cb_columns[ZFS_GET_NCOLS];
+       int cb_colwidths[ZFS_GET_NCOLS + 1];
+       boolean_t cb_scripted;
+       boolean_t cb_literal;
+       boolean_t cb_first;
+       zprop_list_t *cb_proplist;
+       zfs_type_t cb_type;
+} zprop_get_cbdata_t;
+
+void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
+    const char *, const char *, zprop_source_t, const char *,
+    const char *);
+
+/*
+ * Iterator functions.
+ */
+typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
+extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
+extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
+extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
+extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *);
+
+typedef struct get_all_cb {
+       zfs_handle_t    **cb_handles;
+       size_t          cb_alloc;
+       size_t          cb_used;
+       boolean_t       cb_verbose;
+       int             (*cb_getone)(zfs_handle_t *, void *);
+} get_all_cb_t;
+
+void libzfs_add_handle(get_all_cb_t *, zfs_handle_t *);
+int libzfs_dataset_cmp(const void *, const void *);
+
+/*
+ * Functions to create and destroy datasets.
+ */
+extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
+    nvlist_t *);
+extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
+extern int zfs_destroy(zfs_handle_t *, boolean_t);
+extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
+extern int zfs_destroy_snaps_nvl(libzfs_handle_t *, nvlist_t *, boolean_t);
+extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
+extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
+extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
+    nvlist_t *props);
+extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
+extern int zfs_rename(zfs_handle_t *, const char *, boolean_t, boolean_t);
+
+typedef struct sendflags {
+       /* print informational messages (ie, -v was specified) */
+       boolean_t verbose;
+
+       /* recursive send  (ie, -R) */
+       boolean_t replicate;
+
+       /* for incrementals, do all intermediate snapshots */
+       boolean_t doall;
+
+       /* if dataset is a clone, do incremental from its origin */
+       boolean_t fromorigin;
+
+       /* do deduplication */
+       boolean_t dedup;
+
+       /* send properties (ie, -p) */
+       boolean_t props;
+
+       /* do not send (no-op, ie. -n) */
+       boolean_t dryrun;
+
+       /* parsable verbose output (ie. -P) */
+       boolean_t parsable;
+
+       /* show progress (ie. -v) */
+       boolean_t progress;
+
+       /* large blocks (>128K) are permitted */
+       boolean_t largeblock;
+
+       /* WRITE_EMBEDDED records of type DATA are permitted */
+       boolean_t embed_data;
+} sendflags_t;
+
+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_promote(zfs_handle_t *);
+extern int zfs_hold(zfs_handle_t *, const char *, const char *,
+    boolean_t, int);
+extern int zfs_hold_nvl(zfs_handle_t *, int, nvlist_t *);
+extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
+extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
+extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
+
+typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain,
+    uid_t rid, uint64_t space);
+
+extern int zfs_userspace(zfs_handle_t *, zfs_userquota_prop_t,
+    zfs_userspace_cb_t, void *);
+
+extern int zfs_get_fsacl(zfs_handle_t *, nvlist_t **);
+extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *);
+
+typedef struct recvflags {
+       /* print informational messages (ie, -v was specified) */
+       boolean_t verbose;
+
+       /* the destination is a prefix, not the exact fs (ie, -d) */
+       boolean_t isprefix;
+
+       /*
+        * Only the tail of the sent snapshot path is appended to the
+        * destination to determine the received snapshot name (ie, -e).
+        */
+       boolean_t istail;
+
+       /* do not actually do the recv, just check if it would work (ie, -n) */
+       boolean_t dryrun;
+
+       /* rollback/destroy filesystems as necessary (eg, -F) */
+       boolean_t force;
+
+       /* set "canmount=off" on all modified filesystems */
+       boolean_t canmountoff;
+
+       /* byteswap flag is used internally; callers need not specify */
+       boolean_t byteswap;
+
+       /* do not mount file systems as they are extracted (private) */
+       boolean_t nomount;
+} recvflags_t;
+
+extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *,
+    int, avl_tree_t *);
+
+typedef enum diff_flags {
+       ZFS_DIFF_PARSEABLE = 0x1,
+       ZFS_DIFF_TIMESTAMP = 0x2,
+       ZFS_DIFF_CLASSIFY = 0x4
+} diff_flags_t;
+
+extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
+    int);
+
+/*
+ * Miscellaneous functions.
+ */
+extern const char *zfs_type_to_name(zfs_type_t);
+extern void zfs_refresh_properties(zfs_handle_t *);
+extern int zfs_name_valid(const char *, zfs_type_t);
+extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
+extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
+    zfs_type_t);
+extern int zfs_spa_version(zfs_handle_t *, int *);
+extern boolean_t zfs_bookmark_exists(const char *path);
+extern int zfs_append_partition(char *path, size_t max_len);
+extern int zfs_resolve_shortname(const char *name, char *path, size_t pathlen);
+extern int zfs_strcmp_pathname(char *name, char *cmp_name, int wholedisk);
+
+/*
+ * Mount support functions.
+ */
+extern boolean_t is_mounted(libzfs_handle_t *, const char *special, char **);
+extern boolean_t zfs_is_mounted(zfs_handle_t *, char **);
+extern int zfs_mount(zfs_handle_t *, const char *, int);
+extern int zfs_unmount(zfs_handle_t *, const char *, int);
+extern int zfs_unmountall(zfs_handle_t *, int);
+
+/*
+ * Share support functions.
+ */
+extern boolean_t zfs_is_shared(zfs_handle_t *);
+extern int zfs_share(zfs_handle_t *);
+extern int zfs_unshare(zfs_handle_t *);
+
+/*
+ * Protocol-specific share support functions.
+ */
+extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
+extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
+extern int zfs_share_nfs(zfs_handle_t *);
+extern int zfs_share_smb(zfs_handle_t *);
+extern int zfs_shareall(zfs_handle_t *);
+extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
+extern int zfs_unshare_smb(zfs_handle_t *, const char *);
+extern int zfs_unshareall_nfs(zfs_handle_t *);
+extern int zfs_unshareall_smb(zfs_handle_t *);
+extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
+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);
+
+/*
+ * Utility function to convert a number to a human-readable form.
+ */
+extern void zfs_nicenum(uint64_t, char *, size_t);
+extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
+
+/*
+ * Utility functions to run an external process.
+ */
+#define        STDOUT_VERBOSE  0x01
+#define        STDERR_VERBOSE  0x02
+
+int libzfs_run_process(const char *, char **, int flags);
+
+/*
+ * Given a device or file, determine if it is part of a pool.
+ */
+extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
+    boolean_t *);
+
+/*
+ * Label manipulation.
+ */
+extern int zpool_read_label(int, nvlist_t **, int *);
+extern int zpool_clear_label(int);
+
+/*
+ * Management interfaces for SMB ACL files
+ */
+
+int zfs_smb_acl_add(libzfs_handle_t *, char *, char *, char *);
+int zfs_smb_acl_remove(libzfs_handle_t *, char *, char *, char *);
+int zfs_smb_acl_purge(libzfs_handle_t *, char *, char *);
+int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *);
+
+/*
+ * Enable and disable datasets within a pool by mounting/unmounting and
+ * sharing/unsharing them.
+ */
+extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
+extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
+
+/*
+ * Mappings between vdev and FRU.
+ */
+extern void libzfs_fru_refresh(libzfs_handle_t *);
+extern const char *libzfs_fru_lookup(libzfs_handle_t *, const char *);
+extern const char *libzfs_fru_devpath(libzfs_handle_t *, const char *);
+extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
+    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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_H */
diff --git a/zfs/include/libzfs_core.h b/zfs/include/libzfs_core.h
new file mode 100644 (file)
index 0000000..bdd6c95
--- /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 (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _LIBZFS_CORE_H
+#define        _LIBZFS_CORE_H
+
+#include <libnvpair.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int libzfs_core_init(void);
+void libzfs_core_fini(void);
+
+int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
+int lzc_create(const char *, dmu_objset_type_t, nvlist_t *);
+int lzc_clone(const char *, const char *, nvlist_t *);
+int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
+int lzc_bookmark(nvlist_t *, nvlist_t **);
+int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
+int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **);
+
+int lzc_snaprange_space(const char *, const char *, uint64_t *);
+
+int lzc_hold(nvlist_t *, int, nvlist_t **);
+int lzc_release(nvlist_t *, nvlist_t **);
+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
+};
+
+int lzc_send(const char *, const char *, int, enum lzc_send_flags);
+int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
+int lzc_send_space(const char *, const char *, uint64_t *);
+
+boolean_t lzc_exists(const char *);
+
+int lzc_rollback(const char *, char *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_CORE_H */
diff --git a/zfs/include/libzfs_impl.h b/zfs/include/libzfs_impl.h
new file mode 100644 (file)
index 0000000..e805e3e
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * CDDL HEADER SART
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#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 <libuutil.h>
+#include <libzfs.h>
+#include <libshare.h>
+#include <libzfs_core.h>
+
+#if defined(HAVE_LIBTOPO)
+#include <fm/libtopo.h>
+#endif /* HAVE_LIBTOPO */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef VERIFY
+#undef VERIFY
+#endif
+#define        VERIFY  verify
+
+typedef struct libzfs_fru {
+       char *zf_device;
+       char *zf_fru;
+       struct libzfs_fru *zf_chain;
+       struct libzfs_fru *zf_next;
+} libzfs_fru_t;
+
+struct libzfs_handle {
+       int libzfs_error;
+       int libzfs_fd;
+       FILE *libzfs_mnttab;
+       FILE *libzfs_sharetab;
+       zpool_handle_t *libzfs_pool_handles;
+       uu_avl_pool_t *libzfs_ns_avlpool;
+       uu_avl_t *libzfs_ns_avl;
+       uint64_t libzfs_ns_gen;
+       int libzfs_desc_active;
+       char libzfs_action[1024];
+       char libzfs_desc[1024];
+       int libzfs_printerr;
+       int libzfs_storeerr; /* stuff error messages into buffer */
+       void *libzfs_sharehdl; /* libshare handle */
+       uint_t libzfs_shareflags;
+       boolean_t libzfs_mnttab_enable;
+       avl_tree_t libzfs_mnttab_cache;
+       int libzfs_pool_iter;
+#if defined(HAVE_LIBTOPO)
+       topo_hdl_t *libzfs_topo_hdl;
+       libzfs_fru_t **libzfs_fru_hash;
+       libzfs_fru_t *libzfs_fru_list;
+#endif /* HAVE_LIBTOPO */
+       char libzfs_chassis_id[256];
+};
+
+#define        ZFSSHARE_MISS   0x01    /* Didn't find entry in cache */
+
+struct zfs_handle {
+       libzfs_handle_t *zfs_hdl;
+       zpool_handle_t *zpool_hdl;
+       char zfs_name[ZFS_MAXNAMELEN];
+       zfs_type_t zfs_type; /* type including snapshot */
+       zfs_type_t zfs_head_type; /* type excluding snapshot */
+       dmu_objset_stats_t zfs_dmustats;
+       nvlist_t *zfs_props;
+       nvlist_t *zfs_user_props;
+       nvlist_t *zfs_recvd_props;
+       boolean_t zfs_mntcheck;
+       char *zfs_mntopts;
+       uint8_t *zfs_props_table;
+};
+
+/*
+ * This is different from checking zfs_type, because it will also catch
+ * snapshots of volumes.
+ */
+#define        ZFS_IS_VOLUME(zhp) ((zhp)->zfs_head_type == ZFS_TYPE_VOLUME)
+
+struct zpool_handle {
+       libzfs_handle_t *zpool_hdl;
+       zpool_handle_t *zpool_next;
+       char zpool_name[ZPOOL_MAXNAMELEN];
+       int zpool_state;
+       size_t zpool_config_size;
+       nvlist_t *zpool_config;
+       nvlist_t *zpool_old_config;
+       nvlist_t *zpool_props;
+       diskaddr_t zpool_start_block;
+};
+
+typedef enum {
+       PROTO_NFS = 0,
+       PROTO_SMB = 1,
+       PROTO_END = 2
+} zfs_share_proto_t;
+
+/*
+ * The following can be used as a bitmask and any new values
+ * added must preserve that capability.
+ */
+typedef enum {
+       SHARED_NOT_SHARED = 0x0,
+       SHARED_NFS = 0x2,
+       SHARED_SMB = 0x4
+} zfs_share_type_t;
+
+int zfs_error(libzfs_handle_t *, int, const char *);
+int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
+void zfs_error_aux(libzfs_handle_t *, const char *, ...);
+void *zfs_alloc(libzfs_handle_t *, size_t);
+void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
+char *zfs_asprintf(libzfs_handle_t *, const char *, ...);
+char *zfs_strdup(libzfs_handle_t *, const char *);
+int no_memory(libzfs_handle_t *);
+
+int zfs_standard_error(libzfs_handle_t *, int, const char *);
+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 *);
+
+int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
+    nvlist_t *, char **, uint64_t *, const char *);
+int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp,
+    zfs_type_t type);
+
+/*
+ * Use this changelist_gather() flag to force attempting mounts
+ * on each change node regardless of whether or not it is currently
+ * mounted.
+ */
+#define        CL_GATHER_MOUNT_ALWAYS  1
+
+typedef struct prop_changelist prop_changelist_t;
+
+int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
+int zcmd_write_src_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *);
+int zcmd_write_conf_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *);
+int zcmd_expand_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *);
+int zcmd_read_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t **);
+void zcmd_free_nvlists(zfs_cmd_t *);
+
+int changelist_prefix(prop_changelist_t *);
+int changelist_postfix(prop_changelist_t *);
+void changelist_rename(prop_changelist_t *, const char *, const char *);
+void changelist_remove(prop_changelist_t *, const char *);
+void changelist_free(prop_changelist_t *);
+prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int, int);
+int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
+int changelist_haszonedchild(prop_changelist_t *);
+
+void remove_mountpoint(zfs_handle_t *);
+int create_parents(libzfs_handle_t *, char *, int);
+boolean_t isa_child_of(const char *dataset, const char *parent);
+
+zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
+zfs_handle_t *make_bookmark_handle(zfs_handle_t *, const char *,
+    nvlist_t *props);
+
+int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
+
+boolean_t zpool_name_valid(libzfs_handle_t *, boolean_t, const char *);
+
+int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
+    boolean_t modifying);
+
+void namespace_clear(libzfs_handle_t *);
+
+/*
+ * libshare (sharemgr) interfaces used internally.
+ */
+
+extern int zfs_init_libshare(libzfs_handle_t *, int);
+extern void zfs_uninit_libshare(libzfs_handle_t *);
+extern int zfs_parse_options(char *, zfs_share_proto_t);
+
+extern int zfs_unshare_proto(zfs_handle_t *,
+    const char *, zfs_share_proto_t *);
+
+extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBZFS_IMPL_H */
diff --git a/zfs/include/linux/Makefile.am b/zfs/include/linux/Makefile.am
new file mode 100644 (file)
index 0000000..595d1db
--- /dev/null
@@ -0,0 +1,23 @@
+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)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/linux
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/linux
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/linux/Makefile.in b/zfs/include/linux/Makefile.in
new file mode 100644 (file)
index 0000000..f0596c3
--- /dev/null
@@ -0,0 +1,768 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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:
diff --git a/zfs/include/linux/blkdev_compat.h b/zfs/include/linux/blkdev_compat.h
new file mode 100644 (file)
index 0000000..8179aca
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ * LLNL-CODE-403049.
+ */
+
+#ifndef _ZFS_BLKDEV_H
+#define        _ZFS_BLKDEV_H
+
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+
+#ifndef HAVE_FMODE_T
+typedef unsigned __bitwise__ fmode_t;
+#endif /* HAVE_FMODE_T */
+
+/*
+ * 4.7 - 4.x API,
+ * The blk_queue_write_cache() interface has replaced blk_queue_flush()
+ * interface.  However, the new interface is GPL-only thus we implement
+ * our own trivial wrapper when the GPL-only version is detected.
+ *
+ * 2.6.36 - 4.6 API,
+ * The blk_queue_flush() interface has replaced blk_queue_ordered()
+ * interface.  However, while the old interface was available to all the
+ * new one is GPL-only.   Thus if the GPL-only version is detected we
+ * implement our own trivial helper.
+ *
+ * 2.6.x - 2.6.35
+ * Legacy blk_queue_ordered() interface.
+ */
+static inline void
+blk_queue_set_write_cache(struct request_queue *q, bool wc, bool fua)
+{
+#if defined(HAVE_BLK_QUEUE_WRITE_CACHE_GPL_ONLY)
+       spin_lock_irq(q->queue_lock);
+       if (wc)
+               queue_flag_set(QUEUE_FLAG_WC, q);
+       else
+               queue_flag_clear(QUEUE_FLAG_WC, q);
+       if (fua)
+               queue_flag_set(QUEUE_FLAG_FUA, q);
+       else
+               queue_flag_clear(QUEUE_FLAG_FUA, q);
+       spin_unlock_irq(q->queue_lock);
+#elif defined(HAVE_BLK_QUEUE_WRITE_CACHE)
+       blk_queue_write_cache(q, wc, fua);
+#elif defined(HAVE_BLK_QUEUE_FLUSH_GPL_ONLY)
+       if (wc)
+               q->flush_flags |= REQ_FLUSH;
+       if (fua)
+               q->flush_flags |= REQ_FUA;
+#elif defined(HAVE_BLK_QUEUE_FLUSH)
+       blk_queue_flush(q, (wc ? REQ_FLUSH : 0) | (fua ? REQ_FUA : 0));
+#else
+       blk_queue_ordered(q, QUEUE_ORDERED_DRAIN, NULL);
+#endif
+}
+
+/*
+ * Most of the blk_* macros were removed in 2.6.36.  Ostensibly this was
+ * done to improve readability and allow easier grepping.  However, from
+ * a portability stand point the macros are helpful.  Therefore the needed
+ * macros are redefined here if they are missing from the kernel.
+ */
+#ifndef blk_fs_request
+#define        blk_fs_request(rq)      ((rq)->cmd_type == REQ_TYPE_FS)
+#endif
+
+/*
+ * 2.6.27 API change,
+ * The blk_queue_stackable() queue flag was added in 2.6.27 to handle dm
+ * stacking drivers.  Prior to this request stacking drivers were detected
+ * by checking (q->request_fn == NULL), for earlier kernels we revert to
+ * this legacy behavior.
+ */
+#ifndef blk_queue_stackable
+#define        blk_queue_stackable(q)  ((q)->request_fn == NULL)
+#endif
+
+/*
+ * 2.6.34 API change,
+ * The blk_queue_max_hw_sectors() function replaces blk_queue_max_sectors().
+ */
+#ifndef HAVE_BLK_QUEUE_MAX_HW_SECTORS
+#define        blk_queue_max_hw_sectors __blk_queue_max_hw_sectors
+static inline void
+__blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
+{
+       blk_queue_max_sectors(q, max_hw_sectors);
+}
+#endif
+
+/*
+ * 2.6.34 API change,
+ * The blk_queue_max_segments() function consolidates
+ * blk_queue_max_hw_segments() and blk_queue_max_phys_segments().
+ */
+#ifndef HAVE_BLK_QUEUE_MAX_SEGMENTS
+#define        blk_queue_max_segments __blk_queue_max_segments
+static inline void
+__blk_queue_max_segments(struct request_queue *q, unsigned short max_segments)
+{
+       blk_queue_max_phys_segments(q, max_segments);
+       blk_queue_max_hw_segments(q, max_segments);
+}
+#endif
+
+#ifndef HAVE_GET_DISK_RO
+static inline int
+get_disk_ro(struct gendisk *disk)
+{
+       int policy = 0;
+
+       if (disk->part[0])
+               policy = disk->part[0]->policy;
+
+       return (policy);
+}
+#endif /* HAVE_GET_DISK_RO */
+
+#ifdef HAVE_BIO_BVEC_ITER
+#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_for_each_segment4(bv, bvp, b, i)    \
+       bio_for_each_segment((bv), (b), (i))
+typedef struct bvec_iter bvec_iterator_t;
+#else
+#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_for_each_segment4(bv, bvp, b, i)    \
+       bio_for_each_segment((bvp), (b), (i))
+typedef int bvec_iterator_t;
+#endif
+
+/*
+ * Portable helper for correctly setting the FAILFAST flags.  The
+ * correct usage has changed 3 times from 2.6.12 to 2.6.38.
+ */
+static inline void
+bio_set_flags_failfast(struct block_device *bdev, int *flags)
+{
+#ifdef CONFIG_BUG
+       /*
+        * Disable FAILFAST for loopback devices because of the
+        * following incorrect BUG_ON() in loop_make_request().
+        * This support is also disabled for md devices because the
+        * test suite layers md devices on top of loopback devices.
+        * This may be removed when the loopback driver is fixed.
+        *
+        *   BUG_ON(!lo || (rw != READ && rw != WRITE));
+        */
+       if ((MAJOR(bdev->bd_dev) == LOOP_MAJOR) ||
+           (MAJOR(bdev->bd_dev) == MD_MAJOR))
+               return;
+
+#ifdef BLOCK_EXT_MAJOR
+       if (MAJOR(bdev->bd_dev) == BLOCK_EXT_MAJOR)
+               return;
+#endif /* BLOCK_EXT_MAJOR */
+#endif /* CONFIG_BUG */
+
+#if defined(HAVE_BIO_RW_FAILFAST_DTD)
+       /* BIO_RW_FAILFAST_* preferred interface from 2.6.28 - 2.6.35 */
+       *flags |= (
+           (1 << BIO_RW_FAILFAST_DEV) |
+           (1 << BIO_RW_FAILFAST_TRANSPORT) |
+           (1 << BIO_RW_FAILFAST_DRIVER));
+#elif defined(HAVE_REQ_FAILFAST_MASK)
+       /*
+        * REQ_FAILFAST_* preferred interface from 2.6.36 - 2.6.xx,
+        * the BIO_* and REQ_* flags were unified under REQ_* flags.
+        */
+       *flags |= REQ_FAILFAST_MASK;
+#else
+#error "Undefined block IO FAILFAST interface."
+#endif
+}
+
+/*
+ * Maximum disk label length, it may be undefined for some kernels.
+ */
+#ifndef DISK_NAME_LEN
+#define        DISK_NAME_LEN   32
+#endif /* DISK_NAME_LEN */
+
+/*
+ * 4.3 API change
+ * The bio_endio() prototype changed slightly.  These are helper
+ * macro's to ensure the prototype and invocation are handled.
+ */
+#ifdef HAVE_1ARG_BIO_END_IO_T
+#define        BIO_END_IO_PROTO(fn, x, z)      static void fn(struct bio *x)
+#define        BIO_END_IO(bio, error)          bio->bi_error = error; bio_endio(bio);
+#else
+#define        BIO_END_IO_PROTO(fn, x, z)      static void fn(struct bio *x, int z)
+#define        BIO_END_IO(bio, error)          bio_endio(bio, error);
+#endif /* HAVE_1ARG_BIO_END_IO_T */
+
+/*
+ * 2.6.38 - 2.6.x API,
+ *   blkdev_get_by_path()
+ *   blkdev_put()
+ *
+ * 2.6.28 - 2.6.37 API,
+ *   open_bdev_exclusive()
+ *   close_bdev_exclusive()
+ *
+ * 2.6.12 - 2.6.27 API,
+ *   open_bdev_excl()
+ *   close_bdev_excl()
+ *
+ * Used to exclusively open a block device from within the kernel.
+ */
+#if defined(HAVE_BLKDEV_GET_BY_PATH)
+#define        vdev_bdev_open(path, md, hld)   blkdev_get_by_path(path, \
+                                           (md) | FMODE_EXCL, hld)
+#define        vdev_bdev_close(bdev, md)       blkdev_put(bdev, (md) | FMODE_EXCL)
+#elif defined(HAVE_OPEN_BDEV_EXCLUSIVE)
+#define        vdev_bdev_open(path, md, hld)   open_bdev_exclusive(path, md, hld)
+#define        vdev_bdev_close(bdev, md)       close_bdev_exclusive(bdev, md)
+#else
+#define        vdev_bdev_open(path, md, hld)   open_bdev_excl(path, md, hld)
+#define        vdev_bdev_close(bdev, md)       close_bdev_excl(bdev)
+#endif /* HAVE_BLKDEV_GET_BY_PATH | HAVE_OPEN_BDEV_EXCLUSIVE */
+
+/*
+ * 2.6.22 API change
+ * The function invalidate_bdev() lost it's second argument because
+ * it was unused.
+ */
+#ifdef HAVE_1ARG_INVALIDATE_BDEV
+#define        vdev_bdev_invalidate(bdev)      invalidate_bdev(bdev)
+#else
+#define        vdev_bdev_invalidate(bdev)      invalidate_bdev(bdev, 1)
+#endif /* HAVE_1ARG_INVALIDATE_BDEV */
+
+/*
+ * 2.6.27 API change
+ * 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.
+ */
+#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
+ * To ensure good performance preferentially use the physical block size
+ * for proper alignment.  The physical size is supposed to be the internal
+ * sector size used by the device.  This is often 4096 byte for AF devices,
+ * while a smaller 512 byte logical size is supported for compatibility.
+ *
+ * Unfortunately, many drives still misreport their physical sector size.
+ * For devices which are known to lie you may need to manually set this
+ * at pool creation time with 'zpool create -o ashift=12 ...'.
+ *
+ * When the physical block size interface isn't available, we fall back to
+ * the logical block size interface and then the older hard sector size.
+ */
+#ifdef HAVE_BDEV_PHYSICAL_BLOCK_SIZE
+#define        vdev_bdev_block_size(bdev)      bdev_physical_block_size(bdev)
+#else
+#ifdef HAVE_BDEV_LOGICAL_BLOCK_SIZE
+#define        vdev_bdev_block_size(bdev)      bdev_logical_block_size(bdev)
+#else
+#define        vdev_bdev_block_size(bdev)      bdev_hardsect_size(bdev)
+#endif /* HAVE_BDEV_LOGICAL_BLOCK_SIZE */
+#endif /* HAVE_BDEV_PHYSICAL_BLOCK_SIZE */
+
+#ifndef HAVE_BIO_SET_OP_ATTRS
+/*
+ * Kernels without bio_set_op_attrs use bi_rw for the bio flags.
+ */
+static inline void
+bio_set_op_attrs(struct bio *bio, unsigned rw, unsigned flags)
+{
+       bio->bi_rw |= rw | flags;
+}
+#endif
+
+/*
+ * bio_set_flush - Set the appropriate flags in a bio to guarantee
+ * data are on non-volatile media on completion.
+ *
+ * 2.6.X - 2.6.36 API,
+ *   WRITE_BARRIER - Tells the block layer to commit all previously submitted
+ *   writes to stable storage before this one is started and that the current
+ *   write is on stable storage upon completion.  Also prevents reordering
+ *   on both sides of the current operation.
+ *
+ * 2.6.37 - 4.8 API,
+ *   Introduce  WRITE_FLUSH, WRITE_FUA, and WRITE_FLUSH_FUA flags as a
+ *   replacement for WRITE_BARRIER to allow expressing richer semantics
+ *   to the block layer.  It's up to the block layer to implement the
+ *   semantics correctly. Use the WRITE_FLUSH_FUA flag combination.
+ *
+ * 4.8 - 4.9 API,
+ *   REQ_FLUSH was renamed to REQ_PREFLUSH.  For consistency with previous
+ *   ZoL releases, prefer the WRITE_FLUSH_FUA flag set if it's available.
+ *
+ * 4.10 API,
+ *   The read/write flags and their modifiers, including WRITE_FLUSH,
+ *   WRITE_FUA and WRITE_FLUSH_FUA were removed from fs.h in
+ *   torvalds/linux@70fd7614 and replaced by direct flag modification
+ *   of the REQ_ flags in bio->bi_opf.  Use REQ_PREFLUSH.
+ */
+static inline void
+bio_set_flush(struct bio *bio)
+{
+#if defined(WRITE_BARRIER)     /* < 2.6.37 */
+       bio_set_op_attrs(bio, 0, WRITE_BARRIER);
+#elif defined(WRITE_FLUSH_FUA) /* >= 2.6.37 and <= 4.9 */
+       bio_set_op_attrs(bio, 0, WRITE_FLUSH_FUA);
+#elif defined(REQ_PREFLUSH)    /* >= 4.10 */
+       bio_set_op_attrs(bio, 0, REQ_PREFLUSH);
+#else
+#error "Allowing the build will cause bio_set_flush requests to be ignored."
+       "Please file an issue report at: "
+       "https://github.com/zfsonlinux/zfs/issues/new"
+#endif
+}
+
+/*
+ * 4.8 - 4.x API,
+ *   REQ_OP_FLUSH
+ *
+ * 4.8-rc0 - 4.8-rc1,
+ *   REQ_PREFLUSH
+ *
+ * 2.6.36 - 4.7 API,
+ *   REQ_FLUSH
+ *
+ * 2.6.x - 2.6.35 API,
+ *   HAVE_BIO_RW_BARRIER
+ *
+ * Used to determine if a cache flush has been requested.  This check has
+ * been left intentionally broad in order to cover both a legacy flush
+ * 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)
+{
+#if defined(HAVE_REQ_OP_FLUSH) && defined(HAVE_BIO_BI_OPF)
+       return ((bio_op(bio) == REQ_OP_FLUSH) || (bio->bi_opf & REQ_PREFLUSH));
+#elif defined(REQ_PREFLUSH) && defined(HAVE_BIO_BI_OPF)
+       return (bio->bi_opf & REQ_PREFLUSH);
+#elif defined(REQ_PREFLUSH) && !defined(HAVE_BIO_BI_OPF)
+       return (bio->bi_rw & REQ_PREFLUSH);
+#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"
+#endif
+}
+
+/*
+ * 4.8 - 4.x API,
+ *   REQ_FUA flag moved to bio->bi_opf
+ *
+ * 2.6.x - 4.7 API,
+ *   REQ_FUA
+ */
+static inline boolean_t
+bio_is_fua(struct bio *bio)
+{
+#if defined(HAVE_BIO_BI_OPF)
+       return (bio->bi_opf & REQ_FUA);
+#elif defined(REQ_FUA)
+       return (bio->bi_rw & REQ_FUA);
+#else
+#error "Allowing the build will cause fua requests to be ignored. Please "
+       "file an issue report at: https://github.com/zfsonlinux/zfs/issues/new"
+#endif
+}
+
+/*
+ * 4.8 - 4.x API,
+ *   REQ_OP_DISCARD
+ *
+ * 2.6.36 - 4.7 API,
+ *   REQ_DISCARD
+ *
+ * 2.6.28 - 2.6.35 API,
+ *   BIO_RW_DISCARD
+ *
+ * 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(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 "
+       "an issue report at: https://github.com/zfsonlinux/zfs/issues/new"
+#endif
+}
+
+/*
+ * 4.8 - 4.x API,
+ *   REQ_OP_SECURE_ERASE
+ *
+ * 2.6.36 - 4.7 API,
+ *   REQ_SECURE
+ *
+ * 2.6.x - 2.6.35 API,
+ *   Unsupported by kernel
+ */
+static inline boolean_t
+bio_is_secure_erase(struct bio *bio)
+{
+#if defined(HAVE_REQ_OP_SECURE_ERASE)
+       return (bio_op(bio) == REQ_OP_SECURE_ERASE);
+#elif defined(REQ_SECURE)
+       return (bio->bi_rw & REQ_SECURE);
+#else
+       return (0);
+#endif
+}
+
+/*
+ * 2.6.33 API change
+ * Discard granularity and alignment restrictions may now be set.  For
+ * older kernels which do not support this it is safe to skip it.
+ */
+#ifdef HAVE_DISCARD_GRANULARITY
+static inline void
+blk_queue_discard_granularity(struct request_queue *q, unsigned int dg)
+{
+       q->limits.discard_granularity = dg;
+}
+#else
+#define        blk_queue_discard_granularity(x, dg)    ((void)0)
+#endif /* HAVE_DISCARD_GRANULARITY */
+
+/*
+ * Default Linux IO Scheduler,
+ * Setting the scheduler to noop will allow the Linux IO scheduler to
+ * still perform front and back merging, while leaving the request
+ * ordering and prioritization to the ZFS IO scheduler.
+ */
+#define        VDEV_SCHEDULER                  "noop"
+
+/*
+ * A common holder for vdev_bdev_open() is used to relax the exclusive open
+ * semantics slightly.  Internal vdev disk callers may pass VDEV_HOLDER to
+ * allow them to open the device multiple times.  Other kernel callers and
+ * user space processes which don't pass this value will get EBUSY.  This is
+ * currently required for the correct operation of hot spares.
+ */
+#define        VDEV_HOLDER                     ((void *)0x2401de7)
+
+#ifndef HAVE_GENERIC_IO_ACCT
+#define        generic_start_io_acct(rw, slen, part)           ((void)0)
+#define        generic_end_io_acct(rw, part, start_jiffies)    ((void)0)
+#endif
+
+#endif /* _ZFS_BLKDEV_H */
diff --git a/zfs/include/linux/dcache_compat.h b/zfs/include/linux/dcache_compat.h
new file mode 100644 (file)
index 0000000..bdaa5db
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _ZFS_DCACHE_H
+#define        _ZFS_DCACHE_H
+
+#include <linux/dcache.h>
+
+#define        dname(dentry)   ((char *)((dentry)->d_name.name))
+#define        dlen(dentry)    ((int)((dentry)->d_name.len))
+
+#ifndef HAVE_D_MAKE_ROOT
+#define        d_make_root(inode)      d_alloc_root(inode)
+#endif /* HAVE_D_MAKE_ROOT */
+
+/*
+ * 2.6.30 API change,
+ * The const keyword was added to the 'struct dentry_operations' in
+ * the dentry structure.  To handle this we define an appropriate
+ * dentry_operations_t typedef which can be used.
+ */
+#ifdef HAVE_CONST_DENTRY_OPERATIONS
+typedef const struct dentry_operations dentry_operations_t;
+#else
+typedef struct dentry_operations       dentry_operations_t;
+#endif
+
+/*
+ * 2.6.38 API change,
+ * Added d_set_d_op() helper function which sets some flags in
+ * dentry->d_flags based on which operations are defined.
+ */
+#ifndef HAVE_D_SET_D_OP
+static inline void
+d_set_d_op(struct dentry *dentry, dentry_operations_t *op)
+{
+       dentry->d_op = op;
+}
+#endif /* HAVE_D_SET_D_OP */
+
+/*
+ * 2.6.38 API addition,
+ * Added d_clear_d_op() helper function which clears some flags and the
+ * registered dentry->d_op table.  This is required because d_set_d_op()
+ * issues a warning when the dentry operations table is already set.
+ * For the .zfs control directory to work properly we must be able to
+ * override the default operations table and register custom .d_automount
+ * and .d_revalidate callbacks.
+ */
+static inline void
+d_clear_d_op(struct dentry *dentry)
+{
+#ifdef HAVE_D_SET_D_OP
+       dentry->d_op = NULL;
+       dentry->d_flags &= ~(
+           DCACHE_OP_HASH | DCACHE_OP_COMPARE |
+           DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE);
+#endif /* HAVE_D_SET_D_OP */
+}
+
+#endif /* _ZFS_DCACHE_H */
diff --git a/zfs/include/linux/kmap_compat.h b/zfs/include/linux/kmap_compat.h
new file mode 100644 (file)
index 0000000..59ae566
--- /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 (c) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+#ifndef _ZFS_KMAP_H
+#define        _ZFS_KMAP_H
+
+#include <linux/highmem.h>
+
+#ifdef HAVE_1ARG_KMAP_ATOMIC
+/* 2.6.37 API change */
+#define        zfs_kmap_atomic(page, km_type)          kmap_atomic(page)
+#define        zfs_kunmap_atomic(addr, km_type)        kunmap_atomic(addr)
+#else
+#define        zfs_kmap_atomic(page, km_type)          kmap_atomic(page, km_type)
+#define        zfs_kunmap_atomic(addr, km_type)        kunmap_atomic(addr, km_type)
+#endif
+
+#endif /* _ZFS_KMAP_H */
diff --git a/zfs/include/linux/utsname_compat.h b/zfs/include/linux/utsname_compat.h
new file mode 100644 (file)
index 0000000..88da45c
--- /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
+ */
+
+#ifndef        _ZFS_UTSNAME_H
+#define        _ZFS_UTSNAME_H
+
+#include <linux/utsname.h>
+
+typedef struct new_utsname     utsname_t;
+
+#endif /* _ZFS_UTSNAME_H */
diff --git a/zfs/include/linux/vfs_compat.h b/zfs/include/linux/vfs_compat.h
new file mode 100644 (file)
index 0000000..2350fa5
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Lawrence Livermore National Security, LLC.
+ * Copyright (C) 2015 Jörg Thalheim.
+ */
+
+#ifndef _ZFS_VFS_H
+#define        _ZFS_VFS_H
+
+#include <sys/taskq.h>
+#include <linux/backing-dev.h>
+
+/*
+ * 2.6.28 API change,
+ * Added insert_inode_locked() helper function, prior to this most callers
+ * used insert_inode_hash().  The older method doesn't check for collisions
+ * in the inode_hashtable but it still acceptible for use.
+ */
+#ifndef HAVE_INSERT_INODE_LOCKED
+static inline int
+insert_inode_locked(struct inode *ip)
+{
+       insert_inode_hash(ip);
+       return (0);
+}
+#endif /* HAVE_INSERT_INODE_LOCKED */
+
+/*
+ * 2.6.35 API change,
+ * Add truncate_setsize() if it is not exported by the Linux kernel.
+ *
+ * Truncate the inode and pages associated with the inode. The pages are
+ * unmapped and removed from cache.
+ */
+#ifndef HAVE_TRUNCATE_SETSIZE
+static inline void
+truncate_setsize(struct inode *ip, loff_t new)
+{
+       struct address_space *mapping = ip->i_mapping;
+
+       i_size_write(ip, new);
+
+       unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1);
+       truncate_inode_pages(mapping, new);
+       unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1);
+}
+#endif /* HAVE_TRUNCATE_SETSIZE */
+
+/*
+ * 2.6.32 - 2.6.33, bdi_setup_and_register() is not available.
+ * 2.6.34 - 3.19, bdi_setup_and_register() takes 3 arguments.
+ * 4.0 - x.y, bdi_setup_and_register() takes 2 arguments.
+ */
+#if defined(HAVE_2ARGS_BDI_SETUP_AND_REGISTER)
+static inline int
+zpl_bdi_setup_and_register(struct backing_dev_info *bdi, char *name)
+{
+       return (bdi_setup_and_register(bdi, name));
+}
+#elif defined(HAVE_3ARGS_BDI_SETUP_AND_REGISTER)
+static inline int
+zpl_bdi_setup_and_register(struct backing_dev_info *bdi, char *name)
+{
+       return (bdi_setup_and_register(bdi, name, BDI_CAP_MAP_COPY));
+}
+#else
+extern atomic_long_t zfs_bdi_seq;
+
+static inline int
+zpl_bdi_setup_and_register(struct backing_dev_info *bdi, char *name)
+{
+       char tmp[32];
+       int error;
+
+       bdi->name = name;
+       bdi->capabilities = BDI_CAP_MAP_COPY;
+
+       error = bdi_init(bdi);
+       if (error)
+               return (error);
+
+       sprintf(tmp, "%.28s%s", name, "-%d");
+       error = bdi_register(bdi, NULL, tmp,
+           atomic_long_inc_return(&zfs_bdi_seq));
+       if (error) {
+               bdi_destroy(bdi);
+               return (error);
+       }
+
+       return (error);
+}
+#endif
+
+/*
+ * 2.6.38 API change,
+ * LOOKUP_RCU flag introduced to distinguish rcu-walk from ref-walk cases.
+ */
+#ifndef LOOKUP_RCU
+#define        LOOKUP_RCU      0x0
+#endif /* LOOKUP_RCU */
+
+/*
+ * 3.2-rc1 API change,
+ * Add set_nlink() if it is not exported by the Linux kernel.
+ *
+ * i_nlink is read-only in Linux 3.2, but it can be set directly in
+ * earlier kernels.
+ */
+#ifndef HAVE_SET_NLINK
+static inline void
+set_nlink(struct inode *inode, unsigned int nlink)
+{
+       inode->i_nlink = nlink;
+}
+#endif /* HAVE_SET_NLINK */
+
+/*
+ * 3.3 API change,
+ * The VFS .create, .mkdir and .mknod callbacks were updated to take a
+ * umode_t type rather than an int.  To cleanly handle both definitions
+ * the zpl_umode_t type is introduced and set accordingly.
+ */
+#ifdef HAVE_MKDIR_UMODE_T
+typedef        umode_t         zpl_umode_t;
+#else
+typedef        int             zpl_umode_t;
+#endif
+
+/*
+ * 3.5 API change,
+ * The clear_inode() function replaces end_writeback() and introduces an
+ * ordering change regarding when the inode_sync_wait() occurs.  See the
+ * configure check in config/kernel-clear-inode.m4 for full details.
+ */
+#if defined(HAVE_EVICT_INODE) && !defined(HAVE_CLEAR_INODE)
+#define        clear_inode(ip)         end_writeback(ip)
+#endif /* HAVE_EVICT_INODE && !HAVE_CLEAR_INODE */
+
+/*
+ * 3.6 API change,
+ * The sget() helper function now takes the mount flags as an argument.
+ */
+#ifdef HAVE_5ARG_SGET
+#define        zpl_sget(type, cmp, set, fl, mtd)       sget(type, cmp, set, fl, mtd)
+#else
+#define        zpl_sget(type, cmp, set, fl, mtd)       sget(type, cmp, set, mtd)
+#endif /* HAVE_5ARG_SGET */
+
+#if defined(SEEK_HOLE) && defined(SEEK_DATA) && !defined(HAVE_LSEEK_EXECUTE)
+static inline loff_t
+lseek_execute(
+       struct file *filp,
+       struct inode *inode,
+       loff_t offset,
+       loff_t maxsize)
+{
+       if (offset < 0 && !(filp->f_mode & FMODE_UNSIGNED_OFFSET))
+               return (-EINVAL);
+
+       if (offset > maxsize)
+               return (-EINVAL);
+
+       if (offset != filp->f_pos) {
+               spin_lock(&filp->f_lock);
+               filp->f_pos = offset;
+               filp->f_version = 0;
+               spin_unlock(&filp->f_lock);
+       }
+
+       return (offset);
+}
+#endif /* SEEK_HOLE && SEEK_DATA && !HAVE_LSEEK_EXECUTE */
+
+#if defined(CONFIG_FS_POSIX_ACL)
+/*
+ * These functions safely approximates the behavior of posix_acl_release()
+ * which cannot be used because it calls the GPL-only symbol kfree_rcu().
+ * The in-kernel version, which can access the RCU, frees the ACLs after
+ * the grace period expires.  Because we're unsure how long that grace
+ * period may be this implementation conservatively delays for 60 seconds.
+ * This is several orders of magnitude larger than expected grace period.
+ * At 60 seconds the kernel will also begin issuing RCU stall warnings.
+ */
+#include <linux/posix_acl.h>
+
+#if defined(HAVE_POSIX_ACL_RELEASE) && !defined(HAVE_POSIX_ACL_RELEASE_GPL_ONLY)
+#define        zpl_posix_acl_release(arg)              posix_acl_release(arg)
+#else
+void zpl_posix_acl_release_impl(struct posix_acl *);
+
+static inline void
+zpl_posix_acl_release(struct posix_acl *acl)
+{
+       if ((acl == NULL) || (acl == ACL_NOT_CACHED))
+               return;
+
+       if (atomic_dec_and_test(&acl->a_refcount))
+               zpl_posix_acl_release_impl(acl);
+}
+#endif /* HAVE_POSIX_ACL_RELEASE */
+
+#ifdef HAVE_SET_CACHED_ACL_USABLE
+#define        zpl_set_cached_acl(ip, ty, n)           set_cached_acl(ip, ty, n)
+#define        zpl_forget_cached_acl(ip, ty)           forget_cached_acl(ip, ty)
+#else
+static inline void
+zpl_set_cached_acl(struct inode *ip, int type, struct posix_acl *newer) {
+       struct posix_acl *older = NULL;
+
+       spin_lock(&ip->i_lock);
+
+       if ((newer != ACL_NOT_CACHED) && (newer != NULL))
+               posix_acl_dup(newer);
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               older = ip->i_acl;
+               rcu_assign_pointer(ip->i_acl, newer);
+               break;
+       case ACL_TYPE_DEFAULT:
+               older = ip->i_default_acl;
+               rcu_assign_pointer(ip->i_default_acl, newer);
+               break;
+       }
+
+       spin_unlock(&ip->i_lock);
+
+       zpl_posix_acl_release(older);
+}
+
+static inline void
+zpl_forget_cached_acl(struct inode *ip, int type) {
+       zpl_set_cached_acl(ip, type, (struct posix_acl *)ACL_NOT_CACHED);
+}
+#endif /* HAVE_SET_CACHED_ACL_USABLE */
+
+#ifndef HAVE___POSIX_ACL_CHMOD
+#ifdef HAVE_POSIX_ACL_CHMOD
+#define        __posix_acl_chmod(acl, gfp, mode)       posix_acl_chmod(acl, gfp, mode)
+#define        __posix_acl_create(acl, gfp, mode)      posix_acl_create(acl, gfp, mode)
+#else
+static inline int
+__posix_acl_chmod(struct posix_acl **acl, int flags, umode_t umode) {
+       struct posix_acl *oldacl = *acl;
+       mode_t mode = umode;
+       int error;
+
+       *acl = posix_acl_clone(*acl, flags);
+       zpl_posix_acl_release(oldacl);
+
+       if (!(*acl))
+               return (-ENOMEM);
+
+       error = posix_acl_chmod_masq(*acl, mode);
+       if (error) {
+               zpl_posix_acl_release(*acl);
+               *acl = NULL;
+       }
+
+       return (error);
+}
+
+static inline int
+__posix_acl_create(struct posix_acl **acl, int flags, umode_t *umodep) {
+       struct posix_acl *oldacl = *acl;
+       mode_t mode = *umodep;
+       int error;
+
+       *acl = posix_acl_clone(*acl, flags);
+       zpl_posix_acl_release(oldacl);
+
+       if (!(*acl))
+               return (-ENOMEM);
+
+       error = posix_acl_create_masq(*acl, &mode);
+       *umodep = mode;
+
+       if (error < 0) {
+               zpl_posix_acl_release(*acl);
+               *acl = NULL;
+       }
+
+       return (error);
+}
+#endif /* HAVE_POSIX_ACL_CHMOD */
+#endif /* HAVE___POSIX_ACL_CHMOD */
+
+#ifdef HAVE_POSIX_ACL_EQUIV_MODE_UMODE_T
+typedef umode_t zpl_equivmode_t;
+#else
+typedef mode_t zpl_equivmode_t;
+#endif /* HAVE_POSIX_ACL_EQUIV_MODE_UMODE_T */
+
+/*
+ * 4.8 API change,
+ * posix_acl_valid() now must be passed a namespace, the namespace from
+ * from super block associated with the given inode is used for this purpose.
+ */
+#ifdef HAVE_POSIX_ACL_VALID_WITH_NS
+#define        zpl_posix_acl_valid(ip, acl)  posix_acl_valid(ip->i_sb->s_user_ns, acl)
+#else
+#define        zpl_posix_acl_valid(ip, acl)  posix_acl_valid(acl)
+#endif
+
+#endif /* CONFIG_FS_POSIX_ACL */
+
+/*
+ * 2.6.38 API change,
+ * The is_owner_or_cap() function was renamed to inode_owner_or_capable().
+ */
+#ifdef HAVE_INODE_OWNER_OR_CAPABLE
+#define        zpl_inode_owner_or_capable(ip)          inode_owner_or_capable(ip)
+#else
+#define        zpl_inode_owner_or_capable(ip)          is_owner_or_cap(ip)
+#endif /* HAVE_INODE_OWNER_OR_CAPABLE */
+
+/*
+ * 3.19 API change
+ * struct access f->f_dentry->d_inode was replaced by accessor function
+ * file_inode(f)
+ */
+#ifndef HAVE_FILE_INODE
+static inline struct inode *file_inode(const struct file *f)
+{
+       return (f->f_dentry->d_inode);
+}
+#endif /* HAVE_FILE_INODE */
+
+/*
+ * 2.6.38 API change
+ */
+#ifdef HAVE_FOLLOW_DOWN_ONE
+#define        zpl_follow_down_one(path)               follow_down_one(path)
+#define        zpl_follow_up(path)                     follow_up(path)
+#else
+#define        zpl_follow_down_one(path)               follow_down(path)
+#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 */
diff --git a/zfs/include/linux/xattr_compat.h b/zfs/include/linux/xattr_compat.h
new file mode 100644 (file)
index 0000000..b1c4293
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _ZFS_XATTR_H
+#define        _ZFS_XATTR_H
+
+#include <linux/posix_acl_xattr.h>
+
+/*
+ * 2.6.35 API change,
+ * The const keyword was added to the 'struct xattr_handler' in the
+ * generic Linux super_block structure.  To handle this we define an
+ * appropriate xattr_handler_t typedef which can be used.  This was
+ * the preferred solution because it keeps the code clean and readable.
+ */
+#ifdef HAVE_CONST_XATTR_HANDLER
+typedef const struct xattr_handler     xattr_handler_t;
+#else
+typedef struct xattr_handler           xattr_handler_t;
+#endif
+
+/*
+ * 3.7 API change,
+ * Preferred XATTR_NAME_* definitions introduced, these are mapped to
+ * the previous definitions for older kernels.
+ */
+#ifndef XATTR_NAME_POSIX_ACL_DEFAULT
+#define        XATTR_NAME_POSIX_ACL_DEFAULT    POSIX_ACL_XATTR_DEFAULT
+#endif
+
+#ifndef XATTR_NAME_POSIX_ACL_ACCESS
+#define        XATTR_NAME_POSIX_ACL_ACCESS     POSIX_ACL_XATTR_ACCESS
+#endif
+
+/*
+ * 4.5 API change,
+ */
+#if defined(HAVE_XATTR_LIST_SIMPLE)
+#define        ZPL_XATTR_LIST_WRAPPER(fn)                                      \
+static bool                                                            \
+fn(struct dentry *dentry)                                              \
+{                                                                      \
+       return (!!__ ## fn(dentry->d_inode, NULL, 0, NULL, 0));         \
+}
+/*
+ * 4.4 API change,
+ */
+#elif defined(HAVE_XATTR_LIST_DENTRY)
+#define        ZPL_XATTR_LIST_WRAPPER(fn)                                      \
+static size_t                                                          \
+fn(struct dentry *dentry, char *list, size_t list_size,                        \
+    const char *name, size_t name_len, int type)                       \
+{                                                                      \
+       return (__ ## fn(dentry->d_inode,                               \
+           list, list_size, name, name_len));                          \
+}
+/*
+ * 2.6.33 API change,
+ */
+#elif defined(HAVE_XATTR_LIST_HANDLER)
+#define        ZPL_XATTR_LIST_WRAPPER(fn)                                      \
+static size_t                                                          \
+fn(const struct xattr_handler *handler, struct dentry *dentry,         \
+    char *list, size_t list_size, const char *name, size_t name_len)   \
+{                                                                      \
+       return (__ ## fn(dentry->d_inode,                               \
+           list, list_size, name, name_len));                          \
+}
+/*
+ * 2.6.32 API
+ */
+#elif defined(HAVE_XATTR_LIST_INODE)
+#define        ZPL_XATTR_LIST_WRAPPER(fn)                                      \
+static size_t                                                          \
+fn(struct inode *ip, char *list, size_t list_size,                     \
+    const char *name, size_t name_len)                                 \
+{                                                                      \
+       return (__ ## fn(ip, list, list_size, name, name_len));         \
+}
+#endif
+
+/*
+ * 4.7 API change,
+ * The xattr_handler->get() callback was changed to take a both dentry and
+ * inode, because the dentry might not be attached to an inode yet.
+ */
+#if defined(HAVE_XATTR_GET_DENTRY_INODE)
+#define        ZPL_XATTR_GET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(const struct xattr_handler *handler, struct dentry *dentry,         \
+    struct inode *inode, const char *name, void *buffer, size_t size)  \
+{                                                                      \
+       return (__ ## fn(inode, name, buffer, size));                   \
+}
+/*
+ * 4.4 API change,
+ * The xattr_handler->get() callback was changed to take a xattr_handler,
+ * and handler_flags argument was removed and should be accessed by
+ * handler->flags.
+ */
+#elif defined(HAVE_XATTR_GET_HANDLER)
+#define        ZPL_XATTR_GET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(const struct xattr_handler *handler, struct dentry *dentry,         \
+    const char *name, void *buffer, size_t size)                       \
+{                                                                      \
+       return (__ ## fn(dentry->d_inode, name, buffer, size));         \
+}
+/*
+ * 2.6.33 API change,
+ * The xattr_handler->get() callback was changed to take a dentry
+ * instead of an inode, and a handler_flags argument was added.
+ */
+#elif defined(HAVE_XATTR_GET_DENTRY)
+#define        ZPL_XATTR_GET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(struct dentry *dentry, const char *name, void *buffer, size_t size, \
+    int unused_handler_flags)                                          \
+{                                                                      \
+       return (__ ## fn(dentry->d_inode, name, buffer, size));         \
+}
+/*
+ * 2.6.32 API
+ */
+#elif defined(HAVE_XATTR_GET_INODE)
+#define        ZPL_XATTR_GET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(struct inode *ip, const char *name, void *buffer, size_t size)      \
+{                                                                      \
+       return (__ ## fn(ip, name, buffer, size));                      \
+}
+#endif
+
+/*
+ * 4.7 API change,
+ * The xattr_handler->set() callback was changed to take a both dentry and
+ * inode, because the dentry might not be attached to an inode yet.
+ */
+#if defined(HAVE_XATTR_SET_DENTRY_INODE)
+#define        ZPL_XATTR_SET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(const struct xattr_handler *handler, struct dentry *dentry,         \
+    struct inode *inode, const char *name, const void *buffer,         \
+    size_t size, int flags)                                            \
+{                                                                      \
+       return (__ ## fn(inode, name, buffer, size, flags));            \
+}
+/*
+ * 4.4 API change,
+ * The xattr_handler->set() callback was changed to take a xattr_handler,
+ * and handler_flags argument was removed and should be accessed by
+ * handler->flags.
+ */
+#elif defined(HAVE_XATTR_SET_HANDLER)
+#define        ZPL_XATTR_SET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(const struct xattr_handler *handler, struct dentry *dentry,         \
+    const char *name, const void *buffer, size_t size, int flags)      \
+{                                                                      \
+       return (__ ## fn(dentry->d_inode, name, buffer, size, flags));  \
+}
+/*
+ * 2.6.33 API change,
+ * The xattr_handler->set() callback was changed to take a dentry
+ * instead of an inode, and a handler_flags argument was added.
+ */
+#elif defined(HAVE_XATTR_SET_DENTRY)
+#define        ZPL_XATTR_SET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(struct dentry *dentry, const char *name, const void *buffer,                \
+    size_t size, int flags, int unused_handler_flags)                  \
+{                                                                      \
+       return (__ ## fn(dentry->d_inode, name, buffer, size, flags));  \
+}
+/*
+ * 2.6.32 API
+ */
+#elif defined(HAVE_XATTR_SET_INODE)
+#define        ZPL_XATTR_SET_WRAPPER(fn)                                       \
+static int                                                             \
+fn(struct inode *ip, const char *name, const void *buffer,             \
+    size_t size, int flags)                                            \
+{                                                                      \
+       return (__ ## fn(ip, name, buffer, size, flags));               \
+}
+#endif
+
+#ifdef HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY
+#define        zpl_security_inode_init_security(ip, dip, qstr, nm, val, len)   \
+       security_inode_init_security(ip, dip, qstr, nm, val, len)
+#else
+#define        zpl_security_inode_init_security(ip, dip, qstr, nm, val, len)   \
+       security_inode_init_security(ip, dip, nm, val, len)
+#endif /* HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY */
+
+/*
+ * Linux 3.7 API change. posix_acl_{from,to}_xattr gained the user_ns
+ * parameter.  All callers are expected to pass the &init_user_ns which
+ * is available through the init credential (kcred).
+ */
+#ifdef HAVE_POSIX_ACL_FROM_XATTR_USERNS
+static inline struct posix_acl *
+zpl_acl_from_xattr(const void *value, int size)
+{
+       return (posix_acl_from_xattr(kcred->user_ns, value, size));
+}
+
+static inline int
+zpl_acl_to_xattr(struct posix_acl *acl, void *value, int size)
+{
+       return (posix_acl_to_xattr(kcred->user_ns, acl, value, size));
+}
+
+#else
+
+static inline struct posix_acl *
+zpl_acl_from_xattr(const void *value, int size)
+{
+       return (posix_acl_from_xattr(value, size));
+}
+
+static inline int
+zpl_acl_to_xattr(struct posix_acl *acl, void *value, int size)
+{
+       return (posix_acl_to_xattr(acl, value, size));
+}
+#endif /* HAVE_POSIX_ACL_FROM_XATTR_USERNS */
+
+#endif /* _ZFS_XATTR_H */
diff --git a/zfs/include/sys/Makefile.am b/zfs/include/sys/Makefile.am
new file mode 100644 (file)
index 0000000..77ecfb2
--- /dev/null
@@ -0,0 +1,119 @@
+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)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/sys/Makefile.in b/zfs/include/sys/Makefile.in
new file mode 100644 (file)
index 0000000..e305be7
--- /dev/null
@@ -0,0 +1,1170 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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:
diff --git a/zfs/include/sys/arc.h b/zfs/include/sys/arc.h
new file mode 100644 (file)
index 0000000..db7a64a
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ */
+
+#ifndef        _SYS_ARC_H
+#define        _SYS_ARC_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zio.h>
+#include <sys/dmu.h>
+#include <sys/spa.h>
+#include <sys/refcount.h>
+
+/*
+ * Used by arc_flush() to inform arc_evict_state() that it should evict
+ * all available buffers from the arc state being passed in.
+ */
+#define        ARC_EVICT_ALL   -1ULL
+
+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;
+
+/* generic arc_done_func_t's which you can use */
+arc_done_func_t arc_bcopy_func;
+arc_done_func_t arc_getbuf_func;
+
+/* generic arc_prune_func_t wrapper for callbacks */
+struct arc_prune {
+       arc_prune_func_t        *p_pfunc;
+       void                    *p_private;
+       uint64_t                p_adjust;
+       list_node_t             p_node;
+       refcount_t              p_refcnt;
+};
+
+typedef enum arc_strategy {
+       ARC_STRATEGY_META_ONLY          = 0, /* Evict only meta data buffers */
+       ARC_STRATEGY_META_BALANCED      = 1, /* Evict data buffers if needed */
+} arc_strategy_t;
+
+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 */
+
+       /*
+        * 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 */
+       /* indicates that the buffer contains metadata (otherwise, data) */
+       ARC_FLAG_BUFC_METADATA          = 1 << 16,
+
+       /* Flags specifying whether optional hdr struct fields are defined */
+       ARC_FLAG_HAS_L1HDR              = 1 << 17,
+       ARC_FLAG_HAS_L2HDR              = 1 << 18,
+} arc_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;
+};
+
+typedef enum arc_buf_contents {
+       ARC_BUFC_DATA,                          /* buffer contains data */
+       ARC_BUFC_METADATA,                      /* buffer contains metadata */
+       ARC_BUFC_NUMTYPES
+} arc_buf_contents_t;
+
+/*
+ * The following breakdows of arc_size exist for kstat only.
+ */
+typedef enum arc_space_type {
+       ARC_SPACE_DATA,
+       ARC_SPACE_META,
+       ARC_SPACE_HDRS,
+       ARC_SPACE_L2HDRS,
+       ARC_SPACE_OTHER,
+       ARC_SPACE_NUMTYPES
+} arc_space_type_t;
+
+typedef enum arc_state_type {
+       ARC_STATE_ANON,
+       ARC_STATE_MRU,
+       ARC_STATE_MRU_GHOST,
+       ARC_STATE_MFU,
+       ARC_STATE_MFU_GHOST,
+       ARC_STATE_L2C_ONLY,
+       ARC_STATE_NUMTYPES
+} arc_state_type_t;
+
+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;
+       uint64_t                abi_size;
+       uint64_t                abi_spa;
+       uint64_t                abi_access;
+       uint32_t                abi_mru_hits;
+       uint32_t                abi_mru_ghost_hits;
+       uint32_t                abi_mfu_hits;
+       uint32_t                abi_mfu_ghost_hits;
+       uint32_t                abi_l2arc_hits;
+       uint32_t                abi_holds;
+       uint64_t                abi_l2arc_dattr;
+       uint64_t                abi_l2arc_asize;
+       enum zio_compress       abi_l2arc_compress;
+} arc_buf_info_t;
+
+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);
+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_info(arc_buf_t *buf, arc_buf_info_t *abi, int state_index);
+uint64_t arc_buf_size(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
+
+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);
+
+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);
+
+void arc_init(void);
+void arc_fini(void);
+
+/*
+ * Level 2 ARC
+ */
+
+void l2arc_add_vdev(spa_t *spa, vdev_t *vd);
+void l2arc_remove_vdev(vdev_t *vd);
+boolean_t l2arc_vdev_present(vdev_t *vd);
+void l2arc_init(void);
+void l2arc_fini(void);
+void l2arc_start(void);
+void l2arc_stop(void);
+
+#ifndef _KERNEL
+extern boolean_t arc_watch;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ARC_H */
diff --git a/zfs/include/sys/arc_impl.h b/zfs/include/sys/arc_impl.h
new file mode 100644 (file)
index 0000000..a9dbfc8
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#ifndef _SYS_ARC_IMPL_H
+#define        _SYS_ARC_IMPL_H
+
+#include <sys/arc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Note that buffers can be in one of 6 states:
+ *     ARC_anon        - anonymous (discussed below)
+ *     ARC_mru         - recently used, currently cached
+ *     ARC_mru_ghost   - recentely used, no longer in cache
+ *     ARC_mfu         - frequently used, currently cached
+ *     ARC_mfu_ghost   - frequently used, no longer in cache
+ *     ARC_l2c_only    - exists in L2ARC but not other states
+ * When there are no active references to the buffer, they are
+ * are linked onto a list in one of these arc states.  These are
+ * the only buffers that can be evicted or deleted.  Within each
+ * state there are multiple lists, one for meta-data and one for
+ * non-meta-data.  Meta-data (indirect blocks, blocks of dnodes,
+ * etc.) is tracked separately so that it can be managed more
+ * explicitly: favored over data, limited explicitly.
+ *
+ * Anonymous buffers are buffers that are not associated with
+ * a DVA.  These are buffers that hold dirty block copies
+ * before they are written to stable storage.  By definition,
+ * they are "ref'd" and are considered part of arc_mru
+ * that cannot be freed.  Generally, they will aquire a DVA
+ * as they are written and migrate onto the arc_mru list.
+ *
+ * The ARC_l2c_only state is for buffers that are in the second
+ * level ARC but no longer in any of the ARC_m* lists.  The second
+ * level ARC itself may also contain buffers that are in any of
+ * the ARC_m* states - meaning that a buffer can exist in two
+ * places.  The reason for the ARC_l2c_only state is to keep the
+ * buffer header in the hash table, so that reads that hit the
+ * second level ARC benefit from these fast lookups.
+ */
+
+typedef struct arc_state {
+       /*
+        * list of evictable buffers
+        */
+       multilist_t arcs_list[ARC_BUFC_NUMTYPES];
+       /*
+        * total amount of evictable data in this state
+        */
+       uint64_t arcs_lsize[ARC_BUFC_NUMTYPES];
+       /*
+        * total amount of data in this state; this includes: evictable,
+        * non-evictable, ARC_BUFC_DATA, and ARC_BUFC_METADATA.
+        */
+       refcount_t arcs_size;
+       /*
+        * supports the "dbufs" kstat
+        */
+       arc_state_type_t arcs_state;
+} arc_state_t;
+
+typedef struct arc_callback arc_callback_t;
+
+struct arc_callback {
+       void                    *acb_private;
+       arc_done_func_t         *acb_done;
+       arc_buf_t               *acb_buf;
+       zio_t                   *acb_zio_dummy;
+       arc_callback_t          *acb_next;
+};
+
+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_physdone;
+       arc_done_func_t *awcb_done;
+       arc_buf_t       *awcb_buf;
+};
+
+/*
+ * ARC buffers are separated into multiple structs as a memory saving measure:
+ *   - Common fields struct, always defined, and embedded within it:
+ *       - L2-only fields, always allocated but undefined when not in L2ARC
+ *       - L1-only fields, only allocated when in L1ARC
+ *
+ *           Buffer in L1                     Buffer only in L2
+ *    +------------------------+          +------------------------+
+ *    | arc_buf_hdr_t          |          | arc_buf_hdr_t          |
+ *    |                        |          |                        |
+ *    |                        |          |                        |
+ *    |                        |          |                        |
+ *    +------------------------+          +------------------------+
+ *    | l2arc_buf_hdr_t        |          | l2arc_buf_hdr_t        |
+ *    | (undefined if L1-only) |          |                        |
+ *    +------------------------+          +------------------------+
+ *    | l1arc_buf_hdr_t        |
+ *    |                        |
+ *    |                        |
+ *    |                        |
+ *    |                        |
+ *    +------------------------+
+ *
+ * Because it's possible for the L2ARC to become extremely large, we can wind
+ * up eating a lot of memory in L2ARC buffer headers, so the size of a header
+ * is minimized by only allocating the fields necessary for an L1-cached buffer
+ * when a header is actually in the L1 cache. The sub-headers (l1arc_buf_hdr and
+ * l2arc_buf_hdr) are embedded rather than allocated separately to save a couple
+ * words in pointers. arc_hdr_realloc() is used to switch a header between
+ * these two allocation states.
+ */
+typedef struct l1arc_buf_hdr {
+       kmutex_t                b_freeze_lock;
+
+       arc_buf_t               *b_buf;
+       uint32_t                b_datacnt;
+       /* for waiting on writes to complete */
+       kcondvar_t              b_cv;
+
+
+       /* protected by arc state mutex */
+       arc_state_t             *b_state;
+       multilist_node_t        b_arc_node;
+
+       /* updated atomically */
+       clock_t                 b_arc_access;
+       uint32_t                b_mru_hits;
+       uint32_t                b_mru_ghost_hits;
+       uint32_t                b_mfu_hits;
+       uint32_t                b_mfu_ghost_hits;
+       uint32_t                b_l2_hits;
+
+       /* self protecting */
+       refcount_t              b_refcnt;
+
+       arc_callback_t          *b_acb;
+       /* temporary buffer holder for in-flight compressed data */
+       void                    *b_tmp_cdata;
+} l1arc_buf_hdr_t;
+
+typedef struct l2arc_dev {
+       vdev_t                  *l2ad_vdev;     /* vdev */
+       spa_t                   *l2ad_spa;      /* spa */
+       uint64_t                l2ad_hand;      /* next write location */
+       uint64_t                l2ad_start;     /* first addr on device */
+       uint64_t                l2ad_end;       /* last addr on device */
+       boolean_t               l2ad_first;     /* first sweep through */
+       boolean_t               l2ad_writing;   /* currently writing */
+       kmutex_t                l2ad_mtx;       /* lock for buffer list */
+       list_t                  l2ad_buflist;   /* buffer list */
+       list_node_t             l2ad_node;      /* device list node */
+       refcount_t              l2ad_alloc;     /* allocated bytes */
+} l2arc_dev_t;
+
+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;
+
+typedef struct l2arc_write_callback {
+       l2arc_dev_t     *l2wcb_dev;             /* device info */
+       arc_buf_hdr_t   *l2wcb_head;            /* head of write buflist */
+} l2arc_write_callback_t;
+
+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_hdr_t           *b_hash_next;
+       arc_flags_t             b_flags;
+
+       /* immutable */
+       int32_t                 b_size;
+       uint64_t                b_spa;
+
+       /* L2ARC fields. Undefined when not in L2ARC. */
+       l2arc_buf_hdr_t         b_l2hdr;
+       /* L1ARC fields. Undefined when in l2arc_only state */
+       l1arc_buf_hdr_t         b_l1hdr;
+};
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ARC_IMPL_H */
diff --git a/zfs/include/sys/avl.h b/zfs/include/sys/avl.h
new file mode 100644 (file)
index 0000000..10e0dda
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _AVL_H
+#define        _AVL_H
+
+/*
+ * This is a private header file.  Applications should not directly include
+ * this file.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/avl_impl.h>
+
+/*
+ * This is a generic implementation of AVL trees for use in the Solaris kernel.
+ * The interfaces provide an efficient way of implementing an ordered set of
+ * data structures.
+ *
+ * AVL trees provide an alternative to using an ordered linked list. Using AVL
+ * trees will usually be faster, however they requires more storage. An ordered
+ * linked list in general requires 2 pointers in each data structure. The
+ * AVL tree implementation uses 3 pointers. The following chart gives the
+ * approximate performance of operations with the different approaches:
+ *
+ *     Operation        Link List      AVL tree
+ *     ---------        --------       --------
+ *     lookup             O(n)         O(log(n))
+ *
+ *     insert 1 node    constant       constant
+ *
+ *     delete 1 node    constant       between constant and O(log(n))
+ *
+ *     delete all nodes   O(n)         O(n)
+ *
+ *     visit the next
+ *     or prev node     constant       between constant and O(log(n))
+ *
+ *
+ * The data structure nodes are anchored at an "avl_tree_t" (the equivalent
+ * of a list header) and the individual nodes will have a field of
+ * type "avl_node_t" (corresponding to list pointers).
+ *
+ * The type "avl_index_t" is used to indicate a position in the list for
+ * certain calls.
+ *
+ * The usage scenario is generally:
+ *
+ * 1. Create the list/tree with: avl_create()
+ *
+ * followed by any mixture of:
+ *
+ * 2a. Insert nodes with: avl_add(), or avl_find() and avl_insert()
+ *
+ * 2b. Visited elements with:
+ *      avl_first() - returns the lowest valued node
+ *      avl_last() - returns the highest valued node
+ *      AVL_NEXT() - given a node go to next higher one
+ *      AVL_PREV() - given a node go to previous lower one
+ *
+ * 2c.  Find the node with the closest value either less than or greater
+ *     than a given value with avl_nearest().
+ *
+ * 2d. Remove individual nodes from the list/tree with avl_remove().
+ *
+ * and finally when the list is being destroyed
+ *
+ * 3. Use avl_destroy_nodes() to quickly process/free up any remaining nodes.
+ *    Note that once you use avl_destroy_nodes(), you can no longer
+ *    use any routine except avl_destroy_nodes() and avl_destoy().
+ *
+ * 4. Use avl_destroy() to destroy the AVL tree itself.
+ *
+ * Any locking for multiple thread access is up to the user to provide, just
+ * as is needed for any linked list implementation.
+ */
+
+
+/*
+ * Type used for the root of the AVL tree.
+ */
+typedef struct avl_tree avl_tree_t;
+
+/*
+ * The data nodes in the AVL tree must have a field of this type.
+ */
+typedef struct avl_node avl_node_t;
+
+/*
+ * An opaque type used to locate a position in the tree where a node
+ * would be inserted.
+ */
+typedef uintptr_t avl_index_t;
+
+
+/*
+ * Direction constants used for avl_nearest().
+ */
+#define        AVL_BEFORE      (0)
+#define        AVL_AFTER       (1)
+
+
+/*
+ * Prototypes
+ *
+ * Where not otherwise mentioned, "void *" arguments are a pointer to the
+ * user data structure which must contain a field of type avl_node_t.
+ *
+ * Also assume the user data structures looks like:
+ *     stuct my_type {
+ *             ...
+ *             avl_node_t      my_link;
+ *             ...
+ *     };
+ */
+
+/*
+ * Initialize an AVL tree. Arguments are:
+ *
+ * tree   - the tree to be initialized
+ * compar - function to compare two nodes, it must return exactly: -1, 0, or +1
+ *          -1 for <, 0 for ==, and +1 for >
+ * size   - the value of sizeof(struct my_type)
+ * offset - the value of OFFSETOF(struct my_type, my_link)
+ */
+extern void avl_create(avl_tree_t *tree,
+       int (*compar) (const void *, const void *), size_t size, size_t offset);
+
+
+/*
+ * Find a node with a matching value in the tree. Returns the matching node
+ * found. If not found, it returns NULL and then if "where" is not NULL it sets
+ * "where" for use with avl_insert() or avl_nearest().
+ *
+ * node   - node that has the value being looked for
+ * where  - position for use with avl_nearest() or avl_insert(), may be NULL
+ */
+extern void *avl_find(avl_tree_t *tree, const void *node, avl_index_t *where);
+
+/*
+ * Insert a node into the tree.
+ *
+ * node   - the node to insert
+ * where  - position as returned from avl_find()
+ */
+extern void avl_insert(avl_tree_t *tree, void *node, avl_index_t where);
+
+/*
+ * Insert "new_data" in "tree" in the given "direction" either after
+ * or before the data "here".
+ *
+ * This might be useful for avl clients caching recently accessed
+ * data to avoid doing avl_find() again for insertion.
+ *
+ * new_data    - new data to insert
+ * here                - existing node in "tree"
+ * direction   - either AVL_AFTER or AVL_BEFORE the data "here".
+ */
+extern void avl_insert_here(avl_tree_t *tree, void *new_data, void *here,
+    int direction);
+
+
+/*
+ * Return the first or last valued node in the tree. Will return NULL
+ * if the tree is empty.
+ *
+ */
+extern void *avl_first(avl_tree_t *tree);
+extern void *avl_last(avl_tree_t *tree);
+
+
+/*
+ * Return the next or previous valued node in the tree.
+ * AVL_NEXT() will return NULL if at the last node.
+ * AVL_PREV() will return NULL if at the first node.
+ *
+ * node   - the node from which the next or previous node is found
+ */
+#define        AVL_NEXT(tree, node)    avl_walk(tree, node, AVL_AFTER)
+#define        AVL_PREV(tree, node)    avl_walk(tree, node, AVL_BEFORE)
+
+
+/*
+ * Find the node with the nearest value either greater or less than
+ * the value from a previous avl_find(). Returns the node or NULL if
+ * there isn't a matching one.
+ *
+ * where     - position as returned from avl_find()
+ * direction - either AVL_BEFORE or AVL_AFTER
+ *
+ * EXAMPLE get the greatest node that is less than a given value:
+ *
+ *     avl_tree_t *tree;
+ *     struct my_data look_for_value = {....};
+ *     struct my_data *node;
+ *     struct my_data *less;
+ *     avl_index_t where;
+ *
+ *     node = avl_find(tree, &look_for_value, &where);
+ *     if (node != NULL)
+ *             less = AVL_PREV(tree, node);
+ *     else
+ *             less = avl_nearest(tree, where, AVL_BEFORE);
+ */
+extern void *avl_nearest(avl_tree_t *tree, avl_index_t where, int direction);
+
+
+/*
+ * Add a single node to the tree.
+ * The node must not be in the tree, and it must not
+ * compare equal to any other node already in the tree.
+ *
+ * node   - the node to add
+ */
+extern void avl_add(avl_tree_t *tree, void *node);
+
+
+/*
+ * Remove a single node from the tree.  The node must be in the tree.
+ *
+ * node   - the node to remove
+ */
+extern void avl_remove(avl_tree_t *tree, void *node);
+
+/*
+ * Reinsert a node only if its order has changed relative to its nearest
+ * neighbors. To optimize performance avl_update_lt() checks only the previous
+ * node and avl_update_gt() checks only the next node. Use avl_update_lt() and
+ * avl_update_gt() only if you know the direction in which the order of the
+ * node may change.
+ */
+extern boolean_t avl_update(avl_tree_t *, void *);
+extern boolean_t avl_update_lt(avl_tree_t *, void *);
+extern boolean_t avl_update_gt(avl_tree_t *, void *);
+
+/*
+ * Swaps the contents of the two trees.
+ */
+extern void avl_swap(avl_tree_t *tree1, avl_tree_t *tree2);
+
+/*
+ * Return the number of nodes in the tree
+ */
+extern ulong_t avl_numnodes(avl_tree_t *tree);
+
+/*
+ * Return B_TRUE if there are zero nodes in the tree, B_FALSE otherwise.
+ */
+extern boolean_t avl_is_empty(avl_tree_t *tree);
+
+/*
+ * Used to destroy any remaining nodes in a tree. The cookie argument should
+ * be initialized to NULL before the first call. Returns a node that has been
+ * removed from the tree and may be free()'d. Returns NULL when the tree is
+ * empty.
+ *
+ * Once you call avl_destroy_nodes(), you can only continuing calling it and
+ * finally avl_destroy(). No other AVL routines will be valid.
+ *
+ * cookie - a "void *" used to save state between calls to avl_destroy_nodes()
+ *
+ * EXAMPLE:
+ *     avl_tree_t *tree;
+ *     struct my_data *node;
+ *     void *cookie;
+ *
+ *     cookie = NULL;
+ *     while ((node = avl_destroy_nodes(tree, &cookie)) != NULL)
+ *             free(node);
+ *     avl_destroy(tree);
+ */
+extern void *avl_destroy_nodes(avl_tree_t *tree, void **cookie);
+
+
+/*
+ * Final destroy of an AVL tree. Arguments are:
+ *
+ * tree   - the empty tree to destroy
+ */
+extern void avl_destroy(avl_tree_t *tree);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AVL_H */
diff --git a/zfs/include/sys/avl_impl.h b/zfs/include/sys/avl_impl.h
new file mode 100644 (file)
index 0000000..fddf769
--- /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, 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        _AVL_IMPL_H
+#define        _AVL_IMPL_H
+
+
+
+/*
+ * This is a private header file.  Applications should not directly include
+ * this file.
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * generic AVL tree implementation for kernel use
+ *
+ * There are 5 pieces of information stored for each node in an AVL tree
+ *
+ *     pointer to less than child
+ *     pointer to greater than child
+ *     a pointer to the parent of this node
+ *     an indication  [0/1]  of which child I am of my parent
+ *     a "balance" (-1, 0, +1)  indicating which child tree is taller
+ *
+ * Since they only need 3 bits, the last two fields are packed into the
+ * bottom bits of the parent pointer on 64 bit machines to save on space.
+ */
+
+#ifndef _LP64
+
+struct avl_node {
+       struct avl_node *avl_child[2];  /* left/right children */
+       struct avl_node *avl_parent;    /* this node's parent */
+       unsigned short avl_child_index; /* my index in parent's avl_child[] */
+       short avl_balance;              /* balance value: -1, 0, +1 */
+};
+
+#define        AVL_XPARENT(n)          ((n)->avl_parent)
+#define        AVL_SETPARENT(n, p)     ((n)->avl_parent = (p))
+
+#define        AVL_XCHILD(n)           ((n)->avl_child_index)
+#define        AVL_SETCHILD(n, c)      ((n)->avl_child_index = (unsigned short)(c))
+
+#define        AVL_XBALANCE(n)         ((n)->avl_balance)
+#define        AVL_SETBALANCE(n, b)    ((n)->avl_balance = (short)(b))
+
+#else /* _LP64 */
+
+/*
+ * for 64 bit machines, avl_pcb contains parent pointer, balance and child_index
+ * values packed in the following manner:
+ *
+ * |63                                  3|        2        |1          0 |
+ * |-------------------------------------|-----------------|-------------|
+ * |      avl_parent hi order bits       | avl_child_index | avl_balance |
+ * |                                     |                 |     + 1     |
+ * |-------------------------------------|-----------------|-------------|
+ *
+ */
+struct avl_node {
+       struct avl_node *avl_child[2];  /* left/right children nodes */
+       uintptr_t avl_pcb;              /* parent, child_index, balance */
+};
+
+/*
+ * macros to extract/set fields in avl_pcb
+ *
+ * pointer to the parent of the current node is the high order bits
+ */
+#define        AVL_XPARENT(n)          ((struct avl_node *)((n)->avl_pcb & ~7))
+#define        AVL_SETPARENT(n, p)                                             \
+       ((n)->avl_pcb = (((n)->avl_pcb & 7) | (uintptr_t)(p)))
+
+/*
+ * index of this node in its parent's avl_child[]: bit #2
+ */
+#define        AVL_XCHILD(n)           (((n)->avl_pcb >> 2) & 1)
+#define        AVL_SETCHILD(n, c)                                              \
+       ((n)->avl_pcb = (uintptr_t)(((n)->avl_pcb & ~4) | ((c) << 2)))
+
+/*
+ * balance indication for a node, lowest 2 bits. A valid balance is
+ * -1, 0, or +1, and is encoded by adding 1 to the value to get the
+ * unsigned values of 0, 1, 2.
+ */
+#define        AVL_XBALANCE(n)         ((int)(((n)->avl_pcb & 3) - 1))
+#define        AVL_SETBALANCE(n, b)                                            \
+       ((n)->avl_pcb = (uintptr_t)((((n)->avl_pcb & ~3) | ((b) + 1))))
+
+#endif /* _LP64 */
+
+
+
+/*
+ * switch between a node and data pointer for a given tree
+ * the value of "o" is tree->avl_offset
+ */
+#define        AVL_NODE2DATA(n, o)     ((void *)((uintptr_t)(n) - (o)))
+#define        AVL_DATA2NODE(d, o)     ((struct avl_node *)((uintptr_t)(d) + (o)))
+
+
+
+/*
+ * macros used to create/access an avl_index_t
+ */
+#define        AVL_INDEX2NODE(x)       ((avl_node_t *)((x) & ~1))
+#define        AVL_INDEX2CHILD(x)      ((x) & 1)
+#define        AVL_MKINDEX(n, c)       ((avl_index_t)(n) | (c))
+
+
+/*
+ * The tree structure. The fields avl_root, avl_compar, and avl_offset come
+ * first since they are needed for avl_find().  We want them to fit into
+ * a single 64 byte cache line to make avl_find() as fast as possible.
+ */
+struct avl_tree {
+       struct avl_node *avl_root;      /* root node in tree */
+       int (*avl_compar)(const void *, const void *);
+       size_t avl_offset;              /* offsetof(type, avl_link_t field) */
+       ulong_t avl_numnodes;           /* number of nodes in the tree */
+       size_t avl_size;                /* sizeof user type struct */
+};
+
+
+/*
+ * This will only by used via AVL_NEXT() or AVL_PREV()
+ */
+extern void *avl_walk(struct avl_tree *, void *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AVL_IMPL_H */
diff --git a/zfs/include/sys/blkptr.h b/zfs/include/sys/blkptr.h
new file mode 100644 (file)
index 0000000..b720482
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_BLKPTR_H
+#define        _SYS_BLKPTR_H
+
+#include <sys/spa.h>
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void encode_embedded_bp_compressed(blkptr_t *, void *,
+    enum zio_compress, int, int);
+void decode_embedded_bp_compressed(const blkptr_t *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BLKPTR_H */
diff --git a/zfs/include/sys/bplist.h b/zfs/include/sys/bplist.h
new file mode 100644 (file)
index 0000000..471be90
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_BPLIST_H
+#define        _SYS_BPLIST_H
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct bplist_entry {
+       blkptr_t        bpe_blk;
+       list_node_t     bpe_node;
+} bplist_entry_t;
+
+typedef struct bplist {
+       kmutex_t        bpl_lock;
+       list_t          bpl_list;
+} bplist_t;
+
+typedef int bplist_itor_t(void *arg, const blkptr_t *bp, dmu_tx_t *tx);
+
+void bplist_create(bplist_t *bpl);
+void bplist_destroy(bplist_t *bpl);
+void bplist_append(bplist_t *bpl, const blkptr_t *bp);
+void bplist_iterate(bplist_t *bpl, bplist_itor_t *func,
+    void *arg, dmu_tx_t *tx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BPLIST_H */
diff --git a/zfs/include/sys/bpobj.h b/zfs/include/sys/bpobj.h
new file mode 100644 (file)
index 0000000..2a36519
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_BPOBJ_H
+#define        _SYS_BPOBJ_H
+
+#include <sys/dmu.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/zio.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct bpobj_phys {
+       /*
+        * This is the bonus buffer for the dead lists.  The object's
+        * contents is an array of bpo_entries blkptr_t's, representing
+        * a total of bpo_bytes physical space.
+        */
+       uint64_t        bpo_num_blkptrs;
+       uint64_t        bpo_bytes;
+       uint64_t        bpo_comp;
+       uint64_t        bpo_uncomp;
+       uint64_t        bpo_subobjs;
+       uint64_t        bpo_num_subobjs;
+} bpobj_phys_t;
+
+#define        BPOBJ_SIZE_V0   (2 * sizeof (uint64_t))
+#define        BPOBJ_SIZE_V1   (4 * sizeof (uint64_t))
+
+typedef struct bpobj {
+       kmutex_t        bpo_lock;
+       objset_t        *bpo_os;
+       uint64_t        bpo_object;
+       int             bpo_epb;
+       uint8_t         bpo_havecomp;
+       uint8_t         bpo_havesubobj;
+       bpobj_phys_t    *bpo_phys;
+       dmu_buf_t       *bpo_dbuf;
+       dmu_buf_t       *bpo_cached_dbuf;
+} bpobj_t;
+
+typedef int bpobj_itor_t(void *arg, const blkptr_t *bp, dmu_tx_t *tx);
+
+uint64_t bpobj_alloc(objset_t *mos, int blocksize, dmu_tx_t *tx);
+uint64_t bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx);
+void bpobj_free(objset_t *os, uint64_t obj, dmu_tx_t *tx);
+void bpobj_decr_empty(objset_t *os, dmu_tx_t *tx);
+
+int bpobj_open(bpobj_t *bpo, objset_t *mos, uint64_t object);
+void bpobj_close(bpobj_t *bpo);
+
+int bpobj_iterate(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx);
+int bpobj_iterate_nofree(bpobj_t *bpo, bpobj_itor_t func, void *, dmu_tx_t *);
+
+void bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx);
+void bpobj_enqueue(bpobj_t *bpo, const blkptr_t *bp, dmu_tx_t *tx);
+
+int bpobj_space(bpobj_t *bpo,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
+int bpobj_space_range(bpobj_t *bpo, uint64_t mintxg, uint64_t maxtxg,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BPOBJ_H */
diff --git a/zfs/include/sys/bptree.h b/zfs/include/sys/bptree.h
new file mode 100644 (file)
index 0000000..327c128
--- /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 (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_BPTREE_H
+#define        _SYS_BPTREE_H
+
+#include <sys/spa.h>
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct bptree_phys {
+       uint64_t bt_begin;
+       uint64_t bt_end;
+       uint64_t bt_bytes;
+       uint64_t bt_comp;
+       uint64_t bt_uncomp;
+} bptree_phys_t;
+
+typedef struct bptree_entry_phys {
+       blkptr_t be_bp;
+       uint64_t be_birth_txg; /* only delete blocks born after this txg */
+       zbookmark_phys_t be_zb; /* holds traversal resume point if needed */
+} bptree_entry_phys_t;
+
+typedef int bptree_itor_t(void *arg, const blkptr_t *bp, dmu_tx_t *tx);
+
+uint64_t bptree_alloc(objset_t *os, dmu_tx_t *tx);
+int bptree_free(objset_t *os, uint64_t obj, dmu_tx_t *tx);
+boolean_t bptree_is_empty(objset_t *os, uint64_t obj);
+
+void bptree_add(objset_t *os, uint64_t obj, blkptr_t *bp, uint64_t birth_txg,
+    uint64_t bytes, uint64_t comp, uint64_t uncomp, dmu_tx_t *tx);
+
+int bptree_iterate(objset_t *os, uint64_t obj, boolean_t free,
+    bptree_itor_t func, void *arg, dmu_tx_t *tx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BPTREE_H */
diff --git a/zfs/include/sys/dbuf.h b/zfs/include/sys/dbuf.h
new file mode 100644 (file)
index 0000000..0d262e8
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_DBUF_H
+#define        _SYS_DBUF_H
+
+#include <sys/dmu.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/zio.h>
+#include <sys/arc.h>
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+#include <sys/zrlock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        IN_DMU_SYNC 2
+
+/*
+ * define flags for dbuf_read
+ */
+
+#define        DB_RF_MUST_SUCCEED      (1 << 0)
+#define        DB_RF_CANFAIL           (1 << 1)
+#define        DB_RF_HAVESTRUCT        (1 << 2)
+#define        DB_RF_NOPREFETCH        (1 << 3)
+#define        DB_RF_NEVERWAIT         (1 << 4)
+#define        DB_RF_CACHED            (1 << 5)
+
+/*
+ * The simplified state transition diagram for dbufs looks like:
+ *
+ *             +----> READ ----+
+ *             |               |
+ *             |               V
+ *  (alloc)-->UNCACHED      CACHED-->EVICTING-->(free)
+ *             |               ^        ^
+ *             |               |        |
+ *             +----> FILL ----+        |
+ *             |                        |
+ *             |                        |
+ *             +--------> NOFILL -------+
+ *
+ * DB_SEARCH is an invalid state for a dbuf. It is used by dbuf_free_range
+ * to find all dbufs in a range of a dnode and must be less than any other
+ * dbuf_states_t (see comment on dn_dbufs in dnode.h).
+ */
+typedef enum dbuf_states {
+       DB_SEARCH = -1,
+       DB_UNCACHED,
+       DB_FILL,
+       DB_NOFILL,
+       DB_READ,
+       DB_CACHED,
+       DB_EVICTING
+} dbuf_states_t;
+
+struct dnode;
+struct dmu_tx;
+
+/*
+ * level = 0 means the user data
+ * level = 1 means the single indirect block
+ * etc.
+ */
+
+struct dmu_buf_impl;
+
+typedef enum override_states {
+       DR_NOT_OVERRIDDEN,
+       DR_IN_DMU_SYNC,
+       DR_OVERRIDDEN
+} override_states_t;
+
+typedef struct dbuf_dirty_record {
+       /* link on our parents dirty list */
+       list_node_t dr_dirty_node;
+
+       /* transaction group this data will sync in */
+       uint64_t dr_txg;
+
+       /* zio of outstanding write IO */
+       zio_t *dr_zio;
+
+       /* pointer back to our dbuf */
+       struct dmu_buf_impl *dr_dbuf;
+
+       /* pointer to next dirty record */
+       struct dbuf_dirty_record *dr_next;
+
+       /* pointer to parent dirty record */
+       struct dbuf_dirty_record *dr_parent;
+
+       /* How much space was changed to dsl_pool_dirty_space() for this? */
+       unsigned int dr_accounted;
+
+       union dirty_types {
+               struct dirty_indirect {
+
+                       /* protect access to list */
+                       kmutex_t dr_mtx;
+
+                       /* Our list of dirty children */
+                       list_t dr_children;
+               } di;
+               struct dirty_leaf {
+
+                       /*
+                        * dr_data is set when we dirty the buffer
+                        * so that we can retain the pointer even if it
+                        * gets COW'd in a subsequent transaction group.
+                        */
+                       arc_buf_t *dr_data;
+                       blkptr_t dr_overridden_by;
+                       override_states_t dr_override_state;
+                       uint8_t dr_copies;
+                       boolean_t dr_nopwrite;
+               } dl;
+       } dt;
+} dbuf_dirty_record_t;
+
+typedef struct dmu_buf_impl {
+       /*
+        * The following members are immutable, with the exception of
+        * db.db_data, which is protected by db_mtx.
+        */
+
+       /* the publicly visible structure */
+       dmu_buf_t db;
+
+       /* the objset we belong to */
+       struct objset *db_objset;
+
+       /*
+        * handle to safely access the dnode we belong to (NULL when evicted)
+        */
+       struct dnode_handle *db_dnode_handle;
+
+       /*
+        * our parent buffer; if the dnode points to us directly,
+        * db_parent == db_dnode_handle->dnh_dnode->dn_dbuf
+        * only accessed by sync thread ???
+        * (NULL when evicted)
+        * May change from NULL to non-NULL under the protection of db_mtx
+        * (see dbuf_check_blkptr())
+        */
+       struct dmu_buf_impl *db_parent;
+
+       /*
+        * link for hash table of all dmu_buf_impl_t's
+        */
+       struct dmu_buf_impl *db_hash_next;
+
+       /* our block number */
+       uint64_t db_blkid;
+
+       /*
+        * Pointer to the blkptr_t which points to us. May be NULL if we
+        * don't have one yet. (NULL when evicted)
+        */
+       blkptr_t *db_blkptr;
+
+       /*
+        * Our indirection level.  Data buffers have db_level==0.
+        * Indirect buffers which point to data buffers have
+        * db_level==1. etc.  Buffers which contain dnodes have
+        * db_level==0, since the dnodes are stored in a file.
+        */
+       uint8_t db_level;
+
+       /* db_mtx protects the members below */
+       kmutex_t db_mtx;
+
+       /*
+        * Current state of the buffer
+        */
+       dbuf_states_t db_state;
+
+       /*
+        * Refcount accessed by dmu_buf_{hold,rele}.
+        * If nonzero, the buffer can't be destroyed.
+        * Protected by db_mtx.
+        */
+       refcount_t db_holds;
+
+       /* buffer holding our data */
+       arc_buf_t *db_buf;
+
+       kcondvar_t db_changed;
+       dbuf_dirty_record_t *db_data_pending;
+
+       /* pointer to most recent dirty record for this buffer */
+       dbuf_dirty_record_t *db_last_dirty;
+
+       /*
+        * Our link on the owner dnodes's dn_dbufs list.
+        * Protected by its dn_dbufs_mtx.
+        */
+       avl_node_t db_link;
+
+       /* Data which is unique to data (leaf) blocks: */
+
+       /* User callback information. */
+       dmu_buf_user_t *db_user;
+
+       /*
+        * Evict user data as soon as the dirty and reference
+        * counts are equal.
+        */
+       uint8_t db_user_immediate_evict;
+
+       /*
+        * This block was freed while a read or write was
+        * active.
+        */
+       uint8_t db_freed_in_flight;
+
+       /*
+        * dnode_evict_dbufs() or dnode_evict_bonus() tried to
+        * evict this dbuf, but couldn't due to outstanding
+        * references.  Evict once the refcount drops to 0.
+        */
+       uint8_t db_pending_evict;
+
+       uint8_t db_dirtycnt;
+} dmu_buf_impl_t;
+
+/* Note: the dbuf hash table is exposed only for the mdb module */
+#define        DBUF_MUTEXES 8192
+#define        DBUF_HASH_MUTEX(h, idx) (&(h)->hash_mutexes[(idx) & (DBUF_MUTEXES-1)])
+typedef struct dbuf_hash_table {
+       uint64_t hash_table_mask;
+       dmu_buf_impl_t **hash_table;
+       kmutex_t hash_mutexes[DBUF_MUTEXES];
+} dbuf_hash_table_t;
+
+
+uint64_t dbuf_whichblock(struct dnode *di, 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);
+
+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,
+    void *tag, dmu_buf_impl_t **dbp);
+
+void dbuf_prefetch(struct dnode *dn, uint64_t blkid, zio_priority_t prio);
+
+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,
+    uint64_t blkid, void *tag);
+uint64_t dbuf_refcount(dmu_buf_impl_t *db);
+
+void dbuf_rele(dmu_buf_impl_t *db, void *tag);
+void dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag);
+
+dmu_buf_impl_t *dbuf_find(struct objset *os, uint64_t object, uint8_t level,
+    uint64_t blkid);
+
+int dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags);
+void dmu_buf_will_not_fill(dmu_buf_t *db, dmu_tx_t *tx);
+void dmu_buf_will_fill(dmu_buf_t *db, dmu_tx_t *tx);
+void dmu_buf_fill_done(dmu_buf_t *db, dmu_tx_t *tx);
+void dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx);
+dbuf_dirty_record_t *dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
+arc_buf_t *dbuf_loan_arcbuf(dmu_buf_impl_t *db);
+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_unoverride(dbuf_dirty_record_t *dr);
+void dbuf_sync_list(list_t *list, int level, dmu_tx_t *tx);
+void dbuf_release_bp(dmu_buf_impl_t *db);
+
+void dbuf_free_range(struct dnode *dn, uint64_t start, uint64_t end,
+    struct dmu_tx *);
+
+void dbuf_new_size(dmu_buf_impl_t *db, int size, dmu_tx_t *tx);
+
+void dbuf_stats_init(dbuf_hash_table_t *hash);
+void dbuf_stats_destroy(void);
+
+#define        DB_DNODE(_db)           ((_db)->db_dnode_handle->dnh_dnode)
+#define        DB_DNODE_LOCK(_db)      ((_db)->db_dnode_handle->dnh_zrlock)
+#define        DB_DNODE_ENTER(_db)     (zrl_add(&DB_DNODE_LOCK(_db)))
+#define        DB_DNODE_EXIT(_db)      (zrl_remove(&DB_DNODE_LOCK(_db)))
+#define        DB_DNODE_HELD(_db)      (!zrl_is_zero(&DB_DNODE_LOCK(_db)))
+
+void dbuf_init(void);
+void dbuf_fini(void);
+
+boolean_t dbuf_is_metadata(dmu_buf_impl_t *db);
+
+#define        DBUF_GET_BUFC_TYPE(_db) \
+       (dbuf_is_metadata(_db) ? ARC_BUFC_METADATA : ARC_BUFC_DATA)
+
+#define        DBUF_IS_CACHEABLE(_db)                                          \
+       ((_db)->db_objset->os_primary_cache == ZFS_CACHE_ALL ||         \
+       (dbuf_is_metadata(_db) &&                                       \
+       ((_db)->db_objset->os_primary_cache == ZFS_CACHE_METADATA)))
+
+#define        DBUF_IS_L2CACHEABLE(_db)                                        \
+       ((_db)->db_objset->os_secondary_cache == ZFS_CACHE_ALL ||       \
+       (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
+
+/*
+ * There should be a ## between the string literal and fmt, to make it
+ * clear that we're joining two strings together, but gcc does not
+ * support that preprocessor token.
+ */
+#define        dprintf_dbuf(dbuf, fmt, ...) do { \
+       if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
+       char __db_buf[32]; \
+       uint64_t __db_obj = (dbuf)->db.db_object; \
+       if (__db_obj == DMU_META_DNODE_OBJECT) \
+               (void) strcpy(__db_buf, "mdn"); \
+       else \
+               (void) snprintf(__db_buf, sizeof (__db_buf), "%lld", \
+                   (u_longlong_t)__db_obj); \
+       dprintf_ds((dbuf)->db_objset->os_dsl_dataset, \
+           "obj=%s lvl=%u blkid=%lld " fmt, \
+           __db_buf, (dbuf)->db_level, \
+           (u_longlong_t)(dbuf)->db_blkid, __VA_ARGS__); \
+       } \
+_NOTE(CONSTCOND) } while (0)
+
+#define        dprintf_dbuf_bp(db, bp, fmt, ...) do {                  \
+       if (zfs_flags & ZFS_DEBUG_DPRINTF) {                    \
+       char *__blkbuf = kmem_alloc(BP_SPRINTF_LEN, KM_SLEEP);  \
+       snprintf_blkptr(__blkbuf, BP_SPRINTF_LEN, bp);          \
+       dprintf_dbuf(db, fmt " %s\n", __VA_ARGS__, __blkbuf);   \
+       kmem_free(__blkbuf, BP_SPRINTF_LEN);                    \
+       }                                                       \
+_NOTE(CONSTCOND) } while (0)
+
+#define        DBUF_VERIFY(db) dbuf_verify(db)
+
+#else
+
+#define        dprintf_dbuf(db, fmt, ...)
+#define        dprintf_dbuf_bp(db, bp, fmt, ...)
+#define        DBUF_VERIFY(db)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DBUF_H */
diff --git a/zfs/include/sys/ddt.h b/zfs/include/sys/ddt.h
new file mode 100644 (file)
index 0000000..3befcb8
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef _SYS_DDT_H
+#define        _SYS_DDT_H
+
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+#include <sys/zio.h>
+#include <sys/dmu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * On-disk DDT formats, in the desired search order (newest version first).
+ */
+enum ddt_type {
+       DDT_TYPE_ZAP = 0,
+       DDT_TYPES
+};
+
+/*
+ * DDT classes, in the desired search order (highest replication level first).
+ */
+enum ddt_class {
+       DDT_CLASS_DITTO = 0,
+       DDT_CLASS_DUPLICATE,
+       DDT_CLASS_UNIQUE,
+       DDT_CLASSES
+};
+
+#define        DDT_TYPE_CURRENT                0
+
+#define        DDT_COMPRESS_BYTEORDER_MASK     0x80
+#define        DDT_COMPRESS_FUNCTION_MASK      0x7f
+
+/*
+ * On-disk ddt entry:  key (name) and physical storage (value).
+ */
+typedef struct ddt_key {
+       zio_cksum_t     ddk_cksum;      /* 256-bit block checksum */
+       /*
+        * Encoded with logical & physical size, and compression, as follows:
+        *   +-------+-------+-------+-------+-------+-------+-------+-------+
+        *   |   0   |   0   |   0   | comp  |     PSIZE     |     LSIZE     |
+        *   +-------+-------+-------+-------+-------+-------+-------+-------+
+        */
+       uint64_t        ddk_prop;
+} ddt_key_t;
+
+#define        DDK_GET_LSIZE(ddk)      \
+       BF64_GET_SB((ddk)->ddk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1)
+#define        DDK_SET_LSIZE(ddk, x)   \
+       BF64_SET_SB((ddk)->ddk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1, x)
+
+#define        DDK_GET_PSIZE(ddk)      \
+       BF64_GET_SB((ddk)->ddk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1)
+#define        DDK_SET_PSIZE(ddk, x)   \
+       BF64_SET_SB((ddk)->ddk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1, x)
+
+#define        DDK_GET_COMPRESS(ddk)           BF64_GET((ddk)->ddk_prop, 32, 8)
+#define        DDK_SET_COMPRESS(ddk, x)        BF64_SET((ddk)->ddk_prop, 32, 8, x)
+
+#define        DDT_KEY_WORDS   (sizeof (ddt_key_t) / sizeof (uint64_t))
+
+typedef struct ddt_phys {
+       dva_t           ddp_dva[SPA_DVAS_PER_BP];
+       uint64_t        ddp_refcnt;
+       uint64_t        ddp_phys_birth;
+} ddt_phys_t;
+
+enum ddt_phys_type {
+       DDT_PHYS_DITTO = 0,
+       DDT_PHYS_SINGLE = 1,
+       DDT_PHYS_DOUBLE = 2,
+       DDT_PHYS_TRIPLE = 3,
+       DDT_PHYS_TYPES
+};
+
+/*
+ * In-core ddt entry
+ */
+struct ddt_entry {
+       ddt_key_t       dde_key;
+       ddt_phys_t      dde_phys[DDT_PHYS_TYPES];
+       zio_t           *dde_lead_zio[DDT_PHYS_TYPES];
+       void            *dde_repair_data;
+       enum ddt_type   dde_type;
+       enum ddt_class  dde_class;
+       uint8_t         dde_loading;
+       uint8_t         dde_loaded;
+       kcondvar_t      dde_cv;
+       avl_node_t      dde_node;
+};
+
+/*
+ * In-core ddt
+ */
+struct ddt {
+       kmutex_t        ddt_lock;
+       avl_tree_t      ddt_tree;
+       avl_tree_t      ddt_repair_tree;
+       enum zio_checksum ddt_checksum;
+       spa_t           *ddt_spa;
+       objset_t        *ddt_os;
+       uint64_t        ddt_stat_object;
+       uint64_t        ddt_object[DDT_TYPES][DDT_CLASSES];
+       ddt_histogram_t ddt_histogram[DDT_TYPES][DDT_CLASSES];
+       ddt_histogram_t ddt_histogram_cache[DDT_TYPES][DDT_CLASSES];
+       ddt_object_t    ddt_object_stats[DDT_TYPES][DDT_CLASSES];
+       avl_node_t      ddt_node;
+};
+
+/*
+ * In-core and on-disk bookmark for DDT walks
+ */
+typedef struct ddt_bookmark {
+       uint64_t        ddb_class;
+       uint64_t        ddb_type;
+       uint64_t        ddb_checksum;
+       uint64_t        ddb_cursor;
+} ddt_bookmark_t;
+
+/*
+ * Ops vector to access a specific DDT object type.
+ */
+typedef struct ddt_ops {
+       char ddt_op_name[32];
+       int (*ddt_op_create)(objset_t *os, uint64_t *object, dmu_tx_t *tx,
+           boolean_t prehash);
+       int (*ddt_op_destroy)(objset_t *os, uint64_t object, dmu_tx_t *tx);
+       int (*ddt_op_lookup)(objset_t *os, uint64_t object, ddt_entry_t *dde);
+       void (*ddt_op_prefetch)(objset_t *os, uint64_t object,
+           ddt_entry_t *dde);
+       int (*ddt_op_update)(objset_t *os, uint64_t object, ddt_entry_t *dde,
+           dmu_tx_t *tx);
+       int (*ddt_op_remove)(objset_t *os, uint64_t object, ddt_entry_t *dde,
+           dmu_tx_t *tx);
+       int (*ddt_op_walk)(objset_t *os, uint64_t object, ddt_entry_t *dde,
+           uint64_t *walk);
+       int (*ddt_op_count)(objset_t *os, uint64_t object, uint64_t *count);
+} ddt_ops_t;
+
+#define        DDT_NAMELEN     80
+
+extern void ddt_object_name(ddt_t *ddt, enum ddt_type type,
+    enum ddt_class class, char *name);
+extern int ddt_object_walk(ddt_t *ddt, enum ddt_type type,
+    enum ddt_class class, uint64_t *walk, ddt_entry_t *dde);
+extern int ddt_object_count(ddt_t *ddt, enum ddt_type type,
+    enum ddt_class class, uint64_t *count);
+extern int ddt_object_info(ddt_t *ddt, enum ddt_type type,
+    enum ddt_class class, dmu_object_info_t *);
+extern boolean_t ddt_object_exists(ddt_t *ddt, enum ddt_type type,
+    enum ddt_class class);
+
+extern void ddt_bp_fill(const ddt_phys_t *ddp, blkptr_t *bp,
+    uint64_t txg);
+extern void ddt_bp_create(enum zio_checksum checksum, const ddt_key_t *ddk,
+    const ddt_phys_t *ddp, blkptr_t *bp);
+
+extern void ddt_key_fill(ddt_key_t *ddk, const blkptr_t *bp);
+
+extern void ddt_phys_fill(ddt_phys_t *ddp, const blkptr_t *bp);
+extern void ddt_phys_clear(ddt_phys_t *ddp);
+extern void ddt_phys_addref(ddt_phys_t *ddp);
+extern void ddt_phys_decref(ddt_phys_t *ddp);
+extern void ddt_phys_free(ddt_t *ddt, ddt_key_t *ddk, ddt_phys_t *ddp,
+    uint64_t txg);
+extern ddt_phys_t *ddt_phys_select(const ddt_entry_t *dde, const blkptr_t *bp);
+extern uint64_t ddt_phys_total_refcnt(const ddt_entry_t *dde);
+
+extern void ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src, uint64_t neg);
+
+extern void ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src);
+extern void ddt_histogram_stat(ddt_stat_t *dds, const ddt_histogram_t *ddh);
+extern boolean_t ddt_histogram_empty(const ddt_histogram_t *ddh);
+extern void ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo);
+extern void ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh);
+extern void ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total);
+
+extern uint64_t ddt_get_dedup_dspace(spa_t *spa);
+extern uint64_t ddt_get_pool_dedup_ratio(spa_t *spa);
+
+extern int ddt_ditto_copies_needed(ddt_t *ddt, ddt_entry_t *dde,
+    ddt_phys_t *ddp_willref);
+extern int ddt_ditto_copies_present(ddt_entry_t *dde);
+
+extern size_t ddt_compress(void *src, uchar_t *dst, size_t s_len, size_t d_len);
+extern void ddt_decompress(uchar_t *src, void *dst, size_t s_len, size_t d_len);
+
+extern ddt_t *ddt_select(spa_t *spa, const blkptr_t *bp);
+extern void ddt_enter(ddt_t *ddt);
+extern void ddt_exit(ddt_t *ddt);
+extern void ddt_init(void);
+extern void ddt_fini(void);
+extern ddt_entry_t *ddt_lookup(ddt_t *ddt, const blkptr_t *bp, boolean_t add);
+extern void ddt_prefetch(spa_t *spa, const blkptr_t *bp);
+extern void ddt_remove(ddt_t *ddt, ddt_entry_t *dde);
+
+extern boolean_t ddt_class_contains(spa_t *spa, enum ddt_class max_class,
+    const blkptr_t *bp);
+
+extern ddt_entry_t *ddt_repair_start(ddt_t *ddt, const blkptr_t *bp);
+extern void ddt_repair_done(ddt_t *ddt, ddt_entry_t *dde);
+
+extern int ddt_entry_compare(const void *x1, const void *x2);
+
+extern void ddt_create(spa_t *spa);
+extern int ddt_load(spa_t *spa);
+extern void ddt_unload(spa_t *spa);
+extern void ddt_sync(spa_t *spa, uint64_t txg);
+extern int ddt_walk(spa_t *spa, ddt_bookmark_t *ddb, ddt_entry_t *dde);
+extern int ddt_object_update(ddt_t *ddt, enum ddt_type type,
+    enum ddt_class class, ddt_entry_t *dde, dmu_tx_t *tx);
+
+extern const ddt_ops_t ddt_zap_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DDT_H */
diff --git a/zfs/include/sys/dmu.h b/zfs/include/sys/dmu.h
new file mode 100644 (file)
index 0000000..d9434db
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 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.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#ifndef        _SYS_DMU_H
+#define        _SYS_DMU_H
+
+/*
+ * This file describes the interface that the DMU provides for its
+ * consumers.
+ *
+ * The DMU also interacts with the SPA.  That interface is described in
+ * dmu_spa.h.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/inttypes.h>
+#include <sys/cred.h>
+#include <sys/fs/zfs.h>
+#include <sys/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct page;
+struct vnode;
+struct spa;
+struct zilog;
+struct zio;
+struct blkptr;
+struct zap_cursor;
+struct dsl_dataset;
+struct dsl_pool;
+struct dnode;
+struct drr_begin;
+struct drr_end;
+struct zbookmark_phys;
+struct spa;
+struct nvlist;
+struct arc_buf;
+struct zio_prop;
+struct sa_handle;
+
+typedef struct objset objset_t;
+typedef struct dmu_tx dmu_tx_t;
+typedef struct dsl_dir dsl_dir_t;
+
+typedef enum dmu_object_byteswap {
+       DMU_BSWAP_UINT8,
+       DMU_BSWAP_UINT16,
+       DMU_BSWAP_UINT32,
+       DMU_BSWAP_UINT64,
+       DMU_BSWAP_ZAP,
+       DMU_BSWAP_DNODE,
+       DMU_BSWAP_OBJSET,
+       DMU_BSWAP_ZNODE,
+       DMU_BSWAP_OLDACL,
+       DMU_BSWAP_ACL,
+       /*
+        * Allocating a new byteswap type number makes the on-disk format
+        * incompatible with any other format that uses the same number.
+        *
+        * Data can usually be structured to work with one of the
+        * DMU_BSWAP_UINT* or DMU_BSWAP_ZAP types.
+        */
+       DMU_BSWAP_NUMFUNCS
+} dmu_object_byteswap_t;
+
+#define        DMU_OT_NEWTYPE 0x80
+#define        DMU_OT_METADATA 0x40
+#define        DMU_OT_BYTESWAP_MASK 0x3f
+
+/*
+ * Defines a uint8_t object type. Object types specify if the data
+ * in the object is metadata (boolean) and how to byteswap the data
+ * (dmu_object_byteswap_t).
+ */
+#define        DMU_OT(byteswap, metadata) \
+       (DMU_OT_NEWTYPE | \
+       ((metadata) ? DMU_OT_METADATA : 0) | \
+       ((byteswap) & DMU_OT_BYTESWAP_MASK))
+
+#define        DMU_OT_IS_VALID(ot) (((ot) & DMU_OT_NEWTYPE) ? \
+       ((ot) & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS : \
+       (ot) < DMU_OT_NUMTYPES)
+
+#define        DMU_OT_IS_METADATA(ot) (((ot) & DMU_OT_NEWTYPE) ? \
+       ((ot) & DMU_OT_METADATA) : \
+       dmu_ot[(int)(ot)].ot_metadata)
+
+/*
+ * These object types use bp_fill != 1 for their L0 bp's. Therefore they can't
+ * have their data embedded (i.e. use a BP_IS_EMBEDDED() bp), because bp_fill
+ * is repurposed for embedded BPs.
+ */
+#define        DMU_OT_HAS_FILL(ot) \
+       ((ot) == DMU_OT_DNODE || (ot) == DMU_OT_OBJSET)
+
+#define        DMU_OT_BYTESWAP(ot) (((ot) & DMU_OT_NEWTYPE) ? \
+       ((ot) & DMU_OT_BYTESWAP_MASK) : \
+       dmu_ot[(int)(ot)].ot_byteswap)
+
+typedef enum dmu_object_type {
+       DMU_OT_NONE,
+       /* general: */
+       DMU_OT_OBJECT_DIRECTORY,        /* ZAP */
+       DMU_OT_OBJECT_ARRAY,            /* UINT64 */
+       DMU_OT_PACKED_NVLIST,           /* UINT8 (XDR by nvlist_pack/unpack) */
+       DMU_OT_PACKED_NVLIST_SIZE,      /* UINT64 */
+       DMU_OT_BPOBJ,                   /* UINT64 */
+       DMU_OT_BPOBJ_HDR,               /* UINT64 */
+       /* spa: */
+       DMU_OT_SPACE_MAP_HEADER,        /* UINT64 */
+       DMU_OT_SPACE_MAP,               /* UINT64 */
+       /* zil: */
+       DMU_OT_INTENT_LOG,              /* UINT64 */
+       /* dmu: */
+       DMU_OT_DNODE,                   /* DNODE */
+       DMU_OT_OBJSET,                  /* OBJSET */
+       /* dsl: */
+       DMU_OT_DSL_DIR,                 /* UINT64 */
+       DMU_OT_DSL_DIR_CHILD_MAP,       /* ZAP */
+       DMU_OT_DSL_DS_SNAP_MAP,         /* ZAP */
+       DMU_OT_DSL_PROPS,               /* ZAP */
+       DMU_OT_DSL_DATASET,             /* UINT64 */
+       /* zpl: */
+       DMU_OT_ZNODE,                   /* ZNODE */
+       DMU_OT_OLDACL,                  /* Old ACL */
+       DMU_OT_PLAIN_FILE_CONTENTS,     /* UINT8 */
+       DMU_OT_DIRECTORY_CONTENTS,      /* ZAP */
+       DMU_OT_MASTER_NODE,             /* ZAP */
+       DMU_OT_UNLINKED_SET,            /* ZAP */
+       /* zvol: */
+       DMU_OT_ZVOL,                    /* UINT8 */
+       DMU_OT_ZVOL_PROP,               /* ZAP */
+       /* other; for testing only! */
+       DMU_OT_PLAIN_OTHER,             /* UINT8 */
+       DMU_OT_UINT64_OTHER,            /* UINT64 */
+       DMU_OT_ZAP_OTHER,               /* ZAP */
+       /* new object types: */
+       DMU_OT_ERROR_LOG,               /* ZAP */
+       DMU_OT_SPA_HISTORY,             /* UINT8 */
+       DMU_OT_SPA_HISTORY_OFFSETS,     /* spa_his_phys_t */
+       DMU_OT_POOL_PROPS,              /* ZAP */
+       DMU_OT_DSL_PERMS,               /* ZAP */
+       DMU_OT_ACL,                     /* ACL */
+       DMU_OT_SYSACL,                  /* SYSACL */
+       DMU_OT_FUID,                    /* FUID table (Packed NVLIST UINT8) */
+       DMU_OT_FUID_SIZE,               /* FUID table size UINT64 */
+       DMU_OT_NEXT_CLONES,             /* ZAP */
+       DMU_OT_SCAN_QUEUE,              /* ZAP */
+       DMU_OT_USERGROUP_USED,          /* ZAP */
+       DMU_OT_USERGROUP_QUOTA,         /* ZAP */
+       DMU_OT_USERREFS,                /* ZAP */
+       DMU_OT_DDT_ZAP,                 /* ZAP */
+       DMU_OT_DDT_STATS,               /* ZAP */
+       DMU_OT_SA,                      /* System attr */
+       DMU_OT_SA_MASTER_NODE,          /* ZAP */
+       DMU_OT_SA_ATTR_REGISTRATION,    /* ZAP */
+       DMU_OT_SA_ATTR_LAYOUTS,         /* ZAP */
+       DMU_OT_SCAN_XLATE,              /* ZAP */
+       DMU_OT_DEDUP,                   /* fake dedup BP from ddt_bp_create() */
+       DMU_OT_DEADLIST,                /* ZAP */
+       DMU_OT_DEADLIST_HDR,            /* UINT64 */
+       DMU_OT_DSL_CLONES,              /* ZAP */
+       DMU_OT_BPOBJ_SUBOBJ,            /* UINT64 */
+       /*
+        * Do not allocate new object types here. Doing so makes the on-disk
+        * format incompatible with any other format that uses the same object
+        * type number.
+        *
+        * When creating an object which does not have one of the above types
+        * use the DMU_OTN_* type with the correct byteswap and metadata
+        * values.
+        *
+        * The DMU_OTN_* types do not have entries in the dmu_ot table,
+        * use the DMU_OT_IS_METDATA() and DMU_OT_BYTESWAP() macros instead
+        * of indexing into dmu_ot directly (this works for both DMU_OT_* types
+        * and DMU_OTN_* types).
+        */
+       DMU_OT_NUMTYPES,
+
+       /*
+        * Names for valid types declared with DMU_OT().
+        */
+       DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE),
+       DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE),
+       DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE),
+       DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE),
+       DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE),
+       DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE),
+       DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE),
+       DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE),
+       DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE),
+       DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
+} dmu_object_type_t;
+
+typedef enum txg_how {
+       TXG_WAIT = 1,
+       TXG_NOWAIT,
+       TXG_WAITED,
+} txg_how_t;
+
+void byteswap_uint64_array(void *buf, size_t size);
+void byteswap_uint32_array(void *buf, size_t size);
+void byteswap_uint16_array(void *buf, size_t size);
+void byteswap_uint8_array(void *buf, size_t size);
+void zap_byteswap(void *buf, size_t size);
+void zfs_oldacl_byteswap(void *buf, size_t size);
+void zfs_acl_byteswap(void *buf, size_t size);
+void zfs_znode_byteswap(void *buf, size_t size);
+
+#define        DS_FIND_SNAPSHOTS       (1<<0)
+#define        DS_FIND_CHILDREN        (1<<1)
+#define        DS_FIND_SERIALIZE       (1<<2)
+
+/*
+ * The maximum number of bytes that can be accessed as part of one
+ * operation, including metadata.
+ */
+#define        DMU_MAX_ACCESS (64 * 1024 * 1024) /* 64MB */
+#define        DMU_MAX_DELETEBLKCNT (20480) /* ~5MB of indirect blocks */
+
+#define        DMU_USERUSED_OBJECT     (-1ULL)
+#define        DMU_GROUPUSED_OBJECT    (-2ULL)
+
+/*
+ * artificial blkids for bonus buffer and spill blocks
+ */
+#define        DMU_BONUS_BLKID         (-1ULL)
+#define        DMU_SPILL_BLKID         (-2ULL)
+/*
+ * Public routines to create, destroy, open, and close objsets.
+ */
+int dmu_objset_hold(const char *name, void *tag, objset_t **osp);
+int dmu_objset_own(const char *name, dmu_objset_type_t type,
+    boolean_t readonly, void *tag, objset_t **osp);
+void dmu_objset_rele(objset_t *os, void *tag);
+void dmu_objset_disown(objset_t *os, void *tag);
+int dmu_objset_open_ds(struct dsl_dataset *ds, objset_t **osp);
+
+void dmu_objset_evict_dbufs(objset_t *os);
+int dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
+    void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg);
+int dmu_objset_clone(const char *name, const char *origin);
+int dsl_destroy_snapshots_nvl(struct nvlist *snaps, boolean_t defer,
+    struct nvlist *errlist);
+int dmu_objset_snapshot_one(const char *fsname, const char *snapname);
+int dmu_objset_snapshot_tmp(const char *, const char *, int);
+int dmu_objset_find(char *name, int func(const char *, void *), void *arg,
+    int flags);
+void dmu_objset_byteswap(void *buf, size_t size);
+int dsl_dataset_rename_snapshot(const char *fsname,
+    const char *oldsnapname, const char *newsnapname, boolean_t recursive);
+
+typedef struct dmu_buf {
+       uint64_t db_object;             /* object that this buffer is part of */
+       uint64_t db_offset;             /* byte offset in this object */
+       uint64_t db_size;               /* size of buffer in bytes */
+       void *db_data;                  /* data in buffer */
+} dmu_buf_t;
+
+/*
+ * The names of zap entries in the DIRECTORY_OBJECT of the MOS.
+ */
+#define        DMU_POOL_DIRECTORY_OBJECT       1
+#define        DMU_POOL_CONFIG                 "config"
+#define        DMU_POOL_FEATURES_FOR_WRITE     "features_for_write"
+#define        DMU_POOL_FEATURES_FOR_READ      "features_for_read"
+#define        DMU_POOL_FEATURE_DESCRIPTIONS   "feature_descriptions"
+#define        DMU_POOL_FEATURE_ENABLED_TXG    "feature_enabled_txg"
+#define        DMU_POOL_ROOT_DATASET           "root_dataset"
+#define        DMU_POOL_SYNC_BPOBJ             "sync_bplist"
+#define        DMU_POOL_ERRLOG_SCRUB           "errlog_scrub"
+#define        DMU_POOL_ERRLOG_LAST            "errlog_last"
+#define        DMU_POOL_SPARES                 "spares"
+#define        DMU_POOL_DEFLATE                "deflate"
+#define        DMU_POOL_HISTORY                "history"
+#define        DMU_POOL_PROPS                  "pool_props"
+#define        DMU_POOL_L2CACHE                "l2cache"
+#define        DMU_POOL_TMP_USERREFS           "tmp_userrefs"
+#define        DMU_POOL_DDT                    "DDT-%s-%s-%s"
+#define        DMU_POOL_DDT_STATS              "DDT-statistics"
+#define        DMU_POOL_CREATION_VERSION       "creation_version"
+#define        DMU_POOL_SCAN                   "scan"
+#define        DMU_POOL_FREE_BPOBJ             "free_bpobj"
+#define        DMU_POOL_BPTREE_OBJ             "bptree_obj"
+#define        DMU_POOL_EMPTY_BPOBJ            "empty_bpobj"
+
+/*
+ * Allocate an object from this objset.  The range of object numbers
+ * available is (0, DN_MAX_OBJECT).  Object 0 is the meta-dnode.
+ *
+ * The transaction must be assigned to a txg.  The newly allocated
+ * object will be "held" in the transaction (ie. you can modify the
+ * newly allocated object in this transaction).
+ *
+ * dmu_object_alloc() chooses an object and returns it in *objectp.
+ *
+ * dmu_object_claim() allocates a specific object number.  If that
+ * number is already allocated, it fails and returns EEXIST.
+ *
+ * Return 0 on success, or ENOSPC or EEXIST as specified above.
+ */
+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);
+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_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);
+
+/*
+ * Free an object from this objset.
+ *
+ * The object's data will be freed as well (ie. you don't need to call
+ * dmu_free(object, 0, -1, tx)).
+ *
+ * The object need not be held in the transaction.
+ *
+ * If there are any holds on this object's buffers (via dmu_buf_hold()),
+ * or tx holds on the object (via dmu_tx_hold_object()), you can not
+ * free it; it fails and returns EBUSY.
+ *
+ * If the object is not allocated, it fails and returns ENOENT.
+ *
+ * Return 0 on success, or EBUSY or ENOENT as specified above.
+ */
+int dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx);
+
+/*
+ * Find the next allocated or free object.
+ *
+ * The objectp parameter is in-out.  It will be updated to be the next
+ * object which is allocated.  Ignore objects which have not been
+ * modified since txg.
+ *
+ * XXX Can only be called on a objset with no dirty data.
+ *
+ * Returns 0 on success, or ENOENT if there are no more objects.
+ */
+int dmu_object_next(objset_t *os, uint64_t *objectp,
+    boolean_t hole, uint64_t txg);
+
+/*
+ * Set the data blocksize for an object.
+ *
+ * The object cannot have any blocks allcated beyond the first.  If
+ * the first block is allocated already, the new size must be greater
+ * than the current block size.  If these conditions are not met,
+ * ENOTSUP will be returned.
+ *
+ * Returns 0 on success, or EBUSY if there are any holds on the object
+ * contents, or ENOTSUP as described above.
+ */
+int dmu_object_set_blocksize(objset_t *os, uint64_t object, uint64_t size,
+    int ibs, dmu_tx_t *tx);
+
+/*
+ * Set the checksum property on a dnode.  The new checksum algorithm will
+ * apply to all newly written blocks; existing blocks will not be affected.
+ */
+void dmu_object_set_checksum(objset_t *os, uint64_t object, uint8_t checksum,
+    dmu_tx_t *tx);
+
+/*
+ * Set the compress property on a dnode.  The new compression algorithm will
+ * apply to all newly written blocks; existing blocks will not be affected.
+ */
+void dmu_object_set_compress(objset_t *os, uint64_t object, uint8_t compress,
+    dmu_tx_t *tx);
+
+void
+dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset,
+    void *data, uint8_t etype, uint8_t comp, int uncompressed_size,
+    int compressed_size, int byteorder, dmu_tx_t *tx);
+
+/*
+ * Decide how to write a block: checksum, compression, number of copies, etc.
+ */
+#define        WP_NOFILL       0x1
+#define        WP_DMU_SYNC     0x2
+#define        WP_SPILL        0x4
+
+void dmu_write_policy(objset_t *os, struct dnode *dn, int level, int wp,
+    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
+ * dmu_buf_t with db_offset==-1ULL, and db_size = the size of the bonus
+ * data.  As with any normal buffer, you must call dmu_buf_read() to
+ * read db_data, dmu_buf_will_dirty() before modifying it, and the
+ * object must be held in an assigned transaction before calling
+ * dmu_buf_will_dirty.  You may use dmu_buf_set_user() on the bonus
+ * buffer as well.  You must release what you hold with dmu_buf_rele().
+ *
+ * Returns ENOENT, EIO, or 0.
+ */
+int dmu_bonus_hold(objset_t *os, uint64_t object, void *tag, dmu_buf_t **);
+int dmu_bonus_max(void);
+int dmu_set_bonus(dmu_buf_t *, int, dmu_tx_t *);
+int dmu_set_bonustype(dmu_buf_t *, dmu_object_type_t, dmu_tx_t *);
+dmu_object_type_t dmu_get_bonustype(dmu_buf_t *);
+int dmu_rm_spill(objset_t *, uint64_t, dmu_tx_t *);
+
+/*
+ * Special spill buffer support used by "SA" framework
+ */
+
+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,
+    void *tag, dmu_buf_t **dbp);
+int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp);
+
+/*
+ * Obtain the DMU buffer from the specified object which contains the
+ * specified offset.  dmu_buf_hold() puts a "hold" on the buffer, so
+ * that it will remain in memory.  You must release the hold with
+ * dmu_buf_rele().  You must not access the dmu_buf_t after releasing
+ * what you hold.  You must have a hold on any dmu_buf_t* you pass to the DMU.
+ *
+ * You must call dmu_buf_read, dmu_buf_will_dirty, or dmu_buf_will_fill
+ * on the returned buffer before reading or writing the buffer's
+ * db_data.  The comments for those routines describe what particular
+ * operations are valid after calling them.
+ *
+ * The object number must be a valid, allocated object number.
+ */
+int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset,
+    void *tag, dmu_buf_t **, int flags);
+
+/*
+ * Add a reference to a dmu buffer that has already been held via
+ * dmu_buf_hold() in the current context.
+ */
+void dmu_buf_add_ref(dmu_buf_t *db, void* tag);
+
+/*
+ * Attempt to add a reference to a dmu buffer that is in an unknown state,
+ * using a pointer that may have been invalidated by eviction processing.
+ * The request will succeed if the passed in dbuf still represents the
+ * same os/object/blkid, is ineligible for eviction, and has at least
+ * one hold by a user other than the syncer.
+ */
+boolean_t dmu_buf_try_add_ref(dmu_buf_t *, objset_t *os, uint64_t object,
+    uint64_t blkid, void *tag);
+
+void dmu_buf_rele(dmu_buf_t *db, void *tag);
+uint64_t dmu_buf_refcount(dmu_buf_t *db);
+
+/*
+ * dmu_buf_hold_array holds the DMU buffers which contain all bytes in a
+ * range of an object.  A pointer to an array of dmu_buf_t*'s is
+ * returned (in *dbpp).
+ *
+ * dmu_buf_rele_array releases the hold on an array of dmu_buf_t*'s, and
+ * frees the array.  The hold on the array of buffers MUST be released
+ * with dmu_buf_rele_array.  You can NOT release the hold on each buffer
+ * 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);
+void dmu_buf_rele_array(dmu_buf_t **, int numbufs, void *tag);
+
+typedef void dmu_buf_evict_func_t(void *user_ptr);
+
+/*
+ * A DMU buffer user object may be associated with a dbuf for the
+ * duration of its lifetime.  This allows the user of a dbuf (client)
+ * to attach private data to a dbuf (e.g. in-core only data such as a
+ * dnode_children_t, zap_t, or zap_leaf_t) and be optionally notified
+ * when that dbuf has been evicted.  Clients typically respond to the
+ * eviction notification by freeing their private data, thus ensuring
+ * the same lifetime for both dbuf and private data.
+ *
+ * The mapping from a dmu_buf_user_t to any client private data is the
+ * client's responsibility.  All current consumers of the API with private
+ * data embed a dmu_buf_user_t as the first member of the structure for
+ * their private data.  This allows conversions between the two types
+ * with a simple cast.  Since the DMU buf user API never needs access
+ * to the private data, other strategies can be employed if necessary
+ * or convenient for the client (e.g. using container_of() to do the
+ * conversion for private data that cannot have the dmu_buf_user_t as
+ * its first member).
+ *
+ * Eviction callbacks are executed without the dbuf mutex held or any
+ * other type of mechanism to guarantee that the dbuf is still available.
+ * For this reason, users must assume the dbuf has already been freed
+ * and not reference the dbuf from the callback context.
+ *
+ * Users requesting "immediate eviction" are notified as soon as the dbuf
+ * is only referenced by dirty records (dirties == holds).  Otherwise the
+ * notification occurs after eviction processing for the dbuf begins.
+ */
+typedef struct dmu_buf_user {
+       /*
+        * Asynchronous user eviction callback state.
+        */
+       taskq_ent_t     dbu_tqent;
+
+       /* This instance's eviction function pointer. */
+       dmu_buf_evict_func_t *dbu_evict_func;
+#ifdef ZFS_DEBUG
+       /*
+        * Pointer to user's dbuf pointer.  NULL for clients that do
+        * not associate a dbuf with their user data.
+        *
+        * The dbuf pointer is cleared upon eviction so as to catch
+        * use-after-evict bugs in clients.
+        */
+       dmu_buf_t **dbu_clear_on_evict_dbufp;
+#endif
+} dmu_buf_user_t;
+
+/*
+ * Initialize the given dmu_buf_user_t instance with the eviction function
+ * evict_func, to be called when the user is evicted.
+ *
+ * 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 */
+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)
+{
+       ASSERT(dbu->dbu_evict_func == NULL);
+       ASSERT(evict_func != NULL);
+       dbu->dbu_evict_func = evict_func;
+       taskq_init_ent(&dbu->dbu_tqent);
+#ifdef ZFS_DEBUG
+       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
+ * data is cleared or its reference count goes to zero) eviction processing.
+ *
+ * Returns NULL on success, or the existing user if another user currently
+ * owns the buffer.
+ */
+void *dmu_buf_set_user(dmu_buf_t *db, dmu_buf_user_t *user);
+
+/*
+ * Attach user data to a dbuf and mark it for immediate (its dirty and
+ * reference counts are equal) eviction processing.
+ *
+ * Returns NULL on success, or the existing user if another user currently
+ * owns the buffer.
+ */
+void *dmu_buf_set_user_ie(dmu_buf_t *db, dmu_buf_user_t *user);
+
+/*
+ * Replace the current user of a dbuf.
+ *
+ * If given the current user of a dbuf, replaces the dbuf's user with
+ * "new_user" and returns the user data pointer that was replaced.
+ * Otherwise returns the current, and unmodified, dbuf user pointer.
+ */
+void *dmu_buf_replace_user(dmu_buf_t *db,
+    dmu_buf_user_t *old_user, dmu_buf_user_t *new_user);
+
+/*
+ * Remove the specified user data for a DMU buffer.
+ *
+ * Returns the user that was removed on success, or the current user if
+ * another user currently owns the buffer.
+ */
+void *dmu_buf_remove_user(dmu_buf_t *db, dmu_buf_user_t *user);
+
+/*
+ * Returns the user data (dmu_buf_user_t *) associated with this dbuf.
+ */
+void *dmu_buf_get_user(dmu_buf_t *db);
+
+/* Block until any in-progress dmu buf user evictions complete. */
+void dmu_buf_user_evict_wait(void);
+
+/*
+ * Returns the blkptr associated with this dbuf, or NULL if not set.
+ */
+struct blkptr *dmu_buf_get_blkptr(dmu_buf_t *db);
+
+/*
+ * Indicate that you are going to modify the buffer's data (db_data).
+ *
+ * The transaction (tx) must be assigned to a txg (ie. you've called
+ * dmu_tx_assign()).  The buffer's object must be held in the tx
+ * (ie. you've called dmu_tx_hold_object(tx, db->db_object)).
+ */
+void dmu_buf_will_dirty(dmu_buf_t *db, dmu_tx_t *tx);
+
+/*
+ * Tells if the given dbuf is freeable.
+ */
+boolean_t dmu_buf_freeable(dmu_buf_t *);
+
+/*
+ * You must create a transaction, then hold the objects which you will
+ * (or might) modify as part of this transaction.  Then you must assign
+ * the transaction to a transaction group.  Once the transaction has
+ * been assigned, you can modify buffers which belong to held objects as
+ * part of this transaction.  You can't modify buffers before the
+ * transaction has been assigned; you can't modify buffers which don't
+ * belong to objects which this transaction holds; you can't hold
+ * objects once the transaction has been assigned.  You may hold an
+ * object which you are going to free (with dmu_object_free()), but you
+ * don't have to.
+ *
+ * You can abort the transaction before it has been assigned.
+ *
+ * Note that you may hold buffers (with dmu_buf_hold) at any time,
+ * regardless of transaction state.
+ */
+
+#define        DMU_NEW_OBJECT  (-1ULL)
+#define        DMU_OBJECT_END  (-1ULL)
+
+dmu_tx_t *dmu_tx_create(objset_t *os);
+void dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len);
+void dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off,
+    uint64_t len);
+void dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name);
+void dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object);
+void dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object);
+void dmu_tx_hold_sa(dmu_tx_t *tx, struct sa_handle *hdl, boolean_t may_grow);
+void dmu_tx_hold_sa_create(dmu_tx_t *tx, int total_size);
+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);
+
+/*
+ * To register a commit callback, dmu_tx_callback_register() must be called.
+ *
+ * dcb_data is a pointer to caller private data that is passed on as a
+ * callback parameter. The caller is responsible for properly allocating and
+ * freeing it.
+ *
+ * When registering a callback, the transaction must be already created, but
+ * it cannot be committed or aborted. It can be assigned to a txg or not.
+ *
+ * The callback will be called after the transaction has been safely written
+ * to stable storage and will also be called if the dmu_tx is aborted.
+ * If there is any error which prevents the transaction from being committed to
+ * disk, the callback will be called with a value of error != 0.
+ */
+typedef void dmu_tx_callback_func_t(void *dcb_data, int error);
+
+void dmu_tx_callback_register(dmu_tx_t *tx, dmu_tx_callback_func_t *dcb_func,
+    void *dcb_data);
+
+/*
+ * Free up the data blocks for a defined range of a file.  If size is
+ * -1, the range from offset to end-of-file is freed.
+ */
+int dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
+       uint64_t size, dmu_tx_t *tx);
+int dmu_free_long_range(objset_t *os, uint64_t object, uint64_t offset,
+       uint64_t size);
+int dmu_free_long_object(objset_t *os, uint64_t object);
+
+/*
+ * Convenience functions.
+ *
+ * Canfail routines will return 0 on success, or an errno if there is a
+ * nonrecoverable I/O error.
+ */
+#define        DMU_READ_PREFETCH       0 /* prefetch */
+#define        DMU_READ_NO_PREFETCH    1 /* don't prefetch */
+int dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+       void *buf, uint32_t flags);
+void dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+       const void *buf, dmu_tx_t *tx);
+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,
+       dmu_tx_t *tx);
+int dmu_write_uio_dbuf(dmu_buf_t *zdb, struct uio *uio, uint64_t size,
+       dmu_tx_t *tx);
+#endif
+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);
+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,
+    size_t n);
+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);
+void xuio_stat_wbuf_copied(void);
+void xuio_stat_wbuf_nocopy(void);
+
+extern int zfs_prefetch_disable;
+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);
+
+typedef struct dmu_object_info {
+       /* All sizes are in bytes unless otherwise indicated. */
+       uint32_t doi_data_block_size;
+       uint32_t doi_metadata_block_size;
+       dmu_object_type_t doi_type;
+       dmu_object_type_t doi_bonus_type;
+       uint64_t doi_bonus_size;
+       uint8_t doi_indirection;                /* 2 = dnode->indirect->data */
+       uint8_t doi_checksum;
+       uint8_t doi_compress;
+       uint8_t doi_nblkptr;
+       uint8_t doi_pad[4];
+       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 */
+} dmu_object_info_t;
+
+typedef void (*const arc_byteswap_func_t)(void *buf, size_t size);
+
+typedef struct dmu_object_type_info {
+       dmu_object_byteswap_t   ot_byteswap;
+       boolean_t               ot_metadata;
+       char                    *ot_name;
+} dmu_object_type_info_t;
+
+typedef const struct dmu_object_byteswap_info {
+       arc_byteswap_func_t      ob_func;
+       char                    *ob_name;
+} dmu_object_byteswap_info_t;
+
+extern const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES];
+extern const dmu_object_byteswap_info_t dmu_ot_byteswap[DMU_BSWAP_NUMFUNCS];
+
+/*
+ * Get information on a DMU object.
+ *
+ * Return 0 on success or ENOENT if object is not allocated.
+ *
+ * If doi is NULL, just indicates whether the object exists.
+ */
+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);
+/* 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);
+/*
+ * Like dmu_object_info_from_db, but faster still when you only care about
+ * the size.  This is specifically optimized for zfs_getattr().
+ */
+void dmu_object_size_from_db(dmu_buf_t *db, uint32_t *blksize,
+    u_longlong_t *nblk512);
+
+typedef struct dmu_objset_stats {
+       uint64_t dds_num_clones; /* number of clones of this */
+       uint64_t dds_creation_txg;
+       uint64_t dds_guid;
+       dmu_objset_type_t dds_type;
+       uint8_t dds_is_snapshot;
+       uint8_t dds_inconsistent;
+       char dds_origin[MAXNAMELEN];
+} dmu_objset_stats_t;
+
+/*
+ * Get stats on a dataset.
+ */
+void dmu_objset_fast_stat(objset_t *os, dmu_objset_stats_t *stat);
+
+/*
+ * Add entries to the nvlist for all the objset's properties.  See
+ * zfs_prop_table[] and zfs(1m) for details on the properties.
+ */
+void dmu_objset_stats(objset_t *os, struct nvlist *nv);
+
+/*
+ * Get the space usage statistics for statvfs().
+ *
+ * refdbytes is the amount of space "referenced" by this objset.
+ * availbytes is the amount of space available to this objset, taking
+ * into account quotas & reservations, assuming that no other objsets
+ * use the space first.  These values correspond to the 'referenced' and
+ * 'available' properties, described in the zfs(1m) manpage.
+ *
+ * usedobjs and availobjs are the number of objects currently allocated,
+ * and available.
+ */
+void dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp,
+    uint64_t *usedobjsp, uint64_t *availobjsp);
+
+/*
+ * The fsid_guid is a 56-bit ID that can change to avoid collisions.
+ * (Contrast with the ds_guid which is a 64-bit ID that will never
+ * change, so there is a small probability that it will collide.)
+ */
+uint64_t dmu_objset_fsid_guid(objset_t *os);
+
+/*
+ * Get the [cm]time for an objset's snapshot dir
+ */
+timestruc_t dmu_objset_snap_cmtime(objset_t *os);
+
+int dmu_objset_is_snapshot(objset_t *os);
+
+extern struct spa *dmu_objset_spa(objset_t *os);
+extern struct zilog *dmu_objset_zil(objset_t *os);
+extern struct dsl_pool *dmu_objset_pool(objset_t *os);
+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 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,
+    uint64_t *id, uint64_t *offp, boolean_t *case_conflict);
+extern int dmu_snapshot_lookup(objset_t *os, const char *name, uint64_t *val);
+extern int dmu_snapshot_realname(objset_t *os, char *name, char *real,
+    int maxlen, boolean_t *conflict);
+extern int dmu_dir_list_next(objset_t *os, int namelen, char *name,
+    uint64_t *idp, uint64_t *offp);
+
+typedef int objset_used_cb_t(dmu_object_type_t bonustype,
+    void *bonus, uint64_t *userp, uint64_t *groupp);
+extern void dmu_objset_register_type(dmu_objset_type_t ost,
+    objset_used_cb_t *cb);
+extern void dmu_objset_set_user(objset_t *os, void *user_ptr);
+extern void *dmu_objset_get_user(objset_t *os);
+
+/*
+ * Return the txg number for the given assigned transaction.
+ */
+uint64_t dmu_tx_get_txg(dmu_tx_t *tx);
+
+/*
+ * Synchronous write.
+ * If a parent zio is provided this function initiates a write on the
+ * provided buffer as a child of the parent zio.
+ * In the absence of a parent zio, the write is completed synchronously.
+ * At write completion, blk is filled with the bp of the written block.
+ * Note that while the data covered by this function will be on stable
+ * storage when the write completes this new data does not become a
+ * permanent part of the file until the associated transaction commits.
+ */
+
+/*
+ * {zfs,zvol,ztest}_get_done() args
+ */
+typedef struct zgd {
+       struct zilog    *zgd_zilog;
+       struct blkptr   *zgd_bp;
+       dmu_buf_t       *zgd_db;
+       struct rl       *zgd_rl;
+       void            *zgd_private;
+} zgd_t;
+
+typedef void dmu_sync_cb_t(zgd_t *arg, int error);
+int dmu_sync(struct zio *zio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd);
+
+/*
+ * Find the next hole or data block in file starting at *off
+ * Return found offset in *off. Return ESRCH for end of file.
+ */
+int dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole,
+    uint64_t *off);
+
+/*
+ * Initial setup and final teardown.
+ */
+extern void dmu_init(void);
+extern void dmu_fini(void);
+
+typedef void (*dmu_traverse_cb_t)(objset_t *os, void *arg, struct blkptr *bp,
+    uint64_t object, uint64_t offset, int len);
+void dmu_traverse_objset(objset_t *os, uint64_t txg_start,
+    dmu_traverse_cb_t cb, void *arg);
+
+int dmu_diff(const char *tosnap_name, const char *fromsnap_name,
+    struct vnode *vp, offset_t *offp);
+
+/* CRC64 table */
+#define        ZFS_CRC64_POLY  0xC96C5795D7870F42ULL   /* ECMA-182, reflected form */
+extern uint64_t zfs_crc64_table[256];
+
+extern int zfs_mdcomp_disable;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DMU_H */
diff --git a/zfs/include/sys/dmu_impl.h b/zfs/include/sys/dmu_impl.h
new file mode 100644 (file)
index 0000000..75d094f
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_DMU_IMPL_H
+#define        _SYS_DMU_IMPL_H
+
+#include <sys/txg_impl.h>
+#include <sys/zio.h>
+#include <sys/dnode.h>
+#include <sys/zfs_context.h>
+#include <sys/zfs_ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is the locking strategy for the DMU.  Numbers in parenthesis are
+ * cases that use that lock order, referenced below:
+ *
+ * ARC is self-contained
+ * bplist is self-contained
+ * refcount is self-contained
+ * txg is self-contained (hopefully!)
+ * zst_lock
+ * zf_rwlock
+ *
+ * XXX try to improve evicting path?
+ *
+ * dp_config_rwlock > os_obj_lock > dn_struct_rwlock >
+ *     dn_dbufs_mtx > hash_mutexes > db_mtx > dd_lock > leafs
+ *
+ * dp_config_rwlock
+ *    must be held before: everything
+ *    protects dd namespace changes
+ *    protects property changes globally
+ *    held from:
+ *     dsl_dir_open/r:
+ *     dsl_dir_create_sync/w:
+ *     dsl_dir_sync_destroy/w:
+ *     dsl_dir_rename_sync/w:
+ *     dsl_prop_changed_notify/r:
+ *
+ * os_obj_lock
+ *   must be held before:
+ *     everything except dp_config_rwlock
+ *   protects os_obj_next
+ *   held from:
+ *     dmu_object_alloc: dn_dbufs_mtx, db_mtx, hash_mutexes, dn_struct_rwlock
+ *
+ * dn_struct_rwlock
+ *   must be held before:
+ *     everything except dp_config_rwlock and os_obj_lock
+ *   protects structure of dnode (eg. nlevels)
+ *     db_blkptr can change when syncing out change to nlevels
+ *     dn_maxblkid
+ *     dn_nlevels
+ *     dn_*blksz*
+ *     phys nlevels, maxblkid, physical blkptr_t's (?)
+ *   held from:
+ *     callers of dbuf_read_impl, dbuf_hold[_impl], dbuf_prefetch
+ *     dmu_object_info_from_dnode: dn_dirty_mtx (dn_datablksz)
+ *     dmu_tx_count_free:
+ *     dbuf_read_impl: db_mtx, dmu_zfetch()
+ *     dmu_zfetch: zf_rwlock/r, zst_lock, dbuf_prefetch()
+ *     dbuf_new_size: db_mtx
+ *     dbuf_dirty: db_mtx
+ *     dbuf_findbp: (callers, phys? - the real need)
+ *     dbuf_create: dn_dbufs_mtx, hash_mutexes, db_mtx (phys?)
+ *     dbuf_prefetch: dn_dirty_mtx, hash_mutexes, db_mtx, dn_dbufs_mtx
+ *     dbuf_hold_impl: hash_mutexes, db_mtx, dn_dbufs_mtx, dbuf_findbp()
+ *     dnode_sync/w (increase_indirection): db_mtx (phys)
+ *     dnode_set_blksz/w: dn_dbufs_mtx (dn_*blksz*)
+ *     dnode_new_blkid/w: (dn_maxblkid)
+ *     dnode_free_range/w: dn_dirty_mtx (dn_maxblkid)
+ *     dnode_next_offset: (phys)
+ *
+ * dn_dbufs_mtx
+ *    must be held before:
+ *     db_mtx, hash_mutexes
+ *    protects:
+ *     dn_dbufs
+ *     dn_evicted
+ *    held from:
+ *     dmu_evict_user: db_mtx (dn_dbufs)
+ *     dbuf_free_range: db_mtx (dn_dbufs)
+ *     dbuf_remove_ref: db_mtx, callees:
+ *             dbuf_hash_remove: hash_mutexes, db_mtx
+ *     dbuf_create: hash_mutexes, db_mtx (dn_dbufs)
+ *     dnode_set_blksz: (dn_dbufs)
+ *
+ * hash_mutexes (global)
+ *   must be held before:
+ *     db_mtx
+ *   protects dbuf_hash_table (global) and db_hash_next
+ *   held from:
+ *     dbuf_find: db_mtx
+ *     dbuf_hash_insert: db_mtx
+ *     dbuf_hash_remove: db_mtx
+ *
+ * db_mtx (meta-leaf)
+ *   must be held before:
+ *     dn_mtx, dn_dirty_mtx, dd_lock (leaf mutexes)
+ *   protects:
+ *     db_state
+ *     db_holds
+ *     db_buf
+ *     db_changed
+ *     db_data_pending
+ *     db_dirtied
+ *     db_link
+ *     db_dirty_node (??)
+ *     db_dirtycnt
+ *     db_d.*
+ *     db.*
+ *   held from:
+ *     dbuf_dirty: dn_mtx, dn_dirty_mtx
+ *     dbuf_dirty->dsl_dir_willuse_space: dd_lock
+ *     dbuf_dirty->dbuf_new_block->dsl_dataset_block_freeable: dd_lock
+ *     dbuf_undirty: dn_dirty_mtx (db_d)
+ *     dbuf_write_done: dn_dirty_mtx (db_state)
+ *     dbuf_*
+ *     dmu_buf_update_user: none (db_d)
+ *     dmu_evict_user: none (db_d) (maybe can eliminate)
+ *     dbuf_find: none (db_holds)
+ *     dbuf_hash_insert: none (db_holds)
+ *     dmu_buf_read_array_impl: none (db_state, db_changed)
+ *     dmu_sync: none (db_dirty_node, db_d)
+ *     dnode_reallocate: none (db)
+ *
+ * dn_mtx (leaf)
+ *   protects:
+ *     dn_dirty_dbufs
+ *     dn_ranges
+ *     phys accounting
+ *     dn_allocated_txg
+ *     dn_free_txg
+ *     dn_assigned_txg
+ *     dd_assigned_tx
+ *     dn_notxholds
+ *     dn_dirtyctx
+ *     dn_dirtyctx_firstset
+ *     (dn_phys copy fields?)
+ *     (dn_phys contents?)
+ *   held from:
+ *     dnode_*
+ *     dbuf_dirty: none
+ *     dbuf_sync: none (phys accounting)
+ *     dbuf_undirty: none (dn_ranges, dn_dirty_dbufs)
+ *     dbuf_write_done: none (phys accounting)
+ *     dmu_object_info_from_dnode: none (accounting)
+ *     dmu_tx_commit: none
+ *     dmu_tx_hold_object_impl: none
+ *     dmu_tx_try_assign: dn_notxholds(cv)
+ *     dmu_tx_unassign: none
+ *
+ * dd_lock
+ *    must be held before:
+ *      ds_lock
+ *      ancestors' dd_lock
+ *    protects:
+ *     dd_prop_cbs
+ *     dd_sync_*
+ *     dd_used_bytes
+ *     dd_tempreserved
+ *     dd_space_towrite
+ *     dd_myname
+ *     dd_phys accounting?
+ *    held from:
+ *     dsl_dir_*
+ *     dsl_prop_changed_notify: none (dd_prop_cbs)
+ *     dsl_prop_register: none (dd_prop_cbs)
+ *     dsl_prop_unregister: none (dd_prop_cbs)
+ *     dsl_dataset_block_freeable: none (dd_sync_*)
+ *
+ * os_lock (leaf)
+ *   protects:
+ *     os_dirty_dnodes
+ *     os_free_dnodes
+ *     os_dnodes
+ *     os_downgraded_dbufs
+ *     dn_dirtyblksz
+ *     dn_dirty_link
+ *   held from:
+ *     dnode_create: none (os_dnodes)
+ *     dnode_destroy: none (os_dnodes)
+ *     dnode_setdirty: none (dn_dirtyblksz, os_*_dnodes)
+ *     dnode_free: none (dn_dirtyblksz, os_*_dnodes)
+ *
+ * ds_lock
+ *    protects:
+ *     ds_objset
+ *     ds_open_refcount
+ *     ds_snapname
+ *     ds_phys accounting
+ *     ds_phys userrefs zapobj
+ *     ds_reserved
+ *    held from:
+ *     dsl_dataset_*
+ *
+ * dr_mtx (leaf)
+ *    protects:
+ *     dr_children
+ *    held from:
+ *     dbuf_dirty
+ *     dbuf_undirty
+ *     dbuf_sync_indirect
+ *     dnode_new_blkid
+ */
+
+struct objset;
+struct dmu_pool;
+
+typedef struct dmu_xuio {
+       int next;
+       int cnt;
+       struct arc_buf **bufs;
+       iovec_t *iovp;
+} dmu_xuio_t;
+
+/*
+ * The list of data whose inclusion in a send stream can be pending from
+ * one call to backup_cb to another.  Multiple calls to dump_free() and
+ * dump_freeobjects() can be aggregated into a single DRR_FREE or
+ * DRR_FREEOBJECTS replay record.
+ */
+typedef enum {
+       PENDING_NONE,
+       PENDING_FREE,
+       PENDING_FREEOBJECTS
+} dmu_pendop_t;
+
+typedef struct dmu_sendarg {
+       list_node_t dsa_link;
+       dmu_replay_record_t *dsa_drr;
+       vnode_t *dsa_vp;
+       int dsa_outfd;
+       proc_t *dsa_proc;
+       offset_t *dsa_off;
+       objset_t *dsa_os;
+       zio_cksum_t dsa_zc;
+       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;
+} dmu_sendarg_t;
+
+void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *);
+void dmu_object_free_zapified(objset_t *, uint64_t, dmu_tx_t *);
+int dmu_buf_hold_noread(objset_t *, uint64_t, uint64_t,
+    void *, dmu_buf_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DMU_IMPL_H */
diff --git a/zfs/include/sys/dmu_objset.h b/zfs/include/sys/dmu_objset.h
new file mode 100644 (file)
index 0000000..837a0d5
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#ifndef        _SYS_DMU_OBJSET_H
+#define        _SYS_DMU_OBJSET_H
+
+#include <sys/spa.h>
+#include <sys/arc.h>
+#include <sys/txg.h>
+#include <sys/zfs_context.h>
+#include <sys/dnode.h>
+#include <sys/zio.h>
+#include <sys/zil.h>
+#include <sys/sa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern krwlock_t os_lock;
+
+struct dsl_pool;
+struct dsl_dataset;
+struct dmu_tx;
+
+#define        OBJSET_PHYS_SIZE 2048
+#define        OBJSET_OLD_PHYS_SIZE 1024
+
+#define        OBJSET_BUF_HAS_USERUSED(buf) \
+       (arc_buf_size(buf) > OBJSET_OLD_PHYS_SIZE)
+
+#define        OBJSET_FLAG_USERACCOUNTING_COMPLETE     (1ULL<<0)
+
+typedef struct objset_phys {
+       dnode_phys_t os_meta_dnode;
+       zil_header_t os_zil_header;
+       uint64_t os_type;
+       uint64_t os_flags;
+       char os_pad[OBJSET_PHYS_SIZE - sizeof (dnode_phys_t)*3 -
+           sizeof (zil_header_t) - sizeof (uint64_t)*2];
+       dnode_phys_t os_userused_dnode;
+       dnode_phys_t os_groupused_dnode;
+} objset_phys_t;
+
+struct objset {
+       /* Immutable: */
+       struct dsl_dataset *os_dsl_dataset;
+       spa_t *os_spa;
+       arc_buf_t *os_phys_buf;
+       objset_phys_t *os_phys;
+       /*
+        * The following "special" dnodes have no parent, are exempt
+        * from dnode_move(), and are not recorded in os_dnodes, but they
+        * root their descendents in this objset using handles anyway, so
+        * that all access to dnodes from dbufs consistently uses handles.
+        */
+       dnode_handle_t os_meta_dnode;
+       dnode_handle_t os_userused_dnode;
+       dnode_handle_t os_groupused_dnode;
+       zilog_t *os_zil;
+
+       list_node_t os_evicting_node;
+
+       /* can change, under dsl_dir's locks: */
+       enum zio_checksum os_checksum;
+       enum zio_compress os_compress;
+       uint8_t os_copies;
+       enum zio_checksum os_dedup_checksum;
+       boolean_t os_dedup_verify;
+       zfs_logbias_op_t os_logbias;
+       zfs_cache_type_t os_primary_cache;
+       zfs_cache_type_t os_secondary_cache;
+       zfs_sync_type_t os_sync;
+       zfs_redundant_metadata_type_t os_redundant_metadata;
+       int os_recordsize;
+
+       /* no lock needed: */
+       struct dmu_tx *os_synctx; /* XXX sketchy */
+       blkptr_t *os_rootbp;
+       zil_header_t os_zil_header;
+       list_t os_synced_dnodes;
+       uint64_t os_flags;
+
+       /* Protected by os_obj_lock */
+       kmutex_t os_obj_lock;
+       uint64_t os_obj_next;
+
+       /* Protected by os_lock */
+       kmutex_t os_lock;
+       list_t os_dirty_dnodes[TXG_SIZE];
+       list_t os_free_dnodes[TXG_SIZE];
+       list_t os_dnodes;
+       list_t os_downgraded_dbufs;
+
+       /* stuff we store for the user */
+       kmutex_t os_user_ptr_lock;
+       void *os_user_ptr;
+       sa_os_t *os_sa;
+};
+
+#define        DMU_META_OBJSET         0
+#define        DMU_META_DNODE_OBJECT   0
+#define        DMU_OBJECT_IS_SPECIAL(obj) ((int64_t)(obj) <= 0)
+#define        DMU_META_DNODE(os)      ((os)->os_meta_dnode.dnh_dnode)
+#define        DMU_USERUSED_DNODE(os)  ((os)->os_userused_dnode.dnh_dnode)
+#define        DMU_GROUPUSED_DNODE(os) ((os)->os_groupused_dnode.dnh_dnode)
+
+#define        DMU_OS_IS_L2CACHEABLE(os)                               \
+       ((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,
+    boolean_t readonly, void *tag, objset_t **osp);
+int dmu_objset_own_obj(struct dsl_pool *dp, uint64_t obj,
+    dmu_objset_type_t type, boolean_t readonly, void *tag, objset_t **osp);
+void dmu_objset_refresh_ownership(objset_t *os, void *tag);
+void dmu_objset_rele(objset_t *os, void *tag);
+void dmu_objset_disown(objset_t *os, void *tag);
+int dmu_objset_from_ds(struct dsl_dataset *ds, objset_t **osp);
+
+void dmu_objset_stats(objset_t *os, nvlist_t *nv);
+void dmu_objset_fast_stat(objset_t *os, dmu_objset_stats_t *stat);
+void dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp,
+    uint64_t *usedobjsp, uint64_t *availobjsp);
+uint64_t dmu_objset_fsid_guid(objset_t *os);
+int dmu_objset_find_dp(struct dsl_pool *dp, uint64_t ddobj,
+    int func(struct dsl_pool *, struct dsl_dataset *, void *),
+    void *arg, int flags);
+void dmu_objset_evict_dbufs(objset_t *os);
+timestruc_t dmu_objset_snap_cmtime(objset_t *os);
+
+/* called from dsl */
+void dmu_objset_sync(objset_t *os, zio_t *zio, dmu_tx_t *tx);
+boolean_t dmu_objset_is_dirty(objset_t *os, uint64_t txg);
+objset_t *dmu_objset_create_impl(spa_t *spa, struct dsl_dataset *ds,
+    blkptr_t *bp, dmu_objset_type_t type, dmu_tx_t *tx);
+int dmu_objset_open_impl(spa_t *spa, struct dsl_dataset *ds, blkptr_t *bp,
+    objset_t **osp);
+void dmu_objset_evict(objset_t *os);
+void dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx);
+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);
+int dmu_fsname(const char *snapname, char *buf);
+
+void dmu_objset_evict_done(objset_t *os);
+
+void dmu_objset_init(void);
+void dmu_objset_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DMU_OBJSET_H */
diff --git a/zfs/include/sys/dmu_send.h b/zfs/include/sys/dmu_send.h
new file mode 100644 (file)
index 0000000..2442a1f
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DMU_SEND_H
+#define        _DMU_SEND_H
+
+#include <sys/inttypes.h>
+#include <sys/spa.h>
+
+struct vnode;
+struct dsl_dataset;
+struct drr_begin;
+struct avl_tree;
+
+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);
+int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds,
+    uint64_t *sizep);
+int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg,
+    uint64_t *sizep);
+int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
+    boolean_t embedok, boolean_t large_block_ok,
+    int outfd, struct vnode *vp, offset_t *off);
+
+typedef struct dmu_recv_cookie {
+       struct dsl_dataset *drc_ds;
+       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;
+       struct avl_tree *drc_guid_to_ds_map;
+       zio_cksum_t drc_cksum;
+       uint64_t drc_newsnapobj;
+       void *drc_owner;
+       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_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);
+boolean_t dmu_objset_is_receiving(objset_t *os);
+
+#endif /* _DMU_SEND_H */
diff --git a/zfs/include/sys/dmu_traverse.h b/zfs/include/sys/dmu_traverse.h
new file mode 100644 (file)
index 0000000..544b721
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DMU_TRAVERSE_H
+#define        _SYS_DMU_TRAVERSE_H
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dnode_phys;
+struct dsl_dataset;
+struct zilog;
+struct arc_buf;
+
+typedef int (blkptr_cb_t)(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const struct dnode_phys *dnp, void *arg);
+
+#define        TRAVERSE_PRE                    (1<<0)
+#define        TRAVERSE_POST                   (1<<1)
+#define        TRAVERSE_PREFETCH_METADATA      (1<<2)
+#define        TRAVERSE_PREFETCH_DATA          (1<<3)
+#define        TRAVERSE_PREFETCH (TRAVERSE_PREFETCH_METADATA | TRAVERSE_PREFETCH_DATA)
+#define        TRAVERSE_HARD                   (1<<4)
+
+/* Special traverse error return value to indicate skipping of children */
+#define        TRAVERSE_VISIT_NO_CHILDREN      -1
+
+int traverse_dataset(struct dsl_dataset *ds,
+    uint64_t txg_start, 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);
+int traverse_pool(spa_t *spa,
+    uint64_t txg_start, int flags, blkptr_cb_t func, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DMU_TRAVERSE_H */
diff --git a/zfs/include/sys/dmu_tx.h b/zfs/include/sys/dmu_tx.h
new file mode 100644 (file)
index 0000000..c70c97d
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DMU_TX_H
+#define        _SYS_DMU_TX_H
+
+#include <sys/inttypes.h>
+#include <sys/dmu.h>
+#include <sys/txg.h>
+#include <sys/refcount.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dmu_buf_impl;
+struct dmu_tx_hold;
+struct dnode_link;
+struct dsl_pool;
+struct dnode;
+struct dsl_dir;
+
+struct dmu_tx {
+       /*
+        * No synchronization is needed because a tx can only be handled
+        * by one thread.
+        */
+       list_t tx_holds; /* list of dmu_tx_hold_t */
+       objset_t *tx_objset;
+       struct dsl_dir *tx_dir;
+       struct dsl_pool *tx_pool;
+       uint64_t tx_txg;
+       uint64_t tx_lastsnap_txg;
+       uint64_t tx_lasttried_txg;
+       txg_handle_t tx_txgh;
+       void *tx_tempreserve_cookie;
+       struct dmu_tx_hold *tx_needassign_txh;
+
+       /* list of dmu_tx_callback_t on this dmu_tx */
+       list_t tx_callbacks;
+
+       /* placeholder for syncing context, doesn't need specific holds */
+       boolean_t tx_anyobj;
+
+       /* has this transaction already been delayed? */
+       boolean_t tx_waited;
+
+       /* time this transaction was created */
+       hrtime_t tx_start;
+
+       /* need to wait for sufficient dirty space */
+       boolean_t tx_wait_dirty;
+
+       int tx_err;
+#ifdef DEBUG_DMU_TX
+       uint64_t tx_space_towrite;
+       uint64_t tx_space_tofree;
+       uint64_t tx_space_tooverwrite;
+       uint64_t tx_space_tounref;
+       refcount_t tx_space_written;
+       refcount_t tx_space_freed;
+#endif
+};
+
+enum dmu_tx_hold_type {
+       THT_NEWOBJECT,
+       THT_WRITE,
+       THT_BONUS,
+       THT_FREE,
+       THT_ZAP,
+       THT_SPACE,
+       THT_SPILL,
+       THT_NUMTYPES
+};
+
+typedef struct dmu_tx_hold {
+       dmu_tx_t *txh_tx;
+       list_node_t txh_node;
+       struct dnode *txh_dnode;
+       uint64_t txh_space_towrite;
+       uint64_t txh_space_tofree;
+       uint64_t txh_space_tooverwrite;
+       uint64_t txh_space_tounref;
+       uint64_t txh_memory_tohold;
+       uint64_t txh_fudge;
+#ifdef DEBUG_DMU_TX
+       enum dmu_tx_hold_type txh_type;
+       uint64_t txh_arg1;
+       uint64_t txh_arg2;
+#endif
+} dmu_tx_hold_t;
+
+typedef struct dmu_tx_callback {
+       list_node_t             dcb_node;    /* linked to tx_callbacks list */
+       dmu_tx_callback_func_t  *dcb_func;   /* caller function pointer */
+       void                    *dcb_data;   /* caller private data */
+} dmu_tx_callback_t;
+
+/*
+ * Used for dmu tx kstat.
+ */
+typedef struct dmu_tx_stats {
+       kstat_named_t dmu_tx_assigned;
+       kstat_named_t dmu_tx_delay;
+       kstat_named_t dmu_tx_error;
+       kstat_named_t dmu_tx_suspended;
+       kstat_named_t dmu_tx_group;
+       kstat_named_t dmu_tx_memory_reserve;
+       kstat_named_t dmu_tx_memory_reclaim;
+       kstat_named_t dmu_tx_dirty_throttle;
+       kstat_named_t dmu_tx_dirty_delay;
+       kstat_named_t dmu_tx_dirty_over_max;
+       kstat_named_t dmu_tx_quota;
+} dmu_tx_stats_t;
+
+extern dmu_tx_stats_t dmu_tx_stats;
+
+#define        DMU_TX_STAT_INCR(stat, val) \
+    atomic_add_64(&dmu_tx_stats.stat.value.ui64, (val));
+#define        DMU_TX_STAT_BUMP(stat) \
+    DMU_TX_STAT_INCR(stat, 1);
+
+/*
+ * These routines are defined in dmu.h, and are called by the user.
+ */
+dmu_tx_t *dmu_tx_create(objset_t *dd);
+int dmu_tx_assign(dmu_tx_t *tx, txg_how_t txg_how);
+void dmu_tx_commit(dmu_tx_t *tx);
+void dmu_tx_abort(dmu_tx_t *tx);
+uint64_t dmu_tx_get_txg(dmu_tx_t *tx);
+struct dsl_pool *dmu_tx_pool(dmu_tx_t *tx);
+void dmu_tx_wait(dmu_tx_t *tx);
+
+void dmu_tx_callback_register(dmu_tx_t *tx, dmu_tx_callback_func_t *dcb_func,
+    void *dcb_data);
+void dmu_tx_do_callbacks(list_t *cb_list, int error);
+
+/*
+ * These routines are defined in dmu_spa.h, and are called by the SPA.
+ */
+extern dmu_tx_t *dmu_tx_create_assigned(struct dsl_pool *dp, uint64_t txg);
+
+/*
+ * These routines are only called by the DMU.
+ */
+dmu_tx_t *dmu_tx_create_dd(dsl_dir_t *dd);
+int dmu_tx_is_syncing(dmu_tx_t *tx);
+int dmu_tx_private_ok(dmu_tx_t *tx);
+void dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, uint64_t object);
+void dmu_tx_willuse_space(dmu_tx_t *tx, int64_t delta);
+void dmu_tx_dirty_buf(dmu_tx_t *tx, struct dmu_buf_impl *db);
+int dmu_tx_holds(dmu_tx_t *tx, uint64_t object);
+void dmu_tx_hold_space(dmu_tx_t *tx, uint64_t space);
+
+#ifdef DEBUG_DMU_TX
+#define        DMU_TX_DIRTY_BUF(tx, db)        dmu_tx_dirty_buf(tx, db)
+#else
+#define        DMU_TX_DIRTY_BUF(tx, db)
+#endif
+
+void dmu_tx_init(void);
+void dmu_tx_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DMU_TX_H */
diff --git a/zfs/include/sys/dmu_zfetch.h b/zfs/include/sys/dmu_zfetch.h
new file mode 100644 (file)
index 0000000..38ed1d8
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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        _DFETCH_H
+#define        _DFETCH_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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 */
+} zstream_t;
+
+typedef struct zfetch {
+       krwlock_t       zf_rwlock;      /* protects zfetch structure */
+       list_t          zf_stream;      /* AVL tree 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);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DFETCH_H */
diff --git a/zfs/include/sys/dnode.h b/zfs/include/sys/dnode.h
new file mode 100644 (file)
index 0000000..50e0115
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_DNODE_H
+#define        _SYS_DNODE_H
+
+#include <sys/zfs_context.h>
+#include <sys/avl.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/zio.h>
+#include <sys/refcount.h>
+#include <sys/dmu_zfetch.h>
+#include <sys/zrlock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * dnode_hold() flags.
+ */
+#define        DNODE_MUST_BE_ALLOCATED 1
+#define        DNODE_MUST_BE_FREE      2
+
+/*
+ * dnode_next_offset() flags.
+ */
+#define        DNODE_FIND_HOLE         1
+#define        DNODE_FIND_BACKWARDS    2
+#define        DNODE_FIND_HAVELOCK     4
+
+/*
+ * Fixed constants.
+ */
+#define        DNODE_SHIFT             9       /* 512 bytes */
+#define        DN_MIN_INDBLKSHIFT      10      /* 1k */
+#define        DN_MAX_INDBLKSHIFT      14      /* 16k */
+#define        DNODE_BLOCK_SHIFT       14      /* 16k */
+#define        DNODE_CORE_SIZE         64      /* 64 bytes for dnode sans blkptrs */
+#define        DN_MAX_OBJECT_SHIFT     48      /* 256 trillion (zfs_fid_t limit) */
+#define        DN_MAX_OFFSET_SHIFT     64      /* 2^64 bytes in a dnode */
+
+/*
+ * dnode id flags
+ *
+ * Note: a file will never ever have its
+ * ids moved from bonus->spill
+ * and only in a crypto environment would it be on spill
+ */
+#define        DN_ID_CHKED_BONUS       0x1
+#define        DN_ID_CHKED_SPILL       0x2
+#define        DN_ID_OLD_EXIST         0x4
+#define        DN_ID_NEW_EXIST         0x8
+
+/*
+ * 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        DN_MAX_OBJECT   (1ULL << DN_MAX_OBJECT_SHIFT)
+#define        DN_ZERO_BONUSLEN        (DN_MAX_BONUSLEN + 1)
+#define        DN_KILL_SPILLBLK (1)
+
+#define        DNODES_PER_BLOCK_SHIFT  (DNODE_BLOCK_SHIFT - DNODE_SHIFT)
+#define        DNODES_PER_BLOCK        (1ULL << DNODES_PER_BLOCK_SHIFT)
+#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_BONUS(dnp)   ((void*)((dnp)->dn_bonus + \
+       (((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))
+
+#define        DN_USED_BYTES(dnp) (((dnp)->dn_flags & DNODE_FLAG_USED_BYTES) ? \
+       (dnp)->dn_used : (dnp)->dn_used << SPA_MINBLOCKSHIFT)
+
+#define        EPB(blkshift, typeshift)        (1 << (blkshift - typeshift))
+
+struct dmu_buf_impl;
+struct objset;
+struct zio;
+
+enum dnode_dirtycontext {
+       DN_UNDIRTIED,
+       DN_DIRTY_OPEN,
+       DN_DIRTY_SYNC
+};
+
+/* 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)
+
+/* Does dnode have a SA spill blkptr in bonus? */
+#define        DNODE_FLAG_SPILL_BLKPTR (1<<2)
+
+typedef struct dnode_phys {
+       uint8_t dn_type;                /* dmu_object_type_t */
+       uint8_t dn_indblkshift;         /* ln2(indirect block size) */
+       uint8_t dn_nlevels;             /* 1=dn_blkptr->data blocks */
+       uint8_t dn_nblkptr;             /* length of dn_blkptr */
+       uint8_t dn_bonustype;           /* type of data in bonus buffer */
+       uint8_t dn_checksum;            /* ZIO_CHECKSUM type */
+       uint8_t dn_compress;            /* ZIO_COMPRESS type */
+       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];
+
+       /* accounting is protected by dn_dirty_mtx */
+       uint64_t dn_maxblkid;           /* largest allocated block ID */
+       uint64_t dn_used;               /* bytes (or sectors) of disk space */
+
+       uint64_t dn_pad3[4];
+
+       /*
+        * The tail region is 448 bytes, and there are three ways to
+        * look at it.
+        *
+        * 0       64      128     192     256     320     384     448 (offset)
+        * +---------------+---------------+---------------+-------+
+        * | dn_blkptr[0]  | dn_blkptr[1]  | dn_blkptr[2]  | /     |
+        * +---------------+---------------+---------------+-------+
+        * | dn_blkptr[0]  | dn_bonus[0..319]                      |
+        * +---------------+-----------------------+---------------+
+        * | dn_blkptr[0]  | /                     | dn_spill      |
+        * +---------------+-----------------------+---------------+
+        */
+       union {
+               blkptr_t dn_blkptr[1+DN_MAX_BONUSLEN/sizeof (blkptr_t)];
+               struct {
+                       blkptr_t __dn_ignore1;
+                       uint8_t dn_bonus[DN_MAX_BONUSLEN];
+               };
+               struct {
+                       blkptr_t __dn_ignore2;
+                       uint8_t __dn_ignore3[DN_MAX_BONUSLEN-sizeof (blkptr_t)];
+                       blkptr_t dn_spill;
+               };
+       };
+} dnode_phys_t;
+
+typedef struct dnode {
+       /*
+        * Protects the structure of the dnode, including the number of levels
+        * of indirection (dn_nlevels), dn_maxblkid, and dn_next_*
+        */
+       krwlock_t dn_struct_rwlock;
+
+       /* Our link on dn_objset->os_dnodes list; protected by os_lock.  */
+       list_node_t dn_link;
+
+       /* immutable: */
+       struct objset *dn_objset;
+       uint64_t dn_object;
+       struct dmu_buf_impl *dn_dbuf;
+       struct dnode_handle *dn_handle;
+       dnode_phys_t *dn_phys; /* pointer into dn->dn_dbuf->db.db_data */
+
+       /*
+        * Copies of stuff in dn_phys.  They're valid in the open
+        * context (eg. even before the dnode is first synced).
+        * Where necessary, these are protected by dn_struct_rwlock.
+        */
+       dmu_object_type_t dn_type;      /* object type */
+       uint16_t dn_bonuslen;           /* bonus length */
+       uint8_t dn_bonustype;           /* bonus type */
+       uint8_t dn_nblkptr;             /* number of blkptrs (immutable) */
+       uint8_t dn_checksum;            /* ZIO_CHECKSUM type */
+       uint8_t dn_compress;            /* ZIO_COMPRESS type */
+       uint8_t dn_nlevels;
+       uint8_t dn_indblkshift;
+       uint8_t dn_datablkshift;        /* zero if blksz not power of 2! */
+       uint8_t dn_moved;               /* Has this dnode been moved? */
+       uint16_t dn_datablkszsec;       /* in 512b sectors */
+       uint32_t dn_datablksz;          /* in bytes */
+       uint64_t dn_maxblkid;
+       uint8_t dn_next_type[TXG_SIZE];
+       uint8_t dn_next_nblkptr[TXG_SIZE];
+       uint8_t dn_next_nlevels[TXG_SIZE];
+       uint8_t dn_next_indblkshift[TXG_SIZE];
+       uint8_t dn_next_bonustype[TXG_SIZE];
+       uint8_t dn_rm_spillblk[TXG_SIZE];       /* for removing spill blk */
+       uint16_t dn_next_bonuslen[TXG_SIZE];
+       uint32_t dn_next_blksz[TXG_SIZE];       /* next block size in bytes */
+
+       /* protected by dn_dbufs_mtx; declared here to fill 32-bit hole */
+       uint32_t dn_dbufs_count;        /* count of dn_dbufs */
+       /* There are no level-0 blocks of this blkid or higher in dn_dbufs */
+       uint64_t dn_unlisted_l0_blkid;
+
+       /* protected by os_lock: */
+       list_node_t dn_dirty_link[TXG_SIZE];    /* next on dataset's dirty */
+
+       /* protected by dn_mtx: */
+       kmutex_t dn_mtx;
+       list_t dn_dirty_records[TXG_SIZE];
+       struct range_tree *dn_free_ranges[TXG_SIZE];
+       uint64_t dn_allocated_txg;
+       uint64_t dn_free_txg;
+       uint64_t dn_assigned_txg;
+       kcondvar_t dn_notxholds;
+       enum dnode_dirtycontext dn_dirtyctx;
+       uint8_t *dn_dirtyctx_firstset;          /* dbg: contents meaningless */
+
+       /* protected by own devices */
+       refcount_t dn_tx_holds;
+       refcount_t dn_holds;
+
+       kmutex_t dn_dbufs_mtx;
+       /*
+        * Descendent dbufs, ordered by dbuf_compare. Note that dn_dbufs
+        * can contain multiple dbufs of the same (level, blkid) when a
+        * dbuf is marked DB_EVICTING without being removed from
+        * dn_dbufs. To maintain the avl invariant that there cannot be
+        * duplicate entries, we order the dbufs by an arbitrary value -
+        * their address in memory. This means that dn_dbufs cannot be used to
+        * directly look up a dbuf. Instead, callers must use avl_walk, have
+        * a reference to the dbuf, or look up a non-existant node with
+        * db_state = DB_SEARCH (see dbuf_free_range for an example).
+        */
+       avl_tree_t dn_dbufs;
+
+       /* protected by dn_struct_rwlock */
+       struct dmu_buf_impl *dn_bonus;  /* bonus buffer dbuf */
+
+       boolean_t dn_have_spill;        /* have spill or are spilling */
+
+       /* parent IO for current sync write */
+       zio_t *dn_zio;
+
+       /* used in syncing context */
+       uint64_t dn_oldused;    /* old phys used bytes */
+       uint64_t dn_oldflags;   /* old phys dn_flags */
+       uint64_t dn_olduid, dn_oldgid;
+       uint64_t dn_newuid, dn_newgid;
+       int dn_id_flags;
+
+       /* holds prefetch structure */
+       struct zfetch   dn_zfetch;
+} dnode_t;
+
+/*
+ * Adds a level of indirection between the dbuf and the dnode to avoid
+ * iterating descendent dbufs in dnode_move(). Handles are not allocated
+ * individually, but as an array of child dnodes in dnode_hold_impl().
+ */
+typedef struct dnode_handle {
+       /* Protects dnh_dnode from modification by dnode_move(). */
+       zrlock_t dnh_zrlock;
+       dnode_t *dnh_dnode;
+} dnode_handle_t;
+
+typedef struct dnode_children {
+       dmu_buf_user_t dnc_dbu;         /* User evict data */
+       size_t dnc_count;               /* number of children */
+       dnode_handle_t dnc_children[];  /* sized dynamically */
+} dnode_children_t;
+
+typedef struct free_range {
+       avl_node_t fr_node;
+       uint64_t fr_blkid;
+       uint64_t fr_nblks;
+} free_range_t;
+
+void dnode_special_open(struct objset *dd, dnode_phys_t *dnp,
+    uint64_t object, dnode_handle_t *dnh);
+void dnode_special_close(dnode_handle_t *dnh);
+
+void dnode_setbonuslen(dnode_t *dn, int newsize, dmu_tx_t *tx);
+void dnode_setbonus_type(dnode_t *dn, dmu_object_type_t, dmu_tx_t *tx);
+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,
+    void *ref, dnode_t **dnp);
+boolean_t dnode_add_ref(dnode_t *dn, void *ref);
+void dnode_rele(dnode_t *dn, void *ref);
+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);
+void dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
+    dmu_object_type_t bonustype, int bonuslen, 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);
+void dnode_verify(dnode_t *dn);
+int dnode_set_blksz(dnode_t *dn, uint64_t size, int ibs, dmu_tx_t *tx);
+void dnode_free_range(dnode_t *dn, uint64_t off, uint64_t len, dmu_tx_t *tx);
+void dnode_diduse_space(dnode_t *dn, int64_t space);
+void dnode_willuse_space(dnode_t *dn, int64_t space, dmu_tx_t *tx);
+void dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t);
+uint64_t dnode_block_freed(dnode_t *dn, uint64_t blkid);
+void dnode_init(void);
+void dnode_fini(void);
+int dnode_next_offset(dnode_t *dn, int flags, uint64_t *off,
+    int minlvl, uint64_t blkfill, uint64_t txg);
+void dnode_evict_dbufs(dnode_t *dn);
+void dnode_evict_bonus(dnode_t *dn);
+
+#ifdef ZFS_DEBUG
+
+/*
+ * There should be a ## between the string literal and fmt, to make it
+ * clear that we're joining two strings together, but that piece of shit
+ * gcc doesn't support that preprocessor token.
+ */
+#define        dprintf_dnode(dn, fmt, ...) do { \
+       if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
+       char __db_buf[32]; \
+       uint64_t __db_obj = (dn)->dn_object; \
+       if (__db_obj == DMU_META_DNODE_OBJECT) \
+               (void) strcpy(__db_buf, "mdn"); \
+       else \
+               (void) snprintf(__db_buf, sizeof (__db_buf), "%lld", \
+                   (u_longlong_t)__db_obj);\
+       dprintf_ds((dn)->dn_objset->os_dsl_dataset, "obj=%s " fmt, \
+           __db_buf, __VA_ARGS__); \
+       } \
+_NOTE(CONSTCOND) } while (0)
+
+#define        DNODE_VERIFY(dn)                dnode_verify(dn)
+#define        FREE_VERIFY(db, start, end, tx) free_verify(db, start, end, tx)
+
+#else
+
+#define        dprintf_dnode(db, fmt, ...)
+#define        DNODE_VERIFY(dn)
+#define        FREE_VERIFY(db, start, end, tx)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DNODE_H */
diff --git a/zfs/include/sys/dsl_bookmark.h b/zfs/include/sys/dsl_bookmark.h
new file mode 100644 (file)
index 0000000..3591986
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_BOOKMARK_H
+#define        _SYS_DSL_BOOKMARK_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_pool;
+struct dsl_dataset;
+
+/*
+ * On disk zap object.
+ */
+typedef struct zfs_bookmark_phys {
+       uint64_t zbm_guid;              /* guid of bookmarked dataset */
+       uint64_t zbm_creation_txg;      /* birth transaction group */
+       uint64_t zbm_creation_time;     /* bookmark creation time */
+} zfs_bookmark_phys_t;
+
+int dsl_bookmark_create(nvlist_t *, nvlist_t *);
+int dsl_get_bookmarks(const char *, nvlist_t *, nvlist_t *);
+int dsl_get_bookmarks_impl(dsl_dataset_t *, nvlist_t *, nvlist_t *);
+int dsl_bookmark_destroy(nvlist_t *, nvlist_t *);
+int dsl_bookmark_lookup(struct dsl_pool *, const char *,
+    struct dsl_dataset *, zfs_bookmark_phys_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_BOOKMARK_H */
diff --git a/zfs/include/sys/dsl_dataset.h b/zfs/include/sys/dsl_dataset.h
new file mode 100644 (file)
index 0000000..da6f21c
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_DATASET_H
+#define        _SYS_DSL_DATASET_H
+
+#include <sys/dmu.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/zio.h>
+#include <sys/bplist.h>
+#include <sys/dsl_synctask.h>
+#include <sys/zfs_context.h>
+#include <sys/dsl_deadlist.h>
+#include <sys/refcount.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_dataset;
+struct dsl_dir;
+struct dsl_pool;
+
+#define        DS_FLAG_INCONSISTENT    (1ULL<<0)
+#define        DS_IS_INCONSISTENT(ds)  \
+       (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT)
+
+/*
+ * Do not allow this dataset to be promoted.
+ */
+#define        DS_FLAG_NOPROMOTE       (1ULL<<1)
+
+/*
+ * DS_FLAG_UNIQUE_ACCURATE is set if ds_unique_bytes has been correctly
+ * calculated for head datasets (starting with SPA_VERSION_UNIQUE_ACCURATE,
+ * refquota/refreservations).
+ */
+#define        DS_FLAG_UNIQUE_ACCURATE (1ULL<<2)
+
+/*
+ * DS_FLAG_DEFER_DESTROY is set after 'zfs destroy -d' has been called
+ * on a dataset. This allows the dataset to be destroyed using 'zfs release'.
+ */
+#define        DS_FLAG_DEFER_DESTROY   (1ULL<<3)
+#define        DS_IS_DEFER_DESTROY(ds) \
+       (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_DEFER_DESTROY)
+
+/*
+ * DS_FIELD_* are strings that are used in the "extensified" dataset zap object.
+ * They should be of the format <reverse-dns>:<field>.
+ */
+
+/*
+ * This field's value is the object ID of a zap object which contains the
+ * bookmarks of this dataset.  If it is present, then this dataset is counted
+ * in the refcount of the SPA_FEATURES_BOOKMARKS feature.
+ */
+#define        DS_FIELD_BOOKMARK_NAMES "com.delphix:bookmarks"
+
+/*
+ * This field is present (with value=0) if this dataset may contain large
+ * blocks (>128KB).  If it is present, then this dataset
+ * is counted in the refcount of the SPA_FEATURE_LARGE_BLOCKS feature.
+ */
+#define        DS_FIELD_LARGE_BLOCKS "org.open-zfs:large_blocks"
+
+/*
+ * DS_FLAG_CI_DATASET is set if the dataset contains a file system whose
+ * name lookups should be performed case-insensitively.
+ */
+#define        DS_FLAG_CI_DATASET      (1ULL<<16)
+
+#define        DS_CREATE_FLAG_NODIRTY  (1ULL<<24)
+
+typedef struct dsl_dataset_phys {
+       uint64_t ds_dir_obj;            /* DMU_OT_DSL_DIR */
+       uint64_t ds_prev_snap_obj;      /* DMU_OT_DSL_DATASET */
+       uint64_t ds_prev_snap_txg;
+       uint64_t ds_next_snap_obj;      /* DMU_OT_DSL_DATASET */
+       uint64_t ds_snapnames_zapobj;   /* DMU_OT_DSL_DS_SNAP_MAP 0 for snaps */
+       uint64_t ds_num_children;       /* clone/snap children; ==0 for head */
+       uint64_t ds_creation_time;      /* seconds since 1970 */
+       uint64_t ds_creation_txg;
+       uint64_t ds_deadlist_obj;       /* DMU_OT_DEADLIST */
+       /*
+        * ds_referenced_bytes, ds_compressed_bytes, and ds_uncompressed_bytes
+        * include all blocks referenced by this dataset, including those
+        * shared with any other datasets.
+        */
+       uint64_t ds_referenced_bytes;
+       uint64_t ds_compressed_bytes;
+       uint64_t ds_uncompressed_bytes;
+       uint64_t ds_unique_bytes;       /* only relevant to snapshots */
+       /*
+        * The ds_fsid_guid is a 56-bit ID that can change to avoid
+        * collisions.  The ds_guid is a 64-bit ID that will never
+        * change, so there is a small probability that it will collide.
+        */
+       uint64_t ds_fsid_guid;
+       uint64_t ds_guid;
+       uint64_t ds_flags;              /* DS_FLAG_* */
+       blkptr_t ds_bp;
+       uint64_t ds_next_clones_obj;    /* DMU_OT_DSL_CLONES */
+       uint64_t ds_props_obj;          /* DMU_OT_DSL_PROPS for snaps */
+       uint64_t ds_userrefs_obj;       /* DMU_OT_USERREFS */
+       uint64_t ds_pad[5]; /* pad out to 320 bytes for good measure */
+} dsl_dataset_phys_t;
+
+typedef struct dsl_dataset {
+       dmu_buf_user_t ds_dbu;
+
+       /* Immutable: */
+       struct dsl_dir *ds_dir;
+       dmu_buf_t *ds_dbuf;
+       uint64_t ds_object;
+       uint64_t ds_fsid_guid;
+       boolean_t ds_is_snapshot;
+
+       /* 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;
+       bplist_t ds_pending_deadlist;
+
+       /* protected by lock on pool's dp_dirty_datasets list */
+       txg_node_t ds_dirty_link;
+       list_node_t ds_synced_link;
+
+       /*
+        * ds_phys->ds_<accounting> is also protected by ds_lock.
+        * Protected by ds_lock:
+        */
+       kmutex_t ds_lock;
+       objset_t *ds_objset;
+       uint64_t ds_userrefs;
+       void *ds_owner;
+
+       /*
+        * Long holds prevent the ds from being destroyed; they allow the
+        * ds to remain held even after dropping the dp_config_rwlock.
+        * Owning counts as a long hold.  See the comments above
+        * dsl_pool_hold() for details.
+        */
+       refcount_t ds_longholds;
+
+       /* no locking; only for making guesses */
+       uint64_t ds_trysnap_txg;
+
+       /* for objset_open() */
+       kmutex_t ds_opening_lock;
+
+       uint64_t ds_reserved;   /* cached refreservation */
+       uint64_t ds_quota;      /* cached refquota */
+
+       kmutex_t ds_sendstream_lock;
+       list_t ds_sendstreams;
+
+       /* Protected by ds_lock; keep at end of struct for better locality */
+       char ds_snapname[MAXNAMELEN];
+} dsl_dataset_t;
+
+static inline dsl_dataset_phys_t *
+dsl_dataset_phys(dsl_dataset_t *ds)
+{
+       return (ds->ds_dbuf->db_data);
+}
+
+/*
+ * The max length of a temporary tag prefix is the number of hex digits
+ * required to express UINT64_MAX plus one for the hyphen.
+ */
+#define        MAX_TAG_PREFIX_LEN      17
+
+#define        dsl_dataset_is_snapshot(ds) \
+       (dsl_dataset_phys(ds)->ds_num_children != 0)
+
+#define        DS_UNIQUE_IS_ACCURATE(ds)       \
+       ((dsl_dataset_phys(ds)->ds_flags & DS_FLAG_UNIQUE_ACCURATE) != 0)
+
+int dsl_dataset_hold(struct dsl_pool *dp, const char *name, void *tag,
+    dsl_dataset_t **dsp);
+boolean_t dsl_dataset_try_add_ref(struct dsl_pool *dp, dsl_dataset_t *ds,
+    void *tag);
+int dsl_dataset_hold_obj(struct dsl_pool *dp, uint64_t dsobj, void *tag,
+    dsl_dataset_t **);
+void dsl_dataset_rele(dsl_dataset_t *ds, void *tag);
+int dsl_dataset_own(struct dsl_pool *dp, const char *name,
+    void *tag, dsl_dataset_t **dsp);
+int dsl_dataset_own_obj(struct dsl_pool *dp, uint64_t dsobj,
+    void *tag, dsl_dataset_t **dsp);
+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);
+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,
+    uint64_t flags, dmu_tx_t *tx);
+int dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors);
+int dsl_dataset_promote(const char *name, char *conflsnap);
+int dsl_dataset_rename_snapshot(const char *fsname,
+    const char *oldsnapname, const char *newsnapname, boolean_t recursive);
+int dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
+    minor_t cleanup_minor, const char *htag);
+
+blkptr_t *dsl_dataset_get_blkptr(dsl_dataset_t *ds);
+void dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx);
+
+spa_t *dsl_dataset_get_spa(dsl_dataset_t *ds);
+
+boolean_t dsl_dataset_modified_since_snap(dsl_dataset_t *ds,
+    dsl_dataset_t *snap);
+
+void dsl_dataset_sync(dsl_dataset_t *os, zio_t *zio, dmu_tx_t *tx);
+
+void dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp,
+    dmu_tx_t *tx);
+int dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp,
+    dmu_tx_t *tx, boolean_t async);
+boolean_t dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp,
+    uint64_t blk_birth);
+uint64_t dsl_dataset_prev_snap_txg(dsl_dataset_t *ds);
+int dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name,
+    uint64_t *value);
+
+void dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx);
+void dsl_dataset_stats(dsl_dataset_t *os, nvlist_t *nv);
+void dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat);
+void dsl_dataset_space(dsl_dataset_t *ds,
+    uint64_t *refdbytesp, uint64_t *availbytesp,
+    uint64_t *usedobjsp, uint64_t *availobjsp);
+uint64_t dsl_dataset_fsid_guid(dsl_dataset_t *ds);
+int dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
+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);
+
+int dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota,
+    uint64_t asize, uint64_t inflight, uint64_t *used,
+    uint64_t *ref_rsrv);
+int dsl_dataset_set_refquota(const char *dsname, zprop_source_t source,
+    uint64_t quota);
+int dsl_dataset_set_refreservation(const char *dsname, zprop_source_t source,
+    uint64_t reservation);
+
+boolean_t dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
+    uint64_t earlier_txg);
+void dsl_dataset_long_hold(dsl_dataset_t *ds, void *tag);
+void dsl_dataset_long_rele(dsl_dataset_t *ds, void *tag);
+boolean_t dsl_dataset_long_held(dsl_dataset_t *ds);
+
+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);
+void dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
+    dsl_dataset_t *origin_head, dmu_tx_t *tx);
+int dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
+    dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr);
+void dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
+    dmu_tx_t *tx);
+
+void dsl_dataset_remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj,
+    dmu_tx_t *tx);
+void dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds);
+int dsl_dataset_get_snapname(dsl_dataset_t *ds);
+int dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name,
+    uint64_t *value);
+int dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx,
+    boolean_t adj_cnt);
+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);
+int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
+
+#ifdef ZFS_DEBUG
+#define        dprintf_ds(ds, fmt, ...) do { \
+       if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
+       char *__ds_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); \
+       dsl_dataset_name(ds, __ds_name); \
+       dprintf("ds=%s " fmt, __ds_name, __VA_ARGS__); \
+       kmem_free(__ds_name, MAXNAMELEN); \
+       } \
+_NOTE(CONSTCOND) } while (0)
+#else
+#define        dprintf_ds(dd, fmt, ...)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_DATASET_H */
diff --git a/zfs/include/sys/dsl_deadlist.h b/zfs/include/sys/dsl_deadlist.h
new file mode 100644 (file)
index 0000000..d2c16d7
--- /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
+ */
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_DEADLIST_H
+#define        _SYS_DSL_DEADLIST_H
+
+#include <sys/bpobj.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dmu_buf;
+struct dsl_dataset;
+
+typedef struct dsl_deadlist_phys {
+       uint64_t dl_used;
+       uint64_t dl_comp;
+       uint64_t dl_uncomp;
+       uint64_t dl_pad[37]; /* pad out to 320b for future expansion */
+} dsl_deadlist_phys_t;
+
+typedef struct dsl_deadlist {
+       objset_t *dl_os;
+       uint64_t dl_object;
+       avl_tree_t dl_tree;
+       boolean_t dl_havetree;
+       struct dmu_buf *dl_dbuf;
+       dsl_deadlist_phys_t *dl_phys;
+       kmutex_t dl_lock;
+
+       /* if it's the old on-disk format: */
+       bpobj_t dl_bpobj;
+       boolean_t dl_oldfmt;
+} dsl_deadlist_t;
+
+typedef struct dsl_deadlist_entry {
+       avl_node_t dle_node;
+       uint64_t dle_mintxg;
+       bpobj_t dle_bpobj;
+} dsl_deadlist_entry_t;
+
+void dsl_deadlist_open(dsl_deadlist_t *dl, objset_t *os, uint64_t object);
+void dsl_deadlist_close(dsl_deadlist_t *dl);
+uint64_t dsl_deadlist_alloc(objset_t *os, dmu_tx_t *tx);
+void dsl_deadlist_free(objset_t *os, uint64_t dlobj, dmu_tx_t *tx);
+void dsl_deadlist_insert(dsl_deadlist_t *dl, const blkptr_t *bp, dmu_tx_t *tx);
+void dsl_deadlist_add_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx);
+void dsl_deadlist_remove_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx);
+uint64_t dsl_deadlist_clone(dsl_deadlist_t *dl, uint64_t maxtxg,
+    uint64_t mrs_obj, dmu_tx_t *tx);
+void dsl_deadlist_space(dsl_deadlist_t *dl,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
+void dsl_deadlist_space_range(dsl_deadlist_t *dl,
+    uint64_t mintxg, uint64_t maxtxg,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
+void dsl_deadlist_merge(dsl_deadlist_t *dl, uint64_t obj, dmu_tx_t *tx);
+void dsl_deadlist_move_bpobj(dsl_deadlist_t *dl, bpobj_t *bpo, uint64_t mintxg,
+    dmu_tx_t *tx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_DEADLIST_H */
diff --git a/zfs/include/sys/dsl_deleg.h b/zfs/include/sys/dsl_deleg.h
new file mode 100644 (file)
index 0000000..59e8e05
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_DELEG_H
+#define        _SYS_DSL_DELEG_H
+
+#include <sys/dmu.h>
+#include <sys/dsl_pool.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        ZFS_DELEG_PERM_NONE             ""
+#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_HOLD             "hold"
+#define        ZFS_DELEG_PERM_RELEASE          "release"
+#define        ZFS_DELEG_PERM_DIFF             "diff"
+#define        ZFS_DELEG_PERM_BOOKMARK         "bookmark"
+
+/*
+ * Note: the names of properties that are marked delegatable are also
+ * valid delegated permissions
+ */
+
+int dsl_deleg_get(const char *ddname, nvlist_t **nvp);
+int dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset);
+int dsl_deleg_access(const char *ddname, const char *perm, cred_t *cr);
+int dsl_deleg_access_impl(struct dsl_dataset *ds, const char *perm, cred_t *cr);
+void dsl_deleg_set_create_perms(dsl_dir_t *dd, dmu_tx_t *tx, cred_t *cr);
+int dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr);
+int dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr);
+int dsl_deleg_destroy(objset_t *os, uint64_t zapobj, dmu_tx_t *tx);
+boolean_t dsl_delegation_on(objset_t *os);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_DELEG_H */
diff --git a/zfs/include/sys/dsl_destroy.h b/zfs/include/sys/dsl_destroy.h
new file mode 100644 (file)
index 0000000..3f63864
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_DESTROY_H
+#define        _SYS_DSL_DESTROY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nvlist;
+struct dsl_dataset;
+struct dmu_tx;
+
+int dsl_destroy_snapshots_nvl(struct nvlist *, boolean_t,
+    struct nvlist *);
+int dsl_destroy_snapshot(const char *, boolean_t);
+int dsl_destroy_head(const char *);
+int dsl_destroy_head_check_impl(struct dsl_dataset *, int);
+void dsl_destroy_head_sync_impl(struct dsl_dataset *, struct dmu_tx *);
+int dsl_destroy_inconsistent(const char *, void *);
+int dsl_destroy_snapshot_check_impl(struct dsl_dataset *, boolean_t);
+void dsl_destroy_snapshot_sync_impl(struct dsl_dataset *,
+    boolean_t, struct dmu_tx *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_DESTROY_H */
diff --git a/zfs/include/sys/dsl_dir.h b/zfs/include/sys/dsl_dir.h
new file mode 100644 (file)
index 0000000..55f3a8e
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_DIR_H
+#define        _SYS_DSL_DIR_H
+
+#include <sys/dmu.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_synctask.h>
+#include <sys/refcount.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_dataset;
+
+/*
+ * DD_FIELD_* are strings that are used in the "extensified" dsl_dir zap object.
+ * They should be of the format <reverse-dns>:<field>.
+ */
+
+#define        DD_FIELD_FILESYSTEM_COUNT       "com.joyent:filesystem_count"
+#define        DD_FIELD_SNAPSHOT_COUNT         "com.joyent:snapshot_count"
+
+typedef enum dd_used {
+       DD_USED_HEAD,
+       DD_USED_SNAP,
+       DD_USED_CHILD,
+       DD_USED_CHILD_RSRV,
+       DD_USED_REFRSRV,
+       DD_USED_NUM
+} dd_used_t;
+
+#define        DD_FLAG_USED_BREAKDOWN (1<<0)
+
+typedef struct dsl_dir_phys {
+       uint64_t dd_creation_time; /* not actually used */
+       uint64_t dd_head_dataset_obj;
+       uint64_t dd_parent_obj;
+       uint64_t dd_origin_obj;
+       uint64_t dd_child_dir_zapobj;
+       /*
+        * how much space our children are accounting for; for leaf
+        * datasets, == physical space used by fs + snaps
+        */
+       uint64_t dd_used_bytes;
+       uint64_t dd_compressed_bytes;
+       uint64_t dd_uncompressed_bytes;
+       /* Administrative quota setting */
+       uint64_t dd_quota;
+       /* Administrative reservation setting */
+       uint64_t dd_reserved;
+       uint64_t dd_props_zapobj;
+       uint64_t dd_deleg_zapobj; /* dataset delegation permissions */
+       uint64_t dd_flags;
+       uint64_t dd_used_breakdown[DD_USED_NUM];
+       uint64_t dd_clones; /* dsl_dir objects */
+       uint64_t dd_pad[13]; /* pad out to 256 bytes for good measure */
+} dsl_dir_phys_t;
+
+struct dsl_dir {
+       dmu_buf_user_t dd_dbu;
+
+       /* These are immutable; no lock needed: */
+       uint64_t dd_object;
+       dsl_pool_t *dd_pool;
+
+       /* Stable until user eviction; no lock needed: */
+       dmu_buf_t *dd_dbuf;
+
+       /* protected by lock on pool's dp_dirty_dirs list */
+       txg_node_t dd_dirty_link;
+
+       /* protected by dp_config_rwlock */
+       dsl_dir_t *dd_parent;
+
+       /* Protected by dd_lock */
+       kmutex_t dd_lock;
+       list_t dd_prop_cbs; /* list of dsl_prop_cb_record_t's */
+       timestruc_t dd_snap_cmtime; /* last time snapshot namespace changed */
+       uint64_t dd_origin_txg;
+
+       /* gross estimate of space used by in-flight tx's */
+       uint64_t dd_tempreserved[TXG_SIZE];
+       /* amount of space we expect to write; == amount of dirty data */
+       int64_t dd_space_towrite[TXG_SIZE];
+
+       /* protected by dd_lock; keep at end of struct for better locality */
+       char dd_myname[MAXNAMELEN];
+};
+
+static inline dsl_dir_phys_t *
+dsl_dir_phys(dsl_dir_t *dd)
+{
+       return (dd->dd_dbuf->db_data);
+}
+
+void dsl_dir_rele(dsl_dir_t *dd, void *tag);
+void dsl_dir_async_rele(dsl_dir_t *dd, void *tag);
+int dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
+    dsl_dir_t **, const char **tail);
+int dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
+    const char *tail, void *tag, dsl_dir_t **);
+void dsl_dir_name(dsl_dir_t *dd, char *buf);
+int dsl_dir_namelen(dsl_dir_t *dd);
+uint64_t dsl_dir_create_sync(dsl_pool_t *dp, dsl_dir_t *pds,
+    const char *name, dmu_tx_t *tx);
+void dsl_dir_stats(dsl_dir_t *dd, nvlist_t *nv);
+uint64_t dsl_dir_space_available(dsl_dir_t *dd,
+    dsl_dir_t *ancestor, int64_t delta, int ondiskonly);
+void dsl_dir_dirty(dsl_dir_t *dd, dmu_tx_t *tx);
+void dsl_dir_sync(dsl_dir_t *dd, dmu_tx_t *tx);
+int dsl_dir_tempreserve_space(dsl_dir_t *dd, uint64_t mem,
+    uint64_t asize, uint64_t fsize, uint64_t usize, void **tr_cookiep,
+    dmu_tx_t *tx);
+void dsl_dir_tempreserve_clear(void *tr_cookie, dmu_tx_t *tx);
+void dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx);
+void dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
+    int64_t used, int64_t compressed, int64_t uncompressed, dmu_tx_t *tx);
+void dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta,
+    dd_used_t oldtype, dd_used_t newtype, dmu_tx_t *tx);
+int dsl_dir_set_quota(const char *ddname, zprop_source_t source,
+    uint64_t quota);
+int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
+    uint64_t reservation);
+int dsl_dir_activate_fs_ss_limit(const char *);
+int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *,
+    cred_t *);
+void dsl_fs_ss_count_adjust(dsl_dir_t *, int64_t, const char *, dmu_tx_t *);
+int dsl_dir_rename(const char *oldname, const char *newname);
+int dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
+    uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *);
+boolean_t dsl_dir_is_clone(dsl_dir_t *dd);
+void dsl_dir_new_refreservation(dsl_dir_t *dd, struct dsl_dataset *ds,
+    uint64_t reservation, cred_t *cr, dmu_tx_t *tx);
+void dsl_dir_snap_cmtime_update(dsl_dir_t *dd);
+timestruc_t dsl_dir_snap_cmtime(dsl_dir_t *dd);
+void dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value,
+    dmu_tx_t *tx);
+void dsl_dir_zapify(dsl_dir_t *dd, dmu_tx_t *tx);
+boolean_t dsl_dir_is_zapified(dsl_dir_t *dd);
+
+/* internal reserved dir name */
+#define        MOS_DIR_NAME "$MOS"
+#define        ORIGIN_DIR_NAME "$ORIGIN"
+#define        XLATION_DIR_NAME "$XLATION"
+#define        FREE_DIR_NAME "$FREE"
+#define        LEAK_DIR_NAME "$LEAK"
+
+#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); \
+       dsl_dir_name(dd, __ds_name); \
+       dprintf("dd=%s " fmt, __ds_name, __VA_ARGS__); \
+       kmem_free(__ds_name, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1); \
+       } \
+_NOTE(CONSTCOND) } while (0)
+#else
+#define        dprintf_dd(dd, fmt, ...)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_DIR_H */
diff --git a/zfs/include/sys/dsl_pool.h b/zfs/include/sys/dsl_pool.h
new file mode 100644 (file)
index 0000000..48b12e8
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_POOL_H
+#define        _SYS_DSL_POOL_H
+
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/txg_impl.h>
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+#include <sys/dnode.h>
+#include <sys/ddt.h>
+#include <sys/arc.h>
+#include <sys/bpobj.h>
+#include <sys/bptree.h>
+#include <sys/rrwlock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int zfs_txg_synctime_ms;
+
+struct objset;
+struct dsl_dir;
+struct dsl_dataset;
+struct dsl_pool;
+struct dmu_tx;
+struct dsl_scan;
+
+extern unsigned long zfs_dirty_data_max;
+extern unsigned long zfs_dirty_data_max_max;
+extern unsigned long zfs_dirty_data_sync;
+extern int zfs_dirty_data_max_percent;
+extern int zfs_dirty_data_max_max_percent;
+extern int zfs_delay_min_dirty_percent;
+extern unsigned long zfs_delay_scale;
+
+/* These macros are for indexing into the zfs_all_blkstats_t. */
+#define        DMU_OT_DEFERRED DMU_OT_NONE
+#define        DMU_OT_OTHER    DMU_OT_NUMTYPES /* place holder for DMU_OT() types */
+#define        DMU_OT_TOTAL    (DMU_OT_NUMTYPES + 1)
+
+typedef struct zfs_blkstat {
+       uint64_t        zb_count;
+       uint64_t        zb_asize;
+       uint64_t        zb_lsize;
+       uint64_t        zb_psize;
+       uint64_t        zb_gangs;
+       uint64_t        zb_ditto_2_of_2_samevdev;
+       uint64_t        zb_ditto_2_of_3_samevdev;
+       uint64_t        zb_ditto_3_of_3_samevdev;
+} zfs_blkstat_t;
+
+typedef struct zfs_all_blkstats {
+       zfs_blkstat_t   zab_type[DN_MAX_LEVELS + 1][DMU_OT_TOTAL + 1];
+} zfs_all_blkstats_t;
+
+
+typedef struct dsl_pool {
+       /* Immutable */
+       spa_t *dp_spa;
+       struct objset *dp_meta_objset;
+       struct dsl_dir *dp_root_dir;
+       struct dsl_dir *dp_mos_dir;
+       struct dsl_dir *dp_free_dir;
+       struct dsl_dir *dp_leak_dir;
+       struct dsl_dataset *dp_origin_snap;
+       uint64_t dp_root_dir_obj;
+       struct taskq *dp_iput_taskq;
+
+       /* No lock needed - sync context only */
+       blkptr_t dp_meta_rootbp;
+       uint64_t dp_tmp_userrefs_obj;
+       bpobj_t dp_free_bpobj;
+       uint64_t dp_bptree_obj;
+       uint64_t dp_empty_bpobj;
+
+       struct dsl_scan *dp_scan;
+
+       /* Uses dp_lock */
+       kmutex_t dp_lock;
+       kcondvar_t dp_spaceavail_cv;
+       uint64_t dp_dirty_pertxg[TXG_SIZE];
+       uint64_t dp_dirty_total;
+       uint64_t dp_mos_used_delta;
+       uint64_t dp_mos_compressed_delta;
+       uint64_t dp_mos_uncompressed_delta;
+
+       /*
+        * Time of most recently scheduled (furthest in the future)
+        * wakeup for delayed transactions.
+        */
+       hrtime_t dp_last_wakeup;
+
+       /* Has its own locking */
+       tx_state_t dp_tx;
+       txg_list_t dp_dirty_datasets;
+       txg_list_t dp_dirty_zilogs;
+       txg_list_t dp_dirty_dirs;
+       txg_list_t dp_sync_tasks;
+
+       /*
+        * Protects administrative changes (properties, namespace)
+        *
+        * It is only held for write in syncing context.  Therefore
+        * syncing context does not need to ever have it for read, since
+        * nobody else could possibly have it for write.
+        */
+       rrwlock_t dp_config_rwlock;
+
+       zfs_all_blkstats_t *dp_blkstats;
+} dsl_pool_t;
+
+int dsl_pool_init(spa_t *spa, uint64_t txg, dsl_pool_t **dpp);
+int dsl_pool_open(dsl_pool_t *dp);
+void dsl_pool_close(dsl_pool_t *dp);
+dsl_pool_t *dsl_pool_create(spa_t *spa, nvlist_t *zplprops, uint64_t txg);
+void dsl_pool_sync(dsl_pool_t *dp, uint64_t txg);
+void dsl_pool_sync_done(dsl_pool_t *dp, uint64_t txg);
+int dsl_pool_sync_context(dsl_pool_t *dp);
+uint64_t dsl_pool_adjustedsize(dsl_pool_t *dp, boolean_t netfree);
+uint64_t dsl_pool_adjustedfree(dsl_pool_t *dp, boolean_t netfree);
+void dsl_pool_dirty_space(dsl_pool_t *dp, int64_t space, dmu_tx_t *tx);
+void dsl_pool_undirty_space(dsl_pool_t *dp, int64_t space, uint64_t txg);
+void dsl_free(dsl_pool_t *dp, uint64_t txg, const blkptr_t *bpp);
+void dsl_free_sync(zio_t *pio, dsl_pool_t *dp, uint64_t txg,
+    const blkptr_t *bpp);
+void dsl_pool_create_origin(dsl_pool_t *dp, dmu_tx_t *tx);
+void dsl_pool_upgrade_clones(dsl_pool_t *dp, dmu_tx_t *tx);
+void dsl_pool_upgrade_dir_clones(dsl_pool_t *dp, dmu_tx_t *tx);
+void dsl_pool_mos_diduse_space(dsl_pool_t *dp,
+    int64_t used, int64_t comp, int64_t uncomp);
+boolean_t dsl_pool_need_dirty_delay(dsl_pool_t *dp);
+void dsl_pool_config_enter(dsl_pool_t *dp, void *tag);
+void dsl_pool_config_enter_prio(dsl_pool_t *dp, void *tag);
+void dsl_pool_config_exit(dsl_pool_t *dp, void *tag);
+boolean_t dsl_pool_config_held(dsl_pool_t *dp);
+boolean_t dsl_pool_config_held_writer(dsl_pool_t *dp);
+
+taskq_t *dsl_pool_iput_taskq(dsl_pool_t *dp);
+
+int dsl_pool_user_hold(dsl_pool_t *dp, uint64_t dsobj,
+    const char *tag, uint64_t now, dmu_tx_t *tx);
+int dsl_pool_user_release(dsl_pool_t *dp, uint64_t dsobj,
+    const char *tag, dmu_tx_t *tx);
+void dsl_pool_clean_tmp_userrefs(dsl_pool_t *dp);
+int dsl_pool_open_special_dir(dsl_pool_t *dp, const char *name, dsl_dir_t **);
+int dsl_pool_hold(const char *name, void *tag, dsl_pool_t **dp);
+void dsl_pool_rele(dsl_pool_t *dp, void *tag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_POOL_H */
diff --git a/zfs/include/sys/dsl_prop.h b/zfs/include/sys/dsl_prop.h
new file mode 100644 (file)
index 0000000..5fe18d6
--- /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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_PROP_H
+#define        _SYS_DSL_PROP_H
+
+#include <sys/dmu.h>
+#include <sys/dsl_pool.h>
+#include <sys/zfs_context.h>
+#include <sys/dsl_synctask.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_dataset;
+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_cb_record {
+       list_node_t cbr_node; /* link on dd_prop_cbs */
+       struct dsl_dataset *cbr_ds;
+       const char *cbr_propname;
+       dsl_prop_changed_cb_t *cbr_func;
+       void *cbr_arg;
+} dsl_prop_cb_record_t;
+
+typedef struct dsl_props_arg {
+       nvlist_t *pa_props;
+       zprop_source_t pa_source;
+} dsl_props_arg_t;
+
+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_notify_all(struct dsl_dir *dd);
+boolean_t dsl_prop_hascb(struct dsl_dataset *ds);
+
+int dsl_prop_get(const char *ddname, const char *propname,
+    int intsz, int numints, void *buf, char *setpoint);
+int dsl_prop_get_integer(const char *ddname, const char *propname,
+    uint64_t *valuep, char *setpoint);
+int dsl_prop_get_all(objset_t *os, nvlist_t **nvp);
+int dsl_prop_get_received(const char *dsname, nvlist_t **nvp);
+int dsl_prop_get_ds(struct dsl_dataset *ds, const char *propname,
+    int intsz, int numints, void *buf, char *setpoint);
+int dsl_prop_get_int_ds(struct dsl_dataset *ds, const char *propname,
+    uint64_t *valuep);
+int dsl_prop_get_dd(struct dsl_dir *dd, const char *propname,
+    int intsz, int numints, void *buf, char *setpoint,
+    boolean_t snapshot);
+
+void dsl_props_set_sync_impl(struct dsl_dataset *ds, zprop_source_t source,
+    nvlist_t *props, dmu_tx_t *tx);
+void dsl_prop_set_sync_impl(struct dsl_dataset *ds, const char *propname,
+    zprop_source_t source, int intsz, int numints, const void *value,
+    dmu_tx_t *tx);
+int dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *nvl);
+int dsl_prop_set_int(const char *dsname, const char *propname,
+    zprop_source_t source, uint64_t value);
+int dsl_prop_set_string(const char *dsname, const char *propname,
+    zprop_source_t source, const char *value);
+int dsl_prop_inherit(const char *dsname, const char *propname,
+    zprop_source_t source);
+
+int dsl_prop_predict(dsl_dir_t *dd, const char *propname,
+    zprop_source_t source, uint64_t value, uint64_t *newvalp);
+
+/* flag first receive on or after SPA_VERSION_RECVD_PROPS */
+boolean_t dsl_prop_get_hasrecvd(const char *dsname);
+int dsl_prop_set_hasrecvd(const char *dsname);
+void dsl_prop_unset_hasrecvd(const char *dsname);
+
+void dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value);
+void dsl_prop_nvlist_add_string(nvlist_t *nv,
+    zfs_prop_t prop, const char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_PROP_H */
diff --git a/zfs/include/sys/dsl_scan.h b/zfs/include/sys/dsl_scan.h
new file mode 100644 (file)
index 0000000..44a11ba
--- /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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_SCAN_H
+#define        _SYS_DSL_SCAN_H
+
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+#include <sys/ddt.h>
+#include <sys/bplist.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct objset;
+struct dsl_dir;
+struct dsl_dataset;
+struct dsl_pool;
+struct dmu_tx;
+
+/*
+ * All members of this structure must be uint64_t, for byteswap
+ * purposes.
+ */
+typedef struct dsl_scan_phys {
+       uint64_t scn_func; /* pool_scan_func_t */
+       uint64_t scn_state; /* dsl_scan_state_t */
+       uint64_t scn_queue_obj;
+       uint64_t scn_min_txg;
+       uint64_t scn_max_txg;
+       uint64_t scn_cur_min_txg;
+       uint64_t scn_cur_max_txg;
+       uint64_t scn_start_time;
+       uint64_t scn_end_time;
+       uint64_t scn_to_examine; /* total bytes to be scanned */
+       uint64_t scn_examined; /* bytes scanned so far */
+       uint64_t scn_to_process;
+       uint64_t scn_processed;
+       uint64_t scn_errors;    /* scan I/O error count */
+       uint64_t scn_ddt_class_max;
+       ddt_bookmark_t scn_ddt_bookmark;
+       zbookmark_phys_t scn_bookmark;
+       uint64_t scn_flags; /* dsl_scan_flags_t */
+} dsl_scan_phys_t;
+
+#define        SCAN_PHYS_NUMINTS (sizeof (dsl_scan_phys_t) / sizeof (uint64_t))
+
+typedef enum dsl_scan_flags {
+       DSF_VISIT_DS_AGAIN = 1<<0,
+} dsl_scan_flags_t;
+
+#define        DSL_SCAN_FLAGS_MASK (DSF_VISIT_DS_AGAIN)
+
+/*
+ * Every pool will have one dsl_scan_t and this structure will contain
+ * in-memory information about the scan and a pointer to the on-disk
+ * representation (i.e. dsl_scan_phys_t). Most of the state of the scan
+ * is contained on-disk to allow the scan to resume in the event of a reboot
+ * or panic. This structure maintains information about the behavior of a
+ * running scan, some caching information, and how it should traverse the pool.
+ *
+ * The following members of this structure direct the behavior of the scan:
+ *
+ * scn_pausing -       a scan that cannot be completed in a single txg or
+ *                     has exceeded its allotted time will need to pause.
+ *                     When this flag is set the scanner will stop traversing
+ *                     the pool and write out the current state to disk.
+ *
+ * scn_restart_txg -   directs the scanner to either restart or start a
+ *                     a scan at the specified txg value.
+ *
+ * scn_done_txg -      when a scan completes its traversal it will set
+ *                     the completion txg to the next txg. This is necessary
+ *                     to ensure that any blocks that were freed during
+ *                     the scan but have not yet been processed (i.e deferred
+ *                     frees) are accounted for.
+ *
+ * This structure also maintains information about deferred frees which are
+ * a special kind of traversal. Deferred free can exist in either a bptree or
+ * a bpobj structure. The scn_is_bptree flag will indicate the type of
+ * deferred free that is in progress. If the deferred free is part of an
+ * asynchronous destroy then the scn_async_destroying flag will be set.
+ */
+typedef struct dsl_scan {
+       struct dsl_pool *scn_dp;
+
+       boolean_t scn_pausing;
+       uint64_t scn_restart_txg;
+       uint64_t scn_done_txg;
+       uint64_t scn_sync_start_time;
+       zio_t *scn_zio_root;
+
+       /* for freeing blocks */
+       boolean_t scn_is_bptree;
+       boolean_t scn_async_destroying;
+       boolean_t scn_async_stalled;
+
+       /* for debugging / information */
+       uint64_t scn_visited_this_txg;
+
+       dsl_scan_phys_t scn_phys;
+} dsl_scan_t;
+
+int dsl_scan_init(struct dsl_pool *dp, uint64_t txg);
+void dsl_scan_fini(struct dsl_pool *dp);
+void dsl_scan_sync(struct dsl_pool *, dmu_tx_t *);
+int dsl_scan_cancel(struct dsl_pool *);
+int dsl_scan(struct dsl_pool *, pool_scan_func_t);
+void dsl_resilver_restart(struct dsl_pool *, uint64_t txg);
+boolean_t dsl_scan_resilvering(struct dsl_pool *dp);
+boolean_t dsl_dataset_unstable(struct dsl_dataset *ds);
+void dsl_scan_ddt_entry(dsl_scan_t *scn, enum zio_checksum checksum,
+    ddt_entry_t *dde, dmu_tx_t *tx);
+void dsl_scan_ds_destroyed(struct dsl_dataset *ds, struct dmu_tx *tx);
+void dsl_scan_ds_snapshotted(struct dsl_dataset *ds, struct dmu_tx *tx);
+void dsl_scan_ds_clone_swapped(struct dsl_dataset *ds1, struct dsl_dataset *ds2,
+    struct dmu_tx *tx);
+boolean_t dsl_scan_active(dsl_scan_t *scn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_SCAN_H */
diff --git a/zfs/include/sys/dsl_synctask.h b/zfs/include/sys/dsl_synctask.h
new file mode 100644 (file)
index 0000000..6139303
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_SYNCTASK_H
+#define        _SYS_DSL_SYNCTASK_H
+
+#include <sys/txg.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_pool;
+
+typedef int (dsl_checkfunc_t)(void *, dmu_tx_t *);
+typedef void (dsl_syncfunc_t)(void *, dmu_tx_t *);
+
+typedef enum zfs_space_check {
+       /*
+        * Normal space check: if there is less than 3.2% free space,
+        * the operation will fail.  Operations which are logically
+        * creating things should use this (e.g. "zfs create", "zfs snapshot").
+        * User writes (via the ZPL / ZVOL) also fail at this point.
+        */
+       ZFS_SPACE_CHECK_NORMAL,
+
+       /*
+        * Space check allows use of half the slop space.  If there
+        * is less than 1.6% free space, the operation will fail.  Most
+        * operations should use this (e.g. "zfs set", "zfs rename"),
+        * because we want them to succeed even after user writes are failing,
+        * so that they can be used as part of the space recovery process.
+        */
+       ZFS_SPACE_CHECK_RESERVED,
+
+       /*
+        * No space check is performed.  Only operations which we expect to
+        * result in a net reduction in space should use this
+        * (e.g. "zfs destroy". Setting quotas & reservations also uses
+        * this because it needs to circumvent the quota/reservation checks).
+        *
+        * See also the comments above spa_slop_shift.
+        */
+       ZFS_SPACE_CHECK_NONE,
+} zfs_space_check_t;
+
+typedef struct dsl_sync_task {
+       txg_node_t dst_node;
+       struct dsl_pool *dst_pool;
+       uint64_t dst_txg;
+       int dst_space;
+       zfs_space_check_t dst_space_check;
+       dsl_checkfunc_t *dst_checkfunc;
+       dsl_syncfunc_t *dst_syncfunc;
+       void *dst_arg;
+       int dst_error;
+       boolean_t dst_nowaiter;
+} dsl_sync_task_t;
+
+void dsl_sync_task_sync(dsl_sync_task_t *, dmu_tx_t *);
+int dsl_sync_task(const char *, dsl_checkfunc_t *,
+    dsl_syncfunc_t *, void *, int, zfs_space_check_t);
+void dsl_sync_task_nowait(struct dsl_pool *, dsl_syncfunc_t *,
+    void *, int, zfs_space_check_t, dmu_tx_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_SYNCTASK_H */
diff --git a/zfs/include/sys/dsl_userhold.h b/zfs/include/sys/dsl_userhold.h
new file mode 100644 (file)
index 0000000..071aeb8
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+#ifndef        _SYS_DSL_USERHOLD_H
+#define        _SYS_DSL_USERHOLD_H
+
+#include <sys/nvpair.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_pool;
+struct dsl_dataset;
+struct dmu_tx;
+
+int dsl_dataset_user_hold(nvlist_t *holds, minor_t cleanup_minor,
+    nvlist_t *errlist);
+int dsl_dataset_user_release(nvlist_t *holds, nvlist_t *errlist);
+int dsl_dataset_get_holds(const char *dsname, nvlist_t *nvl);
+void dsl_dataset_user_release_tmp(struct dsl_pool *dp, nvlist_t *holds);
+int dsl_dataset_user_hold_check_one(struct dsl_dataset *ds, const char *htag,
+    boolean_t temphold, struct dmu_tx *tx);
+void dsl_dataset_user_hold_sync_one(struct dsl_dataset *ds, const char *htag,
+    minor_t minor, uint64_t now, struct dmu_tx *tx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DSL_USERHOLD_H */
diff --git a/zfs/include/sys/efi_partition.h b/zfs/include/sys/efi_partition.h
new file mode 100644 (file)
index 0000000..ee367a5
--- /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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_EFI_PARTITION_H
+#define        _SYS_EFI_PARTITION_H
+
+#include <sys/uuid.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * GUID Partition Table Header
+ */
+
+#define        EFI_MIN_LABEL_SIZE 92
+#define        EFI_LABEL_SIZE  512
+#define        LEN_EFI_PAD     (EFI_LABEL_SIZE - \
+                           ((5 * sizeof (diskaddr_t)) + \
+                           (7 * sizeof (uint_t)) + \
+                           (8 * sizeof (char)) + \
+                           (1 * (sizeof (struct uuid)))))
+
+#define        EFI_SIGNATURE   0x5452415020494645ULL
+
+/* EFI Guid Partition Table Header -- little endian on-disk format */
+typedef struct efi_gpt {
+       uint64_t        efi_gpt_Signature;
+       uint_t          efi_gpt_Revision;
+       uint_t          efi_gpt_HeaderSize;
+       uint_t          efi_gpt_HeaderCRC32;
+       uint_t          efi_gpt_Reserved1;
+       diskaddr_t      efi_gpt_MyLBA;
+       diskaddr_t      efi_gpt_AlternateLBA;
+       diskaddr_t      efi_gpt_FirstUsableLBA;
+       diskaddr_t      efi_gpt_LastUsableLBA;
+       struct uuid     efi_gpt_DiskGUID;
+       diskaddr_t      efi_gpt_PartitionEntryLBA;
+       uint_t          efi_gpt_NumberOfPartitionEntries;
+       uint_t          efi_gpt_SizeOfPartitionEntry;
+       uint_t          efi_gpt_PartitionEntryArrayCRC32;
+       char            efi_gpt_Reserved2[LEN_EFI_PAD];
+} efi_gpt_t;
+
+/* EFI Guid Partition Entry Attributes -- little endian format */
+typedef struct efi_gpe_Attrs {
+       uint32_t        PartitionAttrs          :16,
+                       Reserved2               :16;
+       uint32_t        Reserved1               :31,
+                       RequiredPartition       :1;
+} efi_gpe_Attrs_t;
+
+/*
+ * 6a96237f-1dd2-11b2-99a6-080020736631        V_UNASSIGNED (not used as such)
+ * 6a82cb45-1dd2-11b2-99a6-080020736631        V_BOOT
+ * 6a85cf4d-1dd2-11b2-99a6-080020736631        V_ROOT
+ * 6a87c46f-1dd2-11b2-99a6-080020736631        V_SWAP
+ * 6a898cc3-1dd2-11b2-99a6-080020736631        V_USR
+ * 6a8b642b-1dd2-11b2-99a6-080020736631        V_BACKUP
+ * 6a8d2ac7-1dd2-11b2-99a6-080020736631        V_STAND (not used)
+ * 6a8ef2e9-1dd2-11b2-99a6-080020736631        V_VAR
+ * 6a90ba39-1dd2-11b2-99a6-080020736631        V_HOME
+ * 6a9283a5-1dd2-11b2-99a6-080020736631        V_ALTSCTR
+ * 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 } }
+
+/* minimum # of bytes for partition table entires, per EFI spec */
+#define        EFI_MIN_ARRAY_SIZE      (16 * 1024)
+
+#define        EFI_PART_NAME_LEN       36
+
+/* size of the "reserved" partition, in blocks */
+#define        EFI_MIN_RESV_SIZE       (16 * 1024)
+
+/* EFI Guid Partition Entry */
+typedef struct efi_gpe {
+       struct uuid     efi_gpe_PartitionTypeGUID;
+       struct uuid     efi_gpe_UniquePartitionGUID;
+       diskaddr_t      efi_gpe_StartingLBA;
+       diskaddr_t      efi_gpe_EndingLBA;
+       efi_gpe_Attrs_t efi_gpe_Attributes;
+       ushort_t        efi_gpe_PartitionName[EFI_PART_NAME_LEN];
+} efi_gpe_t;
+
+/*
+ * passed to the useful (we hope) routines (efi_alloc_and_read and
+ * efi_write) that take this VTOC-like struct.  These routines handle
+ * converting this struct into the EFI struct, generate UUIDs and
+ * checksums, and perform any necessary byte-swapping to the on-disk
+ * format.
+ */
+/* Solaris library abstraction for EFI partitons */
+typedef struct dk_part {
+       diskaddr_t      p_start;        /* starting LBA */
+       diskaddr_t      p_size;         /* size in blocks */
+       struct uuid     p_guid;         /* partion type GUID */
+       ushort_t        p_tag;          /* converted to part'n type GUID */
+       ushort_t        p_flag;         /* attributes */
+       char            p_name[EFI_PART_NAME_LEN]; /* partition name */
+       struct uuid     p_uguid;        /* unique partition GUID */
+       uint_t          p_resv[8];      /* future use - set to zero */
+} dk_part_t;
+
+/* Solaris library abstraction for an EFI GPT */
+#define        EFI_VERSION102          0x00010002
+#define        EFI_VERSION100          0x00010000
+#define        EFI_VERSION_CURRENT     EFI_VERSION100
+typedef struct dk_gpt {
+       uint_t          efi_version;    /* set to EFI_VERSION_CURRENT */
+       uint_t          efi_nparts;     /* number of partitions below */
+       uint_t          efi_part_size;  /* size of each partition entry */
+                                       /* efi_part_size is unused */
+       uint_t          efi_lbasize;    /* size of block in bytes */
+       diskaddr_t      efi_last_lba;   /* last block on the disk */
+       diskaddr_t      efi_first_u_lba; /* first block after labels */
+       diskaddr_t      efi_last_u_lba; /* last block before backup labels */
+       struct uuid     efi_disk_uguid; /* unique disk GUID */
+       uint_t          efi_flags;
+       uint_t          efi_reserved1;  /* future use - set to zero */
+       diskaddr_t      efi_altern_lba; /* lba of alternate GPT header */
+       uint_t          efi_reserved[12]; /* future use - set to zero */
+       struct dk_part  efi_parts[1];   /* array of partitions */
+} dk_gpt_t;
+
+/* possible values for "efi_flags" */
+#define        EFI_GPT_PRIMARY_CORRUPT 0x1     /* primary label corrupt */
+
+/* the private ioctl between libefi and the driver */
+typedef struct dk_efi {
+       diskaddr_t       dki_lba;       /* starting block */
+       len_t            dki_length;    /* length in bytes */
+       union {
+               efi_gpt_t       *_dki_data;
+               uint64_t        _dki_data_64;
+       } dki_un;
+#define        dki_data        dki_un._dki_data
+#define        dki_data_64     dki_un._dki_data_64
+} dk_efi_t;
+
+struct partition64 {
+       struct uuid     p_type;
+       uint_t          p_partno;
+       uint_t          p_resv1;
+       diskaddr_t      p_start;
+       diskaddr_t      p_size;
+};
+
+/*
+ * Number of EFI partitions
+ */
+#if defined(__linux__)
+#define        EFI_NUMPAR      128 /* Expected by parted-1.8.1 */
+#else
+#define        EFI_NUMPAR      9
+#endif
+
+#ifndef _KERNEL
+extern int     efi_alloc_and_init(int, uint32_t, struct dk_gpt **);
+extern int     efi_alloc_and_read(int, struct dk_gpt **);
+extern int     efi_write(int, struct dk_gpt *);
+extern int     efi_rescan(int);
+extern void    efi_free(struct dk_gpt *);
+extern int     efi_type(int);
+extern void    efi_err_check(struct dk_gpt *);
+extern int     efi_auto_sense(int fd, struct dk_gpt **);
+extern int     efi_use_whole_disk(int fd);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_EFI_PARTITION_H */
diff --git a/zfs/include/sys/fm/Makefile.am b/zfs/include/sys/fm/Makefile.am
new file mode 100644 (file)
index 0000000..8bca5d8
--- /dev/null
@@ -0,0 +1,21 @@
+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)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys/fm
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/fm
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/sys/fm/Makefile.in b/zfs/include/sys/fm/Makefile.in
new file mode 100644 (file)
index 0000000..a840323
--- /dev/null
@@ -0,0 +1,879 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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.am b/zfs/include/sys/fm/fs/Makefile.am
new file mode 100644 (file)
index 0000000..fdc9eb5
--- /dev/null
@@ -0,0 +1,18 @@
+COMMON_H = \
+       $(top_srcdir)/include/sys/fm/fs/zfs.h
+
+KERNEL_H =
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys/fm/fs
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/fm/fs
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/sys/fm/fs/Makefile.in b/zfs/include/sys/fm/fs/Makefile.in
new file mode 100644 (file)
index 0000000..3459791
--- /dev/null
@@ -0,0 +1,759 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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:
diff --git a/zfs/include/sys/fm/fs/zfs.h b/zfs/include/sys/fm/fs/zfs.h
new file mode 100644 (file)
index 0000000..0d7eadd
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_FM_FS_ZFS_H
+#define        _SYS_FM_FS_ZFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        ZFS_ERROR_CLASS                         "fs.zfs"
+
+#define        FM_EREPORT_ZFS_CHECKSUM                 "checksum"
+#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"
+#define        FM_EREPORT_ZFS_DEVICE_NO_REPLICAS       "vdev.no_replicas"
+#define        FM_EREPORT_ZFS_DEVICE_BAD_GUID_SUM      "vdev.bad_guid_sum"
+#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_PAYLOAD_ZFS_POOL             "pool"
+#define        FM_EREPORT_PAYLOAD_ZFS_POOL_FAILMODE    "pool_failmode"
+#define        FM_EREPORT_PAYLOAD_ZFS_POOL_GUID        "pool_guid"
+#define        FM_EREPORT_PAYLOAD_ZFS_POOL_CONTEXT     "pool_context"
+#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_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_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"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_SPARE_PATHS "vdev_spare_paths"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_SPARE_GUIDS "vdev_spare_guids"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_READ_ERRORS "vdev_read_errors"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_WRITE_ERRORS "vdev_write_errors"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_CKSUM_ERRORS "vdev_cksum_errors"
+#define        FM_EREPORT_PAYLOAD_ZFS_PARENT_GUID      "parent_guid"
+#define        FM_EREPORT_PAYLOAD_ZFS_PARENT_TYPE      "parent_type"
+#define        FM_EREPORT_PAYLOAD_ZFS_PARENT_PATH      "parent_path"
+#define        FM_EREPORT_PAYLOAD_ZFS_PARENT_DEVID     "parent_devid"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJSET       "zio_objset"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJECT       "zio_object"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_LEVEL        "zio_level"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_BLKID        "zio_blkid"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_ERR          "zio_err"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_OFFSET       "zio_offset"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_SIZE         "zio_size"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS        "zio_flags"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_STAGE        "zio_stage"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_PIPELINE     "zio_pipeline"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_DELAY        "zio_delay"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_TIMESTAMP    "zio_timestamp"
+#define        FM_EREPORT_PAYLOAD_ZFS_ZIO_DELTA        "zio_delta"
+#define        FM_EREPORT_PAYLOAD_ZFS_PREV_STATE       "prev_state"
+#define        FM_EREPORT_PAYLOAD_ZFS_CKSUM_EXPECTED   "cksum_expected"
+#define        FM_EREPORT_PAYLOAD_ZFS_CKSUM_ACTUAL     "cksum_actual"
+#define        FM_EREPORT_PAYLOAD_ZFS_CKSUM_ALGO       "cksum_algorithm"
+#define        FM_EREPORT_PAYLOAD_ZFS_CKSUM_BYTESWAP   "cksum_byteswap"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_OFFSET_RANGES "bad_ranges"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_RANGE_MIN_GAP "bad_ranges_min_gap"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_RANGE_SETS   "bad_range_sets"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_RANGE_CLEARS "bad_range_clears"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_SET_BITS     "bad_set_bits"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_CLEARED_BITS "bad_cleared_bits"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_SET_HISTOGRAM "bad_set_histogram"
+#define        FM_EREPORT_PAYLOAD_ZFS_BAD_CLEARED_HISTOGRAM "bad_cleared_histogram"
+
+#define        FM_EREPORT_FAILMODE_WAIT                "wait"
+#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"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FM_FS_ZFS_H */
diff --git a/zfs/include/sys/fm/protocol.h b/zfs/include/sys/fm/protocol.h
new file mode 100644 (file)
index 0000000..de05bb2
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef        _SYS_FM_PROTOCOL_H
+#define        _SYS_FM_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+#include <sys/varargs.h>
+#include <sys/nvpair.h>
+#else
+#include <libnvpair.h>
+#include <stdarg.h>
+#endif
+#include <sys/processor.h>
+
+/* FM common member names */
+#define        FM_CLASS                        "class"
+#define        FM_VERSION                      "version"
+
+/* FM protocol category 1 class names */
+#define        FM_EREPORT_CLASS                "ereport"
+#define        FM_FAULT_CLASS                  "fault"
+#define        FM_DEFECT_CLASS                 "defect"
+#define        FM_RSRC_CLASS                   "resource"
+#define        FM_LIST_EVENT                   "list"
+#define        FM_IREPORT_CLASS                "ireport"
+
+/* FM list.* event class values */
+#define        FM_LIST_SUSPECT_CLASS           FM_LIST_EVENT ".suspect"
+#define        FM_LIST_ISOLATED_CLASS          FM_LIST_EVENT ".isolated"
+#define        FM_LIST_REPAIRED_CLASS          FM_LIST_EVENT ".repaired"
+#define        FM_LIST_UPDATED_CLASS           FM_LIST_EVENT ".updated"
+#define        FM_LIST_RESOLVED_CLASS          FM_LIST_EVENT ".resolved"
+
+/* ereport class subcategory values */
+#define        FM_ERROR_CPU                    "cpu"
+#define        FM_ERROR_IO                     "io"
+
+/* ereport version and payload member names */
+#define        FM_EREPORT_VERS0                0
+#define        FM_EREPORT_VERSION              FM_EREPORT_VERS0
+
+/* ereport payload member names */
+#define        FM_EREPORT_DETECTOR             "detector"
+#define        FM_EREPORT_ENA                  "ena"
+#define        FM_EREPORT_TIME                 "time"
+#define        FM_EREPORT_EID                  "eid"
+
+/* list.* event payload member names */
+#define        FM_LIST_EVENT_SIZE              "list-sz"
+
+/* ireport.* event payload member names */
+#define        FM_IREPORT_DETECTOR             "detector"
+#define        FM_IREPORT_UUID                 "uuid"
+#define        FM_IREPORT_PRIORITY             "pri"
+#define        FM_IREPORT_ATTRIBUTES           "attr"
+
+/*
+ * list.suspect, isolated, updated, repaired and resolved
+ * versions/payload member names.
+ */
+#define        FM_SUSPECT_UUID                 "uuid"
+#define        FM_SUSPECT_DIAG_CODE            "code"
+#define        FM_SUSPECT_DIAG_TIME            "diag-time"
+#define        FM_SUSPECT_DE                   "de"
+#define        FM_SUSPECT_FAULT_LIST           "fault-list"
+#define        FM_SUSPECT_FAULT_SZ             "fault-list-sz"
+#define        FM_SUSPECT_FAULT_STATUS         "fault-status"
+#define        FM_SUSPECT_INJECTED             "__injected"
+#define        FM_SUSPECT_MESSAGE              "message"
+#define        FM_SUSPECT_RETIRE               "retire"
+#define        FM_SUSPECT_RESPONSE             "response"
+#define        FM_SUSPECT_SEVERITY             "severity"
+
+#define        FM_SUSPECT_VERS0                0
+#define        FM_SUSPECT_VERSION              FM_SUSPECT_VERS0
+
+#define        FM_SUSPECT_FAULTY               0x1
+#define        FM_SUSPECT_UNUSABLE             0x2
+#define        FM_SUSPECT_NOT_PRESENT          0x4
+#define        FM_SUSPECT_DEGRADED             0x8
+#define        FM_SUSPECT_REPAIRED             0x10
+#define        FM_SUSPECT_REPLACED             0x20
+#define        FM_SUSPECT_ACQUITTED            0x40
+
+/* fault event versions and payload member names */
+#define        FM_FAULT_VERS0                  0
+#define        FM_FAULT_VERSION                FM_FAULT_VERS0
+
+#define        FM_FAULT_ASRU                   "asru"
+#define        FM_FAULT_FRU                    "fru"
+#define        FM_FAULT_FRU_LABEL              "fru-label"
+#define        FM_FAULT_CERTAINTY              "certainty"
+#define        FM_FAULT_RESOURCE               "resource"
+#define        FM_FAULT_LOCATION               "location"
+
+/* resource event versions and payload member names */
+#define        FM_RSRC_VERS0                   0
+#define        FM_RSRC_VERSION                 FM_RSRC_VERS0
+#define        FM_RSRC_RESOURCE                "resource"
+
+/* resource.fm.asru.* payload member names */
+#define        FM_RSRC_ASRU_UUID               "uuid"
+#define        FM_RSRC_ASRU_CODE               "code"
+#define        FM_RSRC_ASRU_FAULTY             "faulty"
+#define        FM_RSRC_ASRU_REPAIRED           "repaired"
+#define        FM_RSRC_ASRU_REPLACED           "replaced"
+#define        FM_RSRC_ASRU_ACQUITTED          "acquitted"
+#define        FM_RSRC_ASRU_RESOLVED           "resolved"
+#define        FM_RSRC_ASRU_UNUSABLE           "unusable"
+#define        FM_RSRC_ASRU_EVENT              "event"
+
+/* resource.fm.xprt.* versions and payload member names */
+#define        FM_RSRC_XPRT_VERS0              0
+#define        FM_RSRC_XPRT_VERSION            FM_RSRC_XPRT_VERS0
+#define        FM_RSRC_XPRT_UUID               "uuid"
+#define        FM_RSRC_XPRT_SUBCLASS           "subclass"
+#define        FM_RSRC_XPRT_FAULT_STATUS       "fault-status"
+#define        FM_RSRC_XPRT_FAULT_HAS_ASRU     "fault-has-asru"
+
+/*
+ * FM ENA Format Macros
+ */
+#define        ENA_FORMAT_MASK                 0x3
+#define        ENA_FORMAT(ena)                 ((ena) & ENA_FORMAT_MASK)
+
+/* ENA format types */
+#define        FM_ENA_FMT0                     0
+#define        FM_ENA_FMT1                     1
+#define        FM_ENA_FMT2                     2
+
+/* Format 1 */
+#define        ENA_FMT1_GEN_MASK               0x00000000000003FCull
+#define        ENA_FMT1_ID_MASK                0xFFFFFFFFFFFFFC00ull
+#define        ENA_FMT1_CPUID_MASK             0x00000000000FFC00ull
+#define        ENA_FMT1_TIME_MASK              0xFFFFFFFFFFF00000ull
+#define        ENA_FMT1_GEN_SHFT               2
+#define        ENA_FMT1_ID_SHFT                10
+#define        ENA_FMT1_CPUID_SHFT             ENA_FMT1_ID_SHFT
+#define        ENA_FMT1_TIME_SHFT              20
+
+/* Format 2 */
+#define        ENA_FMT2_GEN_MASK               0x00000000000003FCull
+#define        ENA_FMT2_ID_MASK                0xFFFFFFFFFFFFFC00ull
+#define        ENA_FMT2_TIME_MASK              ENA_FMT2_ID_MASK
+#define        ENA_FMT2_GEN_SHFT               2
+#define        ENA_FMT2_ID_SHFT                10
+#define        ENA_FMT2_TIME_SHFT              ENA_FMT2_ID_SHFT
+
+/* Common FMRI type names */
+#define        FM_FMRI_AUTHORITY               "authority"
+#define        FM_FMRI_SCHEME                  "scheme"
+#define        FM_FMRI_SVC_AUTHORITY           "svc-authority"
+#define        FM_FMRI_FACILITY                "facility"
+
+/* FMRI authority-type member names */
+#define        FM_FMRI_AUTH_CHASSIS            "chassis-id"
+#define        FM_FMRI_AUTH_PRODUCT_SN         "product-sn"
+#define        FM_FMRI_AUTH_PRODUCT            "product-id"
+#define        FM_FMRI_AUTH_DOMAIN             "domain-id"
+#define        FM_FMRI_AUTH_SERVER             "server-id"
+#define        FM_FMRI_AUTH_HOST               "host-id"
+
+#define        FM_AUTH_VERS0                   0
+#define        FM_FMRI_AUTH_VERSION            FM_AUTH_VERS0
+
+/* scheme name values */
+#define        FM_FMRI_SCHEME_FMD              "fmd"
+#define        FM_FMRI_SCHEME_DEV              "dev"
+#define        FM_FMRI_SCHEME_HC               "hc"
+#define        FM_FMRI_SCHEME_SVC              "svc"
+#define        FM_FMRI_SCHEME_CPU              "cpu"
+#define        FM_FMRI_SCHEME_MEM              "mem"
+#define        FM_FMRI_SCHEME_MOD              "mod"
+#define        FM_FMRI_SCHEME_PKG              "pkg"
+#define        FM_FMRI_SCHEME_LEGACY           "legacy-hc"
+#define        FM_FMRI_SCHEME_ZFS              "zfs"
+#define        FM_FMRI_SCHEME_SW               "sw"
+
+/* Scheme versions */
+#define        FMD_SCHEME_VERSION0             0
+#define        FM_FMD_SCHEME_VERSION           FMD_SCHEME_VERSION0
+#define        DEV_SCHEME_VERSION0             0
+#define        FM_DEV_SCHEME_VERSION           DEV_SCHEME_VERSION0
+#define        FM_HC_VERS0                     0
+#define        FM_HC_SCHEME_VERSION            FM_HC_VERS0
+#define        CPU_SCHEME_VERSION0             0
+#define        CPU_SCHEME_VERSION1             1
+#define        FM_CPU_SCHEME_VERSION           CPU_SCHEME_VERSION1
+#define        MEM_SCHEME_VERSION0             0
+#define        FM_MEM_SCHEME_VERSION           MEM_SCHEME_VERSION0
+#define        MOD_SCHEME_VERSION0             0
+#define        FM_MOD_SCHEME_VERSION           MOD_SCHEME_VERSION0
+#define        PKG_SCHEME_VERSION0             0
+#define        FM_PKG_SCHEME_VERSION           PKG_SCHEME_VERSION0
+#define        LEGACY_SCHEME_VERSION0          0
+#define        FM_LEGACY_SCHEME_VERSION        LEGACY_SCHEME_VERSION0
+#define        SVC_SCHEME_VERSION0             0
+#define        FM_SVC_SCHEME_VERSION           SVC_SCHEME_VERSION0
+#define        ZFS_SCHEME_VERSION0             0
+#define        FM_ZFS_SCHEME_VERSION           ZFS_SCHEME_VERSION0
+#define        SW_SCHEME_VERSION0              0
+#define        FM_SW_SCHEME_VERSION            SW_SCHEME_VERSION0
+
+/* hc scheme member names */
+#define        FM_FMRI_HC_SERIAL_ID            "serial"
+#define        FM_FMRI_HC_PART                 "part"
+#define        FM_FMRI_HC_REVISION             "revision"
+#define        FM_FMRI_HC_ROOT                 "hc-root"
+#define        FM_FMRI_HC_LIST_SZ              "hc-list-sz"
+#define        FM_FMRI_HC_LIST                 "hc-list"
+#define        FM_FMRI_HC_SPECIFIC             "hc-specific"
+
+/* facility member names */
+#define        FM_FMRI_FACILITY_NAME           "facility-name"
+#define        FM_FMRI_FACILITY_TYPE           "facility-type"
+
+/* hc-list version and member names */
+#define        FM_FMRI_HC_NAME                 "hc-name"
+#define        FM_FMRI_HC_ID                   "hc-id"
+
+#define        HC_LIST_VERSION0                0
+#define        FM_HC_LIST_VERSION              HC_LIST_VERSION0
+
+/* hc-specific member names */
+#define        FM_FMRI_HC_SPECIFIC_OFFSET      "offset"
+#define        FM_FMRI_HC_SPECIFIC_PHYSADDR    "physaddr"
+
+/* fmd module scheme member names */
+#define        FM_FMRI_FMD_NAME                "mod-name"
+#define        FM_FMRI_FMD_VERSION             "mod-version"
+
+/* dev scheme member names */
+#define        FM_FMRI_DEV_ID                  "devid"
+#define        FM_FMRI_DEV_TGTPTLUN0           "target-port-l0id"
+#define        FM_FMRI_DEV_PATH                "device-path"
+
+/* pkg scheme member names */
+#define        FM_FMRI_PKG_BASEDIR             "pkg-basedir"
+#define        FM_FMRI_PKG_INST                "pkg-inst"
+#define        FM_FMRI_PKG_VERSION             "pkg-version"
+
+/* svc scheme member names */
+#define        FM_FMRI_SVC_NAME                "svc-name"
+#define        FM_FMRI_SVC_INSTANCE            "svc-instance"
+#define        FM_FMRI_SVC_CONTRACT_ID         "svc-contract-id"
+
+/* svc-authority member names */
+#define        FM_FMRI_SVC_AUTH_SCOPE          "scope"
+#define        FM_FMRI_SVC_AUTH_SYSTEM_FQN     "system-fqn"
+
+/* cpu scheme member names */
+#define        FM_FMRI_CPU_ID                  "cpuid"
+#define        FM_FMRI_CPU_SERIAL_ID           "serial"
+#define        FM_FMRI_CPU_MASK                "cpumask"
+#define        FM_FMRI_CPU_VID                 "cpuvid"
+#define        FM_FMRI_CPU_CPUFRU              "cpufru"
+#define        FM_FMRI_CPU_CACHE_INDEX         "cacheindex"
+#define        FM_FMRI_CPU_CACHE_WAY           "cacheway"
+#define        FM_FMRI_CPU_CACHE_BIT           "cachebit"
+#define        FM_FMRI_CPU_CACHE_TYPE          "cachetype"
+
+#define        FM_FMRI_CPU_CACHE_TYPE_L2       0
+#define        FM_FMRI_CPU_CACHE_TYPE_L3       1
+
+/* legacy-hc scheme member names */
+#define        FM_FMRI_LEGACY_HC               "component"
+#define        FM_FMRI_LEGACY_HC_PREFIX        FM_FMRI_SCHEME_HC":///" \
+    FM_FMRI_LEGACY_HC"="
+
+/* mem scheme member names */
+#define        FM_FMRI_MEM_UNUM                "unum"
+#define        FM_FMRI_MEM_SERIAL_ID           "serial"
+#define        FM_FMRI_MEM_PHYSADDR            "physaddr"
+#define        FM_FMRI_MEM_MEMCONFIG           "memconfig"
+#define        FM_FMRI_MEM_OFFSET              "offset"
+
+/* mod scheme member names */
+#define        FM_FMRI_MOD_PKG                 "mod-pkg"
+#define        FM_FMRI_MOD_NAME                "mod-name"
+#define        FM_FMRI_MOD_ID                  "mod-id"
+#define        FM_FMRI_MOD_DESC                "mod-desc"
+
+/* zfs scheme member names */
+#define        FM_FMRI_ZFS_POOL                "pool"
+#define        FM_FMRI_ZFS_VDEV                "vdev"
+
+/* sw scheme member names - extra indentation for members of an nvlist */
+#define        FM_FMRI_SW_OBJ                  "object"
+#define        FM_FMRI_SW_OBJ_PATH                     "path"
+#define        FM_FMRI_SW_OBJ_ROOT                     "root"
+#define        FM_FMRI_SW_OBJ_PKG                      "pkg"
+#define        FM_FMRI_SW_SITE                 "site"
+#define        FM_FMRI_SW_SITE_TOKEN                   "token"
+#define        FM_FMRI_SW_SITE_MODULE                  "module"
+#define        FM_FMRI_SW_SITE_FILE                    "file"
+#define        FM_FMRI_SW_SITE_LINE                    "line"
+#define        FM_FMRI_SW_SITE_FUNC                    "func"
+#define        FM_FMRI_SW_CTXT                 "context"
+#define        FM_FMRI_SW_CTXT_ORIGIN                  "origin"
+#define        FM_FMRI_SW_CTXT_EXECNAME                "execname"
+#define        FM_FMRI_SW_CTXT_PID                     "pid"
+#define        FM_FMRI_SW_CTXT_ZONE                    "zone"
+#define        FM_FMRI_SW_CTXT_CTID                    "ctid"
+#define        FM_FMRI_SW_CTXT_STACK                   "stack"
+#define        FM_NVA_FREE             0       /* free allocator on nvlist_destroy */
+#define        FM_NVA_RETAIN           1       /* keep allocator on nvlist_destroy */
+
+extern nv_alloc_t *fm_nva_xcreate(char *, size_t);
+extern void fm_nva_xdestroy(nv_alloc_t *);
+extern nvlist_t *fm_nvlist_create(nv_alloc_t *);
+extern void fm_nvlist_destroy(nvlist_t *, int);
+extern void fm_ereport_set(nvlist_t *, int, const char *, uint64_t,
+    const nvlist_t *, ...);
+extern void fm_payload_set(nvlist_t *, ...);
+extern int i_fm_payload_set(nvlist_t *, const char *, va_list);
+extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, nvlist_t *,
+    int, ...);
+extern void fm_fmri_dev_set(nvlist_t *, int, const nvlist_t *, const char *,
+    const char *, const char *);
+extern void fm_fmri_de_set(nvlist_t *, int, const nvlist_t *, const char *);
+extern void fm_fmri_cpu_set(nvlist_t *, int, const nvlist_t *, uint32_t,
+    uint8_t *, const char *);
+extern void fm_fmri_mem_set(nvlist_t *, int, const nvlist_t *, const char *,
+    const char *, uint64_t);
+extern void fm_fmri_zfs_set(nvlist_t *, int, uint64_t, uint64_t);
+extern void fm_fmri_hc_create(nvlist_t *, int, const nvlist_t *, nvlist_t *,
+    nvlist_t *, int, ...);
+
+extern uint64_t fm_ena_increment(uint64_t);
+extern uint64_t fm_ena_generate(uint64_t, uchar_t);
+extern uint64_t fm_ena_generate_cpu(uint64_t, processorid_t, uchar_t);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FM_PROTOCOL_H */
diff --git a/zfs/include/sys/fm/util.h b/zfs/include/sys/fm/util.h
new file mode 100644 (file)
index 0000000..6ee3176
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_FM_UTIL_H
+#define        _SYS_FM_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/nvpair.h>
+
+/*
+ * Shared user/kernel definitions for class length, error channel name,
+ * and kernel event publisher string.
+ */
+#define        FM_MAX_CLASS 100
+#define        FM_ERROR_CHAN   "com.sun:fm:error"
+#define        FM_PUB          "fm"
+
+/*
+ * ereport dump device transport support
+ *
+ * Ereports are written out to the dump device at a proscribed offset from the
+ * end, similar to in-transit log messages.  The ereports are represented as a
+ * erpt_dump_t header followed by ed_size bytes of packed native nvlist data.
+ *
+ * NOTE: All of these constants and the header must be defined so they have the
+ * same representation for *both* 32-bit and 64-bit producers and consumers.
+ */
+#define        ERPT_MAGIC      0xf00d4eddU
+#define        ERPT_MAX_ERRS   16
+#define        ERPT_DATA_SZ    (6 * 1024)
+#define        ERPT_EVCH_MAX   256
+#define        ERPT_HIWAT      64
+
+typedef struct erpt_dump {
+       uint32_t ed_magic;      /* ERPT_MAGIC or zero to indicate end */
+       uint32_t ed_chksum;     /* checksum32() of packed nvlist data */
+       uint32_t ed_size;       /* ereport (nvl) fixed buf size */
+       uint32_t ed_pad;        /* reserved for future use */
+       hrtime_t ed_hrt_nsec;   /* hrtime of this ereport */
+       hrtime_t ed_hrt_base;   /* hrtime sample corresponding to ed_tod_base */
+       struct {
+               uint64_t sec;   /* seconds since gettimeofday() Epoch */
+               uint64_t nsec;  /* nanoseconds past ed_tod_base.sec */
+       } ed_tod_base;
+} erpt_dump_t;
+
+#ifdef _KERNEL
+
+#define        ZEVENT_SHUTDOWN         0x1
+
+typedef void zevent_cb_t(nvlist_t *, nvlist_t *);
+
+typedef struct zevent_s {
+       nvlist_t        *ev_nvl;        /* protected by the zevent_lock */
+       nvlist_t        *ev_detector;   /* " */
+       list_t          ev_ze_list;     /* " */
+       list_node_t     ev_node;        /* " */
+       zevent_cb_t     *ev_cb;         /* " */
+       uint64_t        ev_eid;
+} zevent_t;
+
+typedef struct zfs_zevent {
+       zevent_t        *ze_zevent;     /* protected by the zevent_lock */
+       list_node_t     ze_node;        /* " */
+       uint64_t        ze_dropped;     /* " */
+} zfs_zevent_t;
+
+extern void fm_init(void);
+extern void fm_fini(void);
+extern void fm_nvprint(nvlist_t *);
+extern int zfs_zevent_post(nvlist_t *, nvlist_t *, zevent_cb_t *);
+extern void zfs_zevent_drain_all(int *);
+extern int zfs_zevent_fd_hold(int, minor_t *, zfs_zevent_t **);
+extern void zfs_zevent_fd_rele(int);
+extern int zfs_zevent_next(zfs_zevent_t *, nvlist_t **, uint64_t *, uint64_t *);
+extern int zfs_zevent_wait(zfs_zevent_t *);
+extern int zfs_zevent_seek(zfs_zevent_t *, uint64_t);
+extern void zfs_zevent_init(zfs_zevent_t **);
+extern void zfs_zevent_destroy(zfs_zevent_t *);
+
+#else
+
+static inline void fm_init(void) { }
+static inline void fm_fini(void) { }
+
+#endif  /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FM_UTIL_H */
diff --git a/zfs/include/sys/fs/Makefile.am b/zfs/include/sys/fs/Makefile.am
new file mode 100644 (file)
index 0000000..0859b9f
--- /dev/null
@@ -0,0 +1,18 @@
+COMMON_H = \
+       $(top_srcdir)/include/sys/fs/zfs.h
+
+KERNEL_H =
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys/fs
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/fs
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/sys/fs/Makefile.in b/zfs/include/sys/fs/Makefile.in
new file mode 100644 (file)
index 0000000..b7d24cb
--- /dev/null
@@ -0,0 +1,759 @@
+# 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-aio-fsync.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-blk-queue-unplug.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-generic_readlink.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-rename.m4 \
+       $(top_srcdir)/config/kernel-security-inode-init.m4 \
+       $(top_srcdir)/config/kernel-set-nlink.m4 \
+       $(top_srcdir)/config/kernel-setattr-prepare.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:
diff --git a/zfs/include/sys/fs/zfs.h b/zfs/include/sys/fs/zfs.h
new file mode 100644 (file)
index 0000000..57bf55f
--- /dev/null
@@ -0,0 +1,1000 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#ifndef        _SYS_FS_ZFS_H
+#define        _SYS_FS_ZFS_H
+
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Types and constants shared between userland and the kernel.
+ */
+
+/*
+ * Each dataset can be one of the following types.  These constants can be
+ * combined into masks that can be passed to various functions.
+ */
+typedef enum {
+       ZFS_TYPE_FILESYSTEM     = (1 << 0),
+       ZFS_TYPE_SNAPSHOT       = (1 << 1),
+       ZFS_TYPE_VOLUME         = (1 << 2),
+       ZFS_TYPE_POOL           = (1 << 3),
+       ZFS_TYPE_BOOKMARK       = (1 << 4)
+} zfs_type_t;
+
+typedef enum dmu_objset_type {
+       DMU_OST_NONE,
+       DMU_OST_META,
+       DMU_OST_ZFS,
+       DMU_OST_ZVOL,
+       DMU_OST_OTHER,                  /* For testing only! */
+       DMU_OST_ANY,                    /* Be careful! */
+       DMU_OST_NUMTYPES
+} dmu_objset_type_t;
+
+#define        ZFS_TYPE_DATASET        \
+       (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME | ZFS_TYPE_SNAPSHOT)
+
+#define        ZAP_MAXNAMELEN 256
+#define        ZAP_MAXVALUELEN (1024 * 8)
+#define        ZAP_OLDMAXVALUELEN 1024
+#define        ZFS_MAX_DATASET_NAME_LEN 256
+
+/*
+ * Dataset properties are identified by these constants and must be added to
+ * the end of this list to ensure that external consumers are not affected
+ * by the change. If you make any changes to this list, be sure to update
+ * the property table in module/zcommon/zfs_prop.c.
+ */
+typedef enum {
+       ZFS_PROP_TYPE,
+       ZFS_PROP_CREATION,
+       ZFS_PROP_USED,
+       ZFS_PROP_AVAILABLE,
+       ZFS_PROP_REFERENCED,
+       ZFS_PROP_COMPRESSRATIO,
+       ZFS_PROP_MOUNTED,
+       ZFS_PROP_ORIGIN,
+       ZFS_PROP_QUOTA,
+       ZFS_PROP_RESERVATION,
+       ZFS_PROP_VOLSIZE,
+       ZFS_PROP_VOLBLOCKSIZE,
+       ZFS_PROP_RECORDSIZE,
+       ZFS_PROP_MOUNTPOINT,
+       ZFS_PROP_SHARENFS,
+       ZFS_PROP_CHECKSUM,
+       ZFS_PROP_COMPRESSION,
+       ZFS_PROP_ATIME,
+       ZFS_PROP_DEVICES,
+       ZFS_PROP_EXEC,
+       ZFS_PROP_SETUID,
+       ZFS_PROP_READONLY,
+       ZFS_PROP_ZONED,
+       ZFS_PROP_SNAPDIR,
+       ZFS_PROP_PRIVATE,               /* not exposed to user, temporary */
+       ZFS_PROP_ACLINHERIT,
+       ZFS_PROP_CREATETXG,             /* not exposed to the user */
+       ZFS_PROP_NAME,                  /* not exposed to the user */
+       ZFS_PROP_CANMOUNT,
+       ZFS_PROP_ISCSIOPTIONS,          /* not exposed to the user */
+       ZFS_PROP_XATTR,
+       ZFS_PROP_NUMCLONES,             /* not exposed to the user */
+       ZFS_PROP_COPIES,
+       ZFS_PROP_VERSION,
+       ZFS_PROP_UTF8ONLY,
+       ZFS_PROP_NORMALIZE,
+       ZFS_PROP_CASE,
+       ZFS_PROP_VSCAN,
+       ZFS_PROP_NBMAND,
+       ZFS_PROP_SHARESMB,
+       ZFS_PROP_REFQUOTA,
+       ZFS_PROP_REFRESERVATION,
+       ZFS_PROP_GUID,
+       ZFS_PROP_PRIMARYCACHE,
+       ZFS_PROP_SECONDARYCACHE,
+       ZFS_PROP_USEDSNAP,
+       ZFS_PROP_USEDDS,
+       ZFS_PROP_USEDCHILD,
+       ZFS_PROP_USEDREFRESERV,
+       ZFS_PROP_USERACCOUNTING,        /* not exposed to the user */
+       ZFS_PROP_STMF_SHAREINFO,        /* not exposed to the user */
+       ZFS_PROP_DEFER_DESTROY,
+       ZFS_PROP_USERREFS,
+       ZFS_PROP_LOGBIAS,
+       ZFS_PROP_UNIQUE,                /* not exposed to the user */
+       ZFS_PROP_OBJSETID,              /* not exposed to the user */
+       ZFS_PROP_DEDUP,
+       ZFS_PROP_MLSLABEL,
+       ZFS_PROP_SYNC,
+       ZFS_PROP_REFRATIO,
+       ZFS_PROP_WRITTEN,
+       ZFS_PROP_CLONES,
+       ZFS_PROP_LOGICALUSED,
+       ZFS_PROP_LOGICALREFERENCED,
+       ZFS_PROP_INCONSISTENT,          /* not exposed to the user */
+       ZFS_PROP_FILESYSTEM_LIMIT,
+       ZFS_PROP_SNAPSHOT_LIMIT,
+       ZFS_PROP_FILESYSTEM_COUNT,
+       ZFS_PROP_SNAPSHOT_COUNT,
+       ZFS_PROP_SNAPDEV,
+       ZFS_PROP_ACLTYPE,
+       ZFS_PROP_SELINUX_CONTEXT,
+       ZFS_PROP_SELINUX_FSCONTEXT,
+       ZFS_PROP_SELINUX_DEFCONTEXT,
+       ZFS_PROP_SELINUX_ROOTCONTEXT,
+       ZFS_PROP_RELATIME,
+       ZFS_PROP_REDUNDANT_METADATA,
+       ZFS_PROP_OVERLAY,
+       ZFS_NUM_PROPS
+} zfs_prop_t;
+
+typedef enum {
+       ZFS_PROP_USERUSED,
+       ZFS_PROP_USERQUOTA,
+       ZFS_PROP_GROUPUSED,
+       ZFS_PROP_GROUPQUOTA,
+       ZFS_NUM_USERQUOTA_PROPS
+} zfs_userquota_prop_t;
+
+extern const char *zfs_userquota_prop_prefixes[ZFS_NUM_USERQUOTA_PROPS];
+
+/*
+ * Pool properties are identified by these constants and must be added to the
+ * end of this list to ensure that external consumers are not affected
+ * by the change. If you make any changes to this list, be sure to update
+ * the property table in module/zcommon/zpool_prop.c.
+ */
+typedef enum {
+       ZPOOL_PROP_NAME,
+       ZPOOL_PROP_SIZE,
+       ZPOOL_PROP_CAPACITY,
+       ZPOOL_PROP_ALTROOT,
+       ZPOOL_PROP_HEALTH,
+       ZPOOL_PROP_GUID,
+       ZPOOL_PROP_VERSION,
+       ZPOOL_PROP_BOOTFS,
+       ZPOOL_PROP_DELEGATION,
+       ZPOOL_PROP_AUTOREPLACE,
+       ZPOOL_PROP_CACHEFILE,
+       ZPOOL_PROP_FAILUREMODE,
+       ZPOOL_PROP_LISTSNAPS,
+       ZPOOL_PROP_AUTOEXPAND,
+       ZPOOL_PROP_DEDUPDITTO,
+       ZPOOL_PROP_DEDUPRATIO,
+       ZPOOL_PROP_FREE,
+       ZPOOL_PROP_ALLOCATED,
+       ZPOOL_PROP_READONLY,
+       ZPOOL_PROP_ASHIFT,
+       ZPOOL_PROP_COMMENT,
+       ZPOOL_PROP_EXPANDSZ,
+       ZPOOL_PROP_FREEING,
+       ZPOOL_PROP_FRAGMENTATION,
+       ZPOOL_PROP_LEAKED,
+       ZPOOL_PROP_MAXBLOCKSIZE,
+       ZPOOL_PROP_TNAME,
+       ZPOOL_NUM_PROPS
+} zpool_prop_t;
+
+/* Small enough to not hog a whole line of printout in zpool(1M). */
+#define        ZPROP_MAX_COMMENT       32
+
+#define        ZPROP_CONT              -2
+#define        ZPROP_INVAL             -1
+
+#define        ZPROP_VALUE             "value"
+#define        ZPROP_SOURCE            "source"
+
+typedef enum {
+       ZPROP_SRC_NONE = 0x1,
+       ZPROP_SRC_DEFAULT = 0x2,
+       ZPROP_SRC_TEMPORARY = 0x4,
+       ZPROP_SRC_LOCAL = 0x8,
+       ZPROP_SRC_INHERITED = 0x10,
+       ZPROP_SRC_RECEIVED = 0x20
+} zprop_source_t;
+
+#define        ZPROP_SRC_ALL   0x3f
+
+#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
+ * SPA_VERSION_RECVD_PROPS. The first such receive blows away local properties
+ * just as it did in earlier versions, and thereafter, local properties are
+ * preserved.
+ */
+#define        ZPROP_HAS_RECVD         "$hasrecvd"
+
+typedef enum {
+       ZPROP_ERR_NOCLEAR = 0x1, /* failure to clear existing props */
+       ZPROP_ERR_NORESTORE = 0x2 /* failure to restore props on error */
+} zprop_errflags_t;
+
+typedef int (*zprop_func)(int, void *);
+
+/*
+ * Properties to be set on the root file system of a new pool
+ * are stuffed into their own nvlist, which is then included in
+ * the properties nvlist with the pool properties.
+ */
+#define        ZPOOL_ROOTFS_PROPS      "root-props-nvl"
+
+/*
+ * Dataset property functions shared between libzfs and kernel.
+ */
+const char *zfs_prop_default_string(zfs_prop_t);
+uint64_t zfs_prop_default_numeric(zfs_prop_t);
+boolean_t zfs_prop_readonly(zfs_prop_t);
+boolean_t zfs_prop_inheritable(zfs_prop_t);
+boolean_t zfs_prop_setonce(zfs_prop_t);
+const char *zfs_prop_to_name(zfs_prop_t);
+zfs_prop_t zfs_name_to_prop(const char *);
+boolean_t zfs_prop_user(const char *);
+boolean_t zfs_prop_userquota(const char *);
+boolean_t zfs_prop_written(const char *);
+int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **);
+int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *);
+uint64_t zfs_prop_random_value(zfs_prop_t, uint64_t seed);
+boolean_t zfs_prop_valid_for_type(int, zfs_type_t, boolean_t);
+
+/*
+ * Pool property functions shared between libzfs and kernel.
+ */
+zpool_prop_t zpool_name_to_prop(const char *);
+const char *zpool_prop_to_name(zpool_prop_t);
+const char *zpool_prop_default_string(zpool_prop_t);
+uint64_t zpool_prop_default_numeric(zpool_prop_t);
+boolean_t zpool_prop_readonly(zpool_prop_t);
+boolean_t zpool_prop_feature(const char *);
+boolean_t zpool_prop_unsupported(const char *);
+int zpool_prop_index_to_string(zpool_prop_t, uint64_t, const char **);
+int zpool_prop_string_to_index(zpool_prop_t, const char *, uint64_t *);
+uint64_t zpool_prop_random_value(zpool_prop_t, uint64_t seed);
+
+/*
+ * Definitions for the Delegation.
+ */
+typedef enum {
+       ZFS_DELEG_WHO_UNKNOWN = 0,
+       ZFS_DELEG_USER = 'u',
+       ZFS_DELEG_USER_SETS = 'U',
+       ZFS_DELEG_GROUP = 'g',
+       ZFS_DELEG_GROUP_SETS = 'G',
+       ZFS_DELEG_EVERYONE = 'e',
+       ZFS_DELEG_EVERYONE_SETS = 'E',
+       ZFS_DELEG_CREATE = 'c',
+       ZFS_DELEG_CREATE_SETS = 'C',
+       ZFS_DELEG_NAMED_SET = 's',
+       ZFS_DELEG_NAMED_SET_SETS = 'S'
+} zfs_deleg_who_type_t;
+
+typedef enum {
+       ZFS_DELEG_NONE = 0,
+       ZFS_DELEG_PERM_LOCAL = 1,
+       ZFS_DELEG_PERM_DESCENDENT = 2,
+       ZFS_DELEG_PERM_LOCALDESCENDENT = 3,
+       ZFS_DELEG_PERM_CREATE = 4
+} zfs_deleg_inherit_t;
+
+#define        ZFS_DELEG_PERM_UID      "uid"
+#define        ZFS_DELEG_PERM_GID      "gid"
+#define        ZFS_DELEG_PERM_GROUPS   "groups"
+
+#define        ZFS_MLSLABEL_DEFAULT    "none"
+
+#define        ZFS_SMB_ACL_SRC         "src"
+#define        ZFS_SMB_ACL_TARGET      "target"
+
+typedef enum {
+       ZFS_CANMOUNT_OFF = 0,
+       ZFS_CANMOUNT_ON = 1,
+       ZFS_CANMOUNT_NOAUTO = 2
+} zfs_canmount_type_t;
+
+typedef enum {
+       ZFS_LOGBIAS_LATENCY = 0,
+       ZFS_LOGBIAS_THROUGHPUT = 1
+} zfs_logbias_op_t;
+
+typedef enum zfs_share_op {
+       ZFS_SHARE_NFS = 0,
+       ZFS_UNSHARE_NFS = 1,
+       ZFS_SHARE_SMB = 2,
+       ZFS_UNSHARE_SMB = 3
+} zfs_share_op_t;
+
+typedef enum zfs_smb_acl_op {
+       ZFS_SMB_ACL_ADD,
+       ZFS_SMB_ACL_REMOVE,
+       ZFS_SMB_ACL_RENAME,
+       ZFS_SMB_ACL_PURGE
+} zfs_smb_acl_op_t;
+
+typedef enum zfs_cache_type {
+       ZFS_CACHE_NONE = 0,
+       ZFS_CACHE_METADATA = 1,
+       ZFS_CACHE_ALL = 2
+} zfs_cache_type_t;
+
+typedef enum {
+       ZFS_SYNC_STANDARD = 0,
+       ZFS_SYNC_ALWAYS = 1,
+       ZFS_SYNC_DISABLED = 2
+} zfs_sync_type_t;
+
+typedef enum {
+       ZFS_XATTR_OFF = 0,
+       ZFS_XATTR_DIR = 1,
+       ZFS_XATTR_SA = 2
+} zfs_xattr_type_t;
+
+typedef enum {
+       ZFS_REDUNDANT_METADATA_ALL,
+       ZFS_REDUNDANT_METADATA_MOST
+} zfs_redundant_metadata_type_t;
+
+/*
+ * On-disk version number.
+ */
+#define        SPA_VERSION_1                   1ULL
+#define        SPA_VERSION_2                   2ULL
+#define        SPA_VERSION_3                   3ULL
+#define        SPA_VERSION_4                   4ULL
+#define        SPA_VERSION_5                   5ULL
+#define        SPA_VERSION_6                   6ULL
+#define        SPA_VERSION_7                   7ULL
+#define        SPA_VERSION_8                   8ULL
+#define        SPA_VERSION_9                   9ULL
+#define        SPA_VERSION_10                  10ULL
+#define        SPA_VERSION_11                  11ULL
+#define        SPA_VERSION_12                  12ULL
+#define        SPA_VERSION_13                  13ULL
+#define        SPA_VERSION_14                  14ULL
+#define        SPA_VERSION_15                  15ULL
+#define        SPA_VERSION_16                  16ULL
+#define        SPA_VERSION_17                  17ULL
+#define        SPA_VERSION_18                  18ULL
+#define        SPA_VERSION_19                  19ULL
+#define        SPA_VERSION_20                  20ULL
+#define        SPA_VERSION_21                  21ULL
+#define        SPA_VERSION_22                  22ULL
+#define        SPA_VERSION_23                  23ULL
+#define        SPA_VERSION_24                  24ULL
+#define        SPA_VERSION_25                  25ULL
+#define        SPA_VERSION_26                  26ULL
+#define        SPA_VERSION_27                  27ULL
+#define        SPA_VERSION_28                  28ULL
+#define        SPA_VERSION_5000                5000ULL
+
+/*
+ * When bumping up SPA_VERSION, make sure GRUB ZFS understands the on-disk
+ * format change. Go to usr/src/grub/grub-0.97/stage2/{zfs-include/, fsys_zfs*},
+ * and do the appropriate changes.  Also bump the version number in
+ * usr/src/grub/capability.
+ */
+#define        SPA_VERSION                     SPA_VERSION_5000
+#define        SPA_VERSION_STRING              "5000"
+
+/*
+ * Symbolic names for the changes that caused a SPA_VERSION switch.
+ * Used in the code when checking for presence or absence of a feature.
+ * Feel free to define multiple symbolic names for each version if there
+ * were multiple changes to on-disk structures during that version.
+ *
+ * NOTE: When checking the current SPA_VERSION in your code, be sure
+ *       to use spa_version() since it reports the version of the
+ *       last synced uberblock.  Checking the in-flight version can
+ *       be dangerous in some cases.
+ */
+#define        SPA_VERSION_INITIAL             SPA_VERSION_1
+#define        SPA_VERSION_DITTO_BLOCKS        SPA_VERSION_2
+#define        SPA_VERSION_SPARES              SPA_VERSION_3
+#define        SPA_VERSION_RAIDZ2              SPA_VERSION_3
+#define        SPA_VERSION_BPOBJ_ACCOUNT       SPA_VERSION_3
+#define        SPA_VERSION_RAIDZ_DEFLATE       SPA_VERSION_3
+#define        SPA_VERSION_DNODE_BYTES         SPA_VERSION_3
+#define        SPA_VERSION_ZPOOL_HISTORY       SPA_VERSION_4
+#define        SPA_VERSION_GZIP_COMPRESSION    SPA_VERSION_5
+#define        SPA_VERSION_BOOTFS              SPA_VERSION_6
+#define        SPA_VERSION_SLOGS               SPA_VERSION_7
+#define        SPA_VERSION_DELEGATED_PERMS     SPA_VERSION_8
+#define        SPA_VERSION_FUID                SPA_VERSION_9
+#define        SPA_VERSION_REFRESERVATION      SPA_VERSION_9
+#define        SPA_VERSION_REFQUOTA            SPA_VERSION_9
+#define        SPA_VERSION_UNIQUE_ACCURATE     SPA_VERSION_9
+#define        SPA_VERSION_L2CACHE             SPA_VERSION_10
+#define        SPA_VERSION_NEXT_CLONES         SPA_VERSION_11
+#define        SPA_VERSION_ORIGIN              SPA_VERSION_11
+#define        SPA_VERSION_DSL_SCRUB           SPA_VERSION_11
+#define        SPA_VERSION_SNAP_PROPS          SPA_VERSION_12
+#define        SPA_VERSION_USED_BREAKDOWN      SPA_VERSION_13
+#define        SPA_VERSION_PASSTHROUGH_X       SPA_VERSION_14
+#define        SPA_VERSION_USERSPACE           SPA_VERSION_15
+#define        SPA_VERSION_STMF_PROP           SPA_VERSION_16
+#define        SPA_VERSION_RAIDZ3              SPA_VERSION_17
+#define        SPA_VERSION_USERREFS            SPA_VERSION_18
+#define        SPA_VERSION_HOLES               SPA_VERSION_19
+#define        SPA_VERSION_ZLE_COMPRESSION     SPA_VERSION_20
+#define        SPA_VERSION_DEDUP               SPA_VERSION_21
+#define        SPA_VERSION_RECVD_PROPS         SPA_VERSION_22
+#define        SPA_VERSION_SLIM_ZIL            SPA_VERSION_23
+#define        SPA_VERSION_SA                  SPA_VERSION_24
+#define        SPA_VERSION_SCAN                SPA_VERSION_25
+#define        SPA_VERSION_DIR_CLONES          SPA_VERSION_26
+#define        SPA_VERSION_DEADLISTS           SPA_VERSION_26
+#define        SPA_VERSION_FAST_SNAP           SPA_VERSION_27
+#define        SPA_VERSION_MULTI_REPLACE       SPA_VERSION_28
+#define        SPA_VERSION_BEFORE_FEATURES     SPA_VERSION_28
+#define        SPA_VERSION_FEATURES            SPA_VERSION_5000
+
+#define        SPA_VERSION_IS_SUPPORTED(v) \
+       (((v) >= SPA_VERSION_INITIAL && (v) <= SPA_VERSION_BEFORE_FEATURES) || \
+       ((v) >= SPA_VERSION_FEATURES && (v) <= SPA_VERSION))
+
+/*
+ * ZPL version - rev'd whenever an incompatible on-disk format change
+ * occurs.  This is independent of SPA/DMU/ZAP versioning.  You must
+ * also update the version_table[] and help message in zfs_prop.c.
+ *
+ * When changing, be sure to teach GRUB how to read the new format!
+ * See usr/src/grub/grub-0.97/stage2/{zfs-include/,fsys_zfs*}
+ */
+#define        ZPL_VERSION_1                   1ULL
+#define        ZPL_VERSION_2                   2ULL
+#define        ZPL_VERSION_3                   3ULL
+#define        ZPL_VERSION_4                   4ULL
+#define        ZPL_VERSION_5                   5ULL
+#define        ZPL_VERSION                     ZPL_VERSION_5
+#define        ZPL_VERSION_STRING              "5"
+
+#define        ZPL_VERSION_INITIAL             ZPL_VERSION_1
+#define        ZPL_VERSION_DIRENT_TYPE         ZPL_VERSION_2
+#define        ZPL_VERSION_FUID                ZPL_VERSION_3
+#define        ZPL_VERSION_NORMALIZATION       ZPL_VERSION_3
+#define        ZPL_VERSION_SYSATTR             ZPL_VERSION_3
+#define        ZPL_VERSION_USERSPACE           ZPL_VERSION_4
+#define        ZPL_VERSION_SA                  ZPL_VERSION_5
+
+/* Rewind request information */
+#define        ZPOOL_NO_REWIND         1  /* No policy - default behavior */
+#define        ZPOOL_NEVER_REWIND      2  /* Do not search for best txg or rewind */
+#define        ZPOOL_TRY_REWIND        4  /* Search for best txg, but do not rewind */
+#define        ZPOOL_DO_REWIND         8  /* Rewind to best txg w/in deferred frees */
+#define        ZPOOL_EXTREME_REWIND    16 /* Allow extreme measures to find best txg */
+#define        ZPOOL_REWIND_MASK       28 /* All the possible rewind bits */
+#define        ZPOOL_REWIND_POLICIES   31 /* All the possible policy bits */
+
+typedef struct zpool_rewind_policy {
+       uint32_t        zrp_request;    /* rewind behavior requested */
+       uint64_t        zrp_maxmeta;    /* max acceptable meta-data errors */
+       uint64_t        zrp_maxdata;    /* max acceptable data errors */
+       uint64_t        zrp_txg;        /* specific txg to load */
+} zpool_rewind_policy_t;
+
+/*
+ * The following are configuration names used in the nvlist describing a pool's
+ * configuration.
+ */
+#define        ZPOOL_CONFIG_VERSION            "version"
+#define        ZPOOL_CONFIG_POOL_NAME          "name"
+#define        ZPOOL_CONFIG_POOL_STATE         "state"
+#define        ZPOOL_CONFIG_POOL_TXG           "txg"
+#define        ZPOOL_CONFIG_POOL_GUID          "pool_guid"
+#define        ZPOOL_CONFIG_CREATE_TXG         "create_txg"
+#define        ZPOOL_CONFIG_TOP_GUID           "top_guid"
+#define        ZPOOL_CONFIG_VDEV_TREE          "vdev_tree"
+#define        ZPOOL_CONFIG_TYPE               "type"
+#define        ZPOOL_CONFIG_CHILDREN           "children"
+#define        ZPOOL_CONFIG_ID                 "id"
+#define        ZPOOL_CONFIG_GUID               "guid"
+#define        ZPOOL_CONFIG_PATH               "path"
+#define        ZPOOL_CONFIG_DEVID              "devid"
+#define        ZPOOL_CONFIG_METASLAB_ARRAY     "metaslab_array"
+#define        ZPOOL_CONFIG_METASLAB_SHIFT     "metaslab_shift"
+#define        ZPOOL_CONFIG_ASHIFT             "ashift"
+#define        ZPOOL_CONFIG_ASIZE              "asize"
+#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 */
+#define        ZPOOL_CONFIG_WHOLE_DISK         "whole_disk"
+#define        ZPOOL_CONFIG_ERRCOUNT           "error_count"
+#define        ZPOOL_CONFIG_NOT_PRESENT        "not_present"
+#define        ZPOOL_CONFIG_SPARES             "spares"
+#define        ZPOOL_CONFIG_IS_SPARE           "is_spare"
+#define        ZPOOL_CONFIG_NPARITY            "nparity"
+#define        ZPOOL_CONFIG_HOSTID             "hostid"
+#define        ZPOOL_CONFIG_HOSTNAME           "hostname"
+#define        ZPOOL_CONFIG_LOADED_TIME        "initial_load_time"
+#define        ZPOOL_CONFIG_UNSPARE            "unspare"
+#define        ZPOOL_CONFIG_PHYS_PATH          "phys_path"
+#define        ZPOOL_CONFIG_IS_LOG             "is_log"
+#define        ZPOOL_CONFIG_L2CACHE            "l2cache"
+#define        ZPOOL_CONFIG_HOLE_ARRAY         "hole_array"
+#define        ZPOOL_CONFIG_VDEV_CHILDREN      "vdev_children"
+#define        ZPOOL_CONFIG_IS_HOLE            "is_hole"
+#define        ZPOOL_CONFIG_DDT_HISTOGRAM      "ddt_histogram"
+#define        ZPOOL_CONFIG_DDT_OBJ_STATS      "ddt_object_stats"
+#define        ZPOOL_CONFIG_DDT_STATS          "ddt_stats"
+#define        ZPOOL_CONFIG_SPLIT              "splitcfg"
+#define        ZPOOL_CONFIG_ORIG_GUID          "orig_guid"
+#define        ZPOOL_CONFIG_SPLIT_GUID         "split_guid"
+#define        ZPOOL_CONFIG_SPLIT_LIST         "guid_list"
+#define        ZPOOL_CONFIG_REMOVING           "removing"
+#define        ZPOOL_CONFIG_RESILVER_TXG       "resilver_txg"
+#define        ZPOOL_CONFIG_COMMENT            "comment"
+#define        ZPOOL_CONFIG_SUSPENDED          "suspended"     /* not stored on disk */
+#define        ZPOOL_CONFIG_TIMESTAMP          "timestamp"     /* not stored on disk */
+#define        ZPOOL_CONFIG_BOOTFS             "bootfs"        /* not stored on disk */
+#define        ZPOOL_CONFIG_MISSING_DEVICES    "missing_vdevs" /* not stored on disk */
+#define        ZPOOL_CONFIG_LOAD_INFO          "load_info"     /* not stored on disk */
+#define        ZPOOL_CONFIG_REWIND_INFO        "rewind_info"   /* not stored on disk */
+#define        ZPOOL_CONFIG_UNSUP_FEAT         "unsup_feat"    /* not stored on disk */
+#define        ZPOOL_CONFIG_ENABLED_FEAT       "enabled_feat"  /* not stored on disk */
+#define        ZPOOL_CONFIG_CAN_RDONLY         "can_rdonly"    /* not stored on disk */
+#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 */
+/*
+ * 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
+ * as offline and degraded.
+ */
+#define        ZPOOL_CONFIG_OFFLINE            "offline"
+#define        ZPOOL_CONFIG_FAULTED            "faulted"
+#define        ZPOOL_CONFIG_DEGRADED           "degraded"
+#define        ZPOOL_CONFIG_REMOVED            "removed"
+#define        ZPOOL_CONFIG_FRU                "fru"
+#define        ZPOOL_CONFIG_AUX_STATE          "aux_state"
+
+/* Rewind policy parameters */
+#define        ZPOOL_REWIND_POLICY             "rewind-policy"
+#define        ZPOOL_REWIND_REQUEST            "rewind-request"
+#define        ZPOOL_REWIND_REQUEST_TXG        "rewind-request-txg"
+#define        ZPOOL_REWIND_META_THRESH        "rewind-meta-thresh"
+#define        ZPOOL_REWIND_DATA_THRESH        "rewind-data-thresh"
+
+/* Rewind data discovered */
+#define        ZPOOL_CONFIG_LOAD_TIME          "rewind_txg_ts"
+#define        ZPOOL_CONFIG_LOAD_DATA_ERRORS   "verify_data_errors"
+#define        ZPOOL_CONFIG_REWIND_TIME        "seconds_of_rewind"
+
+#define        VDEV_TYPE_ROOT                  "root"
+#define        VDEV_TYPE_MIRROR                "mirror"
+#define        VDEV_TYPE_REPLACING             "replacing"
+#define        VDEV_TYPE_RAIDZ                 "raidz"
+#define        VDEV_TYPE_DISK                  "disk"
+#define        VDEV_TYPE_FILE                  "file"
+#define        VDEV_TYPE_MISSING               "missing"
+#define        VDEV_TYPE_HOLE                  "hole"
+#define        VDEV_TYPE_SPARE                 "spare"
+#define        VDEV_TYPE_LOG                   "log"
+#define        VDEV_TYPE_L2CACHE               "l2cache"
+
+/*
+ * This is needed in userland to report the minimum necessary device size.
+ */
+#define        SPA_MINDEVSIZE          (64ULL << 20)
+
+/*
+ * Set if the fragmentation has not yet been calculated. This can happen
+ * because the space maps have not been upgraded or the histogram feature
+ * is not enabled.
+ */
+#define        ZFS_FRAG_INVALID        UINT64_MAX
+
+/*
+ * The location of the pool configuration repository, shared between kernel and
+ * userland.
+ */
+#define        ZPOOL_CACHE             "/etc/zfs/zpool.cache"
+
+/*
+ * vdev states are ordered from least to most healthy.
+ * A vdev that's CANT_OPEN or below is considered unusable.
+ */
+typedef enum vdev_state {
+       VDEV_STATE_UNKNOWN = 0, /* Uninitialized vdev                   */
+       VDEV_STATE_CLOSED,      /* Not currently open                   */
+       VDEV_STATE_OFFLINE,     /* Not allowed to open                  */
+       VDEV_STATE_REMOVED,     /* Explicitly removed from system       */
+       VDEV_STATE_CANT_OPEN,   /* Tried to open, but failed            */
+       VDEV_STATE_FAULTED,     /* External request to fault device     */
+       VDEV_STATE_DEGRADED,    /* Replicated vdev with unhealthy kids  */
+       VDEV_STATE_HEALTHY      /* Presumed good                        */
+} vdev_state_t;
+
+#define        VDEV_STATE_ONLINE       VDEV_STATE_HEALTHY
+
+/*
+ * vdev aux states.  When a vdev is in the CANT_OPEN state, the aux field
+ * of the vdev stats structure uses these constants to distinguish why.
+ */
+typedef enum vdev_aux {
+       VDEV_AUX_NONE,          /* no error                             */
+       VDEV_AUX_OPEN_FAILED,   /* ldi_open_*() or vn_open() failed     */
+       VDEV_AUX_CORRUPT_DATA,  /* bad label or disk contents           */
+       VDEV_AUX_NO_REPLICAS,   /* insufficient number of replicas      */
+       VDEV_AUX_BAD_GUID_SUM,  /* vdev guid sum doesn't match          */
+       VDEV_AUX_TOO_SMALL,     /* vdev size is too small               */
+       VDEV_AUX_BAD_LABEL,     /* the label is OK but invalid          */
+       VDEV_AUX_VERSION_NEWER, /* on-disk version is too new           */
+       VDEV_AUX_VERSION_OLDER, /* on-disk version is too old           */
+       VDEV_AUX_UNSUP_FEAT,    /* unsupported features                 */
+       VDEV_AUX_SPARED,        /* hot spare used in another pool       */
+       VDEV_AUX_ERR_EXCEEDED,  /* too many errors                      */
+       VDEV_AUX_IO_FAILURE,    /* experienced I/O failure              */
+       VDEV_AUX_BAD_LOG,       /* cannot read log chain(s)             */
+       VDEV_AUX_EXTERNAL,      /* external diagnosis                   */
+       VDEV_AUX_SPLIT_POOL     /* vdev was split off into another pool */
+} vdev_aux_t;
+
+/*
+ * pool state.  The following states are written to disk as part of the normal
+ * SPA lifecycle: ACTIVE, EXPORTED, DESTROYED, SPARE, L2CACHE.  The remaining
+ * states are software abstractions used at various levels to communicate
+ * pool state.
+ */
+typedef enum pool_state {
+       POOL_STATE_ACTIVE = 0,          /* In active use                */
+       POOL_STATE_EXPORTED,            /* Explicitly exported          */
+       POOL_STATE_DESTROYED,           /* Explicitly destroyed         */
+       POOL_STATE_SPARE,               /* Reserved for hot spare use   */
+       POOL_STATE_L2CACHE,             /* Level 2 ARC device           */
+       POOL_STATE_UNINITIALIZED,       /* Internal spa_t state         */
+       POOL_STATE_UNAVAIL,             /* Internal libzfs state        */
+       POOL_STATE_POTENTIALLY_ACTIVE   /* Internal libzfs state        */
+} pool_state_t;
+
+/*
+ * Scan Functions.
+ */
+typedef enum pool_scan_func {
+       POOL_SCAN_NONE,
+       POOL_SCAN_SCRUB,
+       POOL_SCAN_RESILVER,
+       POOL_SCAN_FUNCS
+} pool_scan_func_t;
+
+/*
+ * ZIO types.  Needed to interpret vdev statistics below.
+ */
+typedef enum zio_type {
+       ZIO_TYPE_NULL = 0,
+       ZIO_TYPE_READ,
+       ZIO_TYPE_WRITE,
+       ZIO_TYPE_FREE,
+       ZIO_TYPE_CLAIM,
+       ZIO_TYPE_IOCTL,
+       ZIO_TYPES
+} zio_type_t;
+
+/*
+ * Pool statistics.  Note: all fields should be 64-bit because this
+ * is passed between kernel and userland as an nvlist uint64 array.
+ */
+typedef struct pool_scan_stat {
+       /* values stored on disk */
+       uint64_t        pss_func;       /* pool_scan_func_t */
+       uint64_t        pss_state;      /* dsl_scan_state_t */
+       uint64_t        pss_start_time; /* scan start time */
+       uint64_t        pss_end_time;   /* scan end time */
+       uint64_t        pss_to_examine; /* total bytes to scan */
+       uint64_t        pss_examined;   /* total examined bytes */
+       uint64_t        pss_to_process; /* total bytes to process */
+       uint64_t        pss_processed;  /* total processed bytes */
+       uint64_t        pss_errors;     /* scan errors  */
+
+       /* values not stored on disk */
+       uint64_t        pss_pass_exam;  /* examined bytes per scan pass */
+       uint64_t        pss_pass_start; /* start time of a scan pass */
+} pool_scan_stat_t;
+
+typedef enum dsl_scan_state {
+       DSS_NONE,
+       DSS_SCANNING,
+       DSS_FINISHED,
+       DSS_CANCELED,
+       DSS_NUM_STATES
+} dsl_scan_state_t;
+
+/*
+ * Errata described by http://zfsonlinux.org/msg/ZFS-8000-ER.  The ordering
+ * of this enum must be maintained to ensure the errata identifiers map to
+ * the correct documentation.  New errata may only be appended to the list
+ * and must contain corresponding documentation at the above link.
+ */
+typedef enum zpool_errata {
+       ZPOOL_ERRATA_NONE,
+       ZPOOL_ERRATA_ZOL_2094_SCRUB,
+       ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY,
+} zpool_errata_t;
+
+/*
+ * Vdev statistics.  Note: all fields should be 64-bit because this
+ * is passed between kernel and userland as an nvlist uint64 array.
+ */
+typedef struct vdev_stat {
+       hrtime_t        vs_timestamp;           /* time since vdev load */
+       uint64_t        vs_state;               /* vdev state           */
+       uint64_t        vs_aux;                 /* see vdev_aux_t       */
+       uint64_t        vs_alloc;               /* space allocated      */
+       uint64_t        vs_space;               /* total capacity       */
+       uint64_t        vs_dspace;              /* deflated capacity    */
+       uint64_t        vs_rsize;               /* replaceable dev size */
+       uint64_t        vs_esize;               /* expandable dev size */
+       uint64_t        vs_ops[ZIO_TYPES];      /* operation count      */
+       uint64_t        vs_bytes[ZIO_TYPES];    /* bytes read/written   */
+       uint64_t        vs_read_errors;         /* read errors          */
+       uint64_t        vs_write_errors;        /* write errors         */
+       uint64_t        vs_checksum_errors;     /* checksum errors      */
+       uint64_t        vs_self_healed;         /* self-healed bytes    */
+       uint64_t        vs_scan_removing;       /* removing?    */
+       uint64_t        vs_scan_processed;      /* scan processed bytes */
+       uint64_t        vs_fragmentation;       /* device fragmentation */
+} vdev_stat_t;
+
+/*
+ * DDT statistics.  Note: all fields should be 64-bit because this
+ * is passed between kernel and userland as an nvlist uint64 array.
+ */
+typedef struct ddt_object {
+       uint64_t        ddo_count;      /* number of elments in ddt     */
+       uint64_t        ddo_dspace;     /* size of ddt on disk          */
+       uint64_t        ddo_mspace;     /* size of ddt in-core          */
+} ddt_object_t;
+
+typedef struct ddt_stat {
+       uint64_t        dds_blocks;     /* blocks                       */
+       uint64_t        dds_lsize;      /* logical size                 */
+       uint64_t        dds_psize;      /* physical size                */
+       uint64_t        dds_dsize;      /* deflated allocated size      */
+       uint64_t        dds_ref_blocks; /* referenced blocks            */
+       uint64_t        dds_ref_lsize;  /* referenced lsize * refcnt    */
+       uint64_t        dds_ref_psize;  /* referenced psize * refcnt    */
+       uint64_t        dds_ref_dsize;  /* referenced dsize * refcnt    */
+} ddt_stat_t;
+
+typedef struct ddt_histogram {
+       ddt_stat_t      ddh_stat[64];   /* power-of-two histogram buckets */
+} ddt_histogram_t;
+
+#define        ZVOL_DRIVER     "zvol"
+#define        ZFS_DRIVER      "zfs"
+#define        ZFS_DEV         "/dev/zfs"
+
+/* general zvol path */
+#define        ZVOL_DIR        "/dev"
+
+#define        ZVOL_MAJOR              230
+#define        ZVOL_MINOR_BITS         4
+#define        ZVOL_MINOR_MASK         ((1U << ZVOL_MINOR_BITS) - 1)
+#define        ZVOL_MINORS             (1 << 4)
+#define        ZVOL_DEV_NAME           "zd"
+
+#define        ZVOL_PROP_NAME          "name"
+#define        ZVOL_DEFAULT_BLOCKSIZE  8192
+
+/*
+ * /dev/zfs ioctl numbers.
+ */
+typedef enum zfs_ioc {
+       /*
+        * Illumos - 70/128 numbers reserved.
+        */
+       ZFS_IOC_FIRST = ('Z' << 8),
+       ZFS_IOC = ZFS_IOC_FIRST,
+       ZFS_IOC_POOL_CREATE = ZFS_IOC_FIRST,
+       ZFS_IOC_POOL_DESTROY,
+       ZFS_IOC_POOL_IMPORT,
+       ZFS_IOC_POOL_EXPORT,
+       ZFS_IOC_POOL_CONFIGS,
+       ZFS_IOC_POOL_STATS,
+       ZFS_IOC_POOL_TRYIMPORT,
+       ZFS_IOC_POOL_SCAN,
+       ZFS_IOC_POOL_FREEZE,
+       ZFS_IOC_POOL_UPGRADE,
+       ZFS_IOC_POOL_GET_HISTORY,
+       ZFS_IOC_VDEV_ADD,
+       ZFS_IOC_VDEV_REMOVE,
+       ZFS_IOC_VDEV_SET_STATE,
+       ZFS_IOC_VDEV_ATTACH,
+       ZFS_IOC_VDEV_DETACH,
+       ZFS_IOC_VDEV_SETPATH,
+       ZFS_IOC_VDEV_SETFRU,
+       ZFS_IOC_OBJSET_STATS,
+       ZFS_IOC_OBJSET_ZPLPROPS,
+       ZFS_IOC_DATASET_LIST_NEXT,
+       ZFS_IOC_SNAPSHOT_LIST_NEXT,
+       ZFS_IOC_SET_PROP,
+       ZFS_IOC_CREATE,
+       ZFS_IOC_DESTROY,
+       ZFS_IOC_ROLLBACK,
+       ZFS_IOC_RENAME,
+       ZFS_IOC_RECV,
+       ZFS_IOC_SEND,
+       ZFS_IOC_INJECT_FAULT,
+       ZFS_IOC_CLEAR_FAULT,
+       ZFS_IOC_INJECT_LIST_NEXT,
+       ZFS_IOC_ERROR_LOG,
+       ZFS_IOC_CLEAR,
+       ZFS_IOC_PROMOTE,
+       ZFS_IOC_SNAPSHOT,
+       ZFS_IOC_DSOBJ_TO_DSNAME,
+       ZFS_IOC_OBJ_TO_PATH,
+       ZFS_IOC_POOL_SET_PROPS,
+       ZFS_IOC_POOL_GET_PROPS,
+       ZFS_IOC_SET_FSACL,
+       ZFS_IOC_GET_FSACL,
+       ZFS_IOC_SHARE,
+       ZFS_IOC_INHERIT_PROP,
+       ZFS_IOC_SMB_ACL,
+       ZFS_IOC_USERSPACE_ONE,
+       ZFS_IOC_USERSPACE_MANY,
+       ZFS_IOC_USERSPACE_UPGRADE,
+       ZFS_IOC_HOLD,
+       ZFS_IOC_RELEASE,
+       ZFS_IOC_GET_HOLDS,
+       ZFS_IOC_OBJSET_RECVD_PROPS,
+       ZFS_IOC_VDEV_SPLIT,
+       ZFS_IOC_NEXT_OBJ,
+       ZFS_IOC_DIFF,
+       ZFS_IOC_TMP_SNAPSHOT,
+       ZFS_IOC_OBJ_TO_STATS,
+       ZFS_IOC_SPACE_WRITTEN,
+       ZFS_IOC_SPACE_SNAPS,
+       ZFS_IOC_DESTROY_SNAPS,
+       ZFS_IOC_POOL_REGUID,
+       ZFS_IOC_POOL_REOPEN,
+       ZFS_IOC_SEND_PROGRESS,
+       ZFS_IOC_LOG_HISTORY,
+       ZFS_IOC_SEND_NEW,
+       ZFS_IOC_SEND_SPACE,
+       ZFS_IOC_CLONE,
+       ZFS_IOC_BOOKMARK,
+       ZFS_IOC_GET_BOOKMARKS,
+       ZFS_IOC_DESTROY_BOOKMARKS,
+
+       /*
+        * Linux - 3/64 numbers reserved.
+        */
+       ZFS_IOC_LINUX = ('Z' << 8) + 0x80,
+       ZFS_IOC_EVENTS_NEXT,
+       ZFS_IOC_EVENTS_CLEAR,
+       ZFS_IOC_EVENTS_SEEK,
+
+       /*
+        * FreeBSD - 1/64 numbers reserved.
+        */
+       ZFS_IOC_FREEBSD = ('Z' << 8) + 0xC0,
+
+       ZFS_IOC_LAST
+} zfs_ioc_t;
+
+/*
+ * zvol ioctl to get dataset name
+ */
+#define        BLKZNAME                _IOR(0x12, 125, char[ZFS_MAXNAMELEN])
+
+/*
+ * Internal SPA load state.  Used by FMA diagnosis engine.
+ */
+typedef enum {
+       SPA_LOAD_NONE,          /* no load in progress  */
+       SPA_LOAD_OPEN,          /* normal open          */
+       SPA_LOAD_IMPORT,        /* import in progress   */
+       SPA_LOAD_TRYIMPORT,     /* tryimport in progress */
+       SPA_LOAD_RECOVER,       /* recovery requested   */
+       SPA_LOAD_ERROR          /* load failed          */
+} spa_load_state_t;
+
+/*
+ * Bookmark name values.
+ */
+#define        ZPOOL_ERR_LIST          "error list"
+#define        ZPOOL_ERR_DATASET       "dataset"
+#define        ZPOOL_ERR_OBJECT        "object"
+
+#define        HIS_MAX_RECORD_LEN      (MAXPATHLEN + MAXPATHLEN + 1)
+
+/*
+ * The following are names used in the nvlist describing
+ * the pool's history log.
+ */
+#define        ZPOOL_HIST_RECORD       "history record"
+#define        ZPOOL_HIST_TIME         "history time"
+#define        ZPOOL_HIST_CMD          "history command"
+#define        ZPOOL_HIST_WHO          "history who"
+#define        ZPOOL_HIST_ZONE         "history zone"
+#define        ZPOOL_HIST_HOST         "history hostname"
+#define        ZPOOL_HIST_TXG          "history txg"
+#define        ZPOOL_HIST_INT_EVENT    "history internal event"
+#define        ZPOOL_HIST_INT_STR      "history internal str"
+#define        ZPOOL_HIST_INT_NAME     "internal_name"
+#define        ZPOOL_HIST_IOCTL        "ioctl"
+#define        ZPOOL_HIST_INPUT_NVL    "in_nvl"
+#define        ZPOOL_HIST_OUTPUT_NVL   "out_nvl"
+#define        ZPOOL_HIST_DSNAME       "dsname"
+#define        ZPOOL_HIST_DSID         "dsid"
+
+/*
+ * Flags for ZFS_IOC_VDEV_SET_STATE
+ */
+#define        ZFS_ONLINE_CHECKREMOVE  0x1
+#define        ZFS_ONLINE_UNSPARE      0x2
+#define        ZFS_ONLINE_FORCEFAULT   0x4
+#define        ZFS_ONLINE_EXPAND       0x8
+#define        ZFS_OFFLINE_TEMPORARY   0x1
+
+/*
+ * Flags for ZFS_IOC_POOL_IMPORT
+ */
+#define        ZFS_IMPORT_NORMAL       0x0
+#define        ZFS_IMPORT_VERBATIM     0x1
+#define        ZFS_IMPORT_ANY_HOST     0x2
+#define        ZFS_IMPORT_MISSING_LOG  0x4
+#define        ZFS_IMPORT_ONLY         0x8
+#define        ZFS_IMPORT_TEMP_NAME    0x10
+
+/*
+ * Sysevent payload members.  ZFS will generate the following sysevents with the
+ * given payloads:
+ *
+ *     ESC_ZFS_RESILVER_START
+ *     ESC_ZFS_RESILVER_END
+ *     ESC_ZFS_POOL_DESTROY
+ *     ESC_ZFS_POOL_REGUID
+ *
+ *             ZFS_EV_POOL_NAME        DATA_TYPE_STRING
+ *             ZFS_EV_POOL_GUID        DATA_TYPE_UINT64
+ *
+ *     ESC_ZFS_VDEV_REMOVE
+ *     ESC_ZFS_VDEV_CLEAR
+ *     ESC_ZFS_VDEV_CHECK
+ *
+ *             ZFS_EV_POOL_NAME        DATA_TYPE_STRING
+ *             ZFS_EV_POOL_GUID        DATA_TYPE_UINT64
+ *             ZFS_EV_VDEV_PATH        DATA_TYPE_STRING        (optional)
+ *             ZFS_EV_VDEV_GUID        DATA_TYPE_UINT64
+ */
+#define        ZFS_EV_POOL_NAME        "pool_name"
+#define        ZFS_EV_POOL_GUID        "pool_guid"
+#define        ZFS_EV_VDEV_PATH        "vdev_path"
+#define        ZFS_EV_VDEV_GUID        "vdev_guid"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_H */
diff --git a/zfs/include/sys/metaslab.h b/zfs/include/sys/metaslab.h
new file mode 100644 (file)
index 0000000..5f831a1
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_METASLAB_H
+#define        _SYS_METASLAB_H
+
+#include <sys/spa.h>
+#include <sys/space_map.h>
+#include <sys/txg.h>
+#include <sys/zio.h>
+#include <sys/avl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct metaslab_ops {
+       uint64_t (*msop_alloc)(metaslab_t *msp, uint64_t size);
+} metaslab_ops_t;
+
+extern metaslab_ops_t *zfs_metaslab_ops;
+
+int metaslab_init(metaslab_group_t *, uint64_t, uint64_t, uint64_t,
+    metaslab_t **);
+void metaslab_fini(metaslab_t *);
+
+void metaslab_load_wait(metaslab_t *);
+int metaslab_load(metaslab_t *);
+void metaslab_unload(metaslab_t *);
+
+void metaslab_sync(metaslab_t *, uint64_t);
+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
+
+int metaslab_alloc(spa_t *, metaslab_class_t *, uint64_t,
+    blkptr_t *, int, uint64_t, blkptr_t *, int);
+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 *);
+void metaslab_fastwrite_mark(spa_t *, const blkptr_t *);
+void metaslab_fastwrite_unmark(spa_t *, const blkptr_t *);
+
+metaslab_class_t *metaslab_class_create(spa_t *, metaslab_ops_t *);
+void metaslab_class_destroy(metaslab_class_t *);
+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 *);
+
+void metaslab_class_space_update(metaslab_class_t *, int64_t, int64_t,
+    int64_t, int64_t);
+uint64_t metaslab_class_get_alloc(metaslab_class_t *);
+uint64_t metaslab_class_get_space(metaslab_class_t *);
+uint64_t metaslab_class_get_dspace(metaslab_class_t *);
+uint64_t metaslab_class_get_deferred(metaslab_class_t *);
+
+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 *);
+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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_METASLAB_H */
diff --git a/zfs/include/sys/metaslab_impl.h b/zfs/include/sys/metaslab_impl.h
new file mode 100644 (file)
index 0000000..88bda07
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_METASLAB_IMPL_H
+#define        _SYS_METASLAB_IMPL_H
+
+#include <sys/metaslab.h>
+#include <sys/space_map.h>
+#include <sys/range_tree.h>
+#include <sys/vdev.h>
+#include <sys/txg.h>
+#include <sys/avl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A metaslab class encompasses a category of allocatable top-level vdevs.
+ * Each top-level vdev is associated with a metaslab group which defines
+ * the allocatable region for that vdev. Examples of these categories include
+ * "normal" for data block allocations (i.e. main pool allocations) or "log"
+ * for allocations designated for intent log devices (i.e. slog devices).
+ * When a block allocation is requested from the SPA it is associated with a
+ * metaslab_class_t, and only top-level vdevs (i.e. metaslab groups) belonging
+ * to the class can be used to satisfy that request. Allocations are done
+ * by traversing the metaslab groups that are linked off of the mc_rotor field.
+ * This rotor points to the next metaslab group where allocations will be
+ * attempted. Allocating a block is a 3 step process -- select the metaslab
+ * group, select the metaslab, and then allocate the block. The metaslab
+ * class defines the low-level block allocator that will be used as the
+ * final step in allocation. These allocators are pluggable allowing each class
+ * to use a block allocator that best suits that class.
+ */
+struct metaslab_class {
+       spa_t                   *mc_spa;
+       metaslab_group_t        *mc_rotor;
+       metaslab_ops_t          *mc_ops;
+       uint64_t                mc_aliquot;
+       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;
+};
+
+/*
+ * Metaslab groups encapsulate all the allocatable regions (i.e. metaslabs)
+ * of a top-level vdev. They are linked togther to form a circular linked
+ * list and can belong to only one metaslab class. Metaslab groups may become
+ * ineligible for allocations for a number of reasons such as limited free
+ * space, fragmentation, or going offline. When this happens the allocator will
+ * simply find the next metaslab group in the linked list and attempt
+ * to allocate from that group instead.
+ */
+struct metaslab_group {
+       kmutex_t                mg_lock;
+       avl_tree_t              mg_metaslab_tree;
+       uint64_t                mg_aliquot;
+       boolean_t               mg_allocatable;         /* can we allocate? */
+       uint64_t                mg_free_capacity;       /* percentage free */
+       int64_t                 mg_bias;
+       int64_t                 mg_activation_count;
+       metaslab_class_t        *mg_class;
+       vdev_t                  *mg_vd;
+       taskq_t                 *mg_taskq;
+       metaslab_group_t        *mg_prev;
+       metaslab_group_t        *mg_next;
+       uint64_t                mg_fragmentation;
+       uint64_t                mg_histogram[RANGE_TREE_HISTOGRAM_SIZE];
+};
+
+/*
+ * This value defines the number of elements in the ms_lbas array. The value
+ * of 64 was chosen as it covers all power of 2 buckets up to UINT64_MAX.
+ * This is the equivalent of highbit(UINT64_MAX).
+ */
+#define        MAX_LBAS        64
+
+/*
+ * Each metaslab maintains a set of in-core trees to track metaslab operations.
+ * The in-core free tree (ms_tree) contains the current list of free segments.
+ * As blocks are allocated, the allocated segment are removed from the ms_tree
+ * and added to a per txg allocation tree (ms_alloctree). As blocks are freed,
+ * they are added to the per txg free tree (ms_freetree). These per txg
+ * trees allow us to process all allocations and frees in syncing context
+ * where it is safe to update the on-disk space maps. One additional in-core
+ * tree is maintained to track deferred frees (ms_defertree). Once a block
+ * is freed it will move from the ms_freetree to the ms_defertree. A deferred
+ * free means that a block has been freed but cannot be used by the pool
+ * until TXG_DEFER_SIZE transactions groups later. For example, a block
+ * that is freed in txg 50 will not be available for reallocation until
+ * txg 52 (50 + TXG_DEFER_SIZE).  This provides a safety net for uberblock
+ * rollback. A pool could be safely rolled back TXG_DEFERS_SIZE
+ * transactions groups and ensure that no block has been reallocated.
+ *
+ * The simplified transition diagram looks like this:
+ *
+ *
+ *      ALLOCATE
+ *         |
+ *         V
+ *    free segment (ms_tree) --------> ms_alloctree ----> (write to space map)
+ *         ^
+ *         |
+ *         |                           ms_freetree <--- FREE
+ *         |                                 |
+ *         |                                 |
+ *         |                                 |
+ *         +----------- ms_defertree <-------+---------> (write to space map)
+ *
+ *
+ * Each metaslab's space is tracked in a single space map in the MOS,
+ * which is only updated in syncing context. Each time we sync a txg,
+ * we append the allocs and frees from that txg to the space map.
+ * The pool space is only updated once all metaslabs have finished syncing.
+ *
+ * To load the in-core free tree we read the space map from disk.
+ * This object contains a series of alloc and free records that are
+ * combined to make up the list of all free segments in this metaslab. These
+ * segments are represented in-core by the ms_tree and are stored in an
+ * AVL tree.
+ *
+ * As the space map grows (as a result of the appends) it will
+ * eventually become space-inefficient. When the metaslab's in-core free tree
+ * is zfs_condense_pct/100 times the size of the minimal on-disk
+ * representation, we rewrite it in its minimized form. If a metaslab
+ * needs to condense then we must set the ms_condensing flag to ensure
+ * that allocations are not performed on the metaslab that is being written.
+ */
+struct metaslab {
+       kmutex_t        ms_lock;
+       kcondvar_t      ms_load_cv;
+       space_map_t     *ms_sm;
+       metaslab_ops_t  *ms_ops;
+       uint64_t        ms_id;
+       uint64_t        ms_start;
+       uint64_t        ms_size;
+       uint64_t        ms_fragmentation;
+
+       range_tree_t    *ms_alloctree[TXG_SIZE];
+       range_tree_t    *ms_freetree[TXG_SIZE];
+       range_tree_t    *ms_defertree[TXG_DEFER_SIZE];
+       range_tree_t    *ms_tree;
+
+       boolean_t       ms_condensing;  /* condensing? */
+       boolean_t       ms_condense_wanted;
+       boolean_t       ms_loaded;
+       boolean_t       ms_loading;
+
+       int64_t         ms_deferspace;  /* sum of ms_defermap[] space   */
+       uint64_t        ms_weight;      /* weight vs. others in group   */
+       uint64_t        ms_access_txg;
+
+       /*
+        * The metaslab block allocators can optionally use a size-ordered
+        * range tree and/or an array of LBAs. Not all allocators use
+        * this functionality. The ms_size_tree should always contain the
+        * same number of segments as the ms_tree. The only difference
+        * is that the ms_size_tree is ordered by segment sizes.
+        */
+       avl_tree_t      ms_size_tree;
+       uint64_t        ms_lbas[MAX_LBAS];
+
+       metaslab_group_t *ms_group;     /* metaslab group               */
+       avl_node_t      ms_group_node;  /* node in metaslab group tree  */
+       txg_node_t      ms_txg_node;    /* per-txg dirty metaslab links */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_METASLAB_IMPL_H */
diff --git a/zfs/include/sys/mntent.h b/zfs/include/sys/mntent.h
new file mode 100644 (file)
index 0000000..fac751b
--- /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://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 1984, 1986, 1987, 1988, 1989 AT&T
+ *             All Rights Reserved
+ */
+
+#ifndef _SYS_MNTENT_H
+#define        _SYS_MNTENT_H
+
+#define        MNTTYPE_ZFS     "zfs"           /* ZFS file system */
+
+#define        MOUNT_SUCCESS   0x00            /* Success */
+#define        MOUNT_USAGE     0x01            /* Invalid invocation or permissions */
+#define        MOUNT_SYSERR    0x02            /* System error (ENOMEM, etc) */
+#define        MOUNT_SOFTWARE  0x04            /* Internal mount bug */
+#define        MOUNT_USER      0x08            /* Interrupted by user (EINTR) */
+#define        MOUNT_FILEIO    0x10            /* Error updating/locking /etc/mtab */
+#define        MOUNT_FAIL      0x20            /* Mount failed */
+#define        MOUNT_SOMEOK    0x40            /* At least on mount succeeded */
+#define        MOUNT_BUSY      0x80            /* Mount failed due to EBUSY */
+
+#define        MNTOPT_ASYNC    "async"         /* all I/O is asynchronous */
+#define        MNTOPT_ATIME    "atime"         /* update atime for files */
+#define        MNTOPT_NOATIME  "noatime"       /* do not update atime for files */
+#define        MNTOPT_AUTO     "auto"          /* automount */
+#define        MNTOPT_NOAUTO   "noauto"        /* do not automount */
+#define        MNTOPT_CONTEXT  "context"       /* selinux context */
+#define        MNTOPT_FSCONTEXT "fscontext"    /* selinux fscontext */
+#define        MNTOPT_DEFCONTEXT "defcontext"  /* selinux defcontext */
+#define        MNTOPT_ROOTCONTEXT "rootcontext" /* selinux rootcontext */
+#define        MNTOPT_DEFAULTS "defaults"      /* defaults */
+#define        MNTOPT_DEVICES  "dev"           /* device-special allowed */
+#define        MNTOPT_NODEVICES "nodev"        /* device-special disallowed */
+#define        MNTOPT_DIRATIME "diratime"      /* update atime for dirs */
+#define        MNTOPT_NODIRATIME "nodiratime"  /* do not update atime for dirs */
+#define        MNTOPT_DIRSYNC  "dirsync"       /* do dir updates synchronously */
+#define        MNTOPT_EXEC     "exec"          /* enable executables */
+#define        MNTOPT_NOEXEC   "noexec"        /* disable executables */
+#define        MNTOPT_GROUP    "group"         /* allow group mount */
+#define        MNTOPT_NOGROUP  "nogroup"       /* do not allow group mount */
+#define        MNTOPT_IVERSION "iversion"      /* update inode version */
+#define        MNTOPT_NOIVERSION "noiversion"  /* do not update inode version */
+#define        MNTOPT_NBMAND   "mand"          /* allow non-blocking mandatory locks */
+#define        MNTOPT_NONBMAND "nomand"        /* deny non-blocking mandatory locks */
+#define        MNTOPT_NETDEV   "_netdev"       /* network device */
+#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_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 */
+#define        MNTOPT_NOOWNER  "noowner"       /* do not allow owner mount */
+#define        MNTOPT_REMOUNT  "remount"       /* change mount options */
+#define        MNTOPT_RO       "ro"            /* read only */
+#define        MNTOPT_RW       "rw"            /* read/write */
+#define        MNTOPT_SYNC     "sync"          /* all I/O is synchronous */
+#define        MNTOPT_USER     "user"          /* allow user mount */
+#define        MNTOPT_NOUSER   "nouser"        /* do not allow user mount */
+#define        MNTOPT_USERS    "users"         /* allow user mount */
+#define        MNTOPT_NOUSERS  "nousers"       /* do not allow user mount */
+#define        MNTOPT_SUB      "sub"           /* allow mounts on subdirs */
+#define        MNTOPT_NOSUB    "nosub"         /* do not allow mounts on subdirs */
+#define        MNTOPT_QUIET    "quiet"         /* quiet mount */
+#define        MNTOPT_LOUD     "loud"          /* verbose mount */
+#define        MNTOPT_BIND     "bind"          /* remount part of a tree */
+#define        MNTOPT_RBIND    "rbind"         /* include subtrees */
+#define        MNTOPT_DIRXATTR "dirxattr"      /* enable directory xattrs */
+#define        MNTOPT_SAXATTR  "saxattr"       /* enable system-attribute xattrs */
+#define        MNTOPT_XATTR    "xattr"         /* enable extended attributes */
+#define        MNTOPT_NOXATTR  "noxattr"       /* disable extended attributes */
+#define        MNTOPT_COMMENT  "comment"       /* comment */
+#define        MNTOPT_ZFSUTIL  "zfsutil"       /* called by zfs utility */
+#define        MNTOPT_ACL      "acl"           /* passed by util-linux-2.24 mount */
+#define        MNTOPT_NOACL    "noacl"         /* likewise */
+#define        MNTOPT_POSIXACL "posixacl"      /* likewise */
+#define        MNTOPT_MNTPOINT "mntpoint"      /* mount point hint */
+
+#endif /* _SYS_MNTENT_H */
diff --git a/zfs/include/sys/multilist.h b/zfs/include/sys/multilist.h
new file mode 100644 (file)
index 0000000..98d707d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_MULTILIST_H
+#define        _SYS_MULTILIST_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef list_node_t multilist_node_t;
+typedef struct multilist multilist_t;
+typedef struct multilist_sublist multilist_sublist_t;
+typedef unsigned int multilist_sublist_index_func_t(multilist_t *, void *);
+
+struct multilist_sublist {
+       /*
+        * The mutex used internally to implement thread safe insertions
+        * and removals to this individual sublist. It can also be locked
+        * by a consumer using multilist_sublist_{lock,unlock}, which is
+        * useful if a consumer needs to traverse the list in a thread
+        * safe manner.
+        */
+       kmutex_t        mls_lock;
+       /*
+        * The actual list object containing all objects in this sublist.
+        */
+       list_t          mls_list;
+       /*
+        * Pad to cache line, in an effort to try and prevent cache line
+        * contention.
+        */
+} ____cacheline_aligned;
+
+struct multilist {
+       /*
+        * This is used to get to the multilist_node_t structure given
+        * the void *object contained on the list.
+        */
+       size_t                          ml_offset;
+       /*
+        * The number of sublists used internally by this multilist.
+        */
+       uint64_t                        ml_num_sublists;
+       /*
+        * The array of pointers to the actual sublists.
+        */
+       multilist_sublist_t             *ml_sublists;
+       /*
+        * Pointer to function which determines the sublist to use
+        * when inserting and removing objects from this multilist.
+        * Please see the comment above multilist_create for details.
+        */
+       multilist_sublist_index_func_t  *ml_index_func;
+};
+
+void multilist_destroy(multilist_t *);
+void multilist_create(multilist_t *, size_t, size_t, unsigned int,
+    multilist_sublist_index_func_t *);
+
+void multilist_insert(multilist_t *, void *);
+void multilist_remove(multilist_t *, void *);
+int  multilist_is_empty(multilist_t *);
+
+unsigned int multilist_get_num_sublists(multilist_t *);
+unsigned int multilist_get_random_index(multilist_t *);
+
+multilist_sublist_t *multilist_sublist_lock(multilist_t *, unsigned int);
+void multilist_sublist_unlock(multilist_sublist_t *);
+
+void multilist_sublist_insert_head(multilist_sublist_t *, void *);
+void multilist_sublist_insert_tail(multilist_sublist_t *, void *);
+void multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj);
+void multilist_sublist_remove(multilist_sublist_t *, void *);
+
+void *multilist_sublist_head(multilist_sublist_t *);
+void *multilist_sublist_tail(multilist_sublist_t *);
+void *multilist_sublist_next(multilist_sublist_t *, void *);
+void *multilist_sublist_prev(multilist_sublist_t *, void *);
+
+void multilist_link_init(multilist_node_t *);
+int  multilist_link_active(multilist_node_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MULTILIST_H */
diff --git a/zfs/include/sys/nvpair.h b/zfs/include/sys/nvpair.h
new file mode 100644 (file)
index 0000000..d2dfad5
--- /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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_NVPAIR_H
+#define        _SYS_NVPAIR_H
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/va_list.h>
+
+#if defined(_KERNEL) && !defined(_BOOT)
+#include <sys/kmem.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       DATA_TYPE_UNKNOWN = 0,
+       DATA_TYPE_BOOLEAN,
+       DATA_TYPE_BYTE,
+       DATA_TYPE_INT16,
+       DATA_TYPE_UINT16,
+       DATA_TYPE_INT32,
+       DATA_TYPE_UINT32,
+       DATA_TYPE_INT64,
+       DATA_TYPE_UINT64,
+       DATA_TYPE_STRING,
+       DATA_TYPE_BYTE_ARRAY,
+       DATA_TYPE_INT16_ARRAY,
+       DATA_TYPE_UINT16_ARRAY,
+       DATA_TYPE_INT32_ARRAY,
+       DATA_TYPE_UINT32_ARRAY,
+       DATA_TYPE_INT64_ARRAY,
+       DATA_TYPE_UINT64_ARRAY,
+       DATA_TYPE_STRING_ARRAY,
+       DATA_TYPE_HRTIME,
+       DATA_TYPE_NVLIST,
+       DATA_TYPE_NVLIST_ARRAY,
+       DATA_TYPE_BOOLEAN_VALUE,
+       DATA_TYPE_INT8,
+       DATA_TYPE_UINT8,
+       DATA_TYPE_BOOLEAN_ARRAY,
+       DATA_TYPE_INT8_ARRAY,
+#if !defined(_KERNEL)
+       DATA_TYPE_UINT8_ARRAY,
+       DATA_TYPE_DOUBLE
+#else
+       DATA_TYPE_UINT8_ARRAY
+#endif
+} data_type_t;
+
+typedef struct nvpair {
+       int32_t nvp_size;       /* size of this nvpair */
+       int16_t nvp_name_sz;    /* length of name string */
+       int16_t nvp_reserve;    /* not used */
+       int32_t nvp_value_elem; /* number of elements for array types */
+       data_type_t nvp_type;   /* type of value */
+       /* name string */
+       /* aligned ptr array for string arrays */
+       /* aligned array of data for value */
+} nvpair_t;
+
+/* nvlist header */
+typedef struct nvlist {
+       int32_t         nvl_version;
+       uint32_t        nvl_nvflag;     /* persistent flags */
+       uint64_t        nvl_priv;       /* ptr to private data if not packed */
+       uint32_t        nvl_flag;
+       int32_t         nvl_pad;        /* currently not used, for alignment */
+} nvlist_t;
+
+/* nvp implementation version */
+#define        NV_VERSION      0
+
+/* nvlist pack encoding */
+#define        NV_ENCODE_NATIVE        0
+#define        NV_ENCODE_XDR           1
+
+/* nvlist persistent unique name flags, stored in nvl_nvflags */
+#define        NV_UNIQUE_NAME          0x1
+#define        NV_UNIQUE_NAME_TYPE     0x2
+
+/* nvlist lookup pairs related flags */
+#define        NV_FLAG_NOENTOK         0x1
+
+/* convenience macros */
+#define        NV_ALIGN(x)             (((ulong_t)(x) + 7ul) & ~7ul)
+#define        NV_ALIGN4(x)            (((x) + 3) & ~3)
+
+#define        NVP_SIZE(nvp)           ((nvp)->nvp_size)
+#define        NVP_NAME(nvp)           ((char *)(nvp) + sizeof (nvpair_t))
+#define        NVP_TYPE(nvp)           ((nvp)->nvp_type)
+#define        NVP_NELEM(nvp)          ((nvp)->nvp_value_elem)
+#define        NVP_VALUE(nvp)          ((char *)(nvp) + NV_ALIGN(sizeof (nvpair_t) \
+                               + (nvp)->nvp_name_sz))
+
+#define        NVL_VERSION(nvl)        ((nvl)->nvl_version)
+#define        NVL_SIZE(nvl)           ((nvl)->nvl_size)
+#define        NVL_FLAG(nvl)           ((nvl)->nvl_flag)
+
+/* NV allocator framework */
+typedef struct nv_alloc_ops nv_alloc_ops_t;
+
+typedef struct nv_alloc {
+       const nv_alloc_ops_t *nva_ops;
+       void *nva_arg;
+} nv_alloc_t;
+
+struct nv_alloc_ops {
+       int (*nv_ao_init)(nv_alloc_t *, va_list);
+       void (*nv_ao_fini)(nv_alloc_t *);
+       void *(*nv_ao_alloc)(nv_alloc_t *, size_t);
+       void (*nv_ao_free)(nv_alloc_t *, void *, size_t);
+       void (*nv_ao_reset)(nv_alloc_t *);
+};
+
+extern const nv_alloc_ops_t *nv_fixed_ops;
+extern nv_alloc_t *nv_alloc_nosleep;
+
+#if defined(_KERNEL) && !defined(_BOOT)
+extern nv_alloc_t *nv_alloc_sleep;
+extern nv_alloc_t *nv_alloc_pushpage;
+#endif
+
+int nv_alloc_init(nv_alloc_t *, const nv_alloc_ops_t *, /* args */ ...);
+void nv_alloc_reset(nv_alloc_t *);
+void nv_alloc_fini(nv_alloc_t *);
+
+/* list management */
+int nvlist_alloc(nvlist_t **, uint_t, int);
+void nvlist_free(nvlist_t *);
+int nvlist_size(nvlist_t *, size_t *, int);
+int nvlist_pack(nvlist_t *, char **, size_t *, int, int);
+int nvlist_unpack(char *, size_t, nvlist_t **, int);
+int nvlist_dup(nvlist_t *, nvlist_t **, int);
+int nvlist_merge(nvlist_t *, nvlist_t *, int);
+
+uint_t nvlist_nvflag(nvlist_t *);
+
+int nvlist_xalloc(nvlist_t **, uint_t, nv_alloc_t *);
+int nvlist_xpack(nvlist_t *, char **, size_t *, int, nv_alloc_t *);
+int nvlist_xunpack(char *, size_t, nvlist_t **, nv_alloc_t *);
+int nvlist_xdup(nvlist_t *, nvlist_t **, nv_alloc_t *);
+nv_alloc_t *nvlist_lookup_nv_alloc(nvlist_t *);
+
+int nvlist_add_nvpair(nvlist_t *, nvpair_t *);
+int nvlist_add_boolean(nvlist_t *, const char *);
+int nvlist_add_boolean_value(nvlist_t *, const char *, boolean_t);
+int nvlist_add_byte(nvlist_t *, const char *, uchar_t);
+int nvlist_add_int8(nvlist_t *, const char *, int8_t);
+int nvlist_add_uint8(nvlist_t *, const char *, uint8_t);
+int nvlist_add_int16(nvlist_t *, const char *, int16_t);
+int nvlist_add_uint16(nvlist_t *, const char *, uint16_t);
+int nvlist_add_int32(nvlist_t *, const char *, int32_t);
+int nvlist_add_uint32(nvlist_t *, const char *, uint32_t);
+int nvlist_add_int64(nvlist_t *, const char *, int64_t);
+int nvlist_add_uint64(nvlist_t *, const char *, uint64_t);
+int nvlist_add_string(nvlist_t *, const char *, const char *);
+int nvlist_add_nvlist(nvlist_t *, const char *, nvlist_t *);
+int nvlist_add_boolean_array(nvlist_t *, const char *, boolean_t *, uint_t);
+int nvlist_add_byte_array(nvlist_t *, const char *, uchar_t *, uint_t);
+int nvlist_add_int8_array(nvlist_t *, const char *, int8_t *, uint_t);
+int nvlist_add_uint8_array(nvlist_t *, const char *, uint8_t *, uint_t);
+int nvlist_add_int16_array(nvlist_t *, const char *, int16_t *, uint_t);
+int nvlist_add_uint16_array(nvlist_t *, const char *, uint16_t *, uint_t);
+int nvlist_add_int32_array(nvlist_t *, const char *, int32_t *, uint_t);
+int nvlist_add_uint32_array(nvlist_t *, const char *, uint32_t *, uint_t);
+int nvlist_add_int64_array(nvlist_t *, const char *, int64_t *, uint_t);
+int nvlist_add_uint64_array(nvlist_t *, const char *, uint64_t *, uint_t);
+int nvlist_add_string_array(nvlist_t *, const char *, char *const *, uint_t);
+int nvlist_add_nvlist_array(nvlist_t *, const char *, nvlist_t **, uint_t);
+int nvlist_add_hrtime(nvlist_t *, const char *, hrtime_t);
+#if !defined(_KERNEL)
+int nvlist_add_double(nvlist_t *, const char *, double);
+#endif
+
+int nvlist_remove(nvlist_t *, const char *, data_type_t);
+int nvlist_remove_all(nvlist_t *, const char *);
+int nvlist_remove_nvpair(nvlist_t *, nvpair_t *);
+
+int nvlist_lookup_boolean(nvlist_t *, const char *);
+int nvlist_lookup_boolean_value(nvlist_t *, const char *, boolean_t *);
+int nvlist_lookup_byte(nvlist_t *, const char *, uchar_t *);
+int nvlist_lookup_int8(nvlist_t *, const char *, int8_t *);
+int nvlist_lookup_uint8(nvlist_t *, const char *, uint8_t *);
+int nvlist_lookup_int16(nvlist_t *, const char *, int16_t *);
+int nvlist_lookup_uint16(nvlist_t *, const char *, uint16_t *);
+int nvlist_lookup_int32(nvlist_t *, const char *, int32_t *);
+int nvlist_lookup_uint32(nvlist_t *, const char *, uint32_t *);
+int nvlist_lookup_int64(nvlist_t *, const char *, int64_t *);
+int nvlist_lookup_uint64(nvlist_t *, const char *, uint64_t *);
+int nvlist_lookup_string(nvlist_t *, const char *, char **);
+int nvlist_lookup_nvlist(nvlist_t *, const char *, nvlist_t **);
+int nvlist_lookup_boolean_array(nvlist_t *, const char *,
+    boolean_t **, uint_t *);
+int nvlist_lookup_byte_array(nvlist_t *, const char *, uchar_t **, uint_t *);
+int nvlist_lookup_int8_array(nvlist_t *, const char *, int8_t **, uint_t *);
+int nvlist_lookup_uint8_array(nvlist_t *, const char *, uint8_t **, uint_t *);
+int nvlist_lookup_int16_array(nvlist_t *, const char *, int16_t **, uint_t *);
+int nvlist_lookup_uint16_array(nvlist_t *, const char *, uint16_t **, uint_t *);
+int nvlist_lookup_int32_array(nvlist_t *, const char *, int32_t **, uint_t *);
+int nvlist_lookup_uint32_array(nvlist_t *, const char *, uint32_t **, uint_t *);
+int nvlist_lookup_int64_array(nvlist_t *, const char *, int64_t **, uint_t *);
+int nvlist_lookup_uint64_array(nvlist_t *, const char *, uint64_t **, uint_t *);
+int nvlist_lookup_string_array(nvlist_t *, const char *, char ***, uint_t *);
+int nvlist_lookup_nvlist_array(nvlist_t *, const char *,
+    nvlist_t ***, uint_t *);
+int nvlist_lookup_hrtime(nvlist_t *, const char *, hrtime_t *);
+int nvlist_lookup_pairs(nvlist_t *, int, ...);
+#if !defined(_KERNEL)
+int nvlist_lookup_double(nvlist_t *, const char *, double *);
+#endif
+
+int nvlist_lookup_nvpair(nvlist_t *, const char *, nvpair_t **);
+int nvlist_lookup_nvpair_embedded_index(nvlist_t *, const char *, nvpair_t **,
+    int *, char **);
+boolean_t nvlist_exists(nvlist_t *, const char *);
+boolean_t nvlist_empty(nvlist_t *);
+
+/* processing nvpair */
+nvpair_t *nvlist_next_nvpair(nvlist_t *, nvpair_t *);
+nvpair_t *nvlist_prev_nvpair(nvlist_t *, nvpair_t *);
+char *nvpair_name(nvpair_t *);
+data_type_t nvpair_type(nvpair_t *);
+int nvpair_type_is_array(nvpair_t *);
+int nvpair_value_boolean_value(nvpair_t *, boolean_t *);
+int nvpair_value_byte(nvpair_t *, uchar_t *);
+int nvpair_value_int8(nvpair_t *, int8_t *);
+int nvpair_value_uint8(nvpair_t *, uint8_t *);
+int nvpair_value_int16(nvpair_t *, int16_t *);
+int nvpair_value_uint16(nvpair_t *, uint16_t *);
+int nvpair_value_int32(nvpair_t *, int32_t *);
+int nvpair_value_uint32(nvpair_t *, uint32_t *);
+int nvpair_value_int64(nvpair_t *, int64_t *);
+int nvpair_value_uint64(nvpair_t *, uint64_t *);
+int nvpair_value_string(nvpair_t *, char **);
+int nvpair_value_nvlist(nvpair_t *, nvlist_t **);
+int nvpair_value_boolean_array(nvpair_t *, boolean_t **, uint_t *);
+int nvpair_value_byte_array(nvpair_t *, uchar_t **, uint_t *);
+int nvpair_value_int8_array(nvpair_t *, int8_t **, uint_t *);
+int nvpair_value_uint8_array(nvpair_t *, uint8_t **, uint_t *);
+int nvpair_value_int16_array(nvpair_t *, int16_t **, uint_t *);
+int nvpair_value_uint16_array(nvpair_t *, uint16_t **, uint_t *);
+int nvpair_value_int32_array(nvpair_t *, int32_t **, uint_t *);
+int nvpair_value_uint32_array(nvpair_t *, uint32_t **, uint_t *);
+int nvpair_value_int64_array(nvpair_t *, int64_t **, uint_t *);
+int nvpair_value_uint64_array(nvpair_t *, uint64_t **, uint_t *);
+int nvpair_value_string_array(nvpair_t *, char ***, uint_t *);
+int nvpair_value_nvlist_array(nvpair_t *, nvlist_t ***, uint_t *);
+int nvpair_value_hrtime(nvpair_t *, hrtime_t *);
+#if !defined(_KERNEL)
+int nvpair_value_double(nvpair_t *, double *);
+#endif
+
+nvlist_t *fnvlist_alloc(void);
+void fnvlist_free(nvlist_t *);
+size_t fnvlist_size(nvlist_t *);
+char *fnvlist_pack(nvlist_t *, size_t *);
+void fnvlist_pack_free(char *, size_t);
+nvlist_t *fnvlist_unpack(char *, size_t);
+nvlist_t *fnvlist_dup(nvlist_t *);
+void fnvlist_merge(nvlist_t *, nvlist_t *);
+size_t fnvlist_num_pairs(nvlist_t *);
+
+void fnvlist_add_boolean(nvlist_t *, const char *);
+void fnvlist_add_boolean_value(nvlist_t *, const char *, boolean_t);
+void fnvlist_add_byte(nvlist_t *, const char *, uchar_t);
+void fnvlist_add_int8(nvlist_t *, const char *, int8_t);
+void fnvlist_add_uint8(nvlist_t *, const char *, uint8_t);
+void fnvlist_add_int16(nvlist_t *, const char *, int16_t);
+void fnvlist_add_uint16(nvlist_t *, const char *, uint16_t);
+void fnvlist_add_int32(nvlist_t *, const char *, int32_t);
+void fnvlist_add_uint32(nvlist_t *, const char *, uint32_t);
+void fnvlist_add_int64(nvlist_t *, const char *, int64_t);
+void fnvlist_add_uint64(nvlist_t *, const char *, uint64_t);
+void fnvlist_add_string(nvlist_t *, const char *, const char *);
+void fnvlist_add_nvlist(nvlist_t *, const char *, nvlist_t *);
+void fnvlist_add_nvpair(nvlist_t *, nvpair_t *);
+void fnvlist_add_boolean_array(nvlist_t *, const char *, boolean_t *, uint_t);
+void fnvlist_add_byte_array(nvlist_t *, const char *, uchar_t *, uint_t);
+void fnvlist_add_int8_array(nvlist_t *, const char *, int8_t *, uint_t);
+void fnvlist_add_uint8_array(nvlist_t *, const char *, uint8_t *, uint_t);
+void fnvlist_add_int16_array(nvlist_t *, const char *, int16_t *, uint_t);
+void fnvlist_add_uint16_array(nvlist_t *, const char *, uint16_t *, uint_t);
+void fnvlist_add_int32_array(nvlist_t *, const char *, int32_t *, uint_t);
+void fnvlist_add_uint32_array(nvlist_t *, const char *, uint32_t *, uint_t);
+void fnvlist_add_int64_array(nvlist_t *, const char *, int64_t *, uint_t);
+void fnvlist_add_uint64_array(nvlist_t *, const char *, uint64_t *, uint_t);
+void fnvlist_add_string_array(nvlist_t *, const char *, char * const *, uint_t);
+void fnvlist_add_nvlist_array(nvlist_t *, const char *, nvlist_t **, uint_t);
+
+void fnvlist_remove(nvlist_t *, const char *);
+void fnvlist_remove_nvpair(nvlist_t *, nvpair_t *);
+
+nvpair_t *fnvlist_lookup_nvpair(nvlist_t *nvl, const char *name);
+boolean_t fnvlist_lookup_boolean(nvlist_t *nvl, const char *name);
+boolean_t fnvlist_lookup_boolean_value(nvlist_t *nvl, const char *name);
+uchar_t fnvlist_lookup_byte(nvlist_t *nvl, const char *name);
+int8_t fnvlist_lookup_int8(nvlist_t *nvl, const char *name);
+int16_t fnvlist_lookup_int16(nvlist_t *nvl, const char *name);
+int32_t fnvlist_lookup_int32(nvlist_t *nvl, const char *name);
+int64_t fnvlist_lookup_int64(nvlist_t *nvl, const char *name);
+uint8_t fnvlist_lookup_uint8(nvlist_t *nvl, const char *name);
+uint16_t fnvlist_lookup_uint16(nvlist_t *nvl, const char *name);
+uint32_t fnvlist_lookup_uint32(nvlist_t *nvl, const char *name);
+uint64_t fnvlist_lookup_uint64(nvlist_t *nvl, const char *name);
+char *fnvlist_lookup_string(nvlist_t *nvl, const char *name);
+nvlist_t *fnvlist_lookup_nvlist(nvlist_t *nvl, const char *name);
+
+boolean_t fnvpair_value_boolean_value(nvpair_t *nvp);
+uchar_t fnvpair_value_byte(nvpair_t *nvp);
+int8_t fnvpair_value_int8(nvpair_t *nvp);
+int16_t fnvpair_value_int16(nvpair_t *nvp);
+int32_t fnvpair_value_int32(nvpair_t *nvp);
+int64_t fnvpair_value_int64(nvpair_t *nvp);
+uint8_t fnvpair_value_uint8(nvpair_t *nvp);
+uint16_t fnvpair_value_uint16(nvpair_t *nvp);
+uint32_t fnvpair_value_uint32(nvpair_t *nvp);
+uint64_t fnvpair_value_uint64(nvpair_t *nvp);
+char *fnvpair_value_string(nvpair_t *nvp);
+nvlist_t *fnvpair_value_nvlist(nvpair_t *nvp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_NVPAIR_H */
diff --git a/zfs/include/sys/nvpair_impl.h b/zfs/include/sys/nvpair_impl.h
new file mode 100644 (file)
index 0000000..b851ddd
--- /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, 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        _NVPAIR_IMPL_H
+#define        _NVPAIR_IMPL_H
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/nvpair.h>
+
+/*
+ * The structures here provided for information and debugging purposes only
+ * may be changed in the future.
+ */
+
+/*
+ * implementation linked list for pre-packed data
+ */
+typedef struct i_nvp i_nvp_t;
+
+struct i_nvp {
+       union {
+               uint64_t        _nvi_align;     /* ensure alignment */
+               struct {
+                       i_nvp_t *_nvi_next;     /* pointer to next nvpair */
+                       i_nvp_t *_nvi_prev;     /* pointer to prev nvpair */
+               } _nvi;
+       } _nvi_un;
+       nvpair_t nvi_nvp;                       /* nvpair */
+};
+#define        nvi_next        _nvi_un._nvi._nvi_next
+#define        nvi_prev        _nvi_un._nvi._nvi_prev
+
+typedef struct {
+       i_nvp_t         *nvp_list;      /* linked list of nvpairs */
+       i_nvp_t         *nvp_last;      /* last nvpair */
+       i_nvp_t         *nvp_curr;      /* current walker nvpair */
+       nv_alloc_t      *nvp_nva;       /* pluggable allocator */
+       uint32_t        nvp_stat;       /* internal state */
+} nvpriv_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NVPAIR_IMPL_H */
diff --git a/zfs/include/sys/range_tree.h b/zfs/include/sys/range_tree.h
new file mode 100644 (file)
index 0000000..9f3ead5
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_RANGE_TREE_H
+#define        _SYS_RANGE_TREE_H
+
+#include <sys/avl.h>
+#include <sys/dmu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        RANGE_TREE_HISTOGRAM_SIZE       64
+
+typedef struct range_tree_ops range_tree_ops_t;
+
+typedef struct range_tree {
+       avl_tree_t      rt_root;        /* offset-ordered segment AVL tree */
+       uint64_t        rt_space;       /* sum of all segments in the map */
+       range_tree_ops_t *rt_ops;
+       void            *rt_arg;
+
+       /*
+        * The rt_histogram maintains a histogram of ranges. Each bucket,
+        * rt_histogram[i], contains the number of ranges whose size is:
+        * 2^i <= size of range in bytes < 2^(i+1)
+        */
+       uint64_t        rt_histogram[RANGE_TREE_HISTOGRAM_SIZE];
+       kmutex_t        *rt_lock;       /* pointer to lock that protects map */
+} range_tree_t;
+
+typedef struct range_seg {
+       avl_node_t      rs_node;        /* AVL node */
+       avl_node_t      rs_pp_node;     /* AVL picker-private node */
+       uint64_t        rs_start;       /* starting offset of this segment */
+       uint64_t        rs_end;         /* ending offset (non-inclusive) */
+} range_seg_t;
+
+struct range_tree_ops {
+       void    (*rtop_create)(range_tree_t *rt, void *arg);
+       void    (*rtop_destroy)(range_tree_t *rt, void *arg);
+       void    (*rtop_add)(range_tree_t *rt, range_seg_t *rs, void *arg);
+       void    (*rtop_remove)(range_tree_t *rt, range_seg_t *rs, void *arg);
+       void    (*rtop_vacate)(range_tree_t *rt, void *arg);
+};
+
+typedef void range_tree_func_t(void *arg, uint64_t start, uint64_t size);
+
+void range_tree_init(void);
+void range_tree_fini(void);
+range_tree_t *range_tree_create(range_tree_ops_t *ops, void *arg, kmutex_t *lp);
+void range_tree_destroy(range_tree_t *rt);
+boolean_t range_tree_contains(range_tree_t *rt, uint64_t start, uint64_t size);
+uint64_t range_tree_space(range_tree_t *rt);
+void range_tree_verify(range_tree_t *rt, uint64_t start, uint64_t size);
+void range_tree_swap(range_tree_t **rtsrc, range_tree_t **rtdst);
+void range_tree_stat_verify(range_tree_t *rt);
+
+void range_tree_add(void *arg, uint64_t start, uint64_t size);
+void range_tree_remove(void *arg, uint64_t start, uint64_t size);
+void range_tree_clear(range_tree_t *rt, uint64_t start, uint64_t size);
+
+void range_tree_vacate(range_tree_t *rt, range_tree_func_t *func, void *arg);
+void range_tree_walk(range_tree_t *rt, range_tree_func_t *func, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_RANGE_TREE_H */
diff --git a/zfs/include/sys/refcount.h b/zfs/include/sys/refcount.h
new file mode 100644 (file)
index 0000000..e767a23
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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        _SYS_REFCOUNT_H
+#define        _SYS_REFCOUNT_H
+
+#include <sys/inttypes.h>
+#include <sys/list.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * If the reference is held only by the calling function and not any
+ * particular object, use FTAG (which is a string) for the holder_tag.
+ * Otherwise, use the object that holds the reference.
+ */
+#define        FTAG ((char *)__func__)
+
+#ifdef ZFS_DEBUG
+typedef struct reference {
+       list_node_t ref_link;
+       void *ref_holder;
+       uint64_t ref_number;
+       uint8_t *ref_removed;
+} reference_t;
+
+typedef struct refcount {
+       kmutex_t rc_mtx;
+       boolean_t rc_tracked;
+       list_t rc_list;
+       list_t rc_removed;
+       int64_t rc_count;
+       int64_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_destroy(refcount_t *rc);
+void refcount_destroy_many(refcount_t *rc, uint64_t number);
+int refcount_is_zero(refcount_t *rc);
+int64_t refcount_count(refcount_t *rc);
+int64_t refcount_add(refcount_t *rc, void *holder_tag);
+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_init(void);
+void refcount_fini(void);
+
+#else  /* ZFS_DEBUG */
+
+typedef struct refcount {
+       uint64_t rc_count;
+} refcount_t;
+
+#define        refcount_create(rc) ((rc)->rc_count = 0)
+#define        refcount_create_untracked(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_many(rc, number, holder) \
+       atomic_add_64_nv(&(rc)->rc_count, number)
+#define        refcount_remove_many(rc, number, holder) \
+       atomic_add_64_nv(&(rc)->rc_count, -number)
+#define        refcount_transfer(dst, src) { \
+       uint64_t __tmp = (src)->rc_count; \
+       atomic_add_64(&(src)->rc_count, -__tmp); \
+       atomic_add_64(&(dst)->rc_count, __tmp); \
+}
+
+#define        refcount_init()
+#define        refcount_fini()
+
+#endif /* ZFS_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_REFCOUNT_H */
diff --git a/zfs/include/sys/rrwlock.h b/zfs/include/sys/rrwlock.h
new file mode 100644 (file)
index 0000000..7a328fd
--- /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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef        _SYS_RR_RW_LOCK_H
+#define        _SYS_RR_RW_LOCK_H
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/inttypes.h>
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+
+/*
+ * A reader-writer lock implementation that allows re-entrant reads, but
+ * still gives writers priority on "new" reads.
+ *
+ * See rrwlock.c for more details about the implementation.
+ *
+ * Fields of the rrwlock_t structure:
+ * - rr_lock: protects modification and reading of rrwlock_t fields
+ * - rr_cv: cv for waking up readers or waiting writers
+ * - rr_writer: thread id of the current writer
+ * - rr_anon_rount: number of active anonymous readers
+ * - rr_linked_rcount: total number of non-anonymous active readers
+ * - rr_writer_wanted: a writer wants the lock
+ */
+typedef struct rrwlock {
+       kmutex_t        rr_lock;
+       kcondvar_t      rr_cv;
+       kthread_t       *rr_writer;
+       refcount_t      rr_anon_rcount;
+       refcount_t      rr_linked_rcount;
+       boolean_t       rr_writer_wanted;
+       boolean_t       rr_track_all;
+} rrwlock_t;
+
+/*
+ * 'tag' is used in reference counting tracking.  The
+ * 'tag' must be the same in a rrw_enter() as in its
+ * corresponding rrw_exit().
+ */
+void rrw_init(rrwlock_t *rrl, boolean_t track_all);
+void rrw_destroy(rrwlock_t *rrl);
+void rrw_enter(rrwlock_t *rrl, krw_t rw, void *tag);
+void rrw_enter_read(rrwlock_t *rrl, void *tag);
+void rrw_enter_read_prio(rrwlock_t *rrl, void *tag);
+void rrw_enter_write(rrwlock_t *rrl);
+void rrw_exit(rrwlock_t *rrl, void *tag);
+boolean_t rrw_held(rrwlock_t *rrl, krw_t rw);
+void rrw_tsd_destroy(void *arg);
+
+#define        RRW_READ_HELD(x)        rrw_held(x, RW_READER)
+#define        RRW_WRITE_HELD(x)       rrw_held(x, RW_WRITER)
+#define        RRW_LOCK_HELD(x) \
+       (rrw_held(x, RW_WRITER) || rrw_held(x, RW_READER))
+
+/*
+ * A reader-mostly lock implementation, tuning above reader-writer locks
+ * for hightly parallel read acquisitions, pessimizing write acquisitions.
+ *
+ * This should be a prime number.  See comment in rrwlock.c near
+ * RRM_TD_LOCK() for details.
+ */
+#define        RRM_NUM_LOCKS           17
+typedef struct rrmlock {
+       rrwlock_t       locks[RRM_NUM_LOCKS];
+} rrmlock_t;
+
+void rrm_init(rrmlock_t *rrl, boolean_t track_all);
+void rrm_destroy(rrmlock_t *rrl);
+void rrm_enter(rrmlock_t *rrl, krw_t rw, void *tag);
+void rrm_enter_read(rrmlock_t *rrl, void *tag);
+void rrm_enter_write(rrmlock_t *rrl);
+void rrm_exit(rrmlock_t *rrl, void *tag);
+boolean_t rrm_held(rrmlock_t *rrl, krw_t rw);
+
+#define        RRM_READ_HELD(x)        rrm_held(x, RW_READER)
+#define        RRM_WRITE_HELD(x)       rrm_held(x, RW_WRITER)
+#define        RRM_LOCK_HELD(x) \
+       (rrm_held(x, RW_WRITER) || rrm_held(x, RW_READER))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_RR_RW_LOCK_H */
diff --git a/zfs/include/sys/sa.h b/zfs/include/sys/sa.h
new file mode 100644 (file)
index 0000000..01d2466
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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        _SYS_SA_H
+#define        _SYS_SA_H
+
+#include <sys/dmu.h>
+
+/*
+ * Currently available byteswap functions.
+ * If it all possible new attributes should used
+ * one of the already defined byteswap functions.
+ * If a new byteswap function is added then the
+ * ZPL/Pool version will need to be bumped.
+ */
+
+typedef enum sa_bswap_type {
+       SA_UINT64_ARRAY,
+       SA_UINT32_ARRAY,
+       SA_UINT16_ARRAY,
+       SA_UINT8_ARRAY,
+       SA_ACL,
+} sa_bswap_type_t;
+
+typedef uint16_t       sa_attr_type_t;
+
+/*
+ * Attribute to register support for.
+ */
+typedef struct sa_attr_reg {
+       char                    *sa_name;       /* attribute name */
+       uint16_t                sa_length;
+       sa_bswap_type_t         sa_byteswap;    /* bswap functon enum */
+       sa_attr_type_t          sa_attr; /* filled in during registration */
+} sa_attr_reg_t;
+
+
+typedef void (sa_data_locator_t)(void **, uint32_t *, uint32_t,
+    boolean_t, void *userptr);
+
+/*
+ * array of attributes to store.
+ *
+ * This array should be treated as opaque/private data.
+ * The SA_BULK_ADD_ATTR() macro should be used for manipulating
+ * the array.
+ *
+ * When sa_replace_all_by_template() is used the attributes
+ * will be stored in the order defined in the array, except that
+ * the attributes may be split between the bonus and the spill buffer
+ *
+ */
+typedef struct sa_bulk_attr {
+       void                    *sa_data;
+       sa_data_locator_t       *sa_data_func;
+       uint16_t                sa_length;
+       sa_attr_type_t          sa_attr;
+       /* the following are private to the sa framework */
+       void                    *sa_addr;
+       uint16_t                sa_buftype;
+       uint16_t                sa_size;
+} sa_bulk_attr_t;
+
+/*
+ * The on-disk format of sa_hdr_phys_t limits SA lengths to 16-bit values.
+ */
+#define        SA_ATTR_MAX_LEN UINT16_MAX
+
+/*
+ * special macro for adding entries for bulk attr support
+ * bulk - sa_bulk_attr_t
+ * count - integer that will be incremented during each add
+ * attr - attribute to manipulate
+ * func - function for accessing data.
+ * data - pointer to data.
+ * len - length of data
+ */
+
+#define        SA_ADD_BULK_ATTR(b, idx, attr, func, data, len) \
+{ \
+       ASSERT3U(len, <=, SA_ATTR_MAX_LEN); \
+       b[idx].sa_attr = attr;\
+       b[idx].sa_data_func = func; \
+       b[idx].sa_data = data; \
+       b[idx++].sa_length = len; \
+}
+
+typedef struct sa_os sa_os_t;
+
+typedef enum sa_handle_type {
+       SA_HDL_SHARED,
+       SA_HDL_PRIVATE
+} sa_handle_type_t;
+
+struct sa_handle;
+typedef void *sa_lookup_tab_t;
+typedef struct sa_handle sa_handle_t;
+
+typedef void (sa_update_cb_t)(sa_handle_t *, dmu_tx_t *tx);
+
+int sa_handle_get(objset_t *, uint64_t, void *userp,
+    sa_handle_type_t, sa_handle_t **);
+int sa_handle_get_from_db(objset_t *, dmu_buf_t *, void *userp,
+    sa_handle_type_t, sa_handle_t **);
+void sa_handle_destroy(sa_handle_t *);
+int sa_buf_hold(objset_t *, uint64_t, void *, dmu_buf_t **);
+void sa_buf_rele(dmu_buf_t *, void *);
+int sa_lookup(sa_handle_t *, sa_attr_type_t, void *buf, uint32_t buflen);
+int sa_update(sa_handle_t *, sa_attr_type_t, void *buf,
+    uint32_t buflen, dmu_tx_t *);
+int sa_remove(sa_handle_t *, sa_attr_type_t, dmu_tx_t *);
+int sa_bulk_lookup(sa_handle_t *, sa_bulk_attr_t *, int count);
+int sa_bulk_lookup_locked(sa_handle_t *, sa_bulk_attr_t *, int count);
+int sa_bulk_update(sa_handle_t *, sa_bulk_attr_t *, int count, dmu_tx_t *);
+int sa_size(sa_handle_t *, sa_attr_type_t, int *);
+int sa_update_from_cb(sa_handle_t *, sa_attr_type_t,
+    uint32_t buflen, sa_data_locator_t *, void *userdata, dmu_tx_t *);
+void sa_object_info(sa_handle_t *, dmu_object_info_t *);
+void sa_object_size(sa_handle_t *, uint32_t *, u_longlong_t *);
+void *sa_get_userdata(sa_handle_t *);
+void sa_set_userp(sa_handle_t *, void *);
+dmu_buf_t *sa_get_db(sa_handle_t *);
+uint64_t sa_handle_object(sa_handle_t *);
+boolean_t sa_attr_would_spill(sa_handle_t *, sa_attr_type_t, int size);
+void sa_spill_rele(sa_handle_t *);
+void sa_register_update_callback(objset_t *, sa_update_cb_t *);
+int sa_setup(objset_t *, uint64_t, sa_attr_reg_t *, int, sa_attr_type_t **);
+void sa_tear_down(objset_t *);
+int sa_replace_all_by_template(sa_handle_t *, sa_bulk_attr_t *,
+    int, dmu_tx_t *);
+int sa_replace_all_by_template_locked(sa_handle_t *, sa_bulk_attr_t *,
+    int, dmu_tx_t *);
+boolean_t sa_enabled(objset_t *);
+void sa_cache_init(void);
+void sa_cache_fini(void);
+int sa_set_sa_object(objset_t *, uint64_t);
+int sa_hdrsize(void *);
+void sa_handle_lock(sa_handle_t *);
+void sa_handle_unlock(sa_handle_t *);
+
+#ifdef _KERNEL
+int sa_lookup_uio(sa_handle_t *, sa_attr_type_t, uio_t *);
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SA_H */
diff --git a/zfs/include/sys/sa_impl.h b/zfs/include/sys/sa_impl.h
new file mode 100644 (file)
index 0000000..6f2f1db
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_SA_IMPL_H
+#define        _SYS_SA_IMPL_H
+
+#include <sys/dmu.h>
+#include <sys/refcount.h>
+#include <sys/list.h>
+
+/*
+ * Array of known attributes and their
+ * various characteristics.
+ */
+typedef struct sa_attr_table {
+       sa_attr_type_t  sa_attr;
+       uint8_t sa_registered;
+       uint16_t sa_length;
+       sa_bswap_type_t sa_byteswap;
+       char *sa_name;
+} sa_attr_table_t;
+
+/*
+ * Zap attribute format for attribute registration
+ *
+ * 64      56      48      40      32      24      16      8       0
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |        unused         |      len      | bswap |   attr num    |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * Zap attribute format for layout information.
+ *
+ * layout information is stored as an array of attribute numbers
+ * The name of the attribute is the layout number (0, 1, 2, ...)
+ *
+ * 16       0
+ * +---- ---+
+ * | attr # |
+ * +--------+
+ * | attr # |
+ * +--- ----+
+ *  ......
+ *
+ */
+
+#define        ATTR_BSWAP(x)   BF32_GET(x, 16, 8)
+#define        ATTR_LENGTH(x)  BF32_GET(x, 24, 16)
+#define        ATTR_NUM(x)     BF32_GET(x, 0, 16)
+#define        ATTR_ENCODE(x, attr, length, bswap) \
+{ \
+       BF64_SET(x, 24, 16, length); \
+       BF64_SET(x, 16, 8, bswap); \
+       BF64_SET(x, 0, 16, attr); \
+}
+
+#define        TOC_OFF(x)              BF32_GET(x, 0, 23)
+#define        TOC_ATTR_PRESENT(x)     BF32_GET(x, 31, 1)
+#define        TOC_LEN_IDX(x)          BF32_GET(x, 24, 4)
+#define        TOC_ATTR_ENCODE(x, len_idx, offset) \
+{ \
+       BF32_SET(x, 31, 1, 1); \
+       BF32_SET(x, 24, 7, len_idx); \
+       BF32_SET(x, 0, 24, offset); \
+}
+
+#define        SA_LAYOUTS      "LAYOUTS"
+#define        SA_REGISTRY     "REGISTRY"
+
+/*
+ * Each unique layout will have their own table
+ * sa_lot (layout_table)
+ */
+typedef struct sa_lot {
+       avl_node_t lot_num_node;
+       avl_node_t lot_hash_node;
+       uint64_t lot_num;
+       uint64_t lot_hash;
+       sa_attr_type_t *lot_attrs;      /* array of attr #'s */
+       uint32_t lot_var_sizes; /* how many aren't fixed size */
+       uint32_t lot_attr_count;        /* total attr count */
+       list_t  lot_idx_tab;    /* should be only a couple of entries */
+       int     lot_instance;   /* used with lot_hash to identify entry */
+} sa_lot_t;
+
+/* index table of offsets */
+typedef struct sa_idx_tab {
+       list_node_t     sa_next;
+       sa_lot_t        *sa_layout;
+       uint16_t        *sa_variable_lengths;
+       refcount_t      sa_refcount;
+       uint32_t        *sa_idx_tab;    /* array of offsets */
+} sa_idx_tab_t;
+
+/*
+ * Since the offset/index information into the actual data
+ * will usually be identical we can share that information with
+ * all handles that have the exact same offsets.
+ *
+ * You would typically only have a large number of different table of
+ * contents if you had a several variable sized attributes.
+ *
+ * Two AVL trees are used to track the attribute layout numbers.
+ * one is keyed by number and will be consulted when a DMU_OT_SA
+ * object is first read.  The second tree is keyed by the hash signature
+ * of the attributes and will be consulted when an attribute is added
+ * to determine if we already have an instance of that layout.  Both
+ * of these tree's are interconnected.  The only difference is that
+ * when an entry is found in the "hash" tree the list of attributes will
+ * need to be compared against the list of attributes you have in hand.
+ * The assumption is that typically attributes will just be updated and
+ * adding a completely new attribute is a very rare operation.
+ */
+struct sa_os {
+       kmutex_t        sa_lock;
+       boolean_t       sa_need_attr_registration;
+       boolean_t       sa_force_spill;
+       uint64_t        sa_master_obj;
+       uint64_t        sa_reg_attr_obj;
+       uint64_t        sa_layout_attr_obj;
+       int             sa_num_attrs;
+       sa_attr_table_t *sa_attr_table;  /* private attr table */
+       sa_update_cb_t  *sa_update_cb;
+       avl_tree_t      sa_layout_num_tree;  /* keyed by layout number */
+       avl_tree_t      sa_layout_hash_tree; /* keyed by layout hash value */
+       int             sa_user_table_sz;
+       sa_attr_type_t  *sa_user_table; /* user name->attr mapping table */
+};
+
+/*
+ * header for all bonus and spill buffers.
+ *
+ * The header has a fixed portion with a variable number
+ * of "lengths" depending on the number of variable sized
+ * attributes which are determined by the "layout number"
+ */
+
+#define        SA_MAGIC        0x2F505A  /* ZFS SA */
+typedef struct sa_hdr_phys {
+       uint32_t sa_magic;
+       /*
+        * Encoded with hdrsize and layout number as follows:
+        * 16      10       0
+        * +--------+-------+
+        * | hdrsz  |layout |
+        * +--------+-------+
+        *
+        * Bits 0-10 are the layout number
+        * Bits 11-16 are the size of the header.
+        * The hdrsize is the number * 8
+        *
+        * For example.
+        * hdrsz of 1 ==> 8 byte header
+        *          2 ==> 16 byte header
+        *
+        */
+       uint16_t sa_layout_info;
+       uint16_t sa_lengths[1]; /* optional sizes for variable length attrs */
+       /* ... Data follows the lengths.  */
+} sa_hdr_phys_t;
+
+#define        SA_HDR_LAYOUT_NUM(hdr) BF32_GET(hdr->sa_layout_info, 0, 10)
+#define        SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 6, 3, 0)
+#define        SA_HDR_LAYOUT_INFO_ENCODE(x, num, size) \
+{ \
+       BF32_SET_SB(x, 10, 6, 3, 0, size); \
+       BF32_SET(x, 0, 10, num); \
+}
+
+typedef enum sa_buf_type {
+       SA_BONUS = 1,
+       SA_SPILL = 2
+} sa_buf_type_t;
+
+typedef enum sa_data_op {
+       SA_LOOKUP,
+       SA_UPDATE,
+       SA_ADD,
+       SA_REPLACE,
+       SA_REMOVE
+} sa_data_op_t;
+
+/*
+ * Opaque handle used for most sa functions
+ *
+ * This needs to be kept as small as possible.
+ */
+
+struct sa_handle {
+       dmu_buf_user_t  sa_dbu;
+       kmutex_t        sa_lock;
+       dmu_buf_t       *sa_bonus;
+       dmu_buf_t       *sa_spill;
+       objset_t        *sa_os;
+       void            *sa_userp;
+       sa_idx_tab_t    *sa_bonus_tab;   /* idx of bonus */
+       sa_idx_tab_t    *sa_spill_tab; /* only present if spill activated */
+};
+
+#define        SA_GET_DB(hdl, type)    \
+       (dmu_buf_impl_t *)((type == SA_BONUS) ? hdl->sa_bonus : hdl->sa_spill)
+
+#define        SA_GET_HDR(hdl, type) \
+       ((sa_hdr_phys_t *)((dmu_buf_impl_t *)(SA_GET_DB(hdl, \
+       type))->db.db_data))
+
+#define        SA_IDX_TAB_GET(hdl, type) \
+       (type == SA_BONUS ? hdl->sa_bonus_tab : hdl->sa_spill_tab)
+
+#define        IS_SA_BONUSTYPE(a)      \
+       ((a == DMU_OT_SA) ? B_TRUE : B_FALSE)
+
+#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_LAYOUT_NUM(x, type) \
+       ((!IS_SA_BONUSTYPE(type) ? 0 : (((IS_SA_BONUSTYPE(type)) && \
+       ((SA_HDR_LAYOUT_NUM(x)) == 0)) ? 1 : SA_HDR_LAYOUT_NUM(x))))
+
+
+#define        SA_REGISTERED_LEN(sa, attr) sa->sa_attr_table[attr].sa_length
+
+#define        SA_ATTR_LEN(sa, idx, attr, hdr) ((SA_REGISTERED_LEN(sa, attr) == 0) ?\
+       hdr->sa_lengths[TOC_LEN_IDX(idx->sa_idx_tab[attr])] : \
+       SA_REGISTERED_LEN(sa, attr))
+
+#define        SA_SET_HDR(hdr, num, size) \
+       { \
+               hdr->sa_magic = SA_MAGIC; \
+               SA_HDR_LAYOUT_INFO_ENCODE(hdr->sa_layout_info, num, size); \
+       }
+
+#define        SA_ATTR_INFO(sa, idx, hdr, attr, bulk, type, hdl) \
+       { \
+               bulk.sa_size = SA_ATTR_LEN(sa, idx, attr, hdr); \
+               bulk.sa_buftype = type; \
+               bulk.sa_addr = \
+                   (void *)((uintptr_t)TOC_OFF(idx->sa_idx_tab[attr]) + \
+                   (uintptr_t)hdr); \
+}
+
+#define        SA_HDR_SIZE_MATCH_LAYOUT(hdr, tb) \
+       (SA_HDR_SIZE(hdr) == (sizeof (sa_hdr_phys_t) + \
+       (tb->lot_var_sizes > 1 ? P2ROUNDUP((tb->lot_var_sizes - 1) * \
+       sizeof (uint16_t), 8) : 0)))
+
+int sa_add_impl(sa_handle_t *, sa_attr_type_t,
+    uint32_t, sa_data_locator_t, void *, dmu_tx_t *);
+
+void sa_register_update_callback_locked(objset_t *, sa_update_cb_t *);
+int sa_size_locked(sa_handle_t *, sa_attr_type_t, int *);
+
+void sa_default_locator(void **, uint32_t *, uint32_t, boolean_t, void *);
+int sa_attr_size(sa_os_t *, sa_idx_tab_t *, sa_attr_type_t,
+    uint16_t *, sa_hdr_phys_t *);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SA_IMPL_H */
diff --git a/zfs/include/sys/sdt.h b/zfs/include/sys/sdt.h
new file mode 100644 (file)
index 0000000..56efa1b
--- /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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SDT_H
+#define        _SYS_SDT_H
+
+#ifndef _KERNEL
+
+#define        ZFS_PROBE(a)                    ((void) 0)
+#define        ZFS_PROBE1(a, c)                ((void) 0)
+#define        ZFS_PROBE2(a, c, e)             ((void) 0)
+#define        ZFS_PROBE3(a, c, e, g)          ((void) 0)
+#define        ZFS_PROBE4(a, c, e, g, i)       ((void) 0)
+#define        ZFS_SET_ERROR(err)              ((void) 0)
+
+#else
+
+#if defined(HAVE_DECLARE_EVENT_CLASS)
+
+#include <sys/trace.h>
+
+/*
+ * The set-error SDT probe is extra static, in that we declare its fake
+ * function literally, rather than with the DTRACE_PROBE1() macro.  This is
+ * necessary so that SET_ERROR() can evaluate to a value, which wouldn't
+ * be possible if it required multiple statements (to declare the function
+ * and then call it).
+ *
+ * SET_ERROR() uses the comma operator so that it can be used without much
+ * additional code.  For example, "return (EINVAL);" becomes
+ * "return (SET_ERROR(EINVAL));".  Note that the argument will be evaluated
+ * twice, so it should not have side effects (e.g. something like:
+ * "return (SET_ERROR(log_error(EINVAL, info)));" would log the error twice).
+ */
+#define        SET_ERROR(err) \
+       (trace_zfs_set__error(__FILE__, __func__, __LINE__, err), err)
+
+#else
+
+#undef SET_ERROR
+#define        SET_ERROR(err) (err)
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+
+#endif /* _KERNEL */
+
+#endif /* _SYS_SDT_H */
diff --git a/zfs/include/sys/spa.h b/zfs/include/sys/spa.h
new file mode 100644 (file)
index 0000000..bfd2e79
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef _SYS_SPA_H
+#define        _SYS_SPA_H
+
+#include <sys/avl.h>
+#include <sys/zfs_context.h>
+#include <sys/kstat.h>
+#include <sys/nvpair.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Forward references that lots of things need.
+ */
+typedef struct spa spa_t;
+typedef struct vdev vdev_t;
+typedef struct metaslab metaslab_t;
+typedef struct metaslab_group metaslab_group_t;
+typedef struct metaslab_class metaslab_class_t;
+typedef struct zio zio_t;
+typedef struct zilog zilog_t;
+typedef struct spa_aux_vdev spa_aux_vdev_t;
+typedef struct ddt ddt_t;
+typedef struct ddt_entry ddt_entry_t;
+typedef struct zbookmark_phys zbookmark_phys_t;
+
+struct dsl_pool;
+struct dsl_dataset;
+
+/*
+ * General-purpose 32-bit and 64-bit bitfield encodings.
+ */
+#define        BF32_DECODE(x, low, len)        P2PHASE((x) >> (low), 1U << (len))
+#define        BF64_DECODE(x, low, len)        P2PHASE((x) >> (low), 1ULL << (len))
+#define        BF32_ENCODE(x, low, len)        (P2PHASE((x), 1U << (len)) << (low))
+#define        BF64_ENCODE(x, low, len)        (P2PHASE((x), 1ULL << (len)) << (low))
+
+#define        BF32_GET(x, low, len)           BF32_DECODE(x, low, len)
+#define        BF64_GET(x, low, len)           BF64_DECODE(x, low, len)
+
+#define        BF32_SET(x, low, len, val) do { \
+       ASSERT3U(val, <, 1U << (len)); \
+       ASSERT3U(low + len, <=, 32); \
+       (x) ^= BF32_ENCODE((x >> low) ^ (val), low, len); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        BF64_SET(x, low, len, val) do { \
+       ASSERT3U(val, <, 1ULL << (len)); \
+       ASSERT3U(low + len, <=, 64); \
+       ((x) ^= BF64_ENCODE((x >> low) ^ (val), low, len)); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        BF32_GET_SB(x, low, len, shift, bias)   \
+       ((BF32_GET(x, low, len) + (bias)) << (shift))
+#define        BF64_GET_SB(x, low, len, shift, bias)   \
+       ((BF64_GET(x, low, len) + (bias)) << (shift))
+
+#define        BF32_SET_SB(x, low, len, shift, bias, val) do { \
+       ASSERT(IS_P2ALIGNED(val, 1U << shift)); \
+       ASSERT3S((val) >> (shift), >=, bias); \
+       BF32_SET(x, low, len, ((val) >> (shift)) - (bias)); \
+_NOTE(CONSTCOND) } while (0)
+#define        BF64_SET_SB(x, low, len, shift, bias, val) do { \
+       ASSERT(IS_P2ALIGNED(val, 1ULL << shift)); \
+       ASSERT3S((val) >> (shift), >=, bias); \
+       BF64_SET(x, low, len, ((val) >> (shift)) - (bias)); \
+_NOTE(CONSTCOND) } while (0)
+
+/*
+ * 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, and the
+ * large latency of reading or writing a large block.
+ *
+ * Note that although blocks up to 16MB are supported, the recordsize
+ * property can not be set larger than zfs_max_recordsize (default 1MB).
+ * See the comment near zfs_max_recordsize in dsl_dataset.c for details.
+ *
+ * Note that although the LSIZE field of the blkptr_t can store sizes up
+ * to 32MB, the dnode's dn_datablkszsec can only store sizes up to
+ * 32MB - 512 bytes.  Therefore, we limit SPA_MAXBLOCKSIZE to 16MB.
+ */
+#define        SPA_MINBLOCKSHIFT       9
+#define        SPA_OLD_MAXBLOCKSHIFT   17
+#define        SPA_MAXBLOCKSHIFT       24
+#define        SPA_MINBLOCKSIZE        (1ULL << SPA_MINBLOCKSHIFT)
+#define        SPA_OLD_MAXBLOCKSIZE    (1ULL << SPA_OLD_MAXBLOCKSHIFT)
+#define        SPA_MAXBLOCKSIZE        (1ULL << SPA_MAXBLOCKSHIFT)
+
+/*
+ * Size of block to hold the configuration data (a packed nvlist)
+ */
+#define        SPA_CONFIG_BLOCKSIZE    (1ULL << 14)
+
+/*
+ * The DVA size encodings for LSIZE and PSIZE support blocks up to 32MB.
+ * The ASIZE encoding should be at least 64 times larger (6 more bits)
+ * to support up to 4-way RAID-Z mirror mode with worst-case gang block
+ * overhead, three DVAs per bp, plus one more bit in case we do anything
+ * else that expands the ASIZE.
+ */
+#define        SPA_LSIZEBITS           16      /* LSIZE up to 32M (2^16 * 512) */
+#define        SPA_PSIZEBITS           16      /* PSIZE up to 32M (2^16 * 512) */
+#define        SPA_ASIZEBITS           24      /* ASIZE up to 64 times larger  */
+
+/*
+ * 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.
+ */
+typedef struct dva {
+       uint64_t        dva_word[2];
+} dva_t;
+
+/*
+ * Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
+ */
+typedef struct zio_cksum {
+       uint64_t        zc_word[4];
+} zio_cksum_t;
+
+/*
+ * Each block is described by its DVAs, time of birth, checksum, etc.
+ * The word-by-word, bit-by-bit layout of the blkptr is as follows:
+ *
+ *     64      56      48      40      32      24      16      8       0
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 0   |               vdev1           | GRID  |         ASIZE         |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 1   |G|                      offset1                                |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 2   |               vdev2           | GRID  |         ASIZE         |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 3   |G|                      offset2                                |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 4   |               vdev3           | GRID  |         ASIZE         |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 5   |G|                      offset3                                |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 6   |BDX|lvl| type  | cksum |E| comp|    PSIZE      |     LSIZE     |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 7   |                       padding                                 |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 8   |                       padding                                 |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 9   |                       physical birth txg                      |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * a   |                       logical birth txg                       |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * b   |                       fill count                              |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * c   |                       checksum[0]                             |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * d   |                       checksum[1]                             |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * e   |                       checksum[2]                             |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * f   |                       checksum[3]                             |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * Legend:
+ *
+ * vdev                virtual device ID
+ * offset      offset into virtual device
+ * LSIZE       logical size
+ * PSIZE       physical size (after compression)
+ * ASIZE       allocated size (including RAID-Z parity and gang block headers)
+ * GRID                RAID-Z layout information (reserved for future use)
+ * cksum       checksum function
+ * comp                compression function
+ * G           gang block indicator
+ * B           byteorder (endianness)
+ * D           dedup
+ * X           encryption (on version 30, which is not supported)
+ * E           blkptr_t contains embedded data (see below)
+ * lvl         level of indirection
+ * type                DMU object type
+ * phys birth  txg of block allocation; zero if same as logical birth txg
+ * log. birth  transaction group in which the block was logically born
+ * fill count  number of non-zero blocks under this bp
+ * checksum[4] 256-bit checksum of the data this bp describes
+ */
+
+/*
+ * "Embedded" blkptr_t's don't actually point to a block, instead they
+ * have a data payload embedded in the blkptr_t itself.  See the comment
+ * in blkptr.c for more details.
+ *
+ * The blkptr_t is laid out as follows:
+ *
+ *     64      56      48      40      32      24      16      8       0
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 0   |      payload                                                  |
+ * 1   |      payload                                                  |
+ * 2   |      payload                                                  |
+ * 3   |      payload                                                  |
+ * 4   |      payload                                                  |
+ * 5   |      payload                                                  |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 6   |BDX|lvl| type  | etype |E| comp| PSIZE|              LSIZE     |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * 7   |      payload                                                  |
+ * 8   |      payload                                                  |
+ * 9   |      payload                                                  |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * a   |                       logical birth txg                       |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ * b   |      payload                                                  |
+ * c   |      payload                                                  |
+ * d   |      payload                                                  |
+ * e   |      payload                                                  |
+ * f   |      payload                                                  |
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * Legend:
+ *
+ * payload             contains the embedded data
+ * B (byteorder)       byteorder (endianness)
+ * D (dedup)           padding (set to zero)
+ * X                   encryption (set to zero; see above)
+ * E (embedded)                set to one
+ * lvl                 indirection level
+ * type                        DMU object type
+ * etype               how to interpret embedded data (BP_EMBEDDED_TYPE_*)
+ * comp                        compression function of payload
+ * PSIZE               size of payload after compression, in bytes
+ * LSIZE               logical size of payload, in bytes
+ *                     note that 25 bits is enough to store the largest
+ *                     "normal" BP's LSIZE (2^16 * 2^9) in bytes
+ * log. birth          transaction group in which the block was logically born
+ *
+ * Note that LSIZE and PSIZE are stored in bytes, whereas for non-embedded
+ * bp's they are stored in units of SPA_MINBLOCKSHIFT.
+ * Generally, the generic BP_GET_*() macros can be used on embedded BP's.
+ * The B, D, X, lvl, type, and comp fields are stored the same as with normal
+ * BP's so the BP_SET_* macros can be used with them.  etype, PSIZE, LSIZE must
+ * be set with the BPE_SET_* macros.  BP_SET_EMBEDDED() should be called before
+ * other macros, as they assert that they are only used on BP's of the correct
+ * "embedded-ness".
+ */
+
+#define        BPE_GET_ETYPE(bp)       \
+       (ASSERT(BP_IS_EMBEDDED(bp)), \
+       BF64_GET((bp)->blk_prop, 40, 8))
+#define        BPE_SET_ETYPE(bp, t)    do { \
+       ASSERT(BP_IS_EMBEDDED(bp)); \
+       BF64_SET((bp)->blk_prop, 40, 8, t); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        BPE_GET_LSIZE(bp)       \
+       (ASSERT(BP_IS_EMBEDDED(bp)), \
+       BF64_GET_SB((bp)->blk_prop, 0, 25, 0, 1))
+#define        BPE_SET_LSIZE(bp, x)    do { \
+       ASSERT(BP_IS_EMBEDDED(bp)); \
+       BF64_SET_SB((bp)->blk_prop, 0, 25, 0, 1, x); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        BPE_GET_PSIZE(bp)       \
+       (ASSERT(BP_IS_EMBEDDED(bp)), \
+       BF64_GET_SB((bp)->blk_prop, 25, 7, 0, 1))
+#define        BPE_SET_PSIZE(bp, x)    do { \
+       ASSERT(BP_IS_EMBEDDED(bp)); \
+       BF64_SET_SB((bp)->blk_prop, 25, 7, 0, 1, x); \
+_NOTE(CONSTCOND) } while (0)
+
+typedef enum bp_embedded_type {
+       BP_EMBEDDED_TYPE_DATA,
+       BP_EMBEDDED_TYPE_RESERVED, /* Reserved for an unintegrated feature. */
+       NUM_BP_EMBEDDED_TYPES = BP_EMBEDDED_TYPE_RESERVED
+} bp_embedded_type_t;
+
+#define        BPE_NUM_WORDS 14
+#define        BPE_PAYLOAD_SIZE (BPE_NUM_WORDS * sizeof (uint64_t))
+#define        BPE_IS_PAYLOADWORD(bp, wp) \
+       ((wp) != &(bp)->blk_prop && (wp) != &(bp)->blk_birth)
+
+#define        SPA_BLKPTRSHIFT 7               /* blkptr_t is 128 bytes        */
+#define        SPA_DVAS_PER_BP 3               /* Number of DVAs in a bp       */
+
+/*
+ * A block is a hole when it has either 1) never been written to, or
+ * 2) is zero-filled. In both cases, ZFS can return all zeroes for all reads
+ * without physically allocating disk space. Holes are represented in the
+ * blkptr_t structure by zeroed blk_dva. Correct checking for holes is
+ * done through the BP_IS_HOLE macro. For holes, the logical size, level,
+ * DMU object type, and birth times are all also stored for holes that
+ * were written to at some point (i.e. were punched after having been filled).
+ */
+typedef struct blkptr {
+       dva_t           blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */
+       uint64_t        blk_prop;       /* size, compression, type, etc     */
+       uint64_t        blk_pad[2];     /* Extra space for the future       */
+       uint64_t        blk_phys_birth; /* txg when block was allocated     */
+       uint64_t        blk_birth;      /* transaction group at birth       */
+       uint64_t        blk_fill;       /* fill count                       */
+       zio_cksum_t     blk_cksum;      /* 256-bit checksum                 */
+} blkptr_t;
+
+/*
+ * Macros to get and set fields in a bp or DVA.
+ */
+#define        DVA_GET_ASIZE(dva)      \
+       BF64_GET_SB((dva)->dva_word[0], 0, SPA_ASIZEBITS, SPA_MINBLOCKSHIFT, 0)
+#define        DVA_SET_ASIZE(dva, x)   \
+       BF64_SET_SB((dva)->dva_word[0], 0, SPA_ASIZEBITS, \
+       SPA_MINBLOCKSHIFT, 0, x)
+
+#define        DVA_GET_GRID(dva)       BF64_GET((dva)->dva_word[0], 24, 8)
+#define        DVA_SET_GRID(dva, x)    BF64_SET((dva)->dva_word[0], 24, 8, x)
+
+#define        DVA_GET_VDEV(dva)       BF64_GET((dva)->dva_word[0], 32, 32)
+#define        DVA_SET_VDEV(dva, x)    BF64_SET((dva)->dva_word[0], 32, 32, x)
+
+#define        DVA_GET_OFFSET(dva)     \
+       BF64_GET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0)
+#define        DVA_SET_OFFSET(dva, x)  \
+       BF64_SET_SB((dva)->dva_word[1], 0, 63, SPA_MINBLOCKSHIFT, 0, x)
+
+#define        DVA_GET_GANG(dva)       BF64_GET((dva)->dva_word[1], 63, 1)
+#define        DVA_SET_GANG(dva, x)    BF64_SET((dva)->dva_word[1], 63, 1, x)
+
+#define        BP_GET_LSIZE(bp)        \
+       (BP_IS_EMBEDDED(bp) ?   \
+       (BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA ? BPE_GET_LSIZE(bp) : 0): \
+       BF64_GET_SB((bp)->blk_prop, 0, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1))
+#define        BP_SET_LSIZE(bp, x)     do { \
+       ASSERT(!BP_IS_EMBEDDED(bp)); \
+       BF64_SET_SB((bp)->blk_prop, \
+           0, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1, x); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        BP_GET_PSIZE(bp)        \
+       (BP_IS_EMBEDDED(bp) ? 0 : \
+       BF64_GET_SB((bp)->blk_prop, 16, SPA_PSIZEBITS, SPA_MINBLOCKSHIFT, 1))
+#define        BP_SET_PSIZE(bp, x)     do { \
+       ASSERT(!BP_IS_EMBEDDED(bp)); \
+       BF64_SET_SB((bp)->blk_prop, \
+           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_IS_EMBEDDED(bp)              BF64_GET((bp)->blk_prop, 39, 1)
+#define        BP_SET_EMBEDDED(bp, x)          BF64_SET((bp)->blk_prop, 39, 1, x)
+
+#define        BP_GET_CHECKSUM(bp)             \
+       (BP_IS_EMBEDDED(bp) ? ZIO_CHECKSUM_OFF : \
+       BF64_GET((bp)->blk_prop, 40, 8))
+#define        BP_SET_CHECKSUM(bp, x)          do { \
+       ASSERT(!BP_IS_EMBEDDED(bp)); \
+       BF64_SET((bp)->blk_prop, 40, 8, x); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        BP_GET_TYPE(bp)                 BF64_GET((bp)->blk_prop, 48, 8)
+#define        BP_SET_TYPE(bp, x)              BF64_SET((bp)->blk_prop, 48, 8, x)
+
+#define        BP_GET_LEVEL(bp)                BF64_GET((bp)->blk_prop, 56, 5)
+#define        BP_SET_LEVEL(bp, x)             BF64_SET((bp)->blk_prop, 56, 5, x)
+
+#define        BP_GET_DEDUP(bp)                BF64_GET((bp)->blk_prop, 62, 1)
+#define        BP_SET_DEDUP(bp, x)             BF64_SET((bp)->blk_prop, 62, 1, x)
+
+#define        BP_GET_BYTEORDER(bp)            BF64_GET((bp)->blk_prop, 63, 1)
+#define        BP_SET_BYTEORDER(bp, x)         BF64_SET((bp)->blk_prop, 63, 1, x)
+
+#define        BP_PHYSICAL_BIRTH(bp)           \
+       (BP_IS_EMBEDDED(bp) ? 0 : \
+       (bp)->blk_phys_birth ? (bp)->blk_phys_birth : (bp)->blk_birth)
+
+#define        BP_SET_BIRTH(bp, logical, physical)     \
+{                                              \
+       ASSERT(!BP_IS_EMBEDDED(bp));            \
+       (bp)->blk_birth = (logical);            \
+       (bp)->blk_phys_birth = ((logical) == (physical) ? 0 : (physical)); \
+}
+
+#define        BP_GET_FILL(bp) (BP_IS_EMBEDDED(bp) ? 1 : (bp)->blk_fill)
+
+#define        BP_GET_ASIZE(bp)        \
+       (BP_IS_EMBEDDED(bp) ? 0 : \
+       DVA_GET_ASIZE(&(bp)->blk_dva[0]) + \
+       DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \
+       DVA_GET_ASIZE(&(bp)->blk_dva[2]))
+
+#define        BP_GET_UCSIZE(bp) \
+       ((BP_GET_LEVEL(bp) > 0 || DMU_OT_IS_METADATA(BP_GET_TYPE(bp))) ? \
+       BP_GET_PSIZE(bp) : BP_GET_LSIZE(bp))
+
+#define        BP_GET_NDVAS(bp)        \
+       (BP_IS_EMBEDDED(bp) ? 0 : \
+       !!DVA_GET_ASIZE(&(bp)->blk_dva[0]) + \
+       !!DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \
+       !!DVA_GET_ASIZE(&(bp)->blk_dva[2]))
+
+#define        BP_COUNT_GANG(bp)       \
+       (BP_IS_EMBEDDED(bp) ? 0 : \
+       (DVA_GET_GANG(&(bp)->blk_dva[0]) + \
+       DVA_GET_GANG(&(bp)->blk_dva[1]) + \
+       DVA_GET_GANG(&(bp)->blk_dva[2])))
+
+#define        DVA_EQUAL(dva1, dva2)   \
+       ((dva1)->dva_word[1] == (dva2)->dva_word[1] && \
+       (dva1)->dva_word[0] == (dva2)->dva_word[0])
+
+#define        BP_EQUAL(bp1, bp2)      \
+       (BP_PHYSICAL_BIRTH(bp1) == BP_PHYSICAL_BIRTH(bp2) &&    \
+       (bp1)->blk_birth == (bp2)->blk_birth &&                 \
+       DVA_EQUAL(&(bp1)->blk_dva[0], &(bp2)->blk_dva[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)))
+#define        DVA_IS_EMPTY(dva)       ((dva)->dva_word[0] == 0ULL &&  \
+                               (dva)->dva_word[1] == 0ULL)
+#define        BP_IS_HOLE(bp) \
+       (!BP_IS_EMBEDDED(bp) && DVA_IS_EMPTY(BP_IDENTITY(bp)))
+
+/* BP_IS_RAIDZ(bp) assumes no block compression */
+#define        BP_IS_RAIDZ(bp)         (DVA_GET_ASIZE(&(bp)->blk_dva[0]) > \
+                               BP_GET_PSIZE(bp))
+
+#define        BP_ZERO(bp)                             \
+{                                              \
+       (bp)->blk_dva[0].dva_word[0] = 0;       \
+       (bp)->blk_dva[0].dva_word[1] = 0;       \
+       (bp)->blk_dva[1].dva_word[0] = 0;       \
+       (bp)->blk_dva[1].dva_word[1] = 0;       \
+       (bp)->blk_dva[2].dva_word[0] = 0;       \
+       (bp)->blk_dva[2].dva_word[1] = 0;       \
+       (bp)->blk_prop = 0;                     \
+       (bp)->blk_pad[0] = 0;                   \
+       (bp)->blk_pad[1] = 0;                   \
+       (bp)->blk_phys_birth = 0;               \
+       (bp)->blk_birth = 0;                    \
+       (bp)->blk_fill = 0;                     \
+       ZIO_SET_CHECKSUM(&(bp)->blk_cksum, 0, 0, 0, 0); \
+}
+
+#ifdef _BIG_ENDIAN
+#define        ZFS_HOST_BYTEORDER      (0ULL)
+#else
+#define        ZFS_HOST_BYTEORDER      (1ULL)
+#endif
+
+#define        BP_SHOULD_BYTESWAP(bp)  (BP_GET_BYTEORDER(bp) != ZFS_HOST_BYTEORDER)
+
+#define        BP_SPRINTF_LEN  320
+
+/*
+ * This macro allows code sharing between zfs, libzpool, and mdb.
+ * 'func' is either snprintf() or mdb_snprintf().
+ * 'ws' (whitespace) can be ' ' for single-line format, '\n' for multi-line.
+ */
+#define        SNPRINTF_BLKPTR(func, ws, buf, size, bp, type, checksum, compress) \
+{                                                                      \
+       static const char *copyname[] =                                 \
+           { "zero", "single", "double", "triple" };                   \
+       int len = 0;                                                    \
+       int copies = 0;                                                 \
+       int d;                                                          \
+                                                                       \
+       if (bp == NULL) {                                               \
+               len += func(buf + len, size - len, "<NULL>");           \
+       } else if (BP_IS_HOLE(bp)) {                                    \
+               len += func(buf + len, size - len,                      \
+                   "HOLE [L%llu %s] "                                  \
+                   "size=%llxL birth=%lluL",                           \
+                   (u_longlong_t)BP_GET_LEVEL(bp),                     \
+                   type,                                               \
+                   (u_longlong_t)BP_GET_LSIZE(bp),                     \
+                   (u_longlong_t)bp->blk_birth);                       \
+       } else if (BP_IS_EMBEDDED(bp)) {                                \
+               len = func(buf + len, size - len,                       \
+                   "EMBEDDED [L%llu %s] et=%u %s "                     \
+                   "size=%llxL/%llxP birth=%lluL",                     \
+                   (u_longlong_t)BP_GET_LEVEL(bp),                     \
+                   type,                                               \
+                   (int)BPE_GET_ETYPE(bp),                             \
+                   compress,                                           \
+                   (u_longlong_t)BPE_GET_LSIZE(bp),                    \
+                   (u_longlong_t)BPE_GET_PSIZE(bp),                    \
+                   (u_longlong_t)bp->blk_birth);                       \
+       } else {                                                        \
+               for (d = 0; d < BP_GET_NDVAS(bp); d++) {                \
+                       const dva_t *dva = &bp->blk_dva[d];             \
+                       if (DVA_IS_VALID(dva))                          \
+                               copies++;                               \
+                       len += func(buf + len, size - len,              \
+                           "DVA[%d]=<%llu:%llx:%llx>%c", d,            \
+                           (u_longlong_t)DVA_GET_VDEV(dva),            \
+                           (u_longlong_t)DVA_GET_OFFSET(dva),          \
+                           (u_longlong_t)DVA_GET_ASIZE(dva),           \
+                           ws);                                        \
+               }                                                       \
+               if (BP_IS_GANG(bp) &&                                   \
+                   DVA_GET_ASIZE(&bp->blk_dva[2]) <=                   \
+                   DVA_GET_ASIZE(&bp->blk_dva[1]) / 2)                 \
+                       copies--;                                       \
+               len += func(buf + len, size - len,                      \
+                   "[L%llu %s] %s %s %s %s %s %s%c"                    \
+                   "size=%llxL/%llxP birth=%lluL/%lluP fill=%llu%c"    \
+                   "cksum=%llx:%llx:%llx:%llx",                        \
+                   (u_longlong_t)BP_GET_LEVEL(bp),                     \
+                   type,                                               \
+                   checksum,                                           \
+                   compress,                                           \
+                   BP_GET_BYTEORDER(bp) == 0 ? "BE" : "LE",            \
+                   BP_IS_GANG(bp) ? "gang" : "contiguous",             \
+                   BP_GET_DEDUP(bp) ? "dedup" : "unique",              \
+                   copyname[copies],                                   \
+                   ws,                                                 \
+                   (u_longlong_t)BP_GET_LSIZE(bp),                     \
+                   (u_longlong_t)BP_GET_PSIZE(bp),                     \
+                   (u_longlong_t)bp->blk_birth,                        \
+                   (u_longlong_t)BP_PHYSICAL_BIRTH(bp),                \
+                   (u_longlong_t)BP_GET_FILL(bp),                      \
+                   ws,                                                 \
+                   (u_longlong_t)bp->blk_cksum.zc_word[0],             \
+                   (u_longlong_t)bp->blk_cksum.zc_word[1],             \
+                   (u_longlong_t)bp->blk_cksum.zc_word[2],             \
+                   (u_longlong_t)bp->blk_cksum.zc_word[3]);            \
+       }                                                               \
+       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)
+
+typedef enum spa_import_type {
+       SPA_IMPORT_EXISTING,
+       SPA_IMPORT_ASSEMBLE
+} spa_import_type_t;
+
+/* state manipulation functions */
+extern int spa_open(const char *pool, spa_t **, void *tag);
+extern int spa_open_rewind(const char *pool, spa_t **, void *tag,
+    nvlist_t *policy, nvlist_t **config);
+extern int spa_get_stats(const char *pool, nvlist_t **config, char *altroot,
+    size_t buflen);
+extern int spa_create(const char *pool, nvlist_t *config, nvlist_t *props,
+    nvlist_t *zplprops);
+extern int spa_import_rootpool(char *devpath, char *devid);
+extern int spa_import(char *pool, nvlist_t *config, nvlist_t *props,
+    uint64_t flags);
+extern nvlist_t *spa_tryimport(nvlist_t *tryconfig);
+extern int spa_destroy(char *pool);
+extern int spa_export(char *pool, nvlist_t **oldconfig, boolean_t force,
+    boolean_t hardforce);
+extern int spa_reset(char *pool);
+extern void spa_async_request(spa_t *spa, int flag);
+extern void spa_async_unrequest(spa_t *spa, int flag);
+extern void spa_async_suspend(spa_t *spa);
+extern void spa_async_resume(spa_t *spa);
+extern spa_t *spa_inject_addref(char *pool);
+extern void spa_inject_delref(spa_t *spa);
+extern void spa_scan_stat_init(spa_t *spa);
+extern int spa_scan_get_stats(spa_t *spa, pool_scan_stat_t *ps);
+
+#define        SPA_ASYNC_CONFIG_UPDATE 0x01
+#define        SPA_ASYNC_REMOVE        0x02
+#define        SPA_ASYNC_PROBE         0x04
+#define        SPA_ASYNC_RESILVER_DONE 0x08
+#define        SPA_ASYNC_RESILVER      0x10
+#define        SPA_ASYNC_AUTOEXPAND    0x20
+#define        SPA_ASYNC_REMOVE_DONE   0x40
+#define        SPA_ASYNC_REMOVE_STOP   0x80
+
+/*
+ * Controls the behavior of spa_vdev_remove().
+ */
+#define        SPA_REMOVE_UNSPARE      0x01
+#define        SPA_REMOVE_DONE         0x02
+
+/* device manipulation */
+extern int spa_vdev_add(spa_t *spa, nvlist_t *nvroot);
+extern int spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot,
+    int replacing);
+extern int spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid,
+    int replace_done);
+extern int spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare);
+extern boolean_t spa_vdev_remove_active(spa_t *spa);
+extern int spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath);
+extern int spa_vdev_setfru(spa_t *spa, uint64_t guid, const char *newfru);
+extern int spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
+    nvlist_t *props, boolean_t exp);
+
+/* spare state (which is global across all pools) */
+extern void spa_spare_add(vdev_t *vd);
+extern void spa_spare_remove(vdev_t *vd);
+extern boolean_t spa_spare_exists(uint64_t guid, uint64_t *pool, int *refcnt);
+extern void spa_spare_activate(vdev_t *vd);
+
+/* L2ARC state (which is global across all pools) */
+extern void spa_l2cache_add(vdev_t *vd);
+extern void spa_l2cache_remove(vdev_t *vd);
+extern boolean_t spa_l2cache_exists(uint64_t guid, uint64_t *pool);
+extern void spa_l2cache_activate(vdev_t *vd);
+extern void spa_l2cache_drop(spa_t *spa);
+
+/* scanning */
+extern int spa_scan(spa_t *spa, pool_scan_func_t func);
+extern int spa_scan_stop(spa_t *spa);
+
+/* spa syncing */
+extern void spa_sync(spa_t *spa, uint64_t txg); /* only for DMU use */
+extern void spa_sync_allpools(void);
+
+extern int zfs_sync_pass_deferred_free;
+
+/* spa namespace global mutex */
+extern kmutex_t spa_namespace_lock;
+
+/*
+ * SPA configuration functions in spa_config.c
+ */
+
+#define        SPA_CONFIG_UPDATE_POOL  0
+#define        SPA_CONFIG_UPDATE_VDEVS 1
+
+extern void spa_config_sync(spa_t *, boolean_t, boolean_t);
+extern void spa_config_load(void);
+extern nvlist_t *spa_all_configs(uint64_t *);
+extern void spa_config_set(spa_t *spa, nvlist_t *config);
+extern nvlist_t *spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg,
+    int getstats);
+extern void spa_config_update(spa_t *spa, int what);
+
+/*
+ * Miscellaneous SPA routines in spa_misc.c
+ */
+
+/* Namespace manipulation */
+extern spa_t *spa_lookup(const char *name);
+extern spa_t *spa_add(const char *name, nvlist_t *config, const char *altroot);
+extern void spa_remove(spa_t *spa);
+extern spa_t *spa_next(spa_t *prev);
+
+/* Refcount functions */
+extern void spa_open_ref(spa_t *spa, void *tag);
+extern void spa_close(spa_t *spa, void *tag);
+extern void spa_async_close(spa_t *spa, void *tag);
+extern boolean_t spa_refcount_zero(spa_t *spa);
+
+#define        SCL_NONE        0x00
+#define        SCL_CONFIG      0x01
+#define        SCL_STATE       0x02
+#define        SCL_L2ARC       0x04            /* hack until L2ARC 2.0 */
+#define        SCL_ALLOC       0x08
+#define        SCL_ZIO         0x10
+#define        SCL_FREE        0x20
+#define        SCL_VDEV        0x40
+#define        SCL_LOCKS       7
+#define        SCL_ALL         ((1 << SCL_LOCKS) - 1)
+#define        SCL_STATE_ALL   (SCL_STATE | SCL_L2ARC | SCL_ZIO)
+
+/* Historical pool statistics */
+typedef struct spa_stats_history {
+       kmutex_t                lock;
+       uint64_t                count;
+       uint64_t                size;
+       kstat_t                 *kstat;
+       void                    *private;
+       list_t                  list;
+} spa_stats_history_t;
+
+typedef struct spa_stats {
+       spa_stats_history_t     read_history;
+       spa_stats_history_t     txg_history;
+       spa_stats_history_t     tx_assign_histogram;
+       spa_stats_history_t     io_history;
+} spa_stats_t;
+
+typedef enum txg_state {
+       TXG_STATE_BIRTH         = 0,
+       TXG_STATE_OPEN          = 1,
+       TXG_STATE_QUIESCED      = 2,
+       TXG_STATE_WAIT_FOR_SYNC = 3,
+       TXG_STATE_SYNCED        = 4,
+       TXG_STATE_COMMITTED     = 5,
+} txg_state_t;
+
+extern void spa_stats_init(spa_t *spa);
+extern void spa_stats_destroy(spa_t *spa);
+extern void spa_read_history_add(spa_t *spa, const zbookmark_phys_t *zb,
+    uint32_t aflags);
+extern void spa_txg_history_add(spa_t *spa, uint64_t txg, hrtime_t birth_time);
+extern int spa_txg_history_set(spa_t *spa,  uint64_t txg,
+    txg_state_t completed_state, hrtime_t completed_time);
+extern int spa_txg_history_set_io(spa_t *spa,  uint64_t txg, uint64_t nread,
+    uint64_t nwritten, uint64_t reads, uint64_t writes, uint64_t ndirty);
+extern void spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs);
+
+/* Pool configuration locks */
+extern int spa_config_tryenter(spa_t *spa, int locks, void *tag, krw_t rw);
+extern void spa_config_enter(spa_t *spa, int locks, void *tag, krw_t rw);
+extern void spa_config_exit(spa_t *spa, int locks, void *tag);
+extern int spa_config_held(spa_t *spa, int locks, krw_t rw);
+
+/* Pool vdev add/remove lock */
+extern uint64_t spa_vdev_enter(spa_t *spa);
+extern uint64_t spa_vdev_config_enter(spa_t *spa);
+extern void spa_vdev_config_exit(spa_t *spa, vdev_t *vd, uint64_t txg,
+    int error, char *tag);
+extern int spa_vdev_exit(spa_t *spa, vdev_t *vd, uint64_t txg, int error);
+
+/* Pool vdev state change lock */
+extern void spa_vdev_state_enter(spa_t *spa, int oplock);
+extern int spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error);
+
+/* Log state */
+typedef enum spa_log_state {
+       SPA_LOG_UNKNOWN = 0,    /* unknown log state */
+       SPA_LOG_MISSING,        /* missing log(s) */
+       SPA_LOG_CLEAR,          /* clear the log(s) */
+       SPA_LOG_GOOD,           /* log(s) are good */
+} spa_log_state_t;
+
+extern spa_log_state_t spa_get_log_state(spa_t *spa);
+extern void spa_set_log_state(spa_t *spa, spa_log_state_t state);
+extern int spa_offline_log(spa_t *spa);
+
+/* Log claim callback */
+extern void spa_claim_notify(zio_t *zio);
+extern void spa_deadman(void *);
+
+/* Accessor functions */
+extern boolean_t spa_shutting_down(spa_t *spa);
+extern struct dsl_pool *spa_get_dsl(spa_t *spa);
+extern boolean_t spa_is_initializing(spa_t *spa);
+extern blkptr_t *spa_get_rootblkptr(spa_t *spa);
+extern void spa_set_rootblkptr(spa_t *spa, const blkptr_t *bp);
+extern void spa_altroot(spa_t *, char *, size_t);
+extern int spa_sync_pass(spa_t *spa);
+extern char *spa_name(spa_t *spa);
+extern uint64_t spa_guid(spa_t *spa);
+extern uint64_t spa_load_guid(spa_t *spa);
+extern uint64_t spa_last_synced_txg(spa_t *spa);
+extern uint64_t spa_first_txg(spa_t *spa);
+extern uint64_t spa_syncing_txg(spa_t *spa);
+extern uint64_t spa_version(spa_t *spa);
+extern pool_state_t spa_state(spa_t *spa);
+extern spa_load_state_t spa_load_state(spa_t *spa);
+extern uint64_t spa_freeze_txg(spa_t *spa);
+extern uint64_t spa_get_asize(spa_t *spa, uint64_t lsize);
+extern uint64_t spa_get_dspace(spa_t *spa);
+extern uint64_t spa_get_slop_space(spa_t *spa);
+extern void spa_update_dspace(spa_t *spa);
+extern uint64_t spa_version(spa_t *spa);
+extern boolean_t spa_deflate(spa_t *spa);
+extern metaslab_class_t *spa_normal_class(spa_t *spa);
+extern metaslab_class_t *spa_log_class(spa_t *spa);
+extern void spa_evicting_os_register(spa_t *, objset_t *os);
+extern void spa_evicting_os_deregister(spa_t *, objset_t *os);
+extern void spa_evicting_os_wait(spa_t *spa);
+extern int spa_max_replication(spa_t *spa);
+extern int spa_prev_software_version(spa_t *spa);
+extern uint8_t spa_get_failmode(spa_t *spa);
+extern boolean_t spa_suspended(spa_t *spa);
+extern uint64_t spa_bootfs(spa_t *spa);
+extern uint64_t spa_delegation(spa_t *spa);
+extern objset_t *spa_meta_objset(spa_t *spa);
+extern uint64_t spa_deadman_synctime(spa_t *spa);
+
+/* Miscellaneous support routines */
+extern void spa_activate_mos_feature(spa_t *spa, const char *feature,
+    dmu_tx_t *tx);
+extern void spa_deactivate_mos_feature(spa_t *spa, const char *feature);
+extern int spa_rename(const char *oldname, const char *newname);
+extern spa_t *spa_by_guid(uint64_t pool_guid, uint64_t device_guid);
+extern boolean_t spa_guid_exists(uint64_t pool_guid, uint64_t device_guid);
+extern char *spa_strdup(const char *);
+extern void spa_strfree(char *);
+extern uint64_t spa_get_random(uint64_t range);
+extern uint64_t spa_generate_guid(spa_t *spa);
+extern void snprintf_blkptr(char *buf, size_t buflen, const blkptr_t *bp);
+extern void spa_freeze(spa_t *spa);
+extern int spa_change_guid(spa_t *spa);
+extern void spa_upgrade(spa_t *spa, uint64_t version);
+extern void spa_evict_all(void);
+extern vdev_t *spa_lookup_by_guid(spa_t *spa, uint64_t guid,
+    boolean_t l2cache);
+extern boolean_t spa_has_spare(spa_t *, uint64_t guid);
+extern uint64_t dva_get_dsize_sync(spa_t *spa, const dva_t *dva);
+extern uint64_t bp_get_dsize_sync(spa_t *spa, const blkptr_t *bp);
+extern uint64_t bp_get_dsize(spa_t *spa, const blkptr_t *bp);
+extern boolean_t spa_has_slogs(spa_t *spa);
+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 void zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp);
+
+extern int spa_mode(spa_t *spa);
+extern uint64_t strtonum(const char *str, char **nptr);
+
+extern char *spa_his_ievent_table[];
+
+extern void spa_history_create_obj(spa_t *spa, dmu_tx_t *tx);
+extern int spa_history_get(spa_t *spa, uint64_t *offset, uint64_t *len_read,
+    char *his_buf);
+extern int spa_history_log(spa_t *spa, const char *his_buf);
+extern int spa_history_log_nvl(spa_t *spa, nvlist_t *nvl);
+extern void spa_history_log_version(spa_t *spa, const char *operation);
+extern void spa_history_log_internal(spa_t *spa, const char *operation,
+    dmu_tx_t *tx, const char *fmt, ...);
+extern void spa_history_log_internal_ds(struct dsl_dataset *ds, const char *op,
+    dmu_tx_t *tx, const char *fmt, ...);
+extern void spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
+    dmu_tx_t *tx, const char *fmt, ...);
+
+/* error handling */
+struct zbookmark_phys;
+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_autoreplace(spa_t *spa, vdev_t *vd);
+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);
+extern void spa_errlog_drain(spa_t *spa);
+extern void spa_errlog_sync(spa_t *spa, uint64_t txg);
+extern void spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub);
+
+/* vdev cache */
+extern void vdev_cache_stat_init(void);
+extern void vdev_cache_stat_fini(void);
+
+/* Initialization and termination */
+extern void spa_init(int flags);
+extern void spa_fini(void);
+extern void spa_boot_init(void);
+
+/* properties */
+extern int spa_prop_set(spa_t *spa, nvlist_t *nvp);
+extern int spa_prop_get(spa_t *spa, nvlist_t **nvp);
+extern void spa_prop_clear_bootfs(spa_t *spa, uint64_t obj, dmu_tx_t *tx);
+extern void spa_configfile_set(spa_t *, nvlist_t *, boolean_t);
+
+/* asynchronous event notification */
+extern void spa_event_notify(spa_t *spa, vdev_t *vdev, const char *name);
+
+#ifdef ZFS_DEBUG
+#define        dprintf_bp(bp, fmt, ...) do {                           \
+       if (zfs_flags & ZFS_DEBUG_DPRINTF) {                    \
+       char *__blkbuf = kmem_alloc(BP_SPRINTF_LEN, KM_SLEEP);  \
+       snprintf_blkptr(__blkbuf, BP_SPRINTF_LEN, (bp));        \
+       dprintf(fmt " %s\n", __VA_ARGS__, __blkbuf);            \
+       kmem_free(__blkbuf, BP_SPRINTF_LEN);                    \
+       } \
+_NOTE(CONSTCOND) } while (0)
+#else
+#define        dprintf_bp(bp, fmt, ...)
+#endif
+
+extern boolean_t spa_debug_enabled(spa_t *spa);
+#define        spa_dbgmsg(spa, ...)                    \
+{                                              \
+       if (spa_debug_enabled(spa))             \
+               zfs_dbgmsg(__VA_ARGS__);        \
+}
+
+extern int spa_mode_global;                    /* mode, e.g. FREAD | FWRITE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SPA_H */
diff --git a/zfs/include/sys/spa_boot.h b/zfs/include/sys/spa_boot.h
new file mode 100644 (file)
index 0000000..1d3622f
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SPA_BOOT_H
+#define        _SYS_SPA_BOOT_H
+
+#include <sys/nvpair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *spa_get_bootprop(char *prop);
+extern void spa_free_bootprop(char *prop);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SPA_BOOT_H */
diff --git a/zfs/include/sys/spa_impl.h b/zfs/include/sys/spa_impl.h
new file mode 100644 (file)
index 0000000..5176eb8
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SPA_IMPL_H
+#define        _SYS_SPA_IMPL_H
+
+#include <sys/spa.h>
+#include <sys/vdev.h>
+#include <sys/metaslab.h>
+#include <sys/dmu.h>
+#include <sys/dsl_pool.h>
+#include <sys/uberblock_impl.h>
+#include <sys/zfs_context.h>
+#include <sys/avl.h>
+#include <sys/refcount.h>
+#include <sys/bplist.h>
+#include <sys/bpobj.h>
+#include <sys/zfeature.h>
+#include <zfeature_common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct spa_error_entry {
+       zbookmark_phys_t        se_bookmark;
+       char                    *se_name;
+       avl_node_t              se_avl;
+} spa_error_entry_t;
+
+typedef struct spa_history_phys {
+       uint64_t sh_pool_create_len;    /* ending offset of zpool create */
+       uint64_t sh_phys_max_off;       /* physical EOF */
+       uint64_t sh_bof;                /* logical BOF */
+       uint64_t sh_eof;                /* logical EOF */
+       uint64_t sh_records_lost;       /* num of records overwritten */
+} spa_history_phys_t;
+
+struct spa_aux_vdev {
+       uint64_t        sav_object;             /* MOS object for device list */
+       nvlist_t        *sav_config;            /* cached device config */
+       vdev_t          **sav_vdevs;            /* devices */
+       int             sav_count;              /* number devices */
+       boolean_t       sav_sync;               /* sync the device list */
+       nvlist_t        **sav_pending;          /* pending device additions */
+       uint_t          sav_npending;           /* # pending devices */
+};
+
+typedef struct spa_config_lock {
+       kmutex_t        scl_lock;
+       kthread_t       *scl_writer;
+       int             scl_write_wanted;
+       kcondvar_t      scl_cv;
+       refcount_t      scl_count;
+} spa_config_lock_t;
+
+typedef struct spa_config_dirent {
+       list_node_t     scd_link;
+       char            *scd_path;
+} spa_config_dirent_t;
+
+typedef enum zio_taskq_type {
+       ZIO_TASKQ_ISSUE = 0,
+       ZIO_TASKQ_ISSUE_HIGH,
+       ZIO_TASKQ_INTERRUPT,
+       ZIO_TASKQ_INTERRUPT_HIGH,
+       ZIO_TASKQ_TYPES
+} zio_taskq_type_t;
+
+/*
+ * State machine for the zpool-poolname process.  The states transitions
+ * are done as follows:
+ *
+ *     From               To                   Routine
+ *     PROC_NONE       -> PROC_CREATED         spa_activate()
+ *     PROC_CREATED    -> PROC_ACTIVE          spa_thread()
+ *     PROC_ACTIVE     -> PROC_DEACTIVATE      spa_deactivate()
+ *     PROC_DEACTIVATE -> PROC_GONE            spa_thread()
+ *     PROC_GONE       -> PROC_NONE            spa_deactivate()
+ */
+typedef enum spa_proc_state {
+       SPA_PROC_NONE,          /* spa_proc = &p0, no process created */
+       SPA_PROC_CREATED,       /* spa_activate() has proc, is waiting */
+       SPA_PROC_ACTIVE,        /* taskqs created, spa_proc set */
+       SPA_PROC_DEACTIVATE,    /* spa_deactivate() requests process exit */
+       SPA_PROC_GONE           /* spa_thread() is exiting, spa_proc = &p0 */
+} spa_proc_state_t;
+
+typedef struct spa_taskqs {
+       uint_t stqs_count;
+       taskq_t **stqs_taskq;
+} spa_taskqs_t;
+
+struct spa {
+       /*
+        * Fields protected by spa_namespace_lock.
+        */
+       char            spa_name[MAXNAMELEN];   /* pool name */
+       char            *spa_comment;           /* comment */
+       avl_node_t      spa_avl;                /* node in spa_namespace_avl */
+       nvlist_t        *spa_config;            /* last synced config */
+       nvlist_t        *spa_config_syncing;    /* currently syncing config */
+       nvlist_t        *spa_config_splitting;  /* config for splitting */
+       nvlist_t        *spa_load_info;         /* info and errors from load */
+       uint64_t        spa_config_txg;         /* txg of last config change */
+       int             spa_sync_pass;          /* iterate-to-convergence */
+       pool_state_t    spa_state;              /* pool state */
+       int             spa_inject_ref;         /* injection references */
+       uint8_t         spa_sync_on;            /* sync threads are running */
+       spa_load_state_t spa_load_state;        /* current load operation */
+       uint64_t        spa_import_flags;       /* import specific flags */
+       spa_taskqs_t    spa_zio_taskq[ZIO_TYPES][ZIO_TASKQ_TYPES];
+       dsl_pool_t      *spa_dsl_pool;
+       boolean_t       spa_is_initializing;    /* true while opening pool */
+       metaslab_class_t *spa_normal_class;     /* normal data class */
+       metaslab_class_t *spa_log_class;        /* intent log data class */
+       uint64_t        spa_first_txg;          /* first txg after spa_open() */
+       uint64_t        spa_final_txg;          /* txg of export/destroy */
+       uint64_t        spa_freeze_txg;         /* freeze pool at this txg */
+       uint64_t        spa_load_max_txg;       /* best initial ub_txg */
+       uint64_t        spa_claim_max_txg;      /* highest claimed birth txg */
+       timespec_t      spa_loaded_ts;          /* 1st successful open time */
+       objset_t        *spa_meta_objset;       /* copy of dp->dp_meta_objset */
+       kmutex_t        spa_evicting_os_lock;   /* Evicting objset list lock */
+       list_t          spa_evicting_os_list;   /* Objsets being evicted. */
+       kcondvar_t      spa_evicting_os_cv;     /* Objset Eviction Completion */
+       txg_list_t      spa_vdev_txg_list;      /* per-txg dirty vdev list */
+       vdev_t          *spa_root_vdev;         /* top-level vdev container */
+       int             spa_min_ashift;         /* of vdevs in normal class */
+       int             spa_max_ashift;         /* of vdevs in normal class */
+       uint64_t        spa_config_guid;        /* config pool guid */
+       uint64_t        spa_load_guid;          /* spa_load initialized guid */
+       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 */
+       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 */
+       uint64_t        spa_config_object;      /* MOS object for pool config */
+       uint64_t        spa_config_generation;  /* config generation number */
+       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 */
+       uberblock_t     spa_ubsync;             /* last synced uberblock */
+       uberblock_t     spa_uberblock;          /* current uberblock */
+       boolean_t       spa_extreme_rewind;     /* rewind past deferred frees */
+       uint64_t        spa_last_io;            /* lbolt of last non-scan I/O */
+       kmutex_t        spa_scrub_lock;         /* resilver/scrub lock */
+       uint64_t        spa_scrub_inflight;     /* in-flight scrub I/Os */
+       kcondvar_t      spa_scrub_io_cv;        /* scrub I/O completion */
+       uint8_t         spa_scrub_active;       /* active or suspended? */
+       uint8_t         spa_scrub_type;         /* type of scrub we're doing */
+       uint8_t         spa_scrub_finished;     /* indicator to rotate logs */
+       uint8_t         spa_scrub_started;      /* started since last boot */
+       uint8_t         spa_scrub_reopen;       /* scrub doing vdev_reopen */
+       uint64_t        spa_scan_pass_start;    /* start time per pass/reboot */
+       uint64_t        spa_scan_pass_exam;     /* examined bytes per pass */
+       kmutex_t        spa_async_lock;         /* protect async state */
+       kthread_t       *spa_async_thread;      /* thread doing async task */
+       int             spa_async_suspended;    /* async tasks suspended */
+       kcondvar_t      spa_async_cv;           /* wait for thread_exit() */
+       uint16_t        spa_async_tasks;        /* async task mask */
+       char            *spa_root;              /* alternate root directory */
+       uint64_t        spa_ena;                /* spa-wide ereport ENA */
+       int             spa_last_open_failed;   /* error if last open failed */
+       uint64_t        spa_last_ubsync_txg;    /* "best" uberblock txg */
+       uint64_t        spa_last_ubsync_txg_ts; /* timestamp from that ub */
+       uint64_t        spa_load_txg;           /* ub txg that loaded */
+       uint64_t        spa_load_txg_ts;        /* timestamp from that ub */
+       uint64_t        spa_load_meta_errors;   /* verify metadata err count */
+       uint64_t        spa_load_data_errors;   /* verify data err count */
+       uint64_t        spa_verify_min_txg;     /* start txg of verify scrub */
+       kmutex_t        spa_errlog_lock;        /* error log lock */
+       uint64_t        spa_errlog_last;        /* last error log object */
+       uint64_t        spa_errlog_scrub;       /* scrub error log object */
+       kmutex_t        spa_errlist_lock;       /* error list/ereport lock */
+       avl_tree_t      spa_errlist_last;       /* last error list */
+       avl_tree_t      spa_errlist_scrub;      /* scrub error list */
+       uint64_t        spa_deflate;            /* should we deflate? */
+       uint64_t        spa_history;            /* history object */
+       kmutex_t        spa_history_lock;       /* history lock */
+       vdev_t          *spa_pending_vdev;      /* pending vdev additions */
+       kmutex_t        spa_props_lock;         /* property lock */
+       uint64_t        spa_pool_props_object;  /* object for properties */
+       uint64_t        spa_bootfs;             /* default boot filesystem */
+       uint64_t        spa_failmode;           /* failure mode for the pool */
+       uint64_t        spa_delegation;         /* delegation on/off */
+       list_t          spa_config_list;        /* previous cache file(s) */
+       /* per-CPU array of root of async I/O: */
+       zio_t           **spa_async_zio_root;
+       zio_t           *spa_suspend_zio_root;  /* root of all suspended I/O */
+       kmutex_t        spa_suspend_lock;       /* protects suspend_zio_root */
+       kcondvar_t      spa_suspend_cv;         /* notification of resume */
+       uint8_t         spa_suspended;          /* pool is suspended */
+       uint8_t         spa_claiming;           /* pool is doing zil_claim() */
+       boolean_t       spa_debug;              /* debug enabled? */
+       boolean_t       spa_is_root;            /* pool is root */
+       int             spa_minref;             /* num refs when first opened */
+       int             spa_mode;               /* FREAD | FWRITE */
+       spa_log_state_t spa_log_state;          /* log state */
+       uint64_t        spa_autoexpand;         /* lun expansion on/off */
+       ddt_t           *spa_ddt[ZIO_CHECKSUM_FUNCTIONS]; /* in-core DDTs */
+       uint64_t        spa_ddt_stat_object;    /* DDT statistics */
+       uint64_t        spa_dedup_ditto;        /* dedup ditto threshold */
+       uint64_t        spa_dedup_checksum;     /* default dedup checksum */
+       uint64_t        spa_dspace;             /* dspace in normal class */
+       kmutex_t        spa_vdev_top_lock;      /* dueling offline/remove */
+       kmutex_t        spa_proc_lock;          /* protects spa_proc* */
+       kcondvar_t      spa_proc_cv;            /* spa_proc_state transitions */
+       spa_proc_state_t spa_proc_state;        /* see definition */
+       proc_t          *spa_proc;              /* "zpool-poolname" process */
+       uint64_t        spa_did;                /* if procp != p0, did of t1 */
+       boolean_t       spa_autoreplace;        /* autoreplace set in open */
+       int             spa_vdev_locks;         /* locks grabbed */
+       uint64_t        spa_creation_version;   /* version at pool creation */
+       uint64_t        spa_prev_software_version; /* See ub_software_version */
+       uint64_t        spa_feat_for_write_obj; /* required to write to pool */
+       uint64_t        spa_feat_for_read_obj;  /* required to read from pool */
+       uint64_t        spa_feat_desc_obj;      /* Feature descriptions */
+       uint64_t        spa_feat_enabled_txg_obj; /* Feature enabled txg */
+       kmutex_t        spa_feat_stats_lock;    /* protects spa_feat_stats */
+       nvlist_t        *spa_feat_stats;        /* Cache of enabled features */
+       /* cache feature refcounts */
+       uint64_t        spa_feat_refcount_cache[SPA_FEATURES];
+       taskqid_t       spa_deadman_tqid;       /* Task id */
+       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_errata;             /* errata issues detected */
+       spa_stats_t     spa_stats;              /* assorted spa statistics */
+       taskq_t         *spa_zvol_taskq;        /* Taskq for minor managment */
+
+       /*
+        * spa_refcount & spa_config_lock must be the last elements
+        * because refcount_t changes size based on compilation options.
+        * In order for the MDB module to function correctly, the other
+        * fields must remain in the same location.
+        */
+       spa_config_lock_t spa_config_lock[SCL_LOCKS]; /* config changes */
+       refcount_t      spa_refcount;           /* number of opens */
+};
+
+extern char *spa_config_path;
+
+extern void spa_taskq_dispatch_ent(spa_t *spa, zio_type_t t, zio_taskq_type_t q,
+    task_func_t *func, void *arg, uint_t flags, taskq_ent_t *ent);
+extern void spa_taskq_dispatch_sync(spa_t *, zio_type_t t, zio_taskq_type_t q,
+    task_func_t *func, void *arg, uint_t flags);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SPA_IMPL_H */
diff --git a/zfs/include/sys/space_map.h b/zfs/include/sys/space_map.h
new file mode 100644 (file)
index 0000000..a59e6d3
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_SPACE_MAP_H
+#define        _SYS_SPACE_MAP_H
+
+#include <sys/avl.h>
+#include <sys/range_tree.h>
+#include <sys/dmu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The size of the space map object has increased to include a histogram.
+ * The SPACE_MAP_SIZE_V0 designates the original size and is used to
+ * maintain backward compatibility.
+ */
+#define        SPACE_MAP_SIZE_V0       (3 * sizeof (uint64_t))
+#define        SPACE_MAP_HISTOGRAM_SIZE        32
+
+/*
+ * The space_map_phys is the on-disk representation of the space map.
+ * Consumers of space maps should never reference any of the members of this
+ * structure directly. These members may only be updated in syncing context.
+ *
+ * Note the smp_object is no longer used but remains in the structure
+ * for backward compatibility.
+ */
+typedef struct space_map_phys {
+       uint64_t        smp_object;     /* on-disk space map object */
+       uint64_t        smp_objsize;    /* size of the object */
+       uint64_t        smp_alloc;      /* space allocated from the map */
+       uint64_t        smp_pad[5];     /* reserved */
+
+       /*
+        * The smp_histogram maintains a histogram of free regions. Each
+        * bucket, smp_histogram[i], contains the number of free regions
+        * whose size is:
+        * 2^(i+sm_shift) <= size of free region in bytes < 2^(i+sm_shift+1)
+        */
+       uint64_t        smp_histogram[SPACE_MAP_HISTOGRAM_SIZE];
+} space_map_phys_t;
+
+/*
+ * The space map object defines a region of space, its size, how much is
+ * allocated, and the on-disk object that stores this information.
+ * Consumers of space maps may only access the members of this structure.
+ */
+typedef struct space_map {
+       uint64_t        sm_start;       /* start of map */
+       uint64_t        sm_size;        /* size of map */
+       uint8_t         sm_shift;       /* unit shift */
+       uint64_t        sm_length;      /* synced length */
+       uint64_t        sm_alloc;       /* synced space allocated */
+       objset_t        *sm_os;         /* objset for this map */
+       uint64_t        sm_object;      /* object id for this map */
+       uint32_t        sm_blksz;       /* block size for space map */
+       dmu_buf_t       *sm_dbuf;       /* space_map_phys_t dbuf */
+       space_map_phys_t *sm_phys;      /* on-disk space map */
+       kmutex_t        *sm_lock;       /* pointer to lock that protects map */
+} space_map_t;
+
+/*
+ * debug entry
+ *
+ *    1      3         10                     50
+ *  ,---+--------+------------+---------------------------------.
+ *  | 1 | action |  syncpass  |        txg (lower bits)         |
+ *  `---+--------+------------+---------------------------------'
+ *   63  62    60 59        50 49                               0
+ *
+ *
+ * non-debug entry
+ *
+ *    1               47                   1           15
+ *  ,-----------------------------------------------------------.
+ *  | 0 |   offset (sm_shift units)    | type |       run       |
+ *  `-----------------------------------------------------------'
+ *   63  62                          17   16   15               0
+ */
+
+/* All this stuff takes and returns bytes */
+#define        SM_RUN_DECODE(x)        (BF64_DECODE(x, 0, 15) + 1)
+#define        SM_RUN_ENCODE(x)        BF64_ENCODE((x) - 1, 0, 15)
+#define        SM_TYPE_DECODE(x)       BF64_DECODE(x, 15, 1)
+#define        SM_TYPE_ENCODE(x)       BF64_ENCODE(x, 15, 1)
+#define        SM_OFFSET_DECODE(x)     BF64_DECODE(x, 16, 47)
+#define        SM_OFFSET_ENCODE(x)     BF64_ENCODE(x, 16, 47)
+#define        SM_DEBUG_DECODE(x)      BF64_DECODE(x, 63, 1)
+#define        SM_DEBUG_ENCODE(x)      BF64_ENCODE(x, 63, 1)
+
+#define        SM_DEBUG_ACTION_DECODE(x)       BF64_DECODE(x, 60, 3)
+#define        SM_DEBUG_ACTION_ENCODE(x)       BF64_ENCODE(x, 60, 3)
+
+#define        SM_DEBUG_SYNCPASS_DECODE(x)     BF64_DECODE(x, 50, 10)
+#define        SM_DEBUG_SYNCPASS_ENCODE(x)     BF64_ENCODE(x, 50, 10)
+
+#define        SM_DEBUG_TXG_DECODE(x)          BF64_DECODE(x, 0, 50)
+#define        SM_DEBUG_TXG_ENCODE(x)          BF64_ENCODE(x, 0, 50)
+
+#define        SM_RUN_MAX                      SM_RUN_DECODE(~0ULL)
+
+typedef enum {
+       SM_ALLOC,
+       SM_FREE
+} maptype_t;
+
+int space_map_load(space_map_t *sm, range_tree_t *rt, maptype_t maptype);
+
+void space_map_histogram_clear(space_map_t *sm);
+void space_map_histogram_add(space_map_t *sm, range_tree_t *rt,
+    dmu_tx_t *tx);
+
+void space_map_update(space_map_t *sm);
+
+uint64_t space_map_object(space_map_t *sm);
+uint64_t space_map_allocated(space_map_t *sm);
+uint64_t space_map_length(space_map_t *sm);
+
+void space_map_write(space_map_t *sm, range_tree_t *rt, maptype_t maptype,
+    dmu_tx_t *tx);
+void space_map_truncate(space_map_t *sm, dmu_tx_t *tx);
+uint64_t space_map_alloc(objset_t *os, dmu_tx_t *tx);
+void space_map_free(space_map_t *sm, dmu_tx_t *tx);
+
+int space_map_open(space_map_t **smp, objset_t *os, uint64_t object,
+    uint64_t start, uint64_t size, uint8_t shift, kmutex_t *lp);
+void space_map_close(space_map_t *sm);
+
+int64_t space_map_alloc_delta(space_map_t *sm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SPACE_MAP_H */
diff --git a/zfs/include/sys/space_reftree.h b/zfs/include/sys/space_reftree.h
new file mode 100644 (file)
index 0000000..249b15b
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_SPACE_REFTREE_H
+#define        _SYS_SPACE_REFTREE_H
+
+#include <sys/range_tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct space_ref {
+       avl_node_t      sr_node;        /* AVL node */
+       uint64_t        sr_offset;      /* range offset (start or end) */
+       int64_t         sr_refcnt;      /* associated reference count */
+} space_ref_t;
+
+void space_reftree_create(avl_tree_t *t);
+void space_reftree_destroy(avl_tree_t *t);
+void space_reftree_add_seg(avl_tree_t *t, uint64_t start, uint64_t end,
+    int64_t refcnt);
+void space_reftree_add_map(avl_tree_t *t, range_tree_t *rt, int64_t refcnt);
+void space_reftree_generate_map(avl_tree_t *t, range_tree_t *rt,
+    int64_t minref);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SPACE_REFTREE_H */
diff --git a/zfs/include/sys/trace.h b/zfs/include/sys/trace.h
new file mode 100644 (file)
index 0000000..f32ba52
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#if !defined(_TRACE_ZFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_ZFS_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * The sys/trace_dbgmsg.h header defines tracepoint events for
+ * dprintf(), dbgmsg(), and SET_ERROR().
+ */
+#define        _SYS_TRACE_DBGMSG_INDIRECT
+#include <sys/trace_dbgmsg.h>
+#undef _SYS_TRACE_DBGMSG_INDIRECT
+
+/*
+ * Redefine the DTRACE_PROBE* functions to use Linux tracepoints
+ */
+#undef DTRACE_PROBE1
+#define        DTRACE_PROBE1(name, t1, arg1) \
+       trace_zfs_##name((arg1))
+
+#undef DTRACE_PROBE2
+#define        DTRACE_PROBE2(name, t1, arg1, t2, arg2) \
+       trace_zfs_##name((arg1), (arg2))
+
+#undef DTRACE_PROBE3
+#define        DTRACE_PROBE3(name, t1, arg1, t2, arg2, t3, arg3) \
+       trace_zfs_##name((arg1), (arg2), (arg3))
+
+#undef DTRACE_PROBE4
+#define        DTRACE_PROBE4(name, t1, arg1, t2, arg2, t3, arg3, t4, arg4) \
+       trace_zfs_##name((arg1), (arg2), (arg3), (arg4))
+
+#endif /* _TRACE_ZFS_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_acl.h b/zfs/include/sys/trace_acl.h
new file mode 100644 (file)
index 0000000..2308942
--- /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
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_acl
+
+#if !defined(_TRACE_ACL_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_ACL_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ *     znode_t *, ...,
+ *     zfs_ace_hdr_t *, ...,
+ *     uint32_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_ace_class,
+       TP_PROTO(znode_t *zn, zfs_ace_hdr_t *ace, uint32_t mask_matched),
+       TP_ARGS(zn, ace, mask_matched),
+       TP_STRUCT__entry(
+           __field(uint64_t,           z_id)
+           __field(uint8_t,            z_unlinked)
+           __field(uint8_t,            z_atime_dirty)
+           __field(uint8_t,            z_zn_prefetch)
+           __field(uint8_t,            z_moved)
+           __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)
+           __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)
+           __field(boolean_t,          z_is_mapped)
+           __field(boolean_t,          z_is_ctldir)
+           __field(boolean_t,          z_is_stale)
+
+           __field(unsigned long,      i_ino)
+           __field(unsigned int,       i_nlink)
+           __field(u64,                i_version)
+           __field(loff_t,             i_size)
+           __field(unsigned int,       i_blkbits)
+           __field(unsigned short,     i_bytes)
+           __field(umode_t,            i_mode)
+           __field(__u32,              i_generation)
+
+           __field(uint16_t,           z_type)
+           __field(uint16_t,           z_flags)
+           __field(uint32_t,           z_access_mask)
+
+           __field(uint32_t,           mask_matched)
+       ),
+       TP_fast_assign(
+           __entry->z_id               = zn->z_id;
+           __entry->z_unlinked         = zn->z_unlinked;
+           __entry->z_atime_dirty      = zn->z_atime_dirty;
+           __entry->z_zn_prefetch      = zn->z_zn_prefetch;
+           __entry->z_moved            = zn->z_moved;
+           __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_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;
+           __entry->z_is_mapped        = zn->z_is_mapped;
+           __entry->z_is_ctldir        = zn->z_is_ctldir;
+           __entry->z_is_stale         = zn->z_is_stale;
+
+           __entry->i_ino              = zn->z_inode.i_ino;
+           __entry->i_nlink            = zn->z_inode.i_nlink;
+           __entry->i_version          = zn->z_inode.i_version;
+           __entry->i_size             = zn->z_inode.i_size;
+           __entry->i_blkbits          = zn->z_inode.i_blkbits;
+           __entry->i_bytes            = zn->z_inode.i_bytes;
+           __entry->i_mode             = zn->z_inode.i_mode;
+           __entry->i_generation       = zn->z_inode.i_generation;
+
+           __entry->z_type             = ace->z_type;
+           __entry->z_flags            = ace->z_flags;
+           __entry->z_access_mask      = ace->z_access_mask;
+
+           __entry->mask_matched       = mask_matched;
+       ),
+       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 "
+           "links %llu pflags %llu uid %llu gid %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",
+           __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_links, __entry->z_pflags, __entry->z_uid,
+           __entry->z_gid, __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)
+);
+
+#define        DEFINE_ACE_EVENT(name) \
+DEFINE_EVENT(zfs_ace_class, name, \
+       TP_PROTO(znode_t *zn, zfs_ace_hdr_t *ace, uint32_t mask_matched), \
+       TP_ARGS(zn, ace, mask_matched))
+DEFINE_ACE_EVENT(zfs_zfs__ace__denies);
+DEFINE_ACE_EVENT(zfs_zfs__ace__allows);
+
+#endif /* _TRACE_ACL_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_acl
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_arc.h b/zfs/include/sys/trace_arc.h
new file mode 100644 (file)
index 0000000..31c3cdc
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this 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_arc
+
+#if !defined(_TRACE_ARC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_ARC_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for one argument tracepoints of the form:
+ *
+ * DTRACE_PROBE1(...,
+ *     arc_buf_hdr_t *, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_arc_buf_hdr_class,
+       TP_PROTO(arc_buf_hdr_t *ab),
+       TP_ARGS(ab),
+       TP_STRUCT__entry(
+           __array(uint64_t,           hdr_dva_word, 2)
+           __field(uint64_t,           hdr_birth)
+           __field(uint32_t,           hdr_flags)
+           __field(uint32_t,           hdr_datacnt)
+           __field(arc_buf_contents_t, hdr_type)
+           __field(uint64_t,           hdr_size)
+           __field(uint64_t,           hdr_spa)
+           __field(arc_state_type_t,   hdr_state_type)
+           __field(clock_t,            hdr_access)
+           __field(uint32_t,           hdr_mru_hits)
+           __field(uint32_t,           hdr_mru_ghost_hits)
+           __field(uint32_t,           hdr_mfu_hits)
+           __field(uint32_t,           hdr_mfu_ghost_hits)
+           __field(uint32_t,           hdr_l2_hits)
+           __field(int64_t,            hdr_refcount)
+       ),
+       TP_fast_assign(
+           __entry->hdr_dva_word[0]    = ab->b_dva.dva_word[0];
+           __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_spa            = ab->b_spa;
+           __entry->hdr_state_type     = ab->b_l1hdr.b_state->arcs_state;
+           __entry->hdr_access         = ab->b_l1hdr.b_arc_access;
+           __entry->hdr_mru_hits       = ab->b_l1hdr.b_mru_hits;
+           __entry->hdr_mru_ghost_hits = ab->b_l1hdr.b_mru_ghost_hits;
+           __entry->hdr_mfu_hits       = ab->b_l1hdr.b_mfu_hits;
+           __entry->hdr_mfu_ghost_hits = ab->b_l1hdr.b_mfu_ghost_hits;
+           __entry->hdr_l2_hits        = ab->b_l1hdr.b_l2_hits;
+           __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 "
+           "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_access, __entry->hdr_mru_hits,
+           __entry->hdr_mru_ghost_hits, __entry->hdr_mfu_hits,
+           __entry->hdr_mfu_ghost_hits, __entry->hdr_l2_hits,
+           __entry->hdr_refcount)
+);
+
+#define        DEFINE_ARC_BUF_HDR_EVENT(name) \
+DEFINE_EVENT(zfs_arc_buf_hdr_class, name, \
+       TP_PROTO(arc_buf_hdr_t *ab), \
+       TP_ARGS(ab))
+DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__hit);
+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_l2arc__hit);
+DEFINE_ARC_BUF_HDR_EVENT(zfs_l2arc__miss);
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ *     vdev_t *, ...,
+ *     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),
+       TP_STRUCT__entry(
+           __field(uint64_t,   vdev_id)
+           __field(uint64_t,   vdev_guid)
+           __field(uint64_t,   vdev_state)
+           ZIO_TP_STRUCT_ENTRY
+       ),
+       TP_fast_assign(
+           __entry->vdev_id    = vd->vdev_id;
+           __entry->vdev_guid  = vd->vdev_guid;
+           __entry->vdev_state = vd->vdev_state;
+           ZIO_TP_FAST_ASSIGN
+       ),
+       TP_printk("vdev { id %llu guid %llu state %llu } "
+           ZIO_TP_PRINTK_FMT, __entry->vdev_id, __entry->vdev_guid,
+           __entry->vdev_state, ZIO_TP_PRINTK_ARGS)
+);
+
+#define        DEFINE_L2ARC_RW_EVENT(name) \
+DEFINE_EVENT(zfs_l2arc_rw_class, name, \
+       TP_PROTO(vdev_t *vd, zio_t *zio), \
+       TP_ARGS(vd, zio))
+DEFINE_L2ARC_RW_EVENT(zfs_l2arc__read);
+DEFINE_L2ARC_RW_EVENT(zfs_l2arc__write);
+
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ *     zio_t *, ...,
+ *     l2arc_write_callback_t *, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_l2arc_iodone_class,
+       TP_PROTO(zio_t *zio, l2arc_write_callback_t *cb),
+       TP_ARGS(zio, cb),
+       TP_STRUCT__entry(ZIO_TP_STRUCT_ENTRY),
+       TP_fast_assign(ZIO_TP_FAST_ASSIGN),
+       TP_printk(ZIO_TP_PRINTK_FMT, ZIO_TP_PRINTK_ARGS)
+);
+
+#define        DEFINE_L2ARC_IODONE_EVENT(name) \
+DEFINE_EVENT(zfs_l2arc_iodone_class, name, \
+       TP_PROTO(zio_t *zio, l2arc_write_callback_t *cb), \
+       TP_ARGS(zio, cb))
+DEFINE_L2ARC_IODONE_EVENT(zfs_l2arc__iodone);
+
+
+/*
+ * Generic support for four argument tracepoints of the form:
+ *
+ * DTRACE_PROBE4(...,
+ *     arc_buf_hdr_t *, ...,
+ *     const blkptr_t *,
+ *     uint64_t,
+ *     const zbookmark_phys_t *);
+ */
+
+DECLARE_EVENT_CLASS(zfs_arc_miss_class,
+       TP_PROTO(arc_buf_hdr_t *hdr,
+           const blkptr_t *bp, uint64_t size, const zbookmark_phys_t *zb),
+       TP_ARGS(hdr, bp, size, zb),
+       TP_STRUCT__entry(
+           __array(uint64_t,           hdr_dva_word, 2)
+           __field(uint64_t,           hdr_birth)
+           __field(uint32_t,           hdr_flags)
+           __field(uint32_t,           hdr_datacnt)
+           __field(arc_buf_contents_t, hdr_type)
+           __field(uint64_t,           hdr_size)
+           __field(uint64_t,           hdr_spa)
+           __field(arc_state_type_t,   hdr_state_type)
+           __field(clock_t,            hdr_access)
+           __field(uint32_t,           hdr_mru_hits)
+           __field(uint32_t,           hdr_mru_ghost_hits)
+           __field(uint32_t,           hdr_mfu_hits)
+           __field(uint32_t,           hdr_mfu_ghost_hits)
+           __field(uint32_t,           hdr_l2_hits)
+           __field(int64_t,            hdr_refcount)
+
+           __array(uint64_t,           bp_dva0, 2)
+           __array(uint64_t,           bp_dva1, 2)
+           __array(uint64_t,           bp_dva2, 2)
+           __array(uint64_t,           bp_cksum, 4)
+
+           __field(uint64_t,           bp_lsize)
+
+           __field(uint64_t,           zb_objset)
+           __field(uint64_t,           zb_object)
+           __field(int64_t,            zb_level)
+           __field(uint64_t,           zb_blkid)
+       ),
+       TP_fast_assign(
+           __entry->hdr_dva_word[0]    = hdr->b_dva.dva_word[0];
+           __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_spa            = hdr->b_spa;
+           __entry->hdr_state_type     = hdr->b_l1hdr.b_state->arcs_state;
+           __entry->hdr_access         = hdr->b_l1hdr.b_arc_access;
+           __entry->hdr_mru_hits       = hdr->b_l1hdr.b_mru_hits;
+           __entry->hdr_mru_ghost_hits = hdr->b_l1hdr.b_mru_ghost_hits;
+           __entry->hdr_mfu_hits       = hdr->b_l1hdr.b_mfu_hits;
+           __entry->hdr_mfu_ghost_hits = hdr->b_l1hdr.b_mfu_ghost_hits;
+           __entry->hdr_l2_hits        = hdr->b_l1hdr.b_l2_hits;
+           __entry->hdr_refcount       = hdr->b_l1hdr.b_refcnt.rc_count;
+
+           __entry->bp_dva0[0]         = bp->blk_dva[0].dva_word[0];
+           __entry->bp_dva0[1]         = bp->blk_dva[0].dva_word[1];
+           __entry->bp_dva1[0]         = bp->blk_dva[1].dva_word[0];
+           __entry->bp_dva1[1]         = bp->blk_dva[1].dva_word[1];
+           __entry->bp_dva2[0]         = bp->blk_dva[2].dva_word[0];
+           __entry->bp_dva2[1]         = bp->blk_dva[2].dva_word[1];
+           __entry->bp_cksum[0]        = bp->blk_cksum.zc_word[0];
+           __entry->bp_cksum[1]        = bp->blk_cksum.zc_word[1];
+           __entry->bp_cksum[2]        = bp->blk_cksum.zc_word[2];
+           __entry->bp_cksum[3]        = bp->blk_cksum.zc_word[3];
+
+           __entry->bp_lsize           = size;
+
+           __entry->zb_objset          = zb->zb_objset;
+           __entry->zb_object          = zb->zb_object;
+           __entry->zb_level           = zb->zb_level;
+           __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 "
+           "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 "
+           "0x%llx:0x%llx cksum 0x%llx:0x%llx:0x%llx:0x%llx "
+           "lsize %llu } zb { objset %llu object %llu level %lli "
+           "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_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, __entry->hdr_refcount,
+           __entry->bp_dva0[0], __entry->bp_dva0[1],
+           __entry->bp_dva1[0], __entry->bp_dva1[1],
+           __entry->bp_dva2[0], __entry->bp_dva2[1],
+           __entry->bp_cksum[0], __entry->bp_cksum[1],
+           __entry->bp_cksum[2], __entry->bp_cksum[3],
+           __entry->bp_lsize, __entry->zb_objset, __entry->zb_object,
+           __entry->zb_level, __entry->zb_blkid)
+);
+
+#define        DEFINE_ARC_MISS_EVENT(name) \
+DEFINE_EVENT(zfs_arc_miss_class, name, \
+       TP_PROTO(arc_buf_hdr_t *hdr, \
+           const blkptr_t *bp, uint64_t size, const zbookmark_phys_t *zb), \
+       TP_ARGS(hdr, bp, size, zb))
+DEFINE_ARC_MISS_EVENT(zfs_arc__miss);
+
+/*
+ * Generic support for four argument tracepoints of the form:
+ *
+ * DTRACE_PROBE4(...,
+ *     l2arc_dev_t *, ...,
+ *     list_t *, ...,
+ *     uint64_t, ...,
+ *     boolean_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_l2arc_evict_class,
+       TP_PROTO(l2arc_dev_t *dev,
+           list_t *buflist, uint64_t taddr, boolean_t all),
+       TP_ARGS(dev, buflist, taddr, all),
+       TP_STRUCT__entry(
+           __field(uint64_t,           vdev_id)
+           __field(uint64_t,           vdev_guid)
+           __field(uint64_t,           vdev_state)
+
+           __field(uint64_t,           l2ad_hand)
+           __field(uint64_t,           l2ad_start)
+           __field(uint64_t,           l2ad_end)
+           __field(boolean_t,          l2ad_first)
+           __field(boolean_t,          l2ad_writing)
+
+           __field(uint64_t,           taddr)
+           __field(boolean_t,          all)
+       ),
+       TP_fast_assign(
+           __entry->vdev_id            = dev->l2ad_vdev->vdev_id;
+           __entry->vdev_guid          = dev->l2ad_vdev->vdev_guid;
+           __entry->vdev_state         = dev->l2ad_vdev->vdev_state;
+
+           __entry->l2ad_hand          = dev->l2ad_hand;
+           __entry->l2ad_start         = dev->l2ad_start;
+           __entry->l2ad_end           = dev->l2ad_end;
+           __entry->l2ad_first         = dev->l2ad_first;
+           __entry->l2ad_writing       = dev->l2ad_writing;
+
+           __entry->taddr              = taddr;
+           __entry->all                = all;
+       ),
+       TP_printk("l2ad { vdev { id %llu guid %llu state %llu } "
+           "hand %llu start %llu end %llu "
+           "first %d writing %d } taddr %llu all %d",
+           __entry->vdev_id, __entry->vdev_guid, __entry->vdev_state,
+           __entry->l2ad_hand, __entry->l2ad_start,
+           __entry->l2ad_end, __entry->l2ad_first, __entry->l2ad_writing,
+           __entry->taddr, __entry->all)
+);
+
+#define        DEFINE_L2ARC_EVICT_EVENT(name) \
+DEFINE_EVENT(zfs_l2arc_evict_class, name, \
+       TP_PROTO(l2arc_dev_t *dev, \
+           list_t *buflist, uint64_t taddr, boolean_t all), \
+       TP_ARGS(dev, buflist, taddr, all))
+DEFINE_L2ARC_EVICT_EVENT(zfs_l2arc__evict);
+
+#endif /* _TRACE_ARC_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_arc
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_dbgmsg.h b/zfs/include/sys/trace_dbgmsg.h
new file mode 100644 (file)
index 0000000..e493a45
--- /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
+ */
+
+/* Do not include this file directly. Please use <sys/trace.h> instead. */
+#ifndef _SYS_TRACE_DBGMSG_INDIRECT
+#error "trace_dbgmsg.h included directly"
+#endif
+
+/*
+ * This file defines tracepoint events for use by the dbgmsg(),
+ * dprintf(), and SET_ERROR() interfaces. These are grouped here because
+ * they all provide a way to store simple messages in the debug log (as
+ * opposed to events used by the DTRACE_PROBE interfaces which typically
+ * dump structured data).
+ *
+ * This header is included inside the trace.h multiple inclusion guard,
+ * and it is guarded above against direct inclusion, so it and need not
+ * be guarded separately.
+ */
+
+/*
+ * Generic support for four argument tracepoints of the form:
+ *
+ * DTRACE_PROBE4(...,
+ *     const char *, ...,
+ *     const char *, ...,
+ *     int, ...,
+ *     const char *, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_dprintf_class,
+       TP_PROTO(const char *file, const char *function, int line,
+           const char *msg),
+       TP_ARGS(file, function, line, msg),
+       TP_STRUCT__entry(
+           __field(const char *,       file)
+           __field(const char *,       function)
+           __field(int,                line)
+           __string(msg, msg)
+       ),
+       TP_fast_assign(
+           __entry->file               = file;
+           __entry->function           = function;
+           __entry->line               = line;
+           __assign_str(msg, msg);
+       ),
+       TP_printk("%s:%d:%s(): %s", __entry->file, __entry->line,
+           __entry->function, __get_str(msg))
+);
+
+#define        DEFINE_DPRINTF_EVENT(name) \
+DEFINE_EVENT(zfs_dprintf_class, name, \
+       TP_PROTO(const char *file, const char *function, int line, \
+           const char *msg), \
+       TP_ARGS(file, function, line, msg))
+DEFINE_DPRINTF_EVENT(zfs_zfs__dprintf);
+
+/*
+ * Generic support for four argument tracepoints of the form:
+ *
+ * DTRACE_PROBE4(...,
+ *     const char *, ...,
+ *     const char *, ...,
+ *     int, ...,
+ *     uintptr_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_set_error_class,
+       TP_PROTO(const char *file, const char *function, int line,
+           uintptr_t error),
+       TP_ARGS(file, function, line, error),
+       TP_STRUCT__entry(
+           __field(const char *,       file)
+           __field(const char *,       function)
+           __field(int,                line)
+           __field(uintptr_t,          error)
+       ),
+       TP_fast_assign(
+           __entry->file = strchr(file, '/') ? strrchr(file, '/') + 1 : file;
+           __entry->function           = function;
+           __entry->line               = line;
+           __entry->error              = error;
+       ),
+       TP_printk("%s:%d:%s(): error 0x%lx", __entry->file, __entry->line,
+           __entry->function, __entry->error)
+);
+
+#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))
+DEFINE_SET_ERROR_EVENT(zfs_set__error);
diff --git a/zfs/include/sys/trace_dbuf.h b/zfs/include/sys/trace_dbuf.h
new file mode 100644 (file)
index 0000000..49e35e3
--- /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 (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_dbuf
+
+#if !defined(_TRACE_DBUF_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_DBUF_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ *     dmu_buf_impl_t *, ...,
+ *     zio_t *, ...);
+ */
+
+#define        DBUF_TP_STRUCT_ENTRY                                    \
+       __field(const char *,   os_spa)                         \
+       __field(uint64_t,       ds_object)                      \
+       __field(uint64_t,       db_object)                      \
+       __field(uint64_t,       db_level)                       \
+       __field(uint64_t,       db_blkid)                       \
+       __field(uint64_t,       db_offset)                      \
+       __field(uint64_t,       db_size)                        \
+       __field(uint64_t,       db_state)                       \
+       __field(int64_t,        db_holds)                       \
+
+#define        DBUF_TP_FAST_ASSIGN                                     \
+       __entry->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;       \
+                                                               \
+       __entry->db_object = db->db.db_object;                  \
+       __entry->db_level  = db->db_level;                      \
+       __entry->db_blkid  = db->db_blkid;                      \
+       __entry->db_offset = db->db.db_offset;                  \
+       __entry->db_size   = db->db.db_size;                    \
+       __entry->db_state  = db->db_state;                      \
+       __entry->db_holds  = refcount_count(&db->db_holds);
+
+#define        DBUF_TP_PRINTK_FMT                                              \
+       "dbuf { spa \"%s\" objset %llu object %llu level %llu "         \
+       "blkid %llu offset %llu size %llu state %llu holds %lld }"
+
+#define        DBUF_TP_PRINTK_ARGS                                     \
+       __entry->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
+
+DECLARE_EVENT_CLASS(zfs_dbuf_class,
+       TP_PROTO(dmu_buf_impl_t *db, zio_t *zio),
+       TP_ARGS(db, zio),
+       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_EVENT(name) \
+DEFINE_EVENT(zfs_dbuf_class, name, \
+       TP_PROTO(dmu_buf_impl_t *db, zio_t *zio), \
+       TP_ARGS(db, zio))
+DEFINE_DBUF_EVENT(zfs_blocked__read);
+
+#endif /* _TRACE_DBUF_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_dbuf
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_dmu.h b/zfs/include/sys/trace_dmu.h
new file mode 100644 (file)
index 0000000..e070997
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_dmu
+
+#if !defined(_TRACE_DMU_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_DMU_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ *     dmu_tx_t *, ...,
+ *     uint64_t, ...,
+ *     uint64_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_delay_mintime_class,
+       TP_PROTO(dmu_tx_t *tx, uint64_t dirty, uint64_t min_tx_time),
+       TP_ARGS(tx, dirty, min_tx_time),
+       TP_STRUCT__entry(
+           __field(uint64_t,                   tx_txg)
+           __field(uint64_t,                   tx_lastsnap_txg)
+           __field(uint64_t,                   tx_lasttried_txg)
+           __field(boolean_t,                  tx_anyobj)
+           __field(boolean_t,                  tx_waited)
+           __field(hrtime_t,                   tx_start)
+           __field(boolean_t,                  tx_wait_dirty)
+           __field(int,                        tx_err)
+#ifdef DEBUG_DMU_TX
+           __field(uint64_t,                   tx_space_towrite)
+           __field(uint64_t,                   tx_space_tofree)
+           __field(uint64_t,                   tx_space_tooverwrite)
+           __field(uint64_t,                   tx_space_tounref)
+           __field(int64_t,                    tx_space_written)
+           __field(int64_t,                    tx_space_freed)
+#endif
+           __field(uint64_t,                   min_tx_time)
+           __field(uint64_t,                   dirty)
+       ),
+       TP_fast_assign(
+           __entry->tx_txg                     = tx->tx_txg;
+           __entry->tx_lastsnap_txg            = tx->tx_lastsnap_txg;
+           __entry->tx_lasttried_txg           = tx->tx_lasttried_txg;
+           __entry->tx_anyobj                  = tx->tx_anyobj;
+           __entry->tx_waited                  = tx->tx_waited;
+           __entry->tx_start                   = tx->tx_start;
+           __entry->tx_wait_dirty              = tx->tx_wait_dirty;
+           __entry->tx_err                     = tx->tx_err;
+#ifdef DEBUG_DMU_TX
+           __entry->tx_space_towrite           = tx->tx_space_towrite;
+           __entry->tx_space_tofree            = tx->tx_space_tofree;
+           __entry->tx_space_tooverwrite       = tx->tx_space_tooverwrite;
+           __entry->tx_space_tounref           = tx->tx_space_tounref;
+           __entry->tx_space_written           = tx->tx_space_written.rc_count;
+           __entry->tx_space_freed             = tx->tx_space_freed.rc_count;
+#endif
+           __entry->dirty                      = dirty;
+           __entry->min_tx_time                = min_tx_time;
+       ),
+       TP_printk("tx { txg %llu lastsnap_txg %llu tx_lasttried_txg %llu "
+           "anyobj %d waited %d start %llu wait_dirty %d err %i "
+#ifdef DEBUG_DMU_TX
+           "space_towrite %llu space_tofree %llu space_tooverwrite %llu "
+           "space_tounref %llu space_written %lli space_freed %lli "
+#endif
+           "} dirty %llu min_tx_time %llu",
+           __entry->tx_txg, __entry->tx_lastsnap_txg,
+           __entry->tx_lasttried_txg, __entry->tx_anyobj, __entry->tx_waited,
+           __entry->tx_start, __entry->tx_wait_dirty, __entry->tx_err,
+#ifdef DEBUG_DMU_TX
+           __entry->tx_space_towrite, __entry->tx_space_tofree,
+           __entry->tx_space_tooverwrite, __entry->tx_space_tounref,
+           __entry->tx_space_written, __entry->tx_space_freed,
+#endif
+           __entry->dirty, __entry->min_tx_time)
+);
+
+#define        DEFINE_DELAY_MINTIME_EVENT(name) \
+DEFINE_EVENT(zfs_delay_mintime_class, name, \
+       TP_PROTO(dmu_tx_t *tx, uint64_t dirty, uint64_t min_tx_time), \
+       TP_ARGS(tx, dirty, min_tx_time))
+DEFINE_DELAY_MINTIME_EVENT(zfs_delay__mintime);
+
+#endif /* _TRACE_DMU_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_dmu
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_dnode.h b/zfs/include/sys/trace_dnode.h
new file mode 100644 (file)
index 0000000..ee63c29
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_dnode
+
+#if !defined(_TRACE_DNODE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_DNODE_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ *     dnode_t *, ...,
+ *     int64_t, ...,
+ *     uint32_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_dnode_move_class,
+       TP_PROTO(dnode_t *dn, int64_t refcount, uint32_t dbufs),
+       TP_ARGS(dn, refcount, dbufs),
+       TP_STRUCT__entry(
+           __field(uint64_t,           dn_object)
+           __field(dmu_object_type_t,  dn_type)
+           __field(uint16_t,           dn_bonuslen)
+           __field(uint8_t,            dn_bonustype)
+           __field(uint8_t,            dn_nblkptr)
+           __field(uint8_t,            dn_checksum)
+           __field(uint8_t,            dn_compress)
+           __field(uint8_t,            dn_nlevels)
+           __field(uint8_t,            dn_indblkshift)
+           __field(uint8_t,            dn_datablkshift)
+           __field(uint8_t,            dn_moved)
+           __field(uint16_t,           dn_datablkszsec)
+           __field(uint32_t,           dn_datablksz)
+           __field(uint64_t,           dn_maxblkid)
+           __field(int64_t,            dn_tx_holds)
+           __field(int64_t,            dn_holds)
+           __field(boolean_t,          dn_have_spill)
+
+           __field(int64_t,            refcount)
+           __field(uint32_t,           dbufs)
+       ),
+       TP_fast_assign(
+           __entry->dn_object          = dn->dn_object;
+           __entry->dn_type            = dn->dn_type;
+           __entry->dn_bonuslen        = dn->dn_bonuslen;
+           __entry->dn_bonustype       = dn->dn_bonustype;
+           __entry->dn_nblkptr         = dn->dn_nblkptr;
+           __entry->dn_checksum        = dn->dn_checksum;
+           __entry->dn_compress        = dn->dn_compress;
+           __entry->dn_nlevels         = dn->dn_nlevels;
+           __entry->dn_indblkshift     = dn->dn_indblkshift;
+           __entry->dn_datablkshift    = dn->dn_datablkshift;
+           __entry->dn_moved           = dn->dn_moved;
+           __entry->dn_datablkszsec    = dn->dn_datablkszsec;
+           __entry->dn_datablksz       = dn->dn_datablksz;
+           __entry->dn_maxblkid        = dn->dn_maxblkid;
+           __entry->dn_tx_holds        = dn->dn_tx_holds.rc_count;
+           __entry->dn_holds           = dn->dn_holds.rc_count;
+           __entry->dn_have_spill      = dn->dn_have_spill;
+
+           __entry->refcount           = refcount;
+           __entry->dbufs              = dbufs;
+       ),
+       TP_printk("dn { object %llu type %d bonuslen %u bonustype %u "
+           "nblkptr %u checksum %u compress %u nlevels %u indblkshift %u "
+           "datablkshift %u moved %u datablkszsec %u datablksz %u "
+           "maxblkid %llu tx_holds %lli holds %lli have_spill %d } "
+           "refcount %lli dbufs %u",
+           __entry->dn_object, __entry->dn_type, __entry->dn_bonuslen,
+           __entry->dn_bonustype, __entry->dn_nblkptr, __entry->dn_checksum,
+           __entry->dn_compress, __entry->dn_nlevels, __entry->dn_indblkshift,
+           __entry->dn_datablkshift, __entry->dn_moved,
+           __entry->dn_datablkszsec, __entry->dn_datablksz,
+           __entry->dn_maxblkid, __entry->dn_tx_holds, __entry->dn_holds,
+           __entry->dn_have_spill, __entry->refcount, __entry->dbufs)
+);
+
+#define        DEFINE_DNODE_MOVE_EVENT(name) \
+DEFINE_EVENT(zfs_dnode_move_class, name, \
+       TP_PROTO(dnode_t *dn, int64_t refcount, uint32_t dbufs), \
+       TP_ARGS(dn, refcount, dbufs))
+DEFINE_DNODE_MOVE_EVENT(zfs_dnode__move);
+
+#endif /* _TRACE_DNODE_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_dnode
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_multilist.h b/zfs/include/sys/trace_multilist.h
new file mode 100644 (file)
index 0000000..08e27a9
--- /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
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_multilist
+
+#if !defined(_TRACE_MULTILIST_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_MULTILIST_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ *     multilist_t *, ...,
+ *     unsigned int, ...,
+ *     void *, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_multilist_insert_remove_class,
+       TP_PROTO(multilist_t *ml, unsigned sublist_idx, void *obj),
+       TP_ARGS(ml, sublist_idx, obj),
+       TP_STRUCT__entry(
+           __field(size_t,             ml_offset)
+           __field(uint64_t,           ml_num_sublists)
+
+           __field(unsigned int,       sublist_idx)
+       ),
+       TP_fast_assign(
+           __entry->ml_offset          = ml->ml_offset;
+           __entry->ml_num_sublists    = ml->ml_num_sublists;
+
+           __entry->sublist_idx        = sublist_idx;
+       ),
+       TP_printk("ml { offset %ld numsublists %llu sublistidx %u } ",
+           __entry->ml_offset, __entry->ml_num_sublists, __entry->sublist_idx)
+);
+
+#define        DEFINE_MULTILIST_INSERT_REMOVE_EVENT(name) \
+DEFINE_EVENT(zfs_multilist_insert_remove_class, name, \
+       TP_PROTO(multilist_t *ml, unsigned int sublist_idx, void *obj), \
+       TP_ARGS(ml, sublist_idx, obj))
+DEFINE_MULTILIST_INSERT_REMOVE_EVENT(zfs_multilist__insert);
+DEFINE_MULTILIST_INSERT_REMOVE_EVENT(zfs_multilist__remove);
+
+#endif /* _TRACE_MULTILIST_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_multilist
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_txg.h b/zfs/include/sys/trace_txg.h
new file mode 100644 (file)
index 0000000..61d6509
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_txg
+
+#if !defined(_TRACE_TXG_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_TXG_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ *     dsl_pool_t *, ...,
+ *     uint64_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_txg_class,
+       TP_PROTO(dsl_pool_t *dp, uint64_t txg),
+       TP_ARGS(dp, txg),
+       TP_STRUCT__entry(
+           __field(uint64_t, txg)
+       ),
+       TP_fast_assign(
+           __entry->txg = txg;
+       ),
+       TP_printk("txg %llu", __entry->txg)
+);
+
+#define        DEFINE_TXG_EVENT(name) \
+DEFINE_EVENT(zfs_txg_class, name, \
+       TP_PROTO(dsl_pool_t *dp, uint64_t txg), \
+       TP_ARGS(dp, txg))
+DEFINE_TXG_EVENT(zfs_dsl_pool_sync__done);
+DEFINE_TXG_EVENT(zfs_txg__quiescing);
+DEFINE_TXG_EVENT(zfs_txg__opened);
+DEFINE_TXG_EVENT(zfs_txg__syncing);
+DEFINE_TXG_EVENT(zfs_txg__synced);
+DEFINE_TXG_EVENT(zfs_txg__quiesced);
+
+#endif /* _TRACE_TXG_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_txg
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_zil.h b/zfs/include/sys/trace_zil.h
new file mode 100644 (file)
index 0000000..e97466f
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_zil
+
+#if !defined(_TRACE_ZIL_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_ZIL_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for one argument tracepoints of the form:
+ *
+ * DTRACE_PROBE1(...,
+ *     zilog_t *, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_zil_class,
+       TP_PROTO(zilog_t *zilog),
+       TP_ARGS(zilog),
+       TP_STRUCT__entry(
+           __field(uint64_t,   zl_lr_seq)
+           __field(uint64_t,   zl_commit_lr_seq)
+           __field(uint64_t,   zl_destroy_txg)
+           __field(uint64_t,   zl_replaying_seq)
+           __field(uint32_t,   zl_suspend)
+           __field(uint8_t,    zl_suspending)
+           __field(uint8_t,    zl_keep_first)
+           __field(uint8_t,    zl_replay)
+           __field(uint8_t,    zl_stop_sync)
+           __field(uint8_t,    zl_writer)
+           __field(uint8_t,    zl_logbias)
+           __field(uint8_t,    zl_sync)
+           __field(int,        zl_parse_error)
+           __field(uint64_t,   zl_parse_blk_seq)
+           __field(uint64_t,   zl_parse_lr_seq)
+           __field(uint64_t,   zl_parse_blk_count)
+           __field(uint64_t,   zl_parse_lr_count)
+           __field(uint64_t,   zl_next_batch)
+           __field(uint64_t,   zl_com_batch)
+           __field(uint64_t,   zl_itx_list_sz)
+           __field(uint64_t,   zl_cur_used)
+           __field(clock_t,    zl_replay_time)
+           __field(uint64_t,   zl_replay_blks)
+       ),
+       TP_fast_assign(
+           __entry->zl_lr_seq          = zilog->zl_lr_seq;
+           __entry->zl_commit_lr_seq   = zilog->zl_commit_lr_seq;
+           __entry->zl_destroy_txg     = zilog->zl_destroy_txg;
+           __entry->zl_replaying_seq   = zilog->zl_replaying_seq;
+           __entry->zl_suspend         = zilog->zl_suspend;
+           __entry->zl_suspending      = zilog->zl_suspending;
+           __entry->zl_keep_first      = zilog->zl_keep_first;
+           __entry->zl_replay          = zilog->zl_replay;
+           __entry->zl_stop_sync       = zilog->zl_stop_sync;
+           __entry->zl_writer          = zilog->zl_writer;
+           __entry->zl_logbias         = zilog->zl_logbias;
+           __entry->zl_sync            = zilog->zl_sync;
+           __entry->zl_parse_error     = zilog->zl_parse_error;
+           __entry->zl_parse_blk_seq   = zilog->zl_parse_blk_seq;
+           __entry->zl_parse_lr_seq    = zilog->zl_parse_lr_seq;
+           __entry->zl_parse_blk_count = zilog->zl_parse_blk_count;
+           __entry->zl_parse_lr_count  = zilog->zl_parse_lr_count;
+           __entry->zl_next_batch      = zilog->zl_next_batch;
+           __entry->zl_com_batch       = zilog->zl_com_batch;
+           __entry->zl_itx_list_sz     = zilog->zl_itx_list_sz;
+           __entry->zl_cur_used        = zilog->zl_cur_used;
+           __entry->zl_replay_time     = zilog->zl_replay_time;
+           __entry->zl_replay_blks     = zilog->zl_replay_blks;
+       ),
+       TP_printk("zl { lr_seq %llu commit_lr_seq %llu destroy_txg %llu "
+           "replaying_seq %llu suspend %u suspending %u keep_first %u "
+           "replay %u stop_sync %u writer %u logbias %u sync %u "
+           "parse_error %u parse_blk_seq %llu parse_lr_seq %llu "
+           "parse_blk_count %llu parse_lr_count %llu next_batch %llu "
+           "com_batch %llu itx_list_sz %llu cur_used %llu replay_time %lu "
+           "replay_blks %llu }",
+           __entry->zl_lr_seq, __entry->zl_commit_lr_seq,
+           __entry->zl_destroy_txg, __entry->zl_replaying_seq,
+           __entry->zl_suspend, __entry->zl_suspending, __entry->zl_keep_first,
+           __entry->zl_replay, __entry->zl_stop_sync, __entry->zl_writer,
+           __entry->zl_logbias, __entry->zl_sync, __entry->zl_parse_error,
+           __entry->zl_parse_blk_seq, __entry->zl_parse_lr_seq,
+           __entry->zl_parse_blk_count, __entry->zl_parse_lr_count,
+           __entry->zl_next_batch, __entry->zl_com_batch,
+           __entry->zl_itx_list_sz, __entry->zl_cur_used,
+           __entry->zl_replay_time, __entry->zl_replay_blks)
+);
+
+#define        DEFINE_ZIL_EVENT(name) \
+DEFINE_EVENT(zfs_zil_class, name, \
+       TP_PROTO(zilog_t *zilog), \
+       TP_ARGS(zilog))
+DEFINE_ZIL_EVENT(zfs_zil__cw1);
+DEFINE_ZIL_EVENT(zfs_zil__cw2);
+
+#endif /* _TRACE_ZIL_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_zil
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/trace_zrlock.h b/zfs/include/sys/trace_zrlock.h
new file mode 100644 (file)
index 0000000..e1399c4
--- /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
+ */
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_zrlock
+
+#if !defined(_TRACE_ZRLOCK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_ZRLOCK_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ *     zrlock_t *, ...,
+ *     uint32_t, ...);
+ */
+
+DECLARE_EVENT_CLASS(zfs_zrlock_class,
+       TP_PROTO(zrlock_t *zrl, uint32_t n),
+       TP_ARGS(zrl, n),
+       TP_STRUCT__entry(
+           __field(int32_t,            refcount)
+#ifdef ZFS_DEBUG
+           __field(pid_t,              owner_pid)
+           __field(const char *,       caller)
+#endif
+           __field(uint32_t,           n)
+       ),
+       TP_fast_assign(
+           __entry->refcount   = zrl->zr_refcount;
+#ifdef ZFS_DEBUG
+           __entry->owner_pid  = zrl->zr_owner ? zrl->zr_owner->pid : 0;
+           __entry->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->n)
+#else
+       TP_printk("zrl { refcount %d } n %u",
+           __entry->refcount, __entry->n)
+#endif
+);
+
+#define        DEFINE_ZRLOCK_EVENT(name) \
+DEFINE_EVENT(zfs_zrlock_class, name, \
+       TP_PROTO(zrlock_t *zrl, uint32_t n), \
+       TP_ARGS(zrl, n))
+DEFINE_ZRLOCK_EVENT(zfs_zrlock__reentry);
+
+#endif /* _TRACE_ZRLOCK_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_zrlock
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
diff --git a/zfs/include/sys/txg.h b/zfs/include/sys/txg.h
new file mode 100644 (file)
index 0000000..44f81be
--- /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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_TXG_H
+#define        _SYS_TXG_H
+
+#include <sys/spa.h>
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        TXG_CONCURRENT_STATES   3       /* open, quiescing, syncing     */
+#define        TXG_SIZE                4               /* next power of 2      */
+#define        TXG_MASK                (TXG_SIZE - 1)  /* mask for size        */
+#define        TXG_INITIAL             TXG_SIZE        /* initial txg          */
+#define        TXG_IDX                 (txg & TXG_MASK)
+
+/* Number of txgs worth of frees we defer adding to in-core spacemaps */
+#define        TXG_DEFER_SIZE          2
+
+typedef struct tx_cpu tx_cpu_t;
+
+typedef struct txg_handle {
+       tx_cpu_t        *th_cpu;
+       uint64_t        th_txg;
+} txg_handle_t;
+
+typedef struct txg_node {
+       struct txg_node *tn_next[TXG_SIZE];
+       uint8_t         tn_member[TXG_SIZE];
+} txg_node_t;
+
+typedef struct txg_list {
+       kmutex_t        tl_lock;
+       size_t          tl_offset;
+       txg_node_t      *tl_head[TXG_SIZE];
+} txg_list_t;
+
+struct dsl_pool;
+
+extern void txg_init(struct dsl_pool *dp, uint64_t txg);
+extern void txg_fini(struct dsl_pool *dp);
+extern void txg_sync_start(struct dsl_pool *dp);
+extern void txg_sync_stop(struct dsl_pool *dp);
+extern uint64_t txg_hold_open(struct dsl_pool *dp, txg_handle_t *txghp);
+extern void txg_rele_to_quiesce(txg_handle_t *txghp);
+extern void txg_rele_to_sync(txg_handle_t *txghp);
+extern void txg_register_callbacks(txg_handle_t *txghp, list_t *tx_callbacks);
+
+extern void txg_delay(struct dsl_pool *dp, uint64_t txg, hrtime_t delta,
+    hrtime_t resolution);
+extern void txg_kick(struct dsl_pool *dp);
+
+/*
+ * Wait until the given transaction group has finished syncing.
+ * Try to make this happen as soon as possible (eg. kick off any
+ * necessary syncs immediately).  If txg==0, wait for the currently open
+ * txg to finish syncing.
+ */
+extern void txg_wait_synced(struct dsl_pool *dp, uint64_t txg);
+
+/*
+ * Wait until the given transaction group, or one after it, is
+ * the open transaction group.  Try to make this happen as soon
+ * as possible (eg. kick off any necessary syncs immediately).
+ * If txg == 0, wait for the next open txg.
+ */
+extern void txg_wait_open(struct dsl_pool *dp, uint64_t txg);
+
+/*
+ * Returns TRUE if we are "backed up" waiting for the syncing
+ * transaction to complete; otherwise returns FALSE.
+ */
+extern boolean_t txg_stalled(struct dsl_pool *dp);
+
+/* returns TRUE if someone is waiting for the next txg to sync */
+extern boolean_t txg_sync_waiting(struct dsl_pool *dp);
+
+/*
+ * Wait for pending commit callbacks of already-synced transactions to finish
+ * processing.
+ */
+extern void txg_wait_callbacks(struct dsl_pool *dp);
+
+/*
+ * Per-txg object lists.
+ */
+
+#define        TXG_CLEAN(txg)  ((txg) - 1)
+
+extern void txg_list_create(txg_list_t *tl, size_t offset);
+extern void txg_list_destroy(txg_list_t *tl);
+extern boolean_t txg_list_empty(txg_list_t *tl, uint64_t txg);
+extern boolean_t txg_all_lists_empty(txg_list_t *tl);
+extern boolean_t txg_list_add(txg_list_t *tl, void *p, uint64_t txg);
+extern boolean_t txg_list_add_tail(txg_list_t *tl, void *p, uint64_t txg);
+extern void *txg_list_remove(txg_list_t *tl, uint64_t txg);
+extern void *txg_list_remove_this(txg_list_t *tl, void *p, uint64_t txg);
+extern boolean_t txg_list_member(txg_list_t *tl, void *p, uint64_t txg);
+extern void *txg_list_head(txg_list_t *tl, uint64_t txg);
+extern void *txg_list_next(txg_list_t *tl, void *p, uint64_t txg);
+
+/* Global tuning */
+extern int zfs_txg_timeout;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TXG_H */
diff --git a/zfs/include/sys/txg_impl.h b/zfs/include/sys/txg_impl.h
new file mode 100644 (file)
index 0000000..e583d61
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_TXG_IMPL_H
+#define        _SYS_TXG_IMPL_H
+
+#include <sys/spa.h>
+#include <sys/txg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The tx_cpu structure is a per-cpu structure that is used to track
+ * the number of active transaction holds (tc_count). As transactions
+ * are assigned into a transaction group the appropriate tc_count is
+ * incremented to indicate that there are pending changes that have yet
+ * to quiesce. Consumers evenutally call txg_rele_to_sync() to decrement
+ * the tc_count. A transaction group is not considered quiesced until all
+ * tx_cpu structures have reached a tc_count of zero.
+ *
+ * This structure is a per-cpu structure by design. Updates to this structure
+ * are frequent and concurrent. Having a single structure would result in
+ * heavy lock contention so a per-cpu design was implemented. With the fanned
+ * out mutex design, consumers only need to lock the mutex associated with
+ * thread's cpu.
+ *
+ * The tx_cpu contains two locks, the tc_lock and tc_open_lock.
+ * The tc_lock is used to protect all members of the tx_cpu structure with
+ * the exception of the tc_open_lock. This lock should only be held for a
+ * short period of time, typically when updating the value of tc_count.
+ *
+ * The tc_open_lock protects the tx_open_txg member of the tx_state structure.
+ * This lock is used to ensure that transactions are only assigned into
+ * the current open transaction group. In order to move the current open
+ * transaction group to the quiesce phase, the txg_quiesce thread must
+ * grab all tc_open_locks, increment the tx_open_txg, and drop the locks.
+ * The tc_open_lock is held until the transaction is assigned into the
+ * transaction group. Typically, this is a short operation but if throttling
+ * is occuring it may be held for longer periods of time.
+ */
+struct tx_cpu {
+       kmutex_t        tc_open_lock;   /* protects tx_open_txg */
+       kmutex_t        tc_lock;        /* protects the rest of this struct */
+       kcondvar_t      tc_cv[TXG_SIZE];
+       uint64_t        tc_count[TXG_SIZE];     /* tx hold count on each txg */
+       list_t          tc_callbacks[TXG_SIZE]; /* commit cb list */
+       char            tc_pad[8];              /* pad to fill 3 cache lines */
+};
+
+/*
+ * The tx_state structure maintains the state information about the different
+ * stages of the pool's transcation groups. A per pool tx_state structure
+ * is used to track this information. The tx_state structure also points to
+ * an array of tx_cpu structures (described above). Although the tx_sync_lock
+ * is used to protect the members of this structure, it is not used to
+ * protect the tx_open_txg. Instead a special lock in the tx_cpu structure
+ * is used. Readers of tx_open_txg must grab the per-cpu tc_open_lock.
+ * Any thread wishing to update tx_open_txg must grab the tc_open_lock on
+ * every cpu (see txg_quiesce()).
+ */
+typedef struct tx_state {
+       tx_cpu_t        *tx_cpu;        /* protects access to tx_open_txg */
+       kmutex_t        tx_sync_lock;   /* protects the rest of this struct */
+
+       uint64_t        tx_open_txg;    /* currently open txg id */
+       uint64_t        tx_quiesced_txg; /* quiesced txg waiting for sync */
+       uint64_t        tx_syncing_txg; /* currently syncing txg id */
+       uint64_t        tx_synced_txg;  /* last synced txg id */
+
+       hrtime_t        tx_open_time;   /* start time of tx_open_txg */
+
+       uint64_t        tx_sync_txg_waiting; /* txg we're waiting to sync */
+       uint64_t        tx_quiesce_txg_waiting; /* txg we're waiting to open */
+
+       kcondvar_t      tx_sync_more_cv;
+       kcondvar_t      tx_sync_done_cv;
+       kcondvar_t      tx_quiesce_more_cv;
+       kcondvar_t      tx_quiesce_done_cv;
+       kcondvar_t      tx_timeout_cv;
+       kcondvar_t      tx_exit_cv;     /* wait for all threads to exit */
+
+       uint8_t         tx_threads;     /* number of threads */
+       uint8_t         tx_exiting;     /* set when we're exiting */
+
+       kthread_t       *tx_sync_thread;
+       kthread_t       *tx_quiesce_thread;
+
+       taskq_t         *tx_commit_cb_taskq; /* commit callback taskq */
+} tx_state_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TXG_IMPL_H */
diff --git a/zfs/include/sys/u8_textprep.h b/zfs/include/sys/u8_textprep.h
new file mode 100644 (file)
index 0000000..f8b5bed
--- /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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_U8_TEXTPREP_H
+#define        _SYS_U8_TEXTPREP_H
+
+
+
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Unicode encoding conversion functions and their macros.
+ */
+#define        UCONV_IN_BIG_ENDIAN             0x0001
+#define        UCONV_OUT_BIG_ENDIAN            0x0002
+#define        UCONV_IN_SYSTEM_ENDIAN          0x0004
+#define        UCONV_OUT_SYSTEM_ENDIAN         0x0008
+#define        UCONV_IN_LITTLE_ENDIAN          0x0010
+#define        UCONV_OUT_LITTLE_ENDIAN         0x0020
+#define        UCONV_IGNORE_NULL               0x0040
+#define        UCONV_IN_ACCEPT_BOM             0x0080
+#define        UCONV_OUT_EMIT_BOM              0x0100
+
+extern int uconv_u16tou32(const uint16_t *, size_t *, uint32_t *, size_t *,
+       int);
+extern int uconv_u16tou8(const uint16_t *, size_t *, uchar_t *, size_t *, int);
+extern int uconv_u32tou16(const uint32_t *, size_t *, uint16_t *, size_t *,
+       int);
+extern int uconv_u32tou8(const uint32_t *, size_t *, uchar_t *, size_t *, int);
+extern int uconv_u8tou16(const uchar_t *, size_t *, uint16_t *, size_t *, int);
+extern int uconv_u8tou32(const uchar_t *, size_t *, uint32_t *, size_t *, int);
+
+/*
+ * UTF-8 text preparation functions and their macros.
+ *
+ * Among the macros defined, U8_CANON_DECOMP, U8_COMPAT_DECOMP, and
+ * U8_CANON_COMP are not public interfaces and must not be used directly
+ * at the flag input argument.
+ */
+#define        U8_STRCMP_CS                    (0x00000001)
+#define        U8_STRCMP_CI_UPPER              (0x00000002)
+#define        U8_STRCMP_CI_LOWER              (0x00000004)
+
+#define        U8_CANON_DECOMP                 (0x00000010)
+#define        U8_COMPAT_DECOMP                (0x00000020)
+#define        U8_CANON_COMP                   (0x00000040)
+
+#define        U8_STRCMP_NFD                   (U8_CANON_DECOMP)
+#define        U8_STRCMP_NFC                   (U8_CANON_DECOMP | U8_CANON_COMP)
+#define        U8_STRCMP_NFKD                  (U8_COMPAT_DECOMP)
+#define        U8_STRCMP_NFKC                  (U8_COMPAT_DECOMP | U8_CANON_COMP)
+
+#define        U8_TEXTPREP_TOUPPER             (U8_STRCMP_CI_UPPER)
+#define        U8_TEXTPREP_TOLOWER             (U8_STRCMP_CI_LOWER)
+
+#define        U8_TEXTPREP_NFD                 (U8_STRCMP_NFD)
+#define        U8_TEXTPREP_NFC                 (U8_STRCMP_NFC)
+#define        U8_TEXTPREP_NFKD                (U8_STRCMP_NFKD)
+#define        U8_TEXTPREP_NFKC                (U8_STRCMP_NFKC)
+
+#define        U8_TEXTPREP_IGNORE_NULL         (0x00010000)
+#define        U8_TEXTPREP_IGNORE_INVALID      (0x00020000)
+#define        U8_TEXTPREP_NOWAIT              (0x00040000)
+
+#define        U8_UNICODE_320                  (0)
+#define        U8_UNICODE_500                  (1)
+#define        U8_UNICODE_LATEST               (U8_UNICODE_500)
+
+#define        U8_VALIDATE_ENTIRE              (0x00100000)
+#define        U8_VALIDATE_CHECK_ADDITIONAL    (0x00200000)
+#define        U8_VALIDATE_UCS2_RANGE          (0x00400000)
+
+#define        U8_ILLEGAL_CHAR                 (-1)
+#define        U8_OUT_OF_RANGE_CHAR            (-2)
+
+extern int u8_validate(char *, size_t, char **, int, int *);
+extern int u8_strcmp(const char *, const char *, size_t, int, size_t, int *);
+extern size_t u8_textprep_str(char *, size_t *, char *, size_t *, int, size_t,
+       int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_U8_TEXTPREP_H */
diff --git a/zfs/include/sys/u8_textprep_data.h b/zfs/include/sys/u8_textprep_data.h
new file mode 100644 (file)
index 0000000..03f71f2
--- /dev/null
@@ -0,0 +1,35376 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * COPYRIGHT AND PERMISSION NOTICE
+ *
+ * Copyright (c) 1991-2006 Unicode, Inc. All rights reserved. Distributed under
+ * the Terms of Use in http://www.unicode.org/copyright.html.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of the Unicode data files and any associated documentation (the
+ * "Data Files") or Unicode software and any associated documentation (the
+ * "Software") to deal in the Data Files or Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, and/or sell copies of the Data Files or Software, and
+ * to permit persons to whom the Data Files or Software are furnished to do so,
+ * provided that (a) the above copyright notice(s) and this permission notice
+ * appear with all copies of the Data Files or Software, (b) both the above
+ * copyright notice(s) and this permission notice appear in associated
+ * documentation, and (c) there is clear notice in each modified Data File or
+ * in the Software as well as in the documentation associated with the Data
+ * File(s) or Software that the data or software has been modified.
+ *
+ * THE DATA FILES AND SOFTWARE ARE 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 OF
+ * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+ * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR
+ * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THE DATA FILES OR SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall not
+ * be used in advertising or otherwise to promote the sale, use or other
+ * dealings in these Data Files or Software without prior written authorization
+ * of the copyright holder.
+ *
+ * Unicode and the Unicode logo are trademarks of Unicode, Inc., and may be
+ * registered in some jurisdictions. All other trademarks and registered
+ * trademarks mentioned herein are the property of their respective owners.
+ */
+/*
+ * This file has been modified by Sun Microsystems, Inc.
+ */
+
+#ifndef _SYS_U8_TEXTPREP_DATA_H
+#define        _SYS_U8_TEXTPREP_DATA_H
+
+
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * To get to the combining class data, composition mappings, decomposition
+ * mappings, and case conversion mappings of Unicode, the data structures
+ * formulated and their meanings are like the following:
+ *
+ * Each UTF-8 character is seen as a 4-byte entity so that U+0061 (or 0x61 in
+ * UTF-8) would be seen as 0x00 0x00 0x00 0x61. Similarly, U+1D15E would be
+ * 0xF0 0x9D 0x85 0x9E in UTF-8.
+ *
+ * The first byte (MSB) value is an index to the b1_tbl, such as
+ * u8_common_b1_tbl and u8_composition_b1_tbl tables. A b1_tbl has
+ * indices to b2_tbl tables that have indices to b3_tbl. Each b3_tbl has
+ * either indices to b4_tbl or indices to b4_tbl and base values for
+ * displacement calculations later by using the u8_displacement_t type at
+ * below. Each b4_tbl table then has indices to the final tables.
+ *
+ * As an example, if we have a character with code value of U+1D15E which is
+ * 0xF0 0x9D 0x85 0x9E in UTF-8, the target decomposition character bytes
+ * that will be mapped by the mapping procedure would be the ones between
+ * the start_index and the end_index computed as like the following:
+ *
+ *     b2_tbl_id = u8_common_b1_tbl[0][0xF0];
+ *     b3_tbl_id = u8_decomp_b2_tbl[0][b2_tbl_id][0x9D];
+ *     b4_tbl_id = u8_decomp_b3_tbl[0][b3_tbl_id][0x85].tbl_id;
+ *     b4_base = u8_decomp_b3_tbl[0][b3_tbl_id][0x85].base;
+ *     if (b4_tbl_id >= 0x8000) {
+ *             b4_tbl_id -= 0x8000;
+ *             start_index = u8_decomp_b4_16bit_tbl[0][b4_tbl_id][0x9E];
+ *             end_index = u8_decomp_b4_16bit_tbl[0][b4_tbl_id][0x9E + 1];
+ *     } else {
+ *             start_index = u8_decomp_b4_tbl[0][b4_tbl_id][0x9E];
+ *             end_index = u8_decomp_b4_tbl[0][b4_tbl_id][0x9E + 1];
+ *     }
+ *
+ * The start_index and the end_index can be used to retrieve the bytes
+ * possibly of multiple UTF-8 characters from the final tables.
+ *
+ * The "[0]" at the above indicates this is for Unicode Version 3.2.0 data
+ * as of today.  Consequently, the "[1]" indicates another Unicode version
+ * data and it is Unicode 5.0.0 as of today.
+ *
+ * The mapping procedures and the data structures are more or less similar or
+ * alike among different mappings. You might want to read the u8_textprep.c
+ * for specific details.
+ *
+ * The tool programs created and used to generate the tables in this file are
+ * saved at PSARC/2007/149/materials/ as tools.tar.gz file.
+ */
+
+/* The following is a component type for the b4_tbl vectors. */
+typedef struct {
+       uint16_t        tbl_id;
+       uint16_t        base;
+} u8_displacement_t;
+
+/*
+ * The U8_TBL_ELEMENT_NOT_DEF macro indicates a byte that is not defined or
+ * used. The U8_TBL_ELEMENT_FILLER indicates the end of a UTF-8 character at
+ * the final tables.
+ */
+#define        U8_TBL_ELEMENT_NOT_DEF          (0xff)
+#define        N_                              U8_TBL_ELEMENT_NOT_DEF
+
+#define        U8_TBL_ELEMENT_FILLER           (0xf7)
+#define        FIL_                            U8_TBL_ELEMENT_FILLER
+
+/*
+ * The common b1_tbl for combining class, decompositions, tolower, and
+ * toupper case conversion mappings.
+ */
+static const uchar_t u8_common_b1_tbl[2][256] = {
+       {
+               0,  N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               1,  N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+       },
+       {
+               0,  N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               1,  N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+       },
+};
+
+static const uchar_t u8_combining_class_b2_tbl[2][2][256] = {
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       1,  2,  3,  4,  N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 5,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 6,  N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       1,  2,  3,  4,  N_, N_, N_, N_,
+                       N_, N_, 5,  N_, N_, N_, N_, 6,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       7,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 8,  N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+
+};
+
+static const uchar_t u8_combining_class_b3_tbl[2][9][256] = {
+       {
+               {       /* Third byte table 0. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 0,  1,  N_, N_,
+                       N_, N_, 2,  N_, N_, N_, 3,  4,
+                       N_, 5,  N_, 6,  7,  8,  N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 1. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 9,  10, 11, 12,
+                       13, 14, 15, 16, 17, 18, N_, 19,
+                       N_, 20, N_, 21, N_, 22, N_, 23,
+                       24, 25, 26, 27, 28, 29, 30, 31,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 2. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       32, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 33, N_, N_, 34,
+                       N_, N_, 35, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 3. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, 36, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 4. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       37, N_, 38, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 5. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 39, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       40, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 6. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 41, 42, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 7. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 8. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+       },
+       {
+               {       /* Third byte table 0. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 0,  1,  N_, N_,
+                       N_, N_, 2,  N_, N_, N_, 3,  4,
+                       5,  6,  N_, 7,  8,  9,  N_, 10,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 1. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 11, 12, 13, 14,
+                       15, 16, 17, 18, 19, 20, N_, 21,
+                       N_, 22, 23, 24, N_, 25, N_, 26,
+                       27, 28, 29, 30, 31, 32, 33, 34,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 2. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       35, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 36, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 37, N_, N_, 38,
+                       N_, N_, 39, N_, 40, N_, N_, N_,
+                       41, N_, N_, N_, 42, 43, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 44,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 3. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, 45, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 4. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       46, N_, 47, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 5. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       48, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 6. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, 49, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       50, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 7. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       51, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {       /* Third byte table 8. */
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 52, 53, N_,
+                       N_, 54, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+       },
+};
+
+/*
+ * Unlike other b4_tbl, the b4_tbl for combining class data has
+ * the combining class values not indices to the final tables.
+ */
+static const uchar_t u8_combining_class_b4_tbl[2][55][256] = {
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 230, 230, 230, 230,
+                       230, 230, 230, 230, 230, 230, 230, 230,
+                       230, 230, 230, 230, 230, 232, 220, 220,
+                       220, 220, 232, 216, 220, 220, 220, 220,
+                       220, 202, 202, 220, 220, 220, 220, 202,
+                       202, 220, 220, 220, 220, 220, 220, 220,
+                       220, 220, 220, 220, 1,   1,   1,   1,
+                       1,   220, 220, 220, 220, 230, 230, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 230, 240, 230, 220,
+                       220, 220, 230, 230, 230, 220, 220, 0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       234, 234, 233, 230, 230, 230, 230, 230,
+                       230, 230, 230, 230, 230, 230, 230, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   230, 230, 230, 230, 0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   220, 230, 230, 230, 230, 220, 230,
+                       230, 230, 222, 220, 230, 230, 230, 230,
+                       230, 230, 0,   220, 220, 220, 220, 220,
+                       230, 230, 220, 230, 230, 222, 228, 230,
+                       10,  11,  12,  13,  14,  15,  16,  17,
+                       18,  19,  0,   20,  21,  22,  0,   23,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   24,  25,  0,   230, 0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   27,  28,  29,  30,  31,
+                       32,  33,  34,  230, 230, 220, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       35,  0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   230, 230,
+                       230, 230, 230, 230, 230, 0,   0,   230,
+                       230, 230, 230, 220, 230, 0,   0,   230,
+                       230, 0,   220, 230, 230, 220, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   36,  0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 220, 230, 230, 220, 230, 230, 220,
+                       220, 220, 230, 220, 220, 230, 220, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 220, 230, 220, 230, 220, 230,
+                       220, 230, 230, 0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   230, 220, 230, 230, 0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   84,  91,  0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   9,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       103, 103, 9,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       107, 107, 107, 107, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       118, 118, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       122, 122, 122, 122, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       220, 220, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   220, 0,   220,
+                       0,   216, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   129, 130, 0,   132, 0,   0,   0,
+                       0,   0,   130, 130, 130, 130, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       130, 0,   230, 230, 9,   0,   230, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   220, 0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       0,   9,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   9,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   228, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 1,   1,   230, 230, 230, 230,
+                       1,   1,   1,   230, 230, 0,   0,   0,
+                       0,   230, 0,   0,   0,   1,   1,   230,
+                       220, 230, 1,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   218, 228, 232, 222, 224, 224,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   8,   8,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 39. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   26,  0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 40. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 41. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   216, 216, 1,
+                       1,   1,   0,   0,   0,   226, 216, 216,
+                       216, 216, 216, 0,   0,   0,   0,   0,
+                       0,   0,   0,   220, 220, 220, 220, 220,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 42. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       220, 220, 220, 0,   0,   230, 230, 230,
+                       230, 230, 220, 220, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   230, 230, 230, 230, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 43. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 44. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 45. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 46. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 47. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 48. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 49. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 50. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 51. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 52. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 53. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 54. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+       },
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 230, 230, 230, 230,
+                       230, 230, 230, 230, 230, 230, 230, 230,
+                       230, 230, 230, 230, 230, 232, 220, 220,
+                       220, 220, 232, 216, 220, 220, 220, 220,
+                       220, 202, 202, 220, 220, 220, 220, 202,
+                       202, 220, 220, 220, 220, 220, 220, 220,
+                       220, 220, 220, 220, 1,   1,   1,   1,
+                       1,   220, 220, 220, 220, 230, 230, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 230, 240, 230, 220,
+                       220, 220, 230, 230, 230, 220, 220, 0,
+                       230, 230, 230, 220, 220, 220, 220, 230,
+                       232, 220, 220, 230, 233, 234, 234, 233,
+                       234, 234, 233, 230, 230, 230, 230, 230,
+                       230, 230, 230, 230, 230, 230, 230, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   230, 230, 230, 230, 0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   220, 230, 230, 230, 230, 220, 230,
+                       230, 230, 222, 220, 230, 230, 230, 230,
+                       230, 230, 220, 220, 220, 220, 220, 220,
+                       230, 230, 220, 230, 230, 222, 228, 230,
+                       10,  11,  12,  13,  14,  15,  16,  17,
+                       18,  19,  19,  20,  21,  22,  0,   23,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   24,  25,  0,   230, 220, 0,   18,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 230, 230, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   27,  28,  29,  30,  31,
+                       32,  33,  34,  230, 230, 220, 220, 230,
+                       230, 230, 230, 230, 220, 230, 230, 0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       35,  0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   230, 230,
+                       230, 230, 230, 230, 230, 0,   0,   230,
+                       230, 230, 230, 220, 230, 0,   0,   230,
+                       230, 0,   220, 230, 230, 220, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   36,  0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 220, 230, 230, 220, 230, 230, 220,
+                       220, 220, 230, 220, 220, 230, 220, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 220, 230, 220, 230, 220, 230,
+                       220, 230, 230, 0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   230, 230, 230, 230, 230,
+                       230, 230, 220, 230, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   230, 220, 230, 230, 0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   84,  91,  0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   9,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   9,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       103, 103, 9,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       107, 107, 107, 107, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       118, 118, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       122, 122, 122, 122, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       220, 220, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   220, 0,   220,
+                       0,   216, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   129, 130, 0,   132, 0,   0,   0,
+                       0,   0,   130, 130, 130, 130, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       130, 0,   230, 230, 9,   0,   230, 230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   220, 0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       0,   9,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   9,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   230, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 39. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   228, 0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 40. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   222, 230, 220, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 41. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   230,
+                       220, 0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 42. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 43. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   230, 220, 230, 230, 230,
+                       230, 230, 230, 230, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 44. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 220, 230, 230, 230, 230, 230,
+                       230, 230, 220, 0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   230, 220,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 45. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 1,   1,   230, 230, 230, 230,
+                       1,   1,   1,   230, 230, 0,   0,   0,
+                       0,   230, 0,   0,   0,   1,   1,   230,
+                       220, 230, 1,   1,   220, 220, 220, 220,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 46. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   218, 228, 232, 222, 224, 224,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 47. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   8,   8,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 48. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   9,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 49. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   26,  0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 50. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 230, 230, 230, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 51. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   220, 0,   230,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       230, 1,   220, 0,   0,   0,   0,   9,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 52. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   216, 216, 1,
+                       1,   1,   0,   0,   0,   226, 216, 216,
+                       216, 216, 216, 0,   0,   0,   0,   0,
+                       0,   0,   0,   220, 220, 220, 220, 220,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 53. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       220, 220, 220, 0,   0,   230, 230, 230,
+                       230, 230, 220, 220, 0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   230, 230, 230, 230, 0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+               {       /* Fourth byte table 54. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   230, 230, 230, 0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+               },
+       },
+};
+
+static const uchar_t u8_composition_b1_tbl[2][256] = {
+       {
+               0,  N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+       },
+       {
+               0,  N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+               N_, N_, N_, N_, N_, N_, N_, N_,
+       },
+};
+
+static const uchar_t u8_composition_b2_tbl[2][1][256] = {
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       1,  2,  3,  4,  N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       1,  2,  3,  4,  N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+
+};
+
+static const u8_displacement_t u8_composition_b3_tbl[2][5][256] = {
+       {
+               {       /* Third byte table 0. */
+                       { 0x8000, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0, 2470 },
+                       { 0x8001, 2491 }, { 1, 2871 }, { 2, 2959 },
+                       { 3, 3061 }, { 4, 3212 }, { 5, 3226 },
+                       { N_, 0 }, { 6, 3270 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0x8002, 3277 },
+                       { 7, 3774 }, { 8, 3949 }, { 9, 4198 },
+                       { N_, 0 }, { 10, 4265 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 11, 4293 }, { 12, 4312 }, { N_, 0 },
+                       { 13, 4326 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 14, 4347 },
+                       { N_, 0 }, { N_, 0 }, { 15, 4374 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 16, 4391 },
+                       { 17, 4416 }, { 18, 4425 }, { N_, 0 },
+                       { 19, 4451 }, { 20, 4460 }, { 21, 4469 },
+                       { N_, 0 }, { 22, 4503 }, { N_, 0 },
+                       { 23, 4529 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 24, 4563 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 25, 4572 }, { 26, 4588 },
+                       { 27, 4620 }, { 28, 4666 }, { 0x8003, 4682 },
+                       { 0x8004, 5254 }, { 29, 5616 }, { 30, 5646 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 31, 5684 },
+                       { 32, 5708 }, { 33, 5732 }, { 34, 5780 },
+                       { 35, 5900 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 36, 6012 }, { 37, 6241 }, { 38, 6358 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+       },
+       {
+               {       /* Third byte table 0. */
+                       { 0x8000, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0, 2470 },
+                       { 0x8001, 2491 }, { 1, 2871 }, { 2, 2959 },
+                       { 3, 3061 }, { 4, 3212 }, { 5, 3226 },
+                       { N_, 0 }, { 6, 3270 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0x8002, 3277 },
+                       { 7, 3774 }, { 8, 3949 }, { 9, 4198 },
+                       { N_, 0 }, { 10, 4265 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 11, 4293 }, { 12, 4312 }, { N_, 0 },
+                       { 13, 4326 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 14, 4347 },
+                       { N_, 0 }, { N_, 0 }, { 15, 4374 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 16, 4391 },
+                       { 17, 4416 }, { 18, 4425 }, { N_, 0 },
+                       { 19, 4451 }, { 20, 4460 }, { 21, 4469 },
+                       { N_, 0 }, { 22, 4503 }, { N_, 0 },
+                       { 23, 4529 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 24, 4563 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 25, 4572 }, { 26, 4662 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 27, 4671 }, { 28, 4687 },
+                       { 29, 4719 }, { 30, 4765 }, { 0x8003, 4781 },
+                       { 0x8004, 5353 }, { 31, 5715 }, { 32, 5745 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 33, 5783 },
+                       { 34, 5807 }, { 35, 5831 }, { 36, 5879 },
+                       { 37, 5999 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 38, 6111 }, { 39, 6340 }, { 40, 6457 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+       },
+};
+
+static const uchar_t u8_composition_b4_tbl[2][41][257] = {
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   29,  58,  58,  58,  58,
+                       58,  58,  58,  58,  58,  58,  58,  58,
+                       58,  58,  58,  73,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   15,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  38,  46,  46,  46,  46,
+                       46,  54,  62,  62,  62,  62,  62,  62,
+                       62,  70,  78,  86,  94,  94,  94,  94,
+                       94,  94,  94,  94,  94,  94,  94,  94,
+                       94,  94,  94,  94,  94,  94,  94,  94,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   36,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       108, 144, 144, 144, 144, 144, 144, 144,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       14,  22,  30,  30,  30,  30,  30,  37,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   15,  15,  15,  15,  70,  70,
+                       70,  70,  112, 133, 154, 154, 154, 162,
+                       162, 162, 162, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   20,  20,  20,  27,  27,  46,  59,
+                       66,  91,  91,  98,  98,  98,  98,  105,
+                       105, 105, 105, 105, 130, 130, 130, 130,
+                       137, 137, 137, 137, 144, 144, 151, 151,
+                       151, 164, 164, 164, 171, 171, 190, 203,
+                       210, 235, 235, 242, 242, 242, 242, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   25,  25,  25,  25,
+                       32,  32,  32,  32,  39,  39,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  53,
+                       53,  53,  53,  53,  53,  53,  53,  53,
+                       53,  53,  53,  53,  53,  53,  53,  53,
+                       53,  53,  53,  53,  53,  53,  53,  53,
+                       53,  53,  53,  53,  53,  60,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  21,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   14,  14,  14,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   9,   9,   9,   9,   9,   9,   9,
+                       9,   18,  18,  18,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   17,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   25,
+                       25,  25,  25,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   17,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   25,  25,  25,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   8,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   8,   16,  16,  16,  16,
+                       16,  16,  16,  24,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   15,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  38,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   8,   16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   16,
+                       16,  16,  16,  16,  16,  16,  16,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   8,   8,   16,  16,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   8,   8,   16,  16,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   8,   8,   8,   8,
+                       8,   16,  16,  16,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  32,  32,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   8,   8,   16,  16,
+                       16,  24,  24,  24,  24,  24,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  40,  40,  40,  48,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  64,  72,  72,  72,  80,
+                       88,  88,  88,  96,  104, 112, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   8,   16,  16,  16,  24,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  40,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  56,  56,  56,  56,  56,
+                       56,  64,  72,  72,  80,  80,  80,  80,
+                       80,  80,  80,  88,  96,  104, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   9,
+                       9,   9,   9,   9,   18,  18,  27,  27,
+                       36,  36,  45,  45,  54,  54,  63,  63,
+                       72,  72,  81,  81,  90,  90,  99,  99,
+                       108, 108, 117, 117, 117, 126, 126, 135,
+                       135, 144, 144, 144, 144, 144, 144, 144,
+                       161, 161, 161, 178, 178, 178, 195, 195,
+                       195, 212, 212, 212, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   18,
+                       18,  18,  18,  18,  27,  27,  36,  36,
+                       45,  45,  54,  54,  63,  63,  72,  72,
+                       81,  81,  90,  90,  99,  99,  108, 108,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   9,   9,   9,   18,  18,  27,
+                       27,  36,  36,  36,  36,  36,  36,  36,
+                       53,  53,  53,  70,  70,  70,  87,  87,
+                       87,  104, 104, 104, 121, 121, 121, 121,
+                       121, 121, 121, 121, 121, 121, 121, 121,
+                       121, 121, 121, 121, 121, 121, 121, 121,
+                       130, 139, 148, 157, 157, 157, 157, 157,
+                       157, 157, 157, 157, 157, 157, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166,
+               },
+               {       /* Fourth byte table 39. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 40. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+       },
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   29,  58,  58,  58,  58,
+                       58,  58,  58,  58,  58,  58,  58,  58,
+                       58,  58,  58,  73,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   15,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  38,  46,  46,  46,  46,
+                       46,  54,  62,  62,  62,  62,  62,  62,
+                       62,  70,  78,  86,  94,  94,  94,  94,
+                       94,  94,  94,  94,  94,  94,  94,  94,
+                       94,  94,  94,  94,  94,  94,  94,  94,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102, 102, 102, 102, 102, 102, 102, 102,
+                       102,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   36,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       108, 144, 144, 144, 144, 144, 144, 144,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151, 151, 151, 151, 151, 151, 151, 151,
+                       151,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       14,  22,  30,  30,  30,  30,  30,  37,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   15,  15,  15,  15,  70,  70,
+                       70,  70,  112, 133, 154, 154, 154, 162,
+                       162, 162, 162, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   20,  20,  20,  27,  27,  46,  59,
+                       66,  91,  91,  98,  98,  98,  98,  105,
+                       105, 105, 105, 105, 130, 130, 130, 130,
+                       137, 137, 137, 137, 144, 144, 151, 151,
+                       151, 164, 164, 164, 171, 171, 190, 203,
+                       210, 235, 235, 242, 242, 242, 242, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249, 249, 249, 249, 249, 249, 249, 249,
+                       249,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   25,  25,  25,  25,
+                       32,  32,  32,  32,  39,  39,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  53,
+                       53,  53,  53,  53,  53,  53,  53,  53,
+                       53,  53,  53,  53,  53,  53,  53,  53,
+                       53,  53,  53,  53,  53,  53,  53,  53,
+                       53,  53,  53,  53,  53,  60,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  21,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   14,  14,  14,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   9,   9,   9,   9,   9,   9,   9,
+                       9,   18,  18,  18,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   17,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   25,
+                       25,  25,  25,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   17,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   25,  25,  25,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  34,  34,
+                       34,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   9,   9,
+                       18,  18,  27,  27,  36,  36,  45,  45,
+                       45,  45,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  63,  63,  72,  72,  81,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   8,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   8,   16,  16,  16,  16,
+                       16,  16,  16,  24,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   15,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  38,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   8,   16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   16,
+                       16,  16,  16,  16,  16,  16,  16,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   8,   8,   16,  16,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   8,   8,   16,  16,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   8,   8,   8,   8,
+                       8,   16,  16,  16,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  32,  32,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   8,   8,   16,  16,
+                       16,  24,  24,  24,  24,  24,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  40,  40,  40,  48,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  64,  72,  72,  72,  80,
+                       88,  88,  88,  96,  104, 112, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120, 120, 120, 120, 120, 120, 120, 120,
+                       120,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   8,   16,  16,  16,  24,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  40,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  56,  56,  56,  56,  56,
+                       56,  64,  72,  72,  80,  80,  80,  80,
+                       80,  80,  80,  88,  96,  104, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   9,
+                       9,   9,   9,   9,   18,  18,  27,  27,
+                       36,  36,  45,  45,  54,  54,  63,  63,
+                       72,  72,  81,  81,  90,  90,  99,  99,
+                       108, 108, 117, 117, 117, 126, 126, 135,
+                       135, 144, 144, 144, 144, 144, 144, 144,
+                       161, 161, 161, 178, 178, 178, 195, 195,
+                       195, 212, 212, 212, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229, 229, 229, 229, 229, 229, 229, 229,
+                       229,
+               },
+               {       /* Fourth byte table 39. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   18,
+                       18,  18,  18,  18,  27,  27,  36,  36,
+                       45,  45,  54,  54,  63,  63,  72,  72,
+                       81,  81,  90,  90,  99,  99,  108, 108,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117, 117, 117, 117, 117, 117, 117, 117,
+                       117,
+               },
+               {       /* Fourth byte table 40. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   9,   9,   9,   18,  18,  27,
+                       27,  36,  36,  36,  36,  36,  36,  36,
+                       53,  53,  53,  70,  70,  70,  87,  87,
+                       87,  104, 104, 104, 121, 121, 121, 121,
+                       121, 121, 121, 121, 121, 121, 121, 121,
+                       121, 121, 121, 121, 121, 121, 121, 121,
+                       130, 139, 148, 157, 157, 157, 157, 157,
+                       157, 157, 157, 157, 157, 157, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166, 166, 166, 166, 166, 166, 166, 166,
+                       166,
+               },
+       },
+};
+
+static const uint16_t u8_composition_b4_16bit_tbl[2][5][257] = {
+       {
+               {       /* Fourth byte 16-bit table 0. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    8,    16,   24,
+                       24,   24,   124,  146,  177,  219,  327,  335,
+                       379,  427,  521,  528,  562,  602,  624,  683,
+                       782,  797,  797,  849,  894,  941,  1061, 1076,
+                       1118, 1133, 1193, 1233, 1233, 1233, 1233, 1233,
+                       1233, 1233, 1333, 1355, 1386, 1428, 1536, 1544,
+                       1588, 1643, 1731, 1744, 1778, 1818, 1840, 1899,
+                       1998, 2013, 2013, 2065, 2110, 2164, 2284, 2299,
+                       2348, 2363, 2430, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470,
+               },
+               {       /* Fourth byte 16-bit table 1. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    29,   29,   36,   43,   56,
+                       64,   64,   64,   93,   93,   93,   93,   93,
+                       101,  101,  101,  101,  101,  130,  151,  158,
+                       158,  165,  165,  165,  165,  190,  190,  190,
+                       190,  190,  190,  219,  219,  226,  233,  246,
+                       254,  254,  254,  283,  283,  283,  283,  283,
+                       291,  291,  291,  291,  291,  320,  341,  348,
+                       348,  355,  355,  355,  355,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,
+               },
+               {       /* Fourth byte 16-bit table 2. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    49,   49,   49,   49,   77,   77,
+                       112,  112,  160,  160,  160,  160,  160,  160,
+                       188,  188,  196,  196,  196,  196,  237,  237,
+                       237,  237,  272,  272,  272,  280,  280,  288,
+                       288,  288,  344,  344,  344,  344,  372,  372,
+                       414,  414,  469,  469,  469,  469,  469,  469,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,
+               },
+               {       /* Fourth byte 16-bit table 3. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    29,   58,   66,   74,   82,   90,   98,
+                       106,  135,  164,  172,  180,  188,  196,  204,
+                       212,  227,  242,  242,  242,  242,  242,  242,
+                       242,  257,  272,  272,  272,  272,  272,  272,
+                       272,  301,  330,  338,  346,  354,  362,  370,
+                       378,  407,  436,  444,  452,  460,  468,  476,
+                       484,  506,  528,  528,  528,  528,  528,  528,
+                       528,  550,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,
+               },
+               {       /* Fourth byte 16-bit table 4. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    15,   30,   30,   30,   30,   30,   30,
+                       30,   45,   60,   60,   60,   60,   60,   60,
+                       60,   82,   104,  104,  104,  104,  104,  104,
+                       104,  104,  126,  126,  126,  126,  126,  126,
+                       126,  155,  184,  192,  200,  208,  216,  224,
+                       232,  261,  290,  298,  306,  314,  322,  330,
+                       338,  346,  346,  346,  346,  354,  354,  354,
+                       354,  354,  354,  354,  354,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,
+               },
+       },
+       {
+               {       /* Fourth byte 16-bit table 0. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    8,    16,   24,
+                       24,   24,   124,  146,  177,  219,  327,  335,
+                       379,  427,  521,  528,  562,  602,  624,  683,
+                       782,  797,  797,  849,  894,  941,  1061, 1076,
+                       1118, 1133, 1193, 1233, 1233, 1233, 1233, 1233,
+                       1233, 1233, 1333, 1355, 1386, 1428, 1536, 1544,
+                       1588, 1643, 1731, 1744, 1778, 1818, 1840, 1899,
+                       1998, 2013, 2013, 2065, 2110, 2164, 2284, 2299,
+                       2348, 2363, 2430, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470, 2470, 2470, 2470, 2470, 2470, 2470, 2470,
+                       2470,
+               },
+               {       /* Fourth byte 16-bit table 1. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    29,   29,   36,   43,   56,
+                       64,   64,   64,   93,   93,   93,   93,   93,
+                       101,  101,  101,  101,  101,  130,  151,  158,
+                       158,  165,  165,  165,  165,  190,  190,  190,
+                       190,  190,  190,  219,  219,  226,  233,  246,
+                       254,  254,  254,  283,  283,  283,  283,  283,
+                       291,  291,  291,  291,  291,  320,  341,  348,
+                       348,  355,  355,  355,  355,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,  380,  380,  380,  380,  380,  380,  380,
+                       380,
+               },
+               {       /* Fourth byte 16-bit table 2. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    49,   49,   49,   49,   77,   77,
+                       112,  112,  160,  160,  160,  160,  160,  160,
+                       188,  188,  196,  196,  196,  196,  237,  237,
+                       237,  237,  272,  272,  272,  280,  280,  288,
+                       288,  288,  344,  344,  344,  344,  372,  372,
+                       414,  414,  469,  469,  469,  469,  469,  469,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,  497,  497,  497,  497,  497,  497,  497,
+                       497,
+               },
+               {       /* Fourth byte 16-bit table 3. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    29,   58,   66,   74,   82,   90,   98,
+                       106,  135,  164,  172,  180,  188,  196,  204,
+                       212,  227,  242,  242,  242,  242,  242,  242,
+                       242,  257,  272,  272,  272,  272,  272,  272,
+                       272,  301,  330,  338,  346,  354,  362,  370,
+                       378,  407,  436,  444,  452,  460,  468,  476,
+                       484,  506,  528,  528,  528,  528,  528,  528,
+                       528,  550,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,  572,  572,  572,  572,  572,  572,  572,
+                       572,
+               },
+               {       /* Fourth byte 16-bit table 4. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    15,   30,   30,   30,   30,   30,   30,
+                       30,   45,   60,   60,   60,   60,   60,   60,
+                       60,   82,   104,  104,  104,  104,  104,  104,
+                       104,  104,  126,  126,  126,  126,  126,  126,
+                       126,  155,  184,  192,  200,  208,  216,  224,
+                       232,  261,  290,  298,  306,  314,  322,  330,
+                       338,  346,  346,  346,  346,  354,  354,  354,
+                       354,  354,  354,  354,  354,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,  362,  362,  362,  362,  362,  362,  362,
+                       362,
+               },
+       },
+};
+
+static const uchar_t u8_composition_final_tbl[2][6623] = {
+       {
+               0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAE, FIL_,
+               0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xA0, FIL_,
+               0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAF, FIL_,
+               0x10, 0xCC, 0x86, FIL_, 0xC4, 0x82, FIL_, 0xCC,
+               0x87, FIL_, 0xC8, 0xA6, FIL_, 0xCC, 0x8F, FIL_,
+               0xC8, 0x80, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0x82,
+               FIL_, 0xCC, 0x81, FIL_, 0xC3, 0x81, FIL_, 0xCC,
+               0x80, FIL_, 0xC3, 0x80, FIL_, 0xCC, 0x83, FIL_,
+               0xC3, 0x83, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA,
+               0xA0, FIL_, 0xCC, 0xA5, FIL_, 0xE1, 0xB8, 0x80,
+               FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x82, FIL_, 0xCC,
+               0x84, FIL_, 0xC4, 0x80, FIL_, 0xCC, 0x88, FIL_,
+               0xC3, 0x84, FIL_, 0xCC, 0x8A, FIL_, 0xC3, 0x85,
+               FIL_, 0xCC, 0xA8, FIL_, 0xC4, 0x84, FIL_, 0xCC,
+               0x89, FIL_, 0xE1, 0xBA, 0xA2, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC7, 0x8D, FIL_, 0x03, 0xCC, 0x87, FIL_,
+               0xE1, 0xB8, 0x82, FIL_, 0xCC, 0xB1, FIL_, 0xE1,
+               0xB8, 0x86, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0x84, FIL_, 0x05, 0xCC, 0xA7, FIL_, 0xC3, 0x87,
+               FIL_, 0xCC, 0x81, FIL_, 0xC4, 0x86, FIL_, 0xCC,
+               0x8C, FIL_, 0xC4, 0x8C, FIL_, 0xCC, 0x87, FIL_,
+               0xC4, 0x8A, FIL_, 0xCC, 0x82, FIL_, 0xC4, 0x88,
+               FIL_, 0x06, 0xCC, 0xB1, FIL_, 0xE1, 0xB8, 0x8E,
+               FIL_, 0xCC, 0xA7, FIL_, 0xE1, 0xB8, 0x90, FIL_,
+               0xCC, 0xAD, FIL_, 0xE1, 0xB8, 0x92, FIL_, 0xCC,
+               0x87, FIL_, 0xE1, 0xB8, 0x8A, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC4, 0x8E, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB8, 0x8C, FIL_, 0x11, 0xCC, 0x80, FIL_, 0xC3,
+               0x88, FIL_, 0xCC, 0x81, FIL_, 0xC3, 0x89, FIL_,
+               0xCC, 0x82, FIL_, 0xC3, 0x8A, FIL_, 0xCC, 0x88,
+               FIL_, 0xC3, 0x8B, FIL_, 0xCC, 0xA7, FIL_, 0xC8,
+               0xA8, FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x86, FIL_,
+               0xCC, 0x8F, FIL_, 0xC8, 0x84, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBA, 0xBA, FIL_, 0xCC, 0xB0, FIL_,
+               0xE1, 0xB8, 0x9A, FIL_, 0xCC, 0xAD, FIL_, 0xE1,
+               0xB8, 0x98, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBA,
+               0xBC, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0xB8,
+               FIL_, 0xCC, 0x84, FIL_, 0xC4, 0x92, FIL_, 0xCC,
+               0x86, FIL_, 0xC4, 0x94, FIL_, 0xCC, 0x87, FIL_,
+               0xC4, 0x96, FIL_, 0xCC, 0xA8, FIL_, 0xC4, 0x98,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0x9A, FIL_, 0x01,
+               0xCC, 0x87, FIL_, 0xE1, 0xB8, 0x9E, FIL_, 0x07,
+               0xCC, 0x8C, FIL_, 0xC7, 0xA6, FIL_, 0xCC, 0x87,
+               FIL_, 0xC4, 0xA0, FIL_, 0xCC, 0x84, FIL_, 0xE1,
+               0xB8, 0xA0, FIL_, 0xCC, 0x82, FIL_, 0xC4, 0x9C,
+               FIL_, 0xCC, 0x81, FIL_, 0xC7, 0xB4, FIL_, 0xCC,
+               0xA7, FIL_, 0xC4, 0xA2, FIL_, 0xCC, 0x86, FIL_,
+               0xC4, 0x9E, FIL_, 0x07, 0xCC, 0xAE, FIL_, 0xE1,
+               0xB8, 0xAA, FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB8,
+               0xA2, FIL_, 0xCC, 0x88, FIL_, 0xE1, 0xB8, 0xA6,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8, 0xA4, FIL_,
+               0xCC, 0xA7, FIL_, 0xE1, 0xB8, 0xA8, FIL_, 0xCC,
+               0x8C, FIL_, 0xC8, 0x9E, FIL_, 0xCC, 0x82, FIL_,
+               0xC4, 0xA4, FIL_, 0x0F, 0xCC, 0x84, FIL_, 0xC4,
+               0xAA, FIL_, 0xCC, 0x80, FIL_, 0xC3, 0x8C, FIL_,
+               0xCC, 0xA8, FIL_, 0xC4, 0xAE, FIL_, 0xCC, 0x83,
+               FIL_, 0xC4, 0xA8, FIL_, 0xCC, 0x88, FIL_, 0xC3,
+               0x8F, FIL_, 0xCC, 0x81, FIL_, 0xC3, 0x8D, FIL_,
+               0xCC, 0x8F, FIL_, 0xC8, 0x88, FIL_, 0xCC, 0x86,
+               FIL_, 0xC4, 0xAC, FIL_, 0xCC, 0x91, FIL_, 0xC8,
+               0x8A, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x8F, FIL_,
+               0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x88, FIL_, 0xCC,
+               0x87, FIL_, 0xC4, 0xB0, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xBB, 0x8A, FIL_, 0xCC, 0xB0, FIL_, 0xE1,
+               0xB8, 0xAC, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0x8E,
+               FIL_, 0x01, 0xCC, 0x82, FIL_, 0xC4, 0xB4, FIL_,
+               0x05, 0xCC, 0x8C, FIL_, 0xC7, 0xA8, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xB8, 0xB4, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB8, 0xB0, FIL_, 0xCC, 0xA7, FIL_,
+               0xC4, 0xB6, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0xB2, FIL_, 0x06, 0xCC, 0xA7, FIL_, 0xC4, 0xBB,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0xBD, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xB8, 0xBA, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xB8, 0xB6, FIL_, 0xCC, 0xAD, FIL_,
+               0xE1, 0xB8, 0xBC, FIL_, 0xCC, 0x81, FIL_, 0xC4,
+               0xB9, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1, 0xB8,
+               0xBE, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x82,
+               FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB9, 0x80, FIL_,
+               0x09, 0xCC, 0x80, FIL_, 0xC7, 0xB8, FIL_, 0xCC,
+               0xAD, FIL_, 0xE1, 0xB9, 0x8A, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0x84, FIL_, 0xCC, 0xB1, FIL_,
+               0xE1, 0xB9, 0x88, FIL_, 0xCC, 0x83, FIL_, 0xC3,
+               0x91, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x86,
+               FIL_, 0xCC, 0x81, FIL_, 0xC5, 0x83, FIL_, 0xCC,
+               0xA7, FIL_, 0xC5, 0x85, FIL_, 0xCC, 0x8C, FIL_,
+               0xC5, 0x87, FIL_, 0x10, 0xCC, 0xA8, FIL_, 0xC7,
+               0xAA, FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x8E, FIL_,
+               0xCC, 0x80, FIL_, 0xC3, 0x92, FIL_, 0xCC, 0x9B,
+               FIL_, 0xC6, 0xA0, FIL_, 0xCC, 0x8F, FIL_, 0xC8,
+               0x8C, FIL_, 0xCC, 0x81, FIL_, 0xC3, 0x93, FIL_,
+               0xCC, 0x87, FIL_, 0xC8, 0xAE, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC7, 0x91, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xBB, 0x8C, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0x94,
+               FIL_, 0xCC, 0x84, FIL_, 0xC5, 0x8C, FIL_, 0xCC,
+               0x83, FIL_, 0xC3, 0x95, FIL_, 0xCC, 0x86, FIL_,
+               0xC5, 0x8E, FIL_, 0xCC, 0x88, FIL_, 0xC3, 0x96,
+               FIL_, 0xCC, 0x8B, FIL_, 0xC5, 0x90, FIL_, 0xCC,
+               0x89, FIL_, 0xE1, 0xBB, 0x8E, FIL_, 0x02, 0xCC,
+               0x87, FIL_, 0xE1, 0xB9, 0x96, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0x94, FIL_, 0x08, 0xCC, 0x91,
+               FIL_, 0xC8, 0x92, FIL_, 0xCC, 0xA7, FIL_, 0xC5,
+               0x96, FIL_, 0xCC, 0x8C, FIL_, 0xC5, 0x98, FIL_,
+               0xCC, 0xB1, FIL_, 0xE1, 0xB9, 0x9E, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xB9, 0x9A, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0x98, FIL_, 0xCC, 0x81, FIL_,
+               0xC5, 0x94, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x90,
+               FIL_, 0x07, 0xCC, 0x81, FIL_, 0xC5, 0x9A, FIL_,
+               0xCC, 0x82, FIL_, 0xC5, 0x9C, FIL_, 0xCC, 0xA7,
+               FIL_, 0xC5, 0x9E, FIL_, 0xCC, 0x8C, FIL_, 0xC5,
+               0xA0, FIL_, 0xCC, 0xA6, FIL_, 0xC8, 0x98, FIL_,
+               0xCC, 0x87, FIL_, 0xE1, 0xB9, 0xA0, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xB9, 0xA2, FIL_, 0x07, 0xCC,
+               0x8C, FIL_, 0xC5, 0xA4, FIL_, 0xCC, 0xB1, FIL_,
+               0xE1, 0xB9, 0xAE, FIL_, 0xCC, 0xA6, FIL_, 0xC8,
+               0x9A, FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0xA2, FIL_,
+               0xCC, 0x87, FIL_, 0xE1, 0xB9, 0xAA, FIL_, 0xCC,
+               0xAD, FIL_, 0xE1, 0xB9, 0xB0, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xB9, 0xAC, FIL_, 0x13, 0xCC, 0xA8,
+               FIL_, 0xC5, 0xB2, FIL_, 0xCC, 0x83, FIL_, 0xC5,
+               0xA8, FIL_, 0xCC, 0x84, FIL_, 0xC5, 0xAA, FIL_,
+               0xCC, 0x81, FIL_, 0xC3, 0x9A, FIL_, 0xCC, 0x86,
+               FIL_, 0xC5, 0xAC, FIL_, 0xCC, 0x8A, FIL_, 0xC5,
+               0xAE, FIL_, 0xCC, 0x80, FIL_, 0xC3, 0x99, FIL_,
+               0xCC, 0x91, FIL_, 0xC8, 0x96, FIL_, 0xCC, 0x8B,
+               FIL_, 0xC5, 0xB0, FIL_, 0xCC, 0xA4, FIL_, 0xE1,
+               0xB9, 0xB2, FIL_, 0xCC, 0xB0, FIL_, 0xE1, 0xB9,
+               0xB4, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x94, FIL_,
+               0xCC, 0xAD, FIL_, 0xE1, 0xB9, 0xB6, FIL_, 0xCC,
+               0x9B, FIL_, 0xC6, 0xAF, FIL_, 0xCC, 0x82, FIL_,
+               0xC3, 0x9B, FIL_, 0xCC, 0x88, FIL_, 0xC3, 0x9C,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x93, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xBB, 0xA4, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0xA6, FIL_, 0x02, 0xCC, 0x83,
+               FIL_, 0xE1, 0xB9, 0xBC, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xB9, 0xBE, FIL_, 0x06, 0xCC, 0x82, FIL_,
+               0xC5, 0xB4, FIL_, 0xCC, 0x88, FIL_, 0xE1, 0xBA,
+               0x84, FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xBA, 0x86,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0x88, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBA, 0x82, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBA, 0x80, FIL_, 0x02, 0xCC,
+               0x87, FIL_, 0xE1, 0xBA, 0x8A, FIL_, 0xCC, 0x88,
+               FIL_, 0xE1, 0xBA, 0x8C, FIL_, 0x09, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0xB6, FIL_, 0xCC, 0x87, FIL_,
+               0xE1, 0xBA, 0x8E, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xBB, 0xB4, FIL_, 0xCC, 0x81, FIL_, 0xC3, 0x9D,
+               FIL_, 0xCC, 0x84, FIL_, 0xC8, 0xB2, FIL_, 0xCC,
+               0x82, FIL_, 0xC5, 0xB6, FIL_, 0xCC, 0x88, FIL_,
+               0xC5, 0xB8, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBB,
+               0xB2, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0xB8,
+               FIL_, 0x06, 0xCC, 0x87, FIL_, 0xC5, 0xBB, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0x92, FIL_, 0xCC,
+               0x8C, FIL_, 0xC5, 0xBD, FIL_, 0xCC, 0xB1, FIL_,
+               0xE1, 0xBA, 0x94, FIL_, 0xCC, 0x82, FIL_, 0xE1,
+               0xBA, 0x90, FIL_, 0xCC, 0x81, FIL_, 0xC5, 0xB9,
+               FIL_, 0x10, 0xCC, 0x8C, FIL_, 0xC7, 0x8E, FIL_,
+               0xCC, 0x8F, FIL_, 0xC8, 0x81, FIL_, 0xCC, 0xA8,
+               FIL_, 0xC4, 0x85, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xBA, 0xA1, FIL_, 0xCC, 0x86, FIL_, 0xC4, 0x83,
+               FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xA3, FIL_,
+               0xCC, 0x84, FIL_, 0xC4, 0x81, FIL_, 0xCC, 0x91,
+               FIL_, 0xC8, 0x83, FIL_, 0xCC, 0x8A, FIL_, 0xC3,
+               0xA5, FIL_, 0xCC, 0x88, FIL_, 0xC3, 0xA4, FIL_,
+               0xCC, 0x83, FIL_, 0xC3, 0xA3, FIL_, 0xCC, 0x82,
+               FIL_, 0xC3, 0xA2, FIL_, 0xCC, 0x81, FIL_, 0xC3,
+               0xA1, FIL_, 0xCC, 0x80, FIL_, 0xC3, 0xA0, FIL_,
+               0xCC, 0x87, FIL_, 0xC8, 0xA7, FIL_, 0xCC, 0xA5,
+               FIL_, 0xE1, 0xB8, 0x81, FIL_, 0x03, 0xCC, 0xB1,
+               FIL_, 0xE1, 0xB8, 0x87, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xB8, 0x85, FIL_, 0xCC, 0x87, FIL_, 0xE1,
+               0xB8, 0x83, FIL_, 0x05, 0xCC, 0x87, FIL_, 0xC4,
+               0x8B, FIL_, 0xCC, 0xA7, FIL_, 0xC3, 0xA7, FIL_,
+               0xCC, 0x82, FIL_, 0xC4, 0x89, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC4, 0x8D, FIL_, 0xCC, 0x81, FIL_, 0xC4,
+               0x87, FIL_, 0x06, 0xCC, 0xAD, FIL_, 0xE1, 0xB8,
+               0x93, FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB8, 0x8B,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8, 0x8D, FIL_,
+               0xCC, 0xB1, FIL_, 0xE1, 0xB8, 0x8F, FIL_, 0xCC,
+               0xA7, FIL_, 0xE1, 0xB8, 0x91, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC4, 0x8F, FIL_, 0x11, 0xCC, 0xA8, FIL_,
+               0xC4, 0x99, FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0x9B,
+               FIL_, 0xCC, 0x87, FIL_, 0xC4, 0x97, FIL_, 0xCC,
+               0x88, FIL_, 0xC3, 0xAB, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xBA, 0xB9, FIL_, 0xCC, 0xB0, FIL_, 0xE1,
+               0xB8, 0x9B, FIL_, 0xCC, 0x84, FIL_, 0xC4, 0x93,
+               FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB8, 0x99, FIL_,
+               0xCC, 0x83, FIL_, 0xE1, 0xBA, 0xBD, FIL_, 0xCC,
+               0x86, FIL_, 0xC4, 0x95, FIL_, 0xCC, 0xA7, FIL_,
+               0xC8, 0xA9, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA,
+               0xBB, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x85, FIL_,
+               0xCC, 0x81, FIL_, 0xC3, 0xA9, FIL_, 0xCC, 0x91,
+               FIL_, 0xC8, 0x87, FIL_, 0xCC, 0x80, FIL_, 0xC3,
+               0xA8, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0xAA, FIL_,
+               0x01, 0xCC, 0x87, FIL_, 0xE1, 0xB8, 0x9F, FIL_,
+               0x07, 0xCC, 0x86, FIL_, 0xC4, 0x9F, FIL_, 0xCC,
+               0xA7, FIL_, 0xC4, 0xA3, FIL_, 0xCC, 0x81, FIL_,
+               0xC7, 0xB5, FIL_, 0xCC, 0x82, FIL_, 0xC4, 0x9D,
+               FIL_, 0xCC, 0x87, FIL_, 0xC4, 0xA1, FIL_, 0xCC,
+               0x8C, FIL_, 0xC7, 0xA7, FIL_, 0xCC, 0x84, FIL_,
+               0xE1, 0xB8, 0xA1, FIL_, 0x08, 0xCC, 0x8C, FIL_,
+               0xC8, 0x9F, FIL_, 0xCC, 0x82, FIL_, 0xC4, 0xA5,
+               FIL_, 0xCC, 0x88, FIL_, 0xE1, 0xB8, 0xA7, FIL_,
+               0xCC, 0x87, FIL_, 0xE1, 0xB8, 0xA3, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xBA, 0x96, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xB8, 0xA5, FIL_, 0xCC, 0xA7, FIL_,
+               0xE1, 0xB8, 0xA9, FIL_, 0xCC, 0xAE, FIL_, 0xE1,
+               0xB8, 0xAB, FIL_, 0x0E, 0xCC, 0x81, FIL_, 0xC3,
+               0xAD, FIL_, 0xCC, 0x80, FIL_, 0xC3, 0xAC, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0x8B, FIL_, 0xCC,
+               0x8C, FIL_, 0xC7, 0x90, FIL_, 0xCC, 0x89, FIL_,
+               0xE1, 0xBB, 0x89, FIL_, 0xCC, 0x91, FIL_, 0xC8,
+               0x8B, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x89, FIL_,
+               0xCC, 0x82, FIL_, 0xC3, 0xAE, FIL_, 0xCC, 0xB0,
+               FIL_, 0xE1, 0xB8, 0xAD, FIL_, 0xCC, 0xA8, FIL_,
+               0xC4, 0xAF, FIL_, 0xCC, 0x86, FIL_, 0xC4, 0xAD,
+               FIL_, 0xCC, 0x84, FIL_, 0xC4, 0xAB, FIL_, 0xCC,
+               0x83, FIL_, 0xC4, 0xA9, FIL_, 0xCC, 0x88, FIL_,
+               0xC3, 0xAF, FIL_, 0x02, 0xCC, 0x82, FIL_, 0xC4,
+               0xB5, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0xB0, FIL_,
+               0x05, 0xCC, 0xA3, FIL_, 0xE1, 0xB8, 0xB3, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xB8, 0xB1, FIL_, 0xCC,
+               0xA7, FIL_, 0xC4, 0xB7, FIL_, 0xCC, 0x8C, FIL_,
+               0xC7, 0xA9, FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xB8,
+               0xB5, FIL_, 0x06, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0xB7, FIL_, 0xCC, 0x81, FIL_, 0xC4, 0xBA, FIL_,
+               0xCC, 0xA7, FIL_, 0xC4, 0xBC, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC4, 0xBE, FIL_, 0xCC, 0xB1, FIL_, 0xE1,
+               0xB8, 0xBB, FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB8,
+               0xBD, FIL_, 0x03, 0xCC, 0xA3, FIL_, 0xE1, 0xB9,
+               0x83, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0xBF,
+               FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB9, 0x81, FIL_,
+               0x09, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x87, FIL_,
+               0xCC, 0x83, FIL_, 0xC3, 0xB1, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0x85, FIL_, 0xCC, 0xB1, FIL_,
+               0xE1, 0xB9, 0x89, FIL_, 0xCC, 0x81, FIL_, 0xC5,
+               0x84, FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0x86, FIL_,
+               0xCC, 0xAD, FIL_, 0xE1, 0xB9, 0x8B, FIL_, 0xCC,
+               0x8C, FIL_, 0xC5, 0x88, FIL_, 0xCC, 0x80, FIL_,
+               0xC7, 0xB9, FIL_, 0x10, 0xCC, 0x89, FIL_, 0xE1,
+               0xBB, 0x8F, FIL_, 0xCC, 0x81, FIL_, 0xC3, 0xB3,
+               FIL_, 0xCC, 0x80, FIL_, 0xC3, 0xB2, FIL_, 0xCC,
+               0x87, FIL_, 0xC8, 0xAF, FIL_, 0xCC, 0x8F, FIL_,
+               0xC8, 0x8D, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBB,
+               0x8D, FIL_, 0xCC, 0x84, FIL_, 0xC5, 0x8D, FIL_,
+               0xCC, 0x8C, FIL_, 0xC7, 0x92, FIL_, 0xCC, 0x86,
+               FIL_, 0xC5, 0x8F, FIL_, 0xCC, 0x8B, FIL_, 0xC5,
+               0x91, FIL_, 0xCC, 0x9B, FIL_, 0xC6, 0xA1, FIL_,
+               0xCC, 0x91, FIL_, 0xC8, 0x8F, FIL_, 0xCC, 0xA8,
+               FIL_, 0xC7, 0xAB, FIL_, 0xCC, 0x88, FIL_, 0xC3,
+               0xB6, FIL_, 0xCC, 0x83, FIL_, 0xC3, 0xB5, FIL_,
+               0xCC, 0x82, FIL_, 0xC3, 0xB4, FIL_, 0x02, 0xCC,
+               0x87, FIL_, 0xE1, 0xB9, 0x97, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0x95, FIL_, 0x08, 0xCC, 0xB1,
+               FIL_, 0xE1, 0xB9, 0x9F, FIL_, 0xCC, 0x87, FIL_,
+               0xE1, 0xB9, 0x99, FIL_, 0xCC, 0x81, FIL_, 0xC5,
+               0x95, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x91, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x9B, FIL_, 0xCC,
+               0x8C, FIL_, 0xC5, 0x99, FIL_, 0xCC, 0x91, FIL_,
+               0xC8, 0x93, FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0x97,
+               FIL_, 0x07, 0xCC, 0xA6, FIL_, 0xC8, 0x99, FIL_,
+               0xCC, 0x8C, FIL_, 0xC5, 0xA1, FIL_, 0xCC, 0x81,
+               FIL_, 0xC5, 0x9B, FIL_, 0xCC, 0x87, FIL_, 0xE1,
+               0xB9, 0xA1, FIL_, 0xCC, 0x82, FIL_, 0xC5, 0x9D,
+               FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0x9F, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xB9, 0xA3, FIL_, 0x08, 0xCC,
+               0x88, FIL_, 0xE1, 0xBA, 0x97, FIL_, 0xCC, 0xAD,
+               FIL_, 0xE1, 0xB9, 0xB1, FIL_, 0xCC, 0xB1, FIL_,
+               0xE1, 0xB9, 0xAF, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB9, 0xAD, FIL_, 0xCC, 0x8C, FIL_, 0xC5, 0xA5,
+               FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0xA3, FIL_, 0xCC,
+               0x87, FIL_, 0xE1, 0xB9, 0xAB, FIL_, 0xCC, 0xA6,
+               FIL_, 0xC8, 0x9B, FIL_, 0x13, 0xCC, 0x81, FIL_,
+               0xC3, 0xBA, FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x97,
+               FIL_, 0xCC, 0x83, FIL_, 0xC5, 0xA9, FIL_, 0xCC,
+               0x8F, FIL_, 0xC8, 0x95, FIL_, 0xCC, 0xA8, FIL_,
+               0xC5, 0xB3, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0xBB,
+               FIL_, 0xCC, 0x88, FIL_, 0xC3, 0xBC, FIL_, 0xCC,
+               0x80, FIL_, 0xC3, 0xB9, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xBB, 0xA5, FIL_, 0xCC, 0xA4, FIL_, 0xE1,
+               0xB9, 0xB3, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB,
+               0xA7, FIL_, 0xCC, 0xB0, FIL_, 0xE1, 0xB9, 0xB5,
+               FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB9, 0xB7, FIL_,
+               0xCC, 0x9B, FIL_, 0xC6, 0xB0, FIL_, 0xCC, 0x84,
+               FIL_, 0xC5, 0xAB, FIL_, 0xCC, 0x8B, FIL_, 0xC5,
+               0xB1, FIL_, 0xCC, 0x86, FIL_, 0xC5, 0xAD, FIL_,
+               0xCC, 0x8C, FIL_, 0xC7, 0x94, FIL_, 0xCC, 0x8A,
+               FIL_, 0xC5, 0xAF, FIL_, 0x02, 0xCC, 0x83, FIL_,
+               0xE1, 0xB9, 0xBD, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB9, 0xBF, FIL_, 0x07, 0xCC, 0x82, FIL_, 0xC5,
+               0xB5, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBA, 0x81,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA, 0x83, FIL_,
+               0xCC, 0x88, FIL_, 0xE1, 0xBA, 0x85, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xBA, 0x89, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xBA, 0x87, FIL_, 0xCC, 0x8A, FIL_,
+               0xE1, 0xBA, 0x98, FIL_, 0x02, 0xCC, 0x87, FIL_,
+               0xE1, 0xBA, 0x8B, FIL_, 0xCC, 0x88, FIL_, 0xE1,
+               0xBA, 0x8D, FIL_, 0x0A, 0xCC, 0x87, FIL_, 0xE1,
+               0xBA, 0x8F, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB,
+               0xB9, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBB, 0xB3,
+               FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0xB7, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0xB5, FIL_, 0xCC,
+               0x82, FIL_, 0xC5, 0xB7, FIL_, 0xCC, 0x84, FIL_,
+               0xC8, 0xB3, FIL_, 0xCC, 0x8A, FIL_, 0xE1, 0xBA,
+               0x99, FIL_, 0xCC, 0x88, FIL_, 0xC3, 0xBF, FIL_,
+               0xCC, 0x81, FIL_, 0xC3, 0xBD, FIL_, 0x06, 0xCC,
+               0x8C, FIL_, 0xC5, 0xBE, FIL_, 0xCC, 0x87, FIL_,
+               0xC5, 0xBC, FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xBA,
+               0x95, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0x93,
+               FIL_, 0xCC, 0x81, FIL_, 0xC5, 0xBA, FIL_, 0xCC,
+               0x82, FIL_, 0xE1, 0xBA, 0x91, FIL_, 0x03, 0xCC,
+               0x80, FIL_, 0xE1, 0xBF, 0xAD, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBF, 0x81, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x85, FIL_, 0x04, 0xCC, 0x89, FIL_, 0xE1,
+               0xBA, 0xA8, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBA,
+               0xAA, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA, 0xA4,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBA, 0xA6, FIL_,
+               0x01, 0xCC, 0x84, FIL_, 0xC7, 0x9E, FIL_, 0x01,
+               0xCC, 0x81, FIL_, 0xC7, 0xBA, FIL_, 0x02, 0xCC,
+               0x84, FIL_, 0xC7, 0xA2, FIL_, 0xCC, 0x81, FIL_,
+               0xC7, 0xBC, FIL_, 0x01, 0xCC, 0x81, FIL_, 0xE1,
+               0xB8, 0x88, FIL_, 0x04, 0xCC, 0x81, FIL_, 0xE1,
+               0xBA, 0xBE, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBB,
+               0x80, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0x84,
+               FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x82, FIL_,
+               0x01, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0xAE, FIL_,
+               0x04, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0x96, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBB, 0x90, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBB, 0x92, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0x94, FIL_, 0x03, 0xCC, 0x84,
+               FIL_, 0xC8, 0xAC, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xB9, 0x8C, FIL_, 0xCC, 0x88, FIL_, 0xE1, 0xB9,
+               0x8E, FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC8, 0xAA,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xC7, 0xBE, FIL_,
+               0x04, 0xCC, 0x80, FIL_, 0xC7, 0x9B, FIL_, 0xCC,
+               0x84, FIL_, 0xC7, 0x95, FIL_, 0xCC, 0x8C, FIL_,
+               0xC7, 0x99, FIL_, 0xCC, 0x81, FIL_, 0xC7, 0x97,
+               FIL_, 0x04, 0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xA9,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBA, 0xA7, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBA, 0xA5, FIL_, 0xCC,
+               0x83, FIL_, 0xE1, 0xBA, 0xAB, FIL_, 0x01, 0xCC,
+               0x84, FIL_, 0xC7, 0x9F, FIL_, 0x01, 0xCC, 0x81,
+               FIL_, 0xC7, 0xBB, FIL_, 0x02, 0xCC, 0x84, FIL_,
+               0xC7, 0xA3, FIL_, 0xCC, 0x81, FIL_, 0xC7, 0xBD,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0x89,
+               FIL_, 0x04, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x83,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA, 0xBF, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBB, 0x81, FIL_, 0xCC,
+               0x83, FIL_, 0xE1, 0xBB, 0x85, FIL_, 0x01, 0xCC,
+               0x81, FIL_, 0xE1, 0xB8, 0xAF, FIL_, 0x04, 0xCC,
+               0x83, FIL_, 0xE1, 0xBB, 0x97, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0x95, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBB, 0x93, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xBB, 0x91, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1,
+               0xB9, 0x8D, FIL_, 0xCC, 0x84, FIL_, 0xC8, 0xAD,
+               FIL_, 0xCC, 0x88, FIL_, 0xE1, 0xB9, 0x8F, FIL_,
+               0x01, 0xCC, 0x84, FIL_, 0xC8, 0xAB, FIL_, 0x01,
+               0xCC, 0x81, FIL_, 0xC7, 0xBF, FIL_, 0x04, 0xCC,
+               0x81, FIL_, 0xC7, 0x98, FIL_, 0xCC, 0x84, FIL_,
+               0xC7, 0x96, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x9A,
+               FIL_, 0xCC, 0x80, FIL_, 0xC7, 0x9C, FIL_, 0x04,
+               0xCC, 0x80, FIL_, 0xE1, 0xBA, 0xB0, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBA, 0xAE, FIL_, 0xCC, 0x83,
+               FIL_, 0xE1, 0xBA, 0xB4, FIL_, 0xCC, 0x89, FIL_,
+               0xE1, 0xBA, 0xB2, FIL_, 0x04, 0xCC, 0x80, FIL_,
+               0xE1, 0xBA, 0xB1, FIL_, 0xCC, 0x83, FIL_, 0xE1,
+               0xBA, 0xB5, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA,
+               0xAF, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xB3,
+               FIL_, 0x02, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0x96,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xB8, 0x94, FIL_,
+               0x02, 0xCC, 0x80, FIL_, 0xE1, 0xB8, 0x95, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xB8, 0x97, FIL_, 0x02,
+               0xCC, 0x80, FIL_, 0xE1, 0xB9, 0x90, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xB9, 0x92, FIL_, 0x02, 0xCC,
+               0x80, FIL_, 0xE1, 0xB9, 0x91, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0x93, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA4, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA5, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA6, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA7, FIL_, 0x01, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0xB8, FIL_, 0x01, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0xB9, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xE1, 0xB9, 0xBA, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xE1, 0xB9, 0xBB, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xBA, 0x9B, FIL_, 0x05, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBB, 0x9C, FIL_, 0xCC, 0x81, FIL_,
+               0xE1, 0xBB, 0x9A, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xBB, 0xA2, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB,
+               0xA0, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x9E,
+               FIL_, 0x05, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0xA1,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBB, 0x9B, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0xA3, FIL_, 0xCC,
+               0x89, FIL_, 0xE1, 0xBB, 0x9F, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBB, 0x9D, FIL_, 0x05, 0xCC, 0x83,
+               FIL_, 0xE1, 0xBB, 0xAE, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xBB, 0xB0, FIL_, 0xCC, 0x89, FIL_, 0xE1,
+               0xBB, 0xAC, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBB,
+               0xA8, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBB, 0xAA,
+               FIL_, 0x05, 0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0xB1,
+               FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0xAF, FIL_,
+               0xCC, 0x89, FIL_, 0xE1, 0xBB, 0xAD, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBB, 0xA9, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBB, 0xAB, FIL_, 0x01, 0xCC, 0x8C,
+               FIL_, 0xC7, 0xAE, FIL_, 0x01, 0xCC, 0x84, FIL_,
+               0xC7, 0xAC, FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC7,
+               0xAD, FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC7, 0xA0,
+               FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC7, 0xA1, FIL_,
+               0x01, 0xCC, 0x86, FIL_, 0xE1, 0xB8, 0x9C, FIL_,
+               0x01, 0xCC, 0x86, FIL_, 0xE1, 0xB8, 0x9D, FIL_,
+               0x01, 0xCC, 0x84, FIL_, 0xC8, 0xB0, FIL_, 0x01,
+               0xCC, 0x84, FIL_, 0xC8, 0xB1, FIL_, 0x01, 0xCC,
+               0x8C, FIL_, 0xC7, 0xAF, FIL_, 0x07, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBC, 0x88, FIL_, 0xCC, 0x94, FIL_,
+               0xE1, 0xBC, 0x89, FIL_, 0xCC, 0x81, FIL_, 0xCE,
+               0x86, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xBC,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBE, 0xBA, FIL_,
+               0xCC, 0x84, FIL_, 0xE1, 0xBE, 0xB9, FIL_, 0xCC,
+               0x86, FIL_, 0xE1, 0xBE, 0xB8, FIL_, 0x04, 0xCC,
+               0x81, FIL_, 0xCE, 0x88, FIL_, 0xCC, 0x94, FIL_,
+               0xE1, 0xBC, 0x99, FIL_, 0xCC, 0x93, FIL_, 0xE1,
+               0xBC, 0x98, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF,
+               0x88, FIL_, 0x05, 0xCC, 0x94, FIL_, 0xE1, 0xBC,
+               0xA9, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF, 0x8A,
+               FIL_, 0xCC, 0x81, FIL_, 0xCE, 0x89, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBF, 0x8C, FIL_, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBC, 0xA8, FIL_, 0x07, 0xCC, 0x81,
+               FIL_, 0xCE, 0x8A, FIL_, 0xCC, 0x88, FIL_, 0xCE,
+               0xAA, FIL_, 0xCC, 0x86, FIL_, 0xE1, 0xBF, 0x98,
+               FIL_, 0xCC, 0x84, FIL_, 0xE1, 0xBF, 0x99, FIL_,
+               0xCC, 0x93, FIL_, 0xE1, 0xBC, 0xB8, FIL_, 0xCC,
+               0x94, FIL_, 0xE1, 0xBC, 0xB9, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBF, 0x9A, FIL_, 0x04, 0xCC, 0x94,
+               FIL_, 0xE1, 0xBD, 0x89, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBF, 0xB8, FIL_, 0xCC, 0x81, FIL_, 0xCE,
+               0x8C, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBD, 0x88,
+               FIL_, 0x01, 0xCC, 0x94, FIL_, 0xE1, 0xBF, 0xAC,
+               FIL_, 0x06, 0xCC, 0x81, FIL_, 0xCE, 0x8E, FIL_,
+               0xCC, 0x86, FIL_, 0xE1, 0xBF, 0xA8, FIL_, 0xCC,
+               0x94, FIL_, 0xE1, 0xBD, 0x99, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBF, 0xAA, FIL_, 0xCC, 0x84, FIL_,
+               0xE1, 0xBF, 0xA9, FIL_, 0xCC, 0x88, FIL_, 0xCE,
+               0xAB, FIL_, 0x05, 0xCC, 0x80, FIL_, 0xE1, 0xBF,
+               0xBA, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0x8F, FIL_,
+               0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xBC, FIL_, 0xCC,
+               0x94, FIL_, 0xE1, 0xBD, 0xA9, FIL_, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBD, 0xA8, FIL_, 0x01, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBE, 0xB4, FIL_, 0x01, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBF, 0x84, FIL_, 0x08, 0xCC, 0x81,
+               FIL_, 0xCE, 0xAC, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBD, 0xB0, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBC,
+               0x80, FIL_, 0xCC, 0x94, FIL_, 0xE1, 0xBC, 0x81,
+               FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBE, 0xB6, FIL_,
+               0xCC, 0x86, FIL_, 0xE1, 0xBE, 0xB0, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xB3, FIL_, 0xCC, 0x84,
+               FIL_, 0xE1, 0xBE, 0xB1, FIL_, 0x04, 0xCC, 0x81,
+               FIL_, 0xCE, 0xAD, FIL_, 0xCC, 0x94, FIL_, 0xE1,
+               0xBC, 0x91, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD,
+               0xB2, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBC, 0x90,
+               FIL_, 0x06, 0xCC, 0x81, FIL_, 0xCE, 0xAE, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xB4, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBF, 0x83, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBF, 0x86, FIL_, 0xCC, 0x94, FIL_,
+               0xE1, 0xBC, 0xA1, FIL_, 0xCC, 0x93, FIL_, 0xE1,
+               0xBC, 0xA0, FIL_, 0x08, 0xCD, 0x82, FIL_, 0xE1,
+               0xBF, 0x96, FIL_, 0xCC, 0x86, FIL_, 0xE1, 0xBF,
+               0x90, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBC, 0xB0,
+               FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xAF, FIL_, 0xCC,
+               0x94, FIL_, 0xE1, 0xBC, 0xB1, FIL_, 0xCC, 0x84,
+               FIL_, 0xE1, 0xBF, 0x91, FIL_, 0xCC, 0x88, FIL_,
+               0xCF, 0x8A, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD,
+               0xB6, FIL_, 0x04, 0xCC, 0x81, FIL_, 0xCF, 0x8C,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xB8, FIL_,
+               0xCC, 0x93, FIL_, 0xE1, 0xBD, 0x80, FIL_, 0xCC,
+               0x94, FIL_, 0xE1, 0xBD, 0x81, FIL_, 0x02, 0xCC,
+               0x93, FIL_, 0xE1, 0xBF, 0xA4, FIL_, 0xCC, 0x94,
+               FIL_, 0xE1, 0xBF, 0xA5, FIL_, 0x08, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBD, 0x90, FIL_, 0xCC, 0x94, FIL_,
+               0xE1, 0xBD, 0x91, FIL_, 0xCC, 0x86, FIL_, 0xE1,
+               0xBF, 0xA0, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBF,
+               0xA6, FIL_, 0xCC, 0x84, FIL_, 0xE1, 0xBF, 0xA1,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xBA, FIL_,
+               0xCC, 0x81, FIL_, 0xCF, 0x8D, FIL_, 0xCC, 0x88,
+               FIL_, 0xCF, 0x8B, FIL_, 0x06, 0xCC, 0x94, FIL_,
+               0xE1, 0xBD, 0xA1, FIL_, 0xCD, 0x85, FIL_, 0xE1,
+               0xBF, 0xB3, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD,
+               0xBC, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBF, 0xB6,
+               FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBD, 0xA0, FIL_,
+               0xCC, 0x81, FIL_, 0xCF, 0x8E, FIL_, 0x03, 0xCD,
+               0x82, FIL_, 0xE1, 0xBF, 0x97, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBF, 0x92, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x90, FIL_, 0x03, 0xCC, 0x80, FIL_, 0xE1,
+               0xBF, 0xA2, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xB0,
+               FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBF, 0xA7, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xB4, FIL_,
+               0x02, 0xCC, 0x88, FIL_, 0xCF, 0x94, FIL_, 0xCC,
+               0x81, FIL_, 0xCF, 0x93, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xD0, 0x87, FIL_, 0x02, 0xCC, 0x86, FIL_,
+               0xD3, 0x90, FIL_, 0xCC, 0x88, FIL_, 0xD3, 0x92,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xD0, 0x83, FIL_,
+               0x03, 0xCC, 0x86, FIL_, 0xD3, 0x96, FIL_, 0xCC,
+               0x80, FIL_, 0xD0, 0x80, FIL_, 0xCC, 0x88, FIL_,
+               0xD0, 0x81, FIL_, 0x02, 0xCC, 0x88, FIL_, 0xD3,
+               0x9C, FIL_, 0xCC, 0x86, FIL_, 0xD3, 0x81, FIL_,
+               0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9E, FIL_, 0x04,
+               0xCC, 0x80, FIL_, 0xD0, 0x8D, FIL_, 0xCC, 0x88,
+               FIL_, 0xD3, 0xA4, FIL_, 0xCC, 0x86, FIL_, 0xD0,
+               0x99, FIL_, 0xCC, 0x84, FIL_, 0xD3, 0xA2, FIL_,
+               0x01, 0xCC, 0x81, FIL_, 0xD0, 0x8C, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xA6, FIL_, 0x04, 0xCC,
+               0x86, FIL_, 0xD0, 0x8E, FIL_, 0xCC, 0x8B, FIL_,
+               0xD3, 0xB2, FIL_, 0xCC, 0x88, FIL_, 0xD3, 0xB0,
+               FIL_, 0xCC, 0x84, FIL_, 0xD3, 0xAE, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xB4, FIL_, 0x01, 0xCC,
+               0x88, FIL_, 0xD3, 0xB8, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xD3, 0xAC, FIL_, 0x02, 0xCC, 0x86, FIL_,
+               0xD3, 0x91, FIL_, 0xCC, 0x88, FIL_, 0xD3, 0x93,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xD1, 0x93, FIL_,
+               0x03, 0xCC, 0x80, FIL_, 0xD1, 0x90, FIL_, 0xCC,
+               0x88, FIL_, 0xD1, 0x91, FIL_, 0xCC, 0x86, FIL_,
+               0xD3, 0x97, FIL_, 0x02, 0xCC, 0x88, FIL_, 0xD3,
+               0x9D, FIL_, 0xCC, 0x86, FIL_, 0xD3, 0x82, FIL_,
+               0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9F, FIL_, 0x04,
+               0xCC, 0x88, FIL_, 0xD3, 0xA5, FIL_, 0xCC, 0x86,
+               FIL_, 0xD0, 0xB9, FIL_, 0xCC, 0x80, FIL_, 0xD1,
+               0x9D, FIL_, 0xCC, 0x84, FIL_, 0xD3, 0xA3, FIL_,
+               0x01, 0xCC, 0x81, FIL_, 0xD1, 0x9C, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xA7, FIL_, 0x04, 0xCC,
+               0x84, FIL_, 0xD3, 0xAF, FIL_, 0xCC, 0x86, FIL_,
+               0xD1, 0x9E, FIL_, 0xCC, 0x8B, FIL_, 0xD3, 0xB3,
+               FIL_, 0xCC, 0x88, FIL_, 0xD3, 0xB1, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xB5, FIL_, 0x01, 0xCC,
+               0x88, FIL_, 0xD3, 0xB9, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xD3, 0xAD, FIL_, 0x01, 0xCC, 0x88, FIL_,
+               0xD1, 0x97, FIL_, 0x01, 0xCC, 0x8F, FIL_, 0xD1,
+               0xB6, FIL_, 0x01, 0xCC, 0x8F, FIL_, 0xD1, 0xB7,
+               FIL_, 0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9A, FIL_,
+               0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9B, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xAA, FIL_, 0x01, 0xCC,
+               0x88, FIL_, 0xD3, 0xAB, FIL_, 0x03, 0xD9, 0x94,
+               FIL_, 0xD8, 0xA3, FIL_, 0xD9, 0x93, FIL_, 0xD8,
+               0xA2, FIL_, 0xD9, 0x95, FIL_, 0xD8, 0xA5, FIL_,
+               0x01, 0xD9, 0x94, FIL_, 0xD8, 0xA4, FIL_, 0x01,
+               0xD9, 0x94, FIL_, 0xD8, 0xA6, FIL_, 0x01, 0xD9,
+               0x94, FIL_, 0xDB, 0x82, FIL_, 0x01, 0xD9, 0x94,
+               FIL_, 0xDB, 0x93, FIL_, 0x01, 0xD9, 0x94, FIL_,
+               0xDB, 0x80, FIL_, 0x01, 0xE0, 0xA4, 0xBC, FIL_,
+               0xE0, 0xA4, 0xA9, FIL_, 0x01, 0xE0, 0xA4, 0xBC,
+               FIL_, 0xE0, 0xA4, 0xB1, FIL_, 0x01, 0xE0, 0xA4,
+               0xBC, FIL_, 0xE0, 0xA4, 0xB4, FIL_, 0x02, 0xE0,
+               0xA6, 0xBE, FIL_, 0xE0, 0xA7, 0x8B, FIL_, 0xE0,
+               0xA7, 0x97, FIL_, 0xE0, 0xA7, 0x8C, FIL_, 0x03,
+               0xE0, 0xAD, 0x97, FIL_, 0xE0, 0xAD, 0x8C, FIL_,
+               0xE0, 0xAC, 0xBE, FIL_, 0xE0, 0xAD, 0x8B, FIL_,
+               0xE0, 0xAD, 0x96, FIL_, 0xE0, 0xAD, 0x88, FIL_,
+               0x01, 0xE0, 0xAF, 0x97, FIL_, 0xE0, 0xAE, 0x94,
+               FIL_, 0x02, 0xE0, 0xAE, 0xBE, FIL_, 0xE0, 0xAF,
+               0x8A, FIL_, 0xE0, 0xAF, 0x97, FIL_, 0xE0, 0xAF,
+               0x8C, FIL_, 0x01, 0xE0, 0xAE, 0xBE, FIL_, 0xE0,
+               0xAF, 0x8B, FIL_, 0x01, 0xE0, 0xB1, 0x96, FIL_,
+               0xE0, 0xB1, 0x88, FIL_, 0x01, 0xE0, 0xB3, 0x95,
+               FIL_, 0xE0, 0xB3, 0x80, FIL_, 0x03, 0xE0, 0xB3,
+               0x95, FIL_, 0xE0, 0xB3, 0x87, FIL_, 0xE0, 0xB3,
+               0x82, FIL_, 0xE0, 0xB3, 0x8A, FIL_, 0xE0, 0xB3,
+               0x96, FIL_, 0xE0, 0xB3, 0x88, FIL_, 0x01, 0xE0,
+               0xB3, 0x95, FIL_, 0xE0, 0xB3, 0x8B, FIL_, 0x02,
+               0xE0, 0xB4, 0xBE, FIL_, 0xE0, 0xB5, 0x8A, FIL_,
+               0xE0, 0xB5, 0x97, FIL_, 0xE0, 0xB5, 0x8C, FIL_,
+               0x01, 0xE0, 0xB4, 0xBE, FIL_, 0xE0, 0xB5, 0x8B,
+               FIL_, 0x03, 0xE0, 0xB7, 0x8F, FIL_, 0xE0, 0xB7,
+               0x9C, FIL_, 0xE0, 0xB7, 0x8A, FIL_, 0xE0, 0xB7,
+               0x9A, FIL_, 0xE0, 0xB7, 0x9F, FIL_, 0xE0, 0xB7,
+               0x9E, FIL_, 0x01, 0xE0, 0xB7, 0x8A, FIL_, 0xE0,
+               0xB7, 0x9D, FIL_, 0x01, 0xE1, 0x80, 0xAE, FIL_,
+               0xE1, 0x80, 0xA6, FIL_, 0x01, 0xCC, 0x84, FIL_,
+               0xE1, 0xB8, 0xB8, FIL_, 0x01, 0xCC, 0x84, FIL_,
+               0xE1, 0xB8, 0xB9, FIL_, 0x01, 0xCC, 0x84, FIL_,
+               0xE1, 0xB9, 0x9C, FIL_, 0x01, 0xCC, 0x84, FIL_,
+               0xE1, 0xB9, 0x9D, FIL_, 0x01, 0xCC, 0x87, FIL_,
+               0xE1, 0xB9, 0xA8, FIL_, 0x01, 0xCC, 0x87, FIL_,
+               0xE1, 0xB9, 0xA9, FIL_, 0x02, 0xCC, 0x86, FIL_,
+               0xE1, 0xBA, 0xB6, FIL_, 0xCC, 0x82, FIL_, 0xE1,
+               0xBA, 0xAC, FIL_, 0x02, 0xCC, 0x86, FIL_, 0xE1,
+               0xBA, 0xB7, FIL_, 0xCC, 0x82, FIL_, 0xE1, 0xBA,
+               0xAD, FIL_, 0x01, 0xCC, 0x82, FIL_, 0xE1, 0xBB,
+               0x86, FIL_, 0x01, 0xCC, 0x82, FIL_, 0xE1, 0xBB,
+               0x87, FIL_, 0x01, 0xCC, 0x82, FIL_, 0xE1, 0xBB,
+               0x98, FIL_, 0x01, 0xCC, 0x82, FIL_, 0xE1, 0xBB,
+               0x99, FIL_, 0x04, 0xCC, 0x80, FIL_, 0xE1, 0xBC,
+               0x82, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x84,
+               FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x80, FIL_,
+               0xCD, 0x82, FIL_, 0xE1, 0xBC, 0x86, FIL_, 0x04,
+               0xCD, 0x82, FIL_, 0xE1, 0xBC, 0x87, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBC, 0x83, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBC, 0x85, FIL_, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x81, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x82, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x83, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x84, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x85, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x86, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x87, FIL_, 0x04, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x88, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBC, 0x8A, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBC,
+               0x8E, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x8C,
+               FIL_, 0x04, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x8D,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0x8B, FIL_,
+               0xCD, 0x82, FIL_, 0xE1, 0xBC, 0x8F, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x89, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x8A, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x8B, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x8C, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x8D, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x8E, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x8F, FIL_, 0x02, 0xCC,
+               0x80, FIL_, 0xE1, 0xBC, 0x92, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBC, 0x94, FIL_, 0x02, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBC, 0x93, FIL_, 0xCC, 0x81, FIL_,
+               0xE1, 0xBC, 0x95, FIL_, 0x02, 0xCC, 0x80, FIL_,
+               0xE1, 0xBC, 0x9A, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xBC, 0x9C, FIL_, 0x02, 0xCC, 0x80, FIL_, 0xE1,
+               0xBC, 0x9B, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC,
+               0x9D, FIL_, 0x04, 0xCD, 0x82, FIL_, 0xE1, 0xBC,
+               0xA6, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x90,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0xA4, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xA2, FIL_, 0x04,
+               0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xA3, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBC, 0xA5, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBC, 0xA7, FIL_, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x91, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x92, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x93, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x94, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x95, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x96, FIL_, 0x01, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0x97, FIL_, 0x04, 0xCD, 0x82, FIL_,
+               0xE1, 0xBC, 0xAE, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xBC, 0xAC, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE,
+               0x98, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xAA,
+               FIL_, 0x04, 0xCD, 0x82, FIL_, 0xE1, 0xBC, 0xAF,
+               FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x99, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBC, 0xAD, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBC, 0xAB, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x9A, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x9B, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x9C, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x9D, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x9E, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0x9F, FIL_, 0x03, 0xCC,
+               0x81, FIL_, 0xE1, 0xBC, 0xB4, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBC, 0xB6, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBC, 0xB2, FIL_, 0x03, 0xCC, 0x81, FIL_,
+               0xE1, 0xBC, 0xB5, FIL_, 0xCD, 0x82, FIL_, 0xE1,
+               0xBC, 0xB7, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC,
+               0xB3, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1, 0xBC,
+               0xBC, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xBA,
+               FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBC, 0xBE, FIL_,
+               0x03, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xBB, FIL_,
+               0xCD, 0x82, FIL_, 0xE1, 0xBC, 0xBF, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBC, 0xBD, FIL_, 0x02, 0xCC,
+               0x80, FIL_, 0xE1, 0xBD, 0x82, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBD, 0x84, FIL_, 0x02, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBD, 0x83, FIL_, 0xCC, 0x81, FIL_,
+               0xE1, 0xBD, 0x85, FIL_, 0x02, 0xCC, 0x81, FIL_,
+               0xE1, 0xBD, 0x8C, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBD, 0x8A, FIL_, 0x02, 0xCC, 0x81, FIL_, 0xE1,
+               0xBD, 0x8D, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD,
+               0x8B, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1, 0xBD,
+               0x94, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBD, 0x96,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0x92, FIL_,
+               0x03, 0xCD, 0x82, FIL_, 0xE1, 0xBD, 0x97, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBD, 0x95, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBD, 0x93, FIL_, 0x03, 0xCC,
+               0x81, FIL_, 0xE1, 0xBD, 0x9D, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBD, 0x9F, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBD, 0x9B, FIL_, 0x04, 0xCC, 0x81, FIL_,
+               0xE1, 0xBD, 0xA4, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBD, 0xA2, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBD,
+               0xA6, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA0,
+               FIL_, 0x04, 0xCD, 0x82, FIL_, 0xE1, 0xBD, 0xA7,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBD, 0xA5, FIL_,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA1, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBD, 0xA3, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA2, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA3, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA4, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA5, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA6, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA7, FIL_, 0x04, 0xCC,
+               0x81, FIL_, 0xE1, 0xBD, 0xAC, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBD, 0xAA, FIL_, 0xCD, 0x82, FIL_,
+               0xE1, 0xBD, 0xAE, FIL_, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xA8, FIL_, 0x04, 0xCC, 0x81, FIL_, 0xE1,
+               0xBD, 0xAD, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE,
+               0xA9, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBD, 0xAF,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xAB, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xAA, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xAB, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xAC, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xAD, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xAE, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xAF, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xB2, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0x82, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xB2, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xB7, FIL_,
+               0x03, 0xCD, 0x82, FIL_, 0xE1, 0xBF, 0x8F, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBF, 0x8D, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBF, 0x8E, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBF, 0x87, FIL_, 0x01, 0xCD,
+               0x85, FIL_, 0xE1, 0xBF, 0xB7, FIL_, 0x03, 0xCC,
+               0x80, FIL_, 0xE1, 0xBF, 0x9D, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBF, 0x9F, FIL_, 0xCC, 0x81, FIL_,
+               0xE1, 0xBF, 0x9E, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x86, 0x9A, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x86, 0x9B, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x86, 0xAE, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x87, 0x8D, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x87, 0x8F, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x87, 0x8E, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x88, 0x84, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x88, 0x89, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x88, 0x8C, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x88, 0xA4, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x88, 0xA6, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0x81, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0x84, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0x87, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0x89, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xAD, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xA2, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xB0, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xB1, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xB4, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xB5, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xB8, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x89, 0xB9, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0x80, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0x81, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xA0, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xA1, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0x84, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0x85, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0x88, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0x89, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xA2, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xA3, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0xAC, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0xAD, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0xAE, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8A, 0xAF, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xAA, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xAB, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xAC, FIL_, 0x01, 0xCC, 0xB8, FIL_,
+               0xE2, 0x8B, 0xAD, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x82, 0x94, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x81, 0x8C, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x81, 0x8E, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0x90, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0x92,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81,
+               0x94, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x81, 0x96, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x81, 0x98, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x81, 0x9A, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x81, 0x9C, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x81, 0x9E, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0xA0, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0xA2,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81,
+               0xA5, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x81, 0xA7, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x81, 0xA9, FIL_, 0x02, 0xE3, 0x82, 0x9A,
+               FIL_, 0xE3, 0x81, 0xB1, FIL_, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x81, 0xB0, FIL_, 0x02, 0xE3, 0x82,
+               0x9A, FIL_, 0xE3, 0x81, 0xB4, FIL_, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x81, 0xB3, FIL_, 0x02, 0xE3,
+               0x82, 0x9A, FIL_, 0xE3, 0x81, 0xB7, FIL_, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x81, 0xB6, FIL_, 0x02,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0xB9, FIL_,
+               0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x81, 0xBA, FIL_,
+               0x02, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0xBC,
+               FIL_, 0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x81, 0xBD,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82,
+               0x9E, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x83, 0xB4, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x82, 0xAC, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x82, 0xAE, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x82, 0xB0, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x82, 0xB2, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82, 0xB4, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82, 0xB6,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82,
+               0xB8, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x82, 0xBA, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x82, 0xBC, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x82, 0xBE, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x83, 0x80, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x83, 0x82, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0x85, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0x87,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83,
+               0x89, FIL_, 0x02, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x83, 0x90, FIL_, 0xE3, 0x82, 0x9A, FIL_, 0xE3,
+               0x83, 0x91, FIL_, 0x02, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x83, 0x93, FIL_, 0xE3, 0x82, 0x9A, FIL_,
+               0xE3, 0x83, 0x94, FIL_, 0x02, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x83, 0x96, FIL_, 0xE3, 0x82, 0x9A,
+               FIL_, 0xE3, 0x83, 0x97, FIL_, 0x02, 0xE3, 0x82,
+               0x9A, FIL_, 0xE3, 0x83, 0x9A, FIL_, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x83, 0x99, FIL_, 0x02, 0xE3,
+               0x82, 0x9A, FIL_, 0xE3, 0x83, 0x9D, FIL_, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x83, 0x9C, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0xB7, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0xB8,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83,
+               0xB9, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x83, 0xBA, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x83, 0xBE, FIL_, 0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,
+       },
+       {
+               0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAE, FIL_,
+               0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xA0, FIL_,
+               0x01, 0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAF, FIL_,
+               0x10, 0xCC, 0xA5, FIL_, 0xE1, 0xB8, 0x80, FIL_,
+               0xCC, 0x87, FIL_, 0xC8, 0xA6, FIL_, 0xCC, 0x83,
+               FIL_, 0xC3, 0x83, FIL_, 0xCC, 0x91, FIL_, 0xC8,
+               0x82, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x80, FIL_,
+               0xCC, 0x8A, FIL_, 0xC3, 0x85, FIL_, 0xCC, 0x88,
+               FIL_, 0xC3, 0x84, FIL_, 0xCC, 0x89, FIL_, 0xE1,
+               0xBA, 0xA2, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA,
+               0xA0, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x8D, FIL_,
+               0xCC, 0x80, FIL_, 0xC3, 0x80, FIL_, 0xCC, 0x81,
+               FIL_, 0xC3, 0x81, FIL_, 0xCC, 0x82, FIL_, 0xC3,
+               0x82, FIL_, 0xCC, 0xA8, FIL_, 0xC4, 0x84, FIL_,
+               0xCC, 0x86, FIL_, 0xC4, 0x82, FIL_, 0xCC, 0x84,
+               FIL_, 0xC4, 0x80, FIL_, 0x03, 0xCC, 0xB1, FIL_,
+               0xE1, 0xB8, 0x86, FIL_, 0xCC, 0x87, FIL_, 0xE1,
+               0xB8, 0x82, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0x84, FIL_, 0x05, 0xCC, 0xA7, FIL_, 0xC3, 0x87,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0x8C, FIL_, 0xCC,
+               0x81, FIL_, 0xC4, 0x86, FIL_, 0xCC, 0x82, FIL_,
+               0xC4, 0x88, FIL_, 0xCC, 0x87, FIL_, 0xC4, 0x8A,
+               FIL_, 0x06, 0xCC, 0xA7, FIL_, 0xE1, 0xB8, 0x90,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0x8E, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xB8, 0x8E, FIL_, 0xCC, 0xAD,
+               FIL_, 0xE1, 0xB8, 0x92, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xB8, 0x8C, FIL_, 0xCC, 0x87, FIL_, 0xE1,
+               0xB8, 0x8A, FIL_, 0x11, 0xCC, 0x84, FIL_, 0xC4,
+               0x92, FIL_, 0xCC, 0x86, FIL_, 0xC4, 0x94, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0xB8, FIL_, 0xCC,
+               0x91, FIL_, 0xC8, 0x86, FIL_, 0xCC, 0x82, FIL_,
+               0xC3, 0x8A, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x84,
+               FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB8, 0x98, FIL_,
+               0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xBA, FIL_, 0xCC,
+               0xA7, FIL_, 0xC8, 0xA8, FIL_, 0xCC, 0x8C, FIL_,
+               0xC4, 0x9A, FIL_, 0xCC, 0x80, FIL_, 0xC3, 0x88,
+               FIL_, 0xCC, 0xA8, FIL_, 0xC4, 0x98, FIL_, 0xCC,
+               0x83, FIL_, 0xE1, 0xBA, 0xBC, FIL_, 0xCC, 0x87,
+               FIL_, 0xC4, 0x96, FIL_, 0xCC, 0x81, FIL_, 0xC3,
+               0x89, FIL_, 0xCC, 0x88, FIL_, 0xC3, 0x8B, FIL_,
+               0xCC, 0xB0, FIL_, 0xE1, 0xB8, 0x9A, FIL_, 0x01,
+               0xCC, 0x87, FIL_, 0xE1, 0xB8, 0x9E, FIL_, 0x07,
+               0xCC, 0x8C, FIL_, 0xC7, 0xA6, FIL_, 0xCC, 0x86,
+               FIL_, 0xC4, 0x9E, FIL_, 0xCC, 0x82, FIL_, 0xC4,
+               0x9C, FIL_, 0xCC, 0xA7, FIL_, 0xC4, 0xA2, FIL_,
+               0xCC, 0x84, FIL_, 0xE1, 0xB8, 0xA0, FIL_, 0xCC,
+               0x81, FIL_, 0xC7, 0xB4, FIL_, 0xCC, 0x87, FIL_,
+               0xC4, 0xA0, FIL_, 0x07, 0xCC, 0x87, FIL_, 0xE1,
+               0xB8, 0xA2, FIL_, 0xCC, 0xA7, FIL_, 0xE1, 0xB8,
+               0xA8, FIL_, 0xCC, 0x82, FIL_, 0xC4, 0xA4, FIL_,
+               0xCC, 0x88, FIL_, 0xE1, 0xB8, 0xA6, FIL_, 0xCC,
+               0x8C, FIL_, 0xC8, 0x9E, FIL_, 0xCC, 0xAE, FIL_,
+               0xE1, 0xB8, 0xAA, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB8, 0xA4, FIL_, 0x0F, 0xCC, 0xB0, FIL_, 0xE1,
+               0xB8, 0xAC, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x8F,
+               FIL_, 0xCC, 0x80, FIL_, 0xC3, 0x8C, FIL_, 0xCC,
+               0x89, FIL_, 0xE1, 0xBB, 0x88, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xBB, 0x8A, FIL_, 0xCC, 0x91, FIL_,
+               0xC8, 0x8A, FIL_, 0xCC, 0x88, FIL_, 0xC3, 0x8F,
+               FIL_, 0xCC, 0x82, FIL_, 0xC3, 0x8E, FIL_, 0xCC,
+               0x81, FIL_, 0xC3, 0x8D, FIL_, 0xCC, 0x83, FIL_,
+               0xC4, 0xA8, FIL_, 0xCC, 0x87, FIL_, 0xC4, 0xB0,
+               FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x88, FIL_, 0xCC,
+               0xA8, FIL_, 0xC4, 0xAE, FIL_, 0xCC, 0x86, FIL_,
+               0xC4, 0xAC, FIL_, 0xCC, 0x84, FIL_, 0xC4, 0xAA,
+               FIL_, 0x01, 0xCC, 0x82, FIL_, 0xC4, 0xB4, FIL_,
+               0x05, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0xB0, FIL_,
+               0xCC, 0x8C, FIL_, 0xC7, 0xA8, FIL_, 0xCC, 0xB1,
+               FIL_, 0xE1, 0xB8, 0xB4, FIL_, 0xCC, 0xA7, FIL_,
+               0xC4, 0xB6, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0xB2, FIL_, 0x06, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0xB6, FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0xBD, FIL_,
+               0xCC, 0xAD, FIL_, 0xE1, 0xB8, 0xBC, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xB8, 0xBA, FIL_, 0xCC, 0xA7,
+               FIL_, 0xC4, 0xBB, FIL_, 0xCC, 0x81, FIL_, 0xC4,
+               0xB9, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1, 0xB8,
+               0xBE, FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB9, 0x80,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x82, FIL_,
+               0x09, 0xCC, 0x83, FIL_, 0xC3, 0x91, FIL_, 0xCC,
+               0x81, FIL_, 0xC5, 0x83, FIL_, 0xCC, 0xA7, FIL_,
+               0xC5, 0x85, FIL_, 0xCC, 0x8C, FIL_, 0xC5, 0x87,
+               FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB9, 0x84, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x86, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xB9, 0x88, FIL_, 0xCC, 0xAD,
+               FIL_, 0xE1, 0xB9, 0x8A, FIL_, 0xCC, 0x80, FIL_,
+               0xC7, 0xB8, FIL_, 0x10, 0xCC, 0x89, FIL_, 0xE1,
+               0xBB, 0x8E, FIL_, 0xCC, 0x84, FIL_, 0xC5, 0x8C,
+               FIL_, 0xCC, 0x82, FIL_, 0xC3, 0x94, FIL_, 0xCC,
+               0x86, FIL_, 0xC5, 0x8E, FIL_, 0xCC, 0x83, FIL_,
+               0xC3, 0x95, FIL_, 0xCC, 0x8B, FIL_, 0xC5, 0x90,
+               FIL_, 0xCC, 0x88, FIL_, 0xC3, 0x96, FIL_, 0xCC,
+               0x9B, FIL_, 0xC6, 0xA0, FIL_, 0xCC, 0x91, FIL_,
+               0xC8, 0x8E, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x91,
+               FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x8C, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xBB, 0x8C, FIL_, 0xCC, 0x80,
+               FIL_, 0xC3, 0x92, FIL_, 0xCC, 0xA8, FIL_, 0xC7,
+               0xAA, FIL_, 0xCC, 0x87, FIL_, 0xC8, 0xAE, FIL_,
+               0xCC, 0x81, FIL_, 0xC3, 0x93, FIL_, 0x02, 0xCC,
+               0x87, FIL_, 0xE1, 0xB9, 0x96, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0x94, FIL_, 0x08, 0xCC, 0xA7,
+               FIL_, 0xC5, 0x96, FIL_, 0xCC, 0x8C, FIL_, 0xC5,
+               0x98, FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x92, FIL_,
+               0xCC, 0x8F, FIL_, 0xC8, 0x90, FIL_, 0xCC, 0x81,
+               FIL_, 0xC5, 0x94, FIL_, 0xCC, 0x87, FIL_, 0xE1,
+               0xB9, 0x98, FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xB9,
+               0x9E, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x9A,
+               FIL_, 0x07, 0xCC, 0xA6, FIL_, 0xC8, 0x98, FIL_,
+               0xCC, 0x81, FIL_, 0xC5, 0x9A, FIL_, 0xCC, 0x82,
+               FIL_, 0xC5, 0x9C, FIL_, 0xCC, 0xA7, FIL_, 0xC5,
+               0x9E, FIL_, 0xCC, 0x8C, FIL_, 0xC5, 0xA0, FIL_,
+               0xCC, 0x87, FIL_, 0xE1, 0xB9, 0xA0, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xB9, 0xA2, FIL_, 0x07, 0xCC,
+               0xA6, FIL_, 0xC8, 0x9A, FIL_, 0xCC, 0x87, FIL_,
+               0xE1, 0xB9, 0xAA, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB9, 0xAC, FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xB9,
+               0xAE, FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB9, 0xB0,
+               FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0xA2, FIL_, 0xCC,
+               0x8C, FIL_, 0xC5, 0xA4, FIL_, 0x13, 0xCC, 0x8A,
+               FIL_, 0xC5, 0xAE, FIL_, 0xCC, 0x88, FIL_, 0xC3,
+               0x9C, FIL_, 0xCC, 0x8B, FIL_, 0xC5, 0xB0, FIL_,
+               0xCC, 0xAD, FIL_, 0xE1, 0xB9, 0xB6, FIL_, 0xCC,
+               0xA8, FIL_, 0xC5, 0xB2, FIL_, 0xCC, 0x8C, FIL_,
+               0xC7, 0x93, FIL_, 0xCC, 0x80, FIL_, 0xC3, 0x99,
+               FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x94, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xBB, 0xA4, FIL_, 0xCC, 0xA4,
+               FIL_, 0xE1, 0xB9, 0xB2, FIL_, 0xCC, 0x81, FIL_,
+               0xC3, 0x9A, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0x9B,
+               FIL_, 0xCC, 0xB0, FIL_, 0xE1, 0xB9, 0xB4, FIL_,
+               0xCC, 0x83, FIL_, 0xC5, 0xA8, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0xA6, FIL_, 0xCC, 0x84, FIL_,
+               0xC5, 0xAA, FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x96,
+               FIL_, 0xCC, 0x86, FIL_, 0xC5, 0xAC, FIL_, 0xCC,
+               0x9B, FIL_, 0xC6, 0xAF, FIL_, 0x02, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xB9, 0xBE, FIL_, 0xCC, 0x83, FIL_,
+               0xE1, 0xB9, 0xBC, FIL_, 0x06, 0xCC, 0x88, FIL_,
+               0xE1, 0xBA, 0x84, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xBA, 0x82, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBA,
+               0x80, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0x88,
+               FIL_, 0xCC, 0x82, FIL_, 0xC5, 0xB4, FIL_, 0xCC,
+               0x87, FIL_, 0xE1, 0xBA, 0x86, FIL_, 0x02, 0xCC,
+               0x88, FIL_, 0xE1, 0xBA, 0x8C, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xBA, 0x8A, FIL_, 0x09, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0xB6, FIL_, 0xCC, 0xA3, FIL_,
+               0xE1, 0xBB, 0xB4, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBB, 0xB2, FIL_, 0xCC, 0x88, FIL_, 0xC5, 0xB8,
+               FIL_, 0xCC, 0x81, FIL_, 0xC3, 0x9D, FIL_, 0xCC,
+               0x83, FIL_, 0xE1, 0xBB, 0xB8, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xBA, 0x8E, FIL_, 0xCC, 0x84, FIL_,
+               0xC8, 0xB2, FIL_, 0xCC, 0x82, FIL_, 0xC5, 0xB6,
+               FIL_, 0x06, 0xCC, 0x82, FIL_, 0xE1, 0xBA, 0x90,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0x92, FIL_,
+               0xCC, 0xB1, FIL_, 0xE1, 0xBA, 0x94, FIL_, 0xCC,
+               0x8C, FIL_, 0xC5, 0xBD, FIL_, 0xCC, 0x87, FIL_,
+               0xC5, 0xBB, FIL_, 0xCC, 0x81, FIL_, 0xC5, 0xB9,
+               FIL_, 0x10, 0xCC, 0xA3, FIL_, 0xE1, 0xBA, 0xA1,
+               FIL_, 0xCC, 0xA8, FIL_, 0xC4, 0x85, FIL_, 0xCC,
+               0x81, FIL_, 0xC3, 0xA1, FIL_, 0xCC, 0x82, FIL_,
+               0xC3, 0xA2, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA,
+               0xA3, FIL_, 0xCC, 0x83, FIL_, 0xC3, 0xA3, FIL_,
+               0xCC, 0x8C, FIL_, 0xC7, 0x8E, FIL_, 0xCC, 0x8A,
+               FIL_, 0xC3, 0xA5, FIL_, 0xCC, 0x88, FIL_, 0xC3,
+               0xA4, FIL_, 0xCC, 0x87, FIL_, 0xC8, 0xA7, FIL_,
+               0xCC, 0x91, FIL_, 0xC8, 0x83, FIL_, 0xCC, 0xA5,
+               FIL_, 0xE1, 0xB8, 0x81, FIL_, 0xCC, 0x84, FIL_,
+               0xC4, 0x81, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x81,
+               FIL_, 0xCC, 0x86, FIL_, 0xC4, 0x83, FIL_, 0xCC,
+               0x80, FIL_, 0xC3, 0xA0, FIL_, 0x03, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xB8, 0x85, FIL_, 0xCC, 0x87, FIL_,
+               0xE1, 0xB8, 0x83, FIL_, 0xCC, 0xB1, FIL_, 0xE1,
+               0xB8, 0x87, FIL_, 0x05, 0xCC, 0x87, FIL_, 0xC4,
+               0x8B, FIL_, 0xCC, 0x8C, FIL_, 0xC4, 0x8D, FIL_,
+               0xCC, 0x82, FIL_, 0xC4, 0x89, FIL_, 0xCC, 0x81,
+               FIL_, 0xC4, 0x87, FIL_, 0xCC, 0xA7, FIL_, 0xC3,
+               0xA7, FIL_, 0x06, 0xCC, 0x87, FIL_, 0xE1, 0xB8,
+               0x8B, FIL_, 0xCC, 0xA7, FIL_, 0xE1, 0xB8, 0x91,
+               FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xB8, 0x8F, FIL_,
+               0xCC, 0xA3, FIL_, 0xE1, 0xB8, 0x8D, FIL_, 0xCC,
+               0x8C, FIL_, 0xC4, 0x8F, FIL_, 0xCC, 0xAD, FIL_,
+               0xE1, 0xB8, 0x93, FIL_, 0x11, 0xCC, 0x80, FIL_,
+               0xC3, 0xA8, FIL_, 0xCC, 0x81, FIL_, 0xC3, 0xA9,
+               FIL_, 0xCC, 0x82, FIL_, 0xC3, 0xAA, FIL_, 0xCC,
+               0x88, FIL_, 0xC3, 0xAB, FIL_, 0xCC, 0x84, FIL_,
+               0xC4, 0x93, FIL_, 0xCC, 0x86, FIL_, 0xC4, 0x95,
+               FIL_, 0xCC, 0x87, FIL_, 0xC4, 0x97, FIL_, 0xCC,
+               0xA8, FIL_, 0xC4, 0x99, FIL_, 0xCC, 0x8C, FIL_,
+               0xC4, 0x9B, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x85,
+               FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x87, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xBA, 0xB9, FIL_, 0xCC, 0xA7,
+               FIL_, 0xC8, 0xA9, FIL_, 0xCC, 0x83, FIL_, 0xE1,
+               0xBA, 0xBD, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA,
+               0xBB, FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB8, 0x99,
+               FIL_, 0xCC, 0xB0, FIL_, 0xE1, 0xB8, 0x9B, FIL_,
+               0x01, 0xCC, 0x87, FIL_, 0xE1, 0xB8, 0x9F, FIL_,
+               0x07, 0xCC, 0x86, FIL_, 0xC4, 0x9F, FIL_, 0xCC,
+               0x87, FIL_, 0xC4, 0xA1, FIL_, 0xCC, 0x82, FIL_,
+               0xC4, 0x9D, FIL_, 0xCC, 0x84, FIL_, 0xE1, 0xB8,
+               0xA1, FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0xA7, FIL_,
+               0xCC, 0xA7, FIL_, 0xC4, 0xA3, FIL_, 0xCC, 0x81,
+               FIL_, 0xC7, 0xB5, FIL_, 0x08, 0xCC, 0xA7, FIL_,
+               0xE1, 0xB8, 0xA9, FIL_, 0xCC, 0xB1, FIL_, 0xE1,
+               0xBA, 0x96, FIL_, 0xCC, 0x8C, FIL_, 0xC8, 0x9F,
+               FIL_, 0xCC, 0xAE, FIL_, 0xE1, 0xB8, 0xAB, FIL_,
+               0xCC, 0x88, FIL_, 0xE1, 0xB8, 0xA7, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xB8, 0xA5, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB8, 0xA3, FIL_, 0xCC, 0x82, FIL_,
+               0xC4, 0xA5, FIL_, 0x0E, 0xCC, 0x88, FIL_, 0xC3,
+               0xAF, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x89,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0x8B, FIL_,
+               0xCC, 0x82, FIL_, 0xC3, 0xAE, FIL_, 0xCC, 0x81,
+               FIL_, 0xC3, 0xAD, FIL_, 0xCC, 0x80, FIL_, 0xC3,
+               0xAC, FIL_, 0xCC, 0x83, FIL_, 0xC4, 0xA9, FIL_,
+               0xCC, 0x84, FIL_, 0xC4, 0xAB, FIL_, 0xCC, 0x86,
+               FIL_, 0xC4, 0xAD, FIL_, 0xCC, 0xA8, FIL_, 0xC4,
+               0xAF, FIL_, 0xCC, 0xB0, FIL_, 0xE1, 0xB8, 0xAD,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x90, FIL_, 0xCC,
+               0x91, FIL_, 0xC8, 0x8B, FIL_, 0xCC, 0x8F, FIL_,
+               0xC8, 0x89, FIL_, 0x02, 0xCC, 0x8C, FIL_, 0xC7,
+               0xB0, FIL_, 0xCC, 0x82, FIL_, 0xC4, 0xB5, FIL_,
+               0x05, 0xCC, 0xB1, FIL_, 0xE1, 0xB8, 0xB5, FIL_,
+               0xCC, 0xA7, FIL_, 0xC4, 0xB7, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC7, 0xA9, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xB8, 0xB1, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0xB3, FIL_, 0x06, 0xCC, 0xA3, FIL_, 0xE1, 0xB8,
+               0xB7, FIL_, 0xCC, 0xAD, FIL_, 0xE1, 0xB8, 0xBD,
+               FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xB8, 0xBB, FIL_,
+               0xCC, 0xA7, FIL_, 0xC4, 0xBC, FIL_, 0xCC, 0x81,
+               FIL_, 0xC4, 0xBA, FIL_, 0xCC, 0x8C, FIL_, 0xC4,
+               0xBE, FIL_, 0x03, 0xCC, 0x87, FIL_, 0xE1, 0xB9,
+               0x81, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x83,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0xBF, FIL_,
+               0x09, 0xCC, 0x80, FIL_, 0xC7, 0xB9, FIL_, 0xCC,
+               0xAD, FIL_, 0xE1, 0xB9, 0x8B, FIL_, 0xCC, 0x83,
+               FIL_, 0xC3, 0xB1, FIL_, 0xCC, 0x81, FIL_, 0xC5,
+               0x84, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0x87,
+               FIL_, 0xCC, 0xB1, FIL_, 0xE1, 0xB9, 0x89, FIL_,
+               0xCC, 0x87, FIL_, 0xE1, 0xB9, 0x85, FIL_, 0xCC,
+               0xA7, FIL_, 0xC5, 0x86, FIL_, 0xCC, 0x8C, FIL_,
+               0xC5, 0x88, FIL_, 0x10, 0xCC, 0xA3, FIL_, 0xE1,
+               0xBB, 0x8D, FIL_, 0xCC, 0x87, FIL_, 0xC8, 0xAF,
+               FIL_, 0xCC, 0x80, FIL_, 0xC3, 0xB2, FIL_, 0xCC,
+               0x91, FIL_, 0xC8, 0x8F, FIL_, 0xCC, 0x89, FIL_,
+               0xE1, 0xBB, 0x8F, FIL_, 0xCC, 0x88, FIL_, 0xC3,
+               0xB6, FIL_, 0xCC, 0x83, FIL_, 0xC3, 0xB5, FIL_,
+               0xCC, 0x81, FIL_, 0xC3, 0xB3, FIL_, 0xCC, 0x8C,
+               FIL_, 0xC7, 0x92, FIL_, 0xCC, 0xA8, FIL_, 0xC7,
+               0xAB, FIL_, 0xCC, 0x9B, FIL_, 0xC6, 0xA1, FIL_,
+               0xCC, 0x84, FIL_, 0xC5, 0x8D, FIL_, 0xCC, 0x86,
+               FIL_, 0xC5, 0x8F, FIL_, 0xCC, 0x8B, FIL_, 0xC5,
+               0x91, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0xB4, FIL_,
+               0xCC, 0x8F, FIL_, 0xC8, 0x8D, FIL_, 0x02, 0xCC,
+               0x87, FIL_, 0xE1, 0xB9, 0x97, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0x95, FIL_, 0x08, 0xCC, 0x8C,
+               FIL_, 0xC5, 0x99, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB9, 0x9B, FIL_, 0xCC, 0x81, FIL_, 0xC5, 0x95,
+               FIL_, 0xCC, 0xA7, FIL_, 0xC5, 0x97, FIL_, 0xCC,
+               0xB1, FIL_, 0xE1, 0xB9, 0x9F, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0x99, FIL_, 0xCC, 0x91, FIL_,
+               0xC8, 0x93, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x91,
+               FIL_, 0x07, 0xCC, 0xA7, FIL_, 0xC5, 0x9F, FIL_,
+               0xCC, 0x82, FIL_, 0xC5, 0x9D, FIL_, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA1, FIL_, 0xCC, 0xA6, FIL_,
+               0xC8, 0x99, FIL_, 0xCC, 0x81, FIL_, 0xC5, 0x9B,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9, 0xA3, FIL_,
+               0xCC, 0x8C, FIL_, 0xC5, 0xA1, FIL_, 0x08, 0xCC,
+               0xA6, FIL_, 0xC8, 0x9B, FIL_, 0xCC, 0xAD, FIL_,
+               0xE1, 0xB9, 0xB1, FIL_, 0xCC, 0xB1, FIL_, 0xE1,
+               0xB9, 0xAF, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xB9,
+               0xAD, FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xB9, 0xAB,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC5, 0xA5, FIL_, 0xCC,
+               0xA7, FIL_, 0xC5, 0xA3, FIL_, 0xCC, 0x88, FIL_,
+               0xE1, 0xBA, 0x97, FIL_, 0x13, 0xCC, 0x8A, FIL_,
+               0xC5, 0xAF, FIL_, 0xCC, 0x8F, FIL_, 0xC8, 0x95,
+               FIL_, 0xCC, 0x8C, FIL_, 0xC7, 0x94, FIL_, 0xCC,
+               0x80, FIL_, 0xC3, 0xB9, FIL_, 0xCC, 0x9B, FIL_,
+               0xC6, 0xB0, FIL_, 0xCC, 0x82, FIL_, 0xC3, 0xBB,
+               FIL_, 0xCC, 0x81, FIL_, 0xC3, 0xBA, FIL_, 0xCC,
+               0x88, FIL_, 0xC3, 0xBC, FIL_, 0xCC, 0x83, FIL_,
+               0xC5, 0xA9, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB,
+               0xA7, FIL_, 0xCC, 0x84, FIL_, 0xC5, 0xAB, FIL_,
+               0xCC, 0x86, FIL_, 0xC5, 0xAD, FIL_, 0xCC, 0xAD,
+               FIL_, 0xE1, 0xB9, 0xB7, FIL_, 0xCC, 0x8B, FIL_,
+               0xC5, 0xB1, FIL_, 0xCC, 0xA8, FIL_, 0xC5, 0xB3,
+               FIL_, 0xCC, 0x91, FIL_, 0xC8, 0x97, FIL_, 0xCC,
+               0xA4, FIL_, 0xE1, 0xB9, 0xB3, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xBB, 0xA5, FIL_, 0xCC, 0xB0, FIL_,
+               0xE1, 0xB9, 0xB5, FIL_, 0x02, 0xCC, 0x83, FIL_,
+               0xE1, 0xB9, 0xBD, FIL_, 0xCC, 0xA3, FIL_, 0xE1,
+               0xB9, 0xBF, FIL_, 0x07, 0xCC, 0x8A, FIL_, 0xE1,
+               0xBA, 0x98, FIL_, 0xCC, 0x87, FIL_, 0xE1, 0xBA,
+               0x87, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA, 0x83,
+               FIL_, 0xCC, 0x82, FIL_, 0xC5, 0xB5, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBA, 0x81, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xBA, 0x89, FIL_, 0xCC, 0x88, FIL_,
+               0xE1, 0xBA, 0x85, FIL_, 0x02, 0xCC, 0x87, FIL_,
+               0xE1, 0xBA, 0x8B, FIL_, 0xCC, 0x88, FIL_, 0xE1,
+               0xBA, 0x8D, FIL_, 0x0A, 0xCC, 0x87, FIL_, 0xE1,
+               0xBA, 0x8F, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBB,
+               0xB5, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0xB7,
+               FIL_, 0xCC, 0x8A, FIL_, 0xE1, 0xBA, 0x99, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBB, 0xB3, FIL_, 0xCC,
+               0x83, FIL_, 0xE1, 0xBB, 0xB9, FIL_, 0xCC, 0x88,
+               FIL_, 0xC3, 0xBF, FIL_, 0xCC, 0x81, FIL_, 0xC3,
+               0xBD, FIL_, 0xCC, 0x84, FIL_, 0xC8, 0xB3, FIL_,
+               0xCC, 0x82, FIL_, 0xC5, 0xB7, FIL_, 0x06, 0xCC,
+               0xB1, FIL_, 0xE1, 0xBA, 0x95, FIL_, 0xCC, 0xA3,
+               FIL_, 0xE1, 0xBA, 0x93, FIL_, 0xCC, 0x82, FIL_,
+               0xE1, 0xBA, 0x91, FIL_, 0xCC, 0x81, FIL_, 0xC5,
+               0xBA, FIL_, 0xCC, 0x87, FIL_, 0xC5, 0xBC, FIL_,
+               0xCC, 0x8C, FIL_, 0xC5, 0xBE, FIL_, 0x03, 0xCC,
+               0x80, FIL_, 0xE1, 0xBF, 0xAD, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBF, 0x81, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x85, FIL_, 0x04, 0xCC, 0x83, FIL_, 0xE1,
+               0xBA, 0xAA, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA,
+               0xA4, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xA8,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBA, 0xA6, FIL_,
+               0x01, 0xCC, 0x84, FIL_, 0xC7, 0x9E, FIL_, 0x01,
+               0xCC, 0x81, FIL_, 0xC7, 0xBA, FIL_, 0x02, 0xCC,
+               0x84, FIL_, 0xC7, 0xA2, FIL_, 0xCC, 0x81, FIL_,
+               0xC7, 0xBC, FIL_, 0x01, 0xCC, 0x81, FIL_, 0xE1,
+               0xB8, 0x88, FIL_, 0x04, 0xCC, 0x83, FIL_, 0xE1,
+               0xBB, 0x84, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBB,
+               0x80, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x82,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA, 0xBE, FIL_,
+               0x01, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0xAE, FIL_,
+               0x04, 0xCC, 0x81, FIL_, 0xE1, 0xBB, 0x90, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBB, 0x92, FIL_, 0xCC,
+               0x89, FIL_, 0xE1, 0xBB, 0x94, FIL_, 0xCC, 0x83,
+               FIL_, 0xE1, 0xBB, 0x96, FIL_, 0x03, 0xCC, 0x84,
+               FIL_, 0xC8, 0xAC, FIL_, 0xCC, 0x88, FIL_, 0xE1,
+               0xB9, 0x8E, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xB9,
+               0x8C, FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC8, 0xAA,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xC7, 0xBE, FIL_,
+               0x04, 0xCC, 0x80, FIL_, 0xC7, 0x9B, FIL_, 0xCC,
+               0x84, FIL_, 0xC7, 0x95, FIL_, 0xCC, 0x8C, FIL_,
+               0xC7, 0x99, FIL_, 0xCC, 0x81, FIL_, 0xC7, 0x97,
+               FIL_, 0x04, 0xCC, 0x81, FIL_, 0xE1, 0xBA, 0xA5,
+               FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBA, 0xAB, FIL_,
+               0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xA9, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBA, 0xA7, FIL_, 0x01, 0xCC,
+               0x84, FIL_, 0xC7, 0x9F, FIL_, 0x01, 0xCC, 0x81,
+               FIL_, 0xC7, 0xBB, FIL_, 0x02, 0xCC, 0x81, FIL_,
+               0xC7, 0xBD, FIL_, 0xCC, 0x84, FIL_, 0xC7, 0xA3,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0x89,
+               FIL_, 0x04, 0xCC, 0x89, FIL_, 0xE1, 0xBB, 0x83,
+               FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0x85, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBB, 0x81, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBA, 0xBF, FIL_, 0x01, 0xCC,
+               0x81, FIL_, 0xE1, 0xB8, 0xAF, FIL_, 0x04, 0xCC,
+               0x80, FIL_, 0xE1, 0xBB, 0x93, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBB, 0x91, FIL_, 0xCC, 0x83, FIL_,
+               0xE1, 0xBB, 0x97, FIL_, 0xCC, 0x89, FIL_, 0xE1,
+               0xBB, 0x95, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1,
+               0xB9, 0x8D, FIL_, 0xCC, 0x88, FIL_, 0xE1, 0xB9,
+               0x8F, FIL_, 0xCC, 0x84, FIL_, 0xC8, 0xAD, FIL_,
+               0x01, 0xCC, 0x84, FIL_, 0xC8, 0xAB, FIL_, 0x01,
+               0xCC, 0x81, FIL_, 0xC7, 0xBF, FIL_, 0x04, 0xCC,
+               0x8C, FIL_, 0xC7, 0x9A, FIL_, 0xCC, 0x84, FIL_,
+               0xC7, 0x96, FIL_, 0xCC, 0x80, FIL_, 0xC7, 0x9C,
+               FIL_, 0xCC, 0x81, FIL_, 0xC7, 0x98, FIL_, 0x04,
+               0xCC, 0x81, FIL_, 0xE1, 0xBA, 0xAE, FIL_, 0xCC,
+               0x83, FIL_, 0xE1, 0xBA, 0xB4, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBA, 0xB2, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBA, 0xB0, FIL_, 0x04, 0xCC, 0x83, FIL_,
+               0xE1, 0xBA, 0xB5, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBA, 0xB1, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBA,
+               0xAF, FIL_, 0xCC, 0x89, FIL_, 0xE1, 0xBA, 0xB3,
+               FIL_, 0x02, 0xCC, 0x81, FIL_, 0xE1, 0xB8, 0x96,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xB8, 0x94, FIL_,
+               0x02, 0xCC, 0x80, FIL_, 0xE1, 0xB8, 0x95, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xB8, 0x97, FIL_, 0x02,
+               0xCC, 0x80, FIL_, 0xE1, 0xB9, 0x90, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xB9, 0x92, FIL_, 0x02, 0xCC,
+               0x81, FIL_, 0xE1, 0xB9, 0x93, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xB9, 0x91, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA4, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA5, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA6, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xB9, 0xA7, FIL_, 0x01, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0xB8, FIL_, 0x01, 0xCC, 0x81,
+               FIL_, 0xE1, 0xB9, 0xB9, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xE1, 0xB9, 0xBA, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xE1, 0xB9, 0xBB, FIL_, 0x01, 0xCC, 0x87,
+               FIL_, 0xE1, 0xBA, 0x9B, FIL_, 0x05, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBB, 0x9C, FIL_, 0xCC, 0x89, FIL_,
+               0xE1, 0xBB, 0x9E, FIL_, 0xCC, 0x83, FIL_, 0xE1,
+               0xBB, 0xA0, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBB,
+               0x9A, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0xA2,
+               FIL_, 0x05, 0xCC, 0x83, FIL_, 0xE1, 0xBB, 0xA1,
+               FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0xA3, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBB, 0x9B, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBB, 0x9D, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0x9F, FIL_, 0x05, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBB, 0xA8, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBB, 0xAA, FIL_, 0xCC, 0x89, FIL_, 0xE1,
+               0xBB, 0xAC, FIL_, 0xCC, 0x83, FIL_, 0xE1, 0xBB,
+               0xAE, FIL_, 0xCC, 0xA3, FIL_, 0xE1, 0xBB, 0xB0,
+               FIL_, 0x05, 0xCC, 0x80, FIL_, 0xE1, 0xBB, 0xAB,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBB, 0xA9, FIL_,
+               0xCC, 0x83, FIL_, 0xE1, 0xBB, 0xAF, FIL_, 0xCC,
+               0xA3, FIL_, 0xE1, 0xBB, 0xB1, FIL_, 0xCC, 0x89,
+               FIL_, 0xE1, 0xBB, 0xAD, FIL_, 0x01, 0xCC, 0x8C,
+               FIL_, 0xC7, 0xAE, FIL_, 0x01, 0xCC, 0x84, FIL_,
+               0xC7, 0xAC, FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC7,
+               0xAD, FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC7, 0xA0,
+               FIL_, 0x01, 0xCC, 0x84, FIL_, 0xC7, 0xA1, FIL_,
+               0x01, 0xCC, 0x86, FIL_, 0xE1, 0xB8, 0x9C, FIL_,
+               0x01, 0xCC, 0x86, FIL_, 0xE1, 0xB8, 0x9D, FIL_,
+               0x01, 0xCC, 0x84, FIL_, 0xC8, 0xB0, FIL_, 0x01,
+               0xCC, 0x84, FIL_, 0xC8, 0xB1, FIL_, 0x01, 0xCC,
+               0x8C, FIL_, 0xC7, 0xAF, FIL_, 0x07, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBC, 0x88, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x86, FIL_, 0xCC, 0x86, FIL_, 0xE1, 0xBE,
+               0xB8, FIL_, 0xCC, 0x84, FIL_, 0xE1, 0xBE, 0xB9,
+               FIL_, 0xCC, 0x94, FIL_, 0xE1, 0xBC, 0x89, FIL_,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xBC, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBE, 0xBA, FIL_, 0x04, 0xCC,
+               0x94, FIL_, 0xE1, 0xBC, 0x99, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBF, 0x88, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x88, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBC,
+               0x98, FIL_, 0x05, 0xCD, 0x85, FIL_, 0xE1, 0xBF,
+               0x8C, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0x89, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBF, 0x8A, FIL_, 0xCC,
+               0x93, FIL_, 0xE1, 0xBC, 0xA8, FIL_, 0xCC, 0x94,
+               FIL_, 0xE1, 0xBC, 0xA9, FIL_, 0x07, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBF, 0x9A, FIL_, 0xCC, 0x84, FIL_,
+               0xE1, 0xBF, 0x99, FIL_, 0xCC, 0x93, FIL_, 0xE1,
+               0xBC, 0xB8, FIL_, 0xCC, 0x94, FIL_, 0xE1, 0xBC,
+               0xB9, FIL_, 0xCC, 0x86, FIL_, 0xE1, 0xBF, 0x98,
+               FIL_, 0xCC, 0x81, FIL_, 0xCE, 0x8A, FIL_, 0xCC,
+               0x88, FIL_, 0xCE, 0xAA, FIL_, 0x04, 0xCC, 0x81,
+               FIL_, 0xCE, 0x8C, FIL_, 0xCC, 0x94, FIL_, 0xE1,
+               0xBD, 0x89, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBD,
+               0x88, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF, 0xB8,
+               FIL_, 0x01, 0xCC, 0x94, FIL_, 0xE1, 0xBF, 0xAC,
+               FIL_, 0x06, 0xCC, 0x94, FIL_, 0xE1, 0xBD, 0x99,
+               FIL_, 0xCC, 0x86, FIL_, 0xE1, 0xBF, 0xA8, FIL_,
+               0xCC, 0x88, FIL_, 0xCE, 0xAB, FIL_, 0xCC, 0x84,
+               FIL_, 0xE1, 0xBF, 0xA9, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x8E, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF,
+               0xAA, FIL_, 0x05, 0xCC, 0x93, FIL_, 0xE1, 0xBD,
+               0xA8, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xBC,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF, 0xBA, FIL_,
+               0xCC, 0x94, FIL_, 0xE1, 0xBD, 0xA9, FIL_, 0xCC,
+               0x81, FIL_, 0xCE, 0x8F, FIL_, 0x01, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBE, 0xB4, FIL_, 0x01, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBF, 0x84, FIL_, 0x08, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBE, 0xB3, FIL_, 0xCC, 0x84, FIL_,
+               0xE1, 0xBE, 0xB1, FIL_, 0xCC, 0x86, FIL_, 0xE1,
+               0xBE, 0xB0, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD,
+               0xB0, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xAC, FIL_,
+               0xCC, 0x94, FIL_, 0xE1, 0xBC, 0x81, FIL_, 0xCC,
+               0x93, FIL_, 0xE1, 0xBC, 0x80, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBE, 0xB6, FIL_, 0x04, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBC, 0x90, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBD, 0xB2, FIL_, 0xCC, 0x94, FIL_, 0xE1,
+               0xBC, 0x91, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xAD,
+               FIL_, 0x06, 0xCC, 0x94, FIL_, 0xE1, 0xBC, 0xA1,
+               FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xAE, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBF, 0x83, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBF, 0x86, FIL_, 0xCC, 0x93, FIL_,
+               0xE1, 0xBC, 0xA0, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBD, 0xB4, FIL_, 0x08, 0xCC, 0x88, FIL_, 0xCF,
+               0x8A, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xAF, FIL_,
+               0xCC, 0x93, FIL_, 0xE1, 0xBC, 0xB0, FIL_, 0xCC,
+               0x94, FIL_, 0xE1, 0xBC, 0xB1, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBD, 0xB6, FIL_, 0xCC, 0x86, FIL_,
+               0xE1, 0xBF, 0x90, FIL_, 0xCC, 0x84, FIL_, 0xE1,
+               0xBF, 0x91, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBF,
+               0x96, FIL_, 0x04, 0xCC, 0x93, FIL_, 0xE1, 0xBD,
+               0x80, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xB8,
+               FIL_, 0xCC, 0x94, FIL_, 0xE1, 0xBD, 0x81, FIL_,
+               0xCC, 0x81, FIL_, 0xCF, 0x8C, FIL_, 0x02, 0xCC,
+               0x93, FIL_, 0xE1, 0xBF, 0xA4, FIL_, 0xCC, 0x94,
+               FIL_, 0xE1, 0xBF, 0xA5, FIL_, 0x08, 0xCC, 0x81,
+               FIL_, 0xCF, 0x8D, FIL_, 0xCC, 0x94, FIL_, 0xE1,
+               0xBD, 0x91, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBF,
+               0xA6, FIL_, 0xCC, 0x88, FIL_, 0xCF, 0x8B, FIL_,
+               0xCC, 0x84, FIL_, 0xE1, 0xBF, 0xA1, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBD, 0xBA, FIL_, 0xCC, 0x93,
+               FIL_, 0xE1, 0xBD, 0x90, FIL_, 0xCC, 0x86, FIL_,
+               0xE1, 0xBF, 0xA0, FIL_, 0x06, 0xCC, 0x80, FIL_,
+               0xE1, 0xBD, 0xBC, FIL_, 0xCC, 0x94, FIL_, 0xE1,
+               0xBD, 0xA1, FIL_, 0xCC, 0x93, FIL_, 0xE1, 0xBD,
+               0xA0, FIL_, 0xCC, 0x81, FIL_, 0xCF, 0x8E, FIL_,
+               0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xB3, FIL_, 0xCD,
+               0x82, FIL_, 0xE1, 0xBF, 0xB6, FIL_, 0x03, 0xCC,
+               0x80, FIL_, 0xE1, 0xBF, 0x92, FIL_, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBF, 0x97, FIL_, 0xCC, 0x81, FIL_,
+               0xCE, 0x90, FIL_, 0x03, 0xCD, 0x82, FIL_, 0xE1,
+               0xBF, 0xA7, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF,
+               0xA2, FIL_, 0xCC, 0x81, FIL_, 0xCE, 0xB0, FIL_,
+               0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xB4, FIL_,
+               0x02, 0xCC, 0x88, FIL_, 0xCF, 0x94, FIL_, 0xCC,
+               0x81, FIL_, 0xCF, 0x93, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xD0, 0x87, FIL_, 0x02, 0xCC, 0x88, FIL_,
+               0xD3, 0x92, FIL_, 0xCC, 0x86, FIL_, 0xD3, 0x90,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xD0, 0x83, FIL_,
+               0x03, 0xCC, 0x88, FIL_, 0xD0, 0x81, FIL_, 0xCC,
+               0x80, FIL_, 0xD0, 0x80, FIL_, 0xCC, 0x86, FIL_,
+               0xD3, 0x96, FIL_, 0x02, 0xCC, 0x86, FIL_, 0xD3,
+               0x81, FIL_, 0xCC, 0x88, FIL_, 0xD3, 0x9C, FIL_,
+               0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9E, FIL_, 0x04,
+               0xCC, 0x84, FIL_, 0xD3, 0xA2, FIL_, 0xCC, 0x88,
+               FIL_, 0xD3, 0xA4, FIL_, 0xCC, 0x86, FIL_, 0xD0,
+               0x99, FIL_, 0xCC, 0x80, FIL_, 0xD0, 0x8D, FIL_,
+               0x01, 0xCC, 0x81, FIL_, 0xD0, 0x8C, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xA6, FIL_, 0x04, 0xCC,
+               0x8B, FIL_, 0xD3, 0xB2, FIL_, 0xCC, 0x88, FIL_,
+               0xD3, 0xB0, FIL_, 0xCC, 0x86, FIL_, 0xD0, 0x8E,
+               FIL_, 0xCC, 0x84, FIL_, 0xD3, 0xAE, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xB4, FIL_, 0x01, 0xCC,
+               0x88, FIL_, 0xD3, 0xB8, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xD3, 0xAC, FIL_, 0x02, 0xCC, 0x86, FIL_,
+               0xD3, 0x91, FIL_, 0xCC, 0x88, FIL_, 0xD3, 0x93,
+               FIL_, 0x01, 0xCC, 0x81, FIL_, 0xD1, 0x93, FIL_,
+               0x03, 0xCC, 0x80, FIL_, 0xD1, 0x90, FIL_, 0xCC,
+               0x86, FIL_, 0xD3, 0x97, FIL_, 0xCC, 0x88, FIL_,
+               0xD1, 0x91, FIL_, 0x02, 0xCC, 0x86, FIL_, 0xD3,
+               0x82, FIL_, 0xCC, 0x88, FIL_, 0xD3, 0x9D, FIL_,
+               0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9F, FIL_, 0x04,
+               0xCC, 0x86, FIL_, 0xD0, 0xB9, FIL_, 0xCC, 0x88,
+               FIL_, 0xD3, 0xA5, FIL_, 0xCC, 0x84, FIL_, 0xD3,
+               0xA3, FIL_, 0xCC, 0x80, FIL_, 0xD1, 0x9D, FIL_,
+               0x01, 0xCC, 0x81, FIL_, 0xD1, 0x9C, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xA7, FIL_, 0x04, 0xCC,
+               0x8B, FIL_, 0xD3, 0xB3, FIL_, 0xCC, 0x84, FIL_,
+               0xD3, 0xAF, FIL_, 0xCC, 0x86, FIL_, 0xD1, 0x9E,
+               FIL_, 0xCC, 0x88, FIL_, 0xD3, 0xB1, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xB5, FIL_, 0x01, 0xCC,
+               0x88, FIL_, 0xD3, 0xB9, FIL_, 0x01, 0xCC, 0x88,
+               FIL_, 0xD3, 0xAD, FIL_, 0x01, 0xCC, 0x88, FIL_,
+               0xD1, 0x97, FIL_, 0x01, 0xCC, 0x8F, FIL_, 0xD1,
+               0xB6, FIL_, 0x01, 0xCC, 0x8F, FIL_, 0xD1, 0xB7,
+               FIL_, 0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9A, FIL_,
+               0x01, 0xCC, 0x88, FIL_, 0xD3, 0x9B, FIL_, 0x01,
+               0xCC, 0x88, FIL_, 0xD3, 0xAA, FIL_, 0x01, 0xCC,
+               0x88, FIL_, 0xD3, 0xAB, FIL_, 0x03, 0xD9, 0x94,
+               FIL_, 0xD8, 0xA3, FIL_, 0xD9, 0x95, FIL_, 0xD8,
+               0xA5, FIL_, 0xD9, 0x93, FIL_, 0xD8, 0xA2, FIL_,
+               0x01, 0xD9, 0x94, FIL_, 0xD8, 0xA4, FIL_, 0x01,
+               0xD9, 0x94, FIL_, 0xD8, 0xA6, FIL_, 0x01, 0xD9,
+               0x94, FIL_, 0xDB, 0x82, FIL_, 0x01, 0xD9, 0x94,
+               FIL_, 0xDB, 0x93, FIL_, 0x01, 0xD9, 0x94, FIL_,
+               0xDB, 0x80, FIL_, 0x01, 0xE0, 0xA4, 0xBC, FIL_,
+               0xE0, 0xA4, 0xA9, FIL_, 0x01, 0xE0, 0xA4, 0xBC,
+               FIL_, 0xE0, 0xA4, 0xB1, FIL_, 0x01, 0xE0, 0xA4,
+               0xBC, FIL_, 0xE0, 0xA4, 0xB4, FIL_, 0x02, 0xE0,
+               0xA6, 0xBE, FIL_, 0xE0, 0xA7, 0x8B, FIL_, 0xE0,
+               0xA7, 0x97, FIL_, 0xE0, 0xA7, 0x8C, FIL_, 0x03,
+               0xE0, 0xAD, 0x96, FIL_, 0xE0, 0xAD, 0x88, FIL_,
+               0xE0, 0xAC, 0xBE, FIL_, 0xE0, 0xAD, 0x8B, FIL_,
+               0xE0, 0xAD, 0x97, FIL_, 0xE0, 0xAD, 0x8C, FIL_,
+               0x01, 0xE0, 0xAF, 0x97, FIL_, 0xE0, 0xAE, 0x94,
+               FIL_, 0x02, 0xE0, 0xAF, 0x97, FIL_, 0xE0, 0xAF,
+               0x8C, FIL_, 0xE0, 0xAE, 0xBE, FIL_, 0xE0, 0xAF,
+               0x8A, FIL_, 0x01, 0xE0, 0xAE, 0xBE, FIL_, 0xE0,
+               0xAF, 0x8B, FIL_, 0x01, 0xE0, 0xB1, 0x96, FIL_,
+               0xE0, 0xB1, 0x88, FIL_, 0x01, 0xE0, 0xB3, 0x95,
+               FIL_, 0xE0, 0xB3, 0x80, FIL_, 0x03, 0xE0, 0xB3,
+               0x82, FIL_, 0xE0, 0xB3, 0x8A, FIL_, 0xE0, 0xB3,
+               0x96, FIL_, 0xE0, 0xB3, 0x88, FIL_, 0xE0, 0xB3,
+               0x95, FIL_, 0xE0, 0xB3, 0x87, FIL_, 0x01, 0xE0,
+               0xB3, 0x95, FIL_, 0xE0, 0xB3, 0x8B, FIL_, 0x02,
+               0xE0, 0xB4, 0xBE, FIL_, 0xE0, 0xB5, 0x8A, FIL_,
+               0xE0, 0xB5, 0x97, FIL_, 0xE0, 0xB5, 0x8C, FIL_,
+               0x01, 0xE0, 0xB4, 0xBE, FIL_, 0xE0, 0xB5, 0x8B,
+               FIL_, 0x03, 0xE0, 0xB7, 0x9F, FIL_, 0xE0, 0xB7,
+               0x9E, FIL_, 0xE0, 0xB7, 0x8A, FIL_, 0xE0, 0xB7,
+               0x9A, FIL_, 0xE0, 0xB7, 0x8F, FIL_, 0xE0, 0xB7,
+               0x9C, FIL_, 0x01, 0xE0, 0xB7, 0x8A, FIL_, 0xE0,
+               0xB7, 0x9D, FIL_, 0x01, 0xE1, 0x80, 0xAE, FIL_,
+               0xE1, 0x80, 0xA6, FIL_, 0x01, 0xE1, 0xAC, 0xB5,
+               FIL_, 0xE1, 0xAC, 0x86, FIL_, 0x01, 0xE1, 0xAC,
+               0xB5, FIL_, 0xE1, 0xAC, 0x88, FIL_, 0x01, 0xE1,
+               0xAC, 0xB5, FIL_, 0xE1, 0xAC, 0x8A, FIL_, 0x01,
+               0xE1, 0xAC, 0xB5, FIL_, 0xE1, 0xAC, 0x8C, FIL_,
+               0x01, 0xE1, 0xAC, 0xB5, FIL_, 0xE1, 0xAC, 0x8E,
+               FIL_, 0x01, 0xE1, 0xAC, 0xB5, FIL_, 0xE1, 0xAC,
+               0x92, FIL_, 0x01, 0xE1, 0xAC, 0xB5, FIL_, 0xE1,
+               0xAC, 0xBB, FIL_, 0x01, 0xE1, 0xAC, 0xB5, FIL_,
+               0xE1, 0xAC, 0xBD, FIL_, 0x01, 0xE1, 0xAC, 0xB5,
+               FIL_, 0xE1, 0xAD, 0x80, FIL_, 0x01, 0xE1, 0xAC,
+               0xB5, FIL_, 0xE1, 0xAD, 0x81, FIL_, 0x01, 0xE1,
+               0xAC, 0xB5, FIL_, 0xE1, 0xAD, 0x83, FIL_, 0x01,
+               0xCC, 0x84, FIL_, 0xE1, 0xB8, 0xB8, FIL_, 0x01,
+               0xCC, 0x84, FIL_, 0xE1, 0xB8, 0xB9, FIL_, 0x01,
+               0xCC, 0x84, FIL_, 0xE1, 0xB9, 0x9C, FIL_, 0x01,
+               0xCC, 0x84, FIL_, 0xE1, 0xB9, 0x9D, FIL_, 0x01,
+               0xCC, 0x87, FIL_, 0xE1, 0xB9, 0xA8, FIL_, 0x01,
+               0xCC, 0x87, FIL_, 0xE1, 0xB9, 0xA9, FIL_, 0x02,
+               0xCC, 0x86, FIL_, 0xE1, 0xBA, 0xB6, FIL_, 0xCC,
+               0x82, FIL_, 0xE1, 0xBA, 0xAC, FIL_, 0x02, 0xCC,
+               0x82, FIL_, 0xE1, 0xBA, 0xAD, FIL_, 0xCC, 0x86,
+               FIL_, 0xE1, 0xBA, 0xB7, FIL_, 0x01, 0xCC, 0x82,
+               FIL_, 0xE1, 0xBB, 0x86, FIL_, 0x01, 0xCC, 0x82,
+               FIL_, 0xE1, 0xBB, 0x87, FIL_, 0x01, 0xCC, 0x82,
+               FIL_, 0xE1, 0xBB, 0x98, FIL_, 0x01, 0xCC, 0x82,
+               FIL_, 0xE1, 0xBB, 0x99, FIL_, 0x04, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBE, 0x80, FIL_, 0xCD, 0x82, FIL_,
+               0xE1, 0xBC, 0x86, FIL_, 0xCC, 0x80, FIL_, 0xE1,
+               0xBC, 0x82, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC,
+               0x84, FIL_, 0x04, 0xCD, 0x82, FIL_, 0xE1, 0xBC,
+               0x87, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x85,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0x83, FIL_,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x81, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x82, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x83, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x84, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x85, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x86, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x87, FIL_, 0x04,
+               0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x8C, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBC, 0x8A, FIL_, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBE, 0x88, FIL_, 0xCD, 0x82, FIL_,
+               0xE1, 0xBC, 0x8E, FIL_, 0x04, 0xCC, 0x80, FIL_,
+               0xE1, 0xBC, 0x8B, FIL_, 0xCD, 0x82, FIL_, 0xE1,
+               0xBC, 0x8F, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC,
+               0x8D, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x89,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x8A,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x8B,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x8C,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x8D,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x8E,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x8F,
+               FIL_, 0x02, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0x92,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x94, FIL_,
+               0x02, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0x93, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBC, 0x95, FIL_, 0x02,
+               0xCC, 0x80, FIL_, 0xE1, 0xBC, 0x9A, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBC, 0x9C, FIL_, 0x02, 0xCC,
+               0x80, FIL_, 0xE1, 0xBC, 0x9B, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBC, 0x9D, FIL_, 0x04, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBC, 0xA2, FIL_, 0xCC, 0x81, FIL_,
+               0xE1, 0xBC, 0xA4, FIL_, 0xCD, 0x82, FIL_, 0xE1,
+               0xBC, 0xA6, FIL_, 0xCD, 0x85, FIL_, 0xE1, 0xBE,
+               0x90, FIL_, 0x04, 0xCD, 0x85, FIL_, 0xE1, 0xBE,
+               0x91, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0xA5,
+               FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBC, 0xA7, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xA3, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x92, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x93, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x94, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x95, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x96, FIL_, 0x01,
+               0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x97, FIL_, 0x04,
+               0xCC, 0x81, FIL_, 0xE1, 0xBC, 0xAC, FIL_, 0xCC,
+               0x80, FIL_, 0xE1, 0xBC, 0xAA, FIL_, 0xCD, 0x85,
+               FIL_, 0xE1, 0xBE, 0x98, FIL_, 0xCD, 0x82, FIL_,
+               0xE1, 0xBC, 0xAE, FIL_, 0x04, 0xCD, 0x82, FIL_,
+               0xE1, 0xBC, 0xAF, FIL_, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0x99, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC,
+               0xAD, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xAB,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x9A,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x9B,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x9C,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x9D,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x9E,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0x9F,
+               FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0xB4,
+               FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xB2, FIL_,
+               0xCD, 0x82, FIL_, 0xE1, 0xBC, 0xB6, FIL_, 0x03,
+               0xCC, 0x80, FIL_, 0xE1, 0xBC, 0xB3, FIL_, 0xCD,
+               0x82, FIL_, 0xE1, 0xBC, 0xB7, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBC, 0xB5, FIL_, 0x03, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBC, 0xBC, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBC, 0xBA, FIL_, 0xCD, 0x82, FIL_, 0xE1,
+               0xBC, 0xBE, FIL_, 0x03, 0xCC, 0x80, FIL_, 0xE1,
+               0xBC, 0xBB, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBC,
+               0xBF, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBC, 0xBD,
+               FIL_, 0x02, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0x82,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBD, 0x84, FIL_,
+               0x02, 0xCC, 0x81, FIL_, 0xE1, 0xBD, 0x85, FIL_,
+               0xCC, 0x80, FIL_, 0xE1, 0xBD, 0x83, FIL_, 0x02,
+               0xCC, 0x80, FIL_, 0xE1, 0xBD, 0x8A, FIL_, 0xCC,
+               0x81, FIL_, 0xE1, 0xBD, 0x8C, FIL_, 0x02, 0xCC,
+               0x80, FIL_, 0xE1, 0xBD, 0x8B, FIL_, 0xCC, 0x81,
+               FIL_, 0xE1, 0xBD, 0x8D, FIL_, 0x03, 0xCD, 0x82,
+               FIL_, 0xE1, 0xBD, 0x96, FIL_, 0xCC, 0x80, FIL_,
+               0xE1, 0xBD, 0x92, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xBD, 0x94, FIL_, 0x03, 0xCC, 0x80, FIL_, 0xE1,
+               0xBD, 0x93, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBD,
+               0x97, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBD, 0x95,
+               FIL_, 0x03, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0x9B,
+               FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBD, 0x9F, FIL_,
+               0xCC, 0x81, FIL_, 0xE1, 0xBD, 0x9D, FIL_, 0x04,
+               0xCD, 0x82, FIL_, 0xE1, 0xBD, 0xA6, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA0, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBD, 0xA2, FIL_, 0xCC, 0x81, FIL_,
+               0xE1, 0xBD, 0xA4, FIL_, 0x04, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0xA1, FIL_, 0xCD, 0x82, FIL_, 0xE1,
+               0xBD, 0xA7, FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBD,
+               0xA5, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xA3,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA2,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA3,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA4,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA5,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA6,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBE, 0xA7,
+               FIL_, 0x04, 0xCC, 0x80, FIL_, 0xE1, 0xBD, 0xAA,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBD, 0xAC, FIL_,
+               0xCD, 0x82, FIL_, 0xE1, 0xBD, 0xAE, FIL_, 0xCD,
+               0x85, FIL_, 0xE1, 0xBE, 0xA8, FIL_, 0x04, 0xCD,
+               0x82, FIL_, 0xE1, 0xBD, 0xAF, FIL_, 0xCC, 0x80,
+               FIL_, 0xE1, 0xBD, 0xAB, FIL_, 0xCD, 0x85, FIL_,
+               0xE1, 0xBE, 0xA9, FIL_, 0xCC, 0x81, FIL_, 0xE1,
+               0xBD, 0xAD, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xAA, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xAB, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xAC, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xAD, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xAE, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xAF, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xB2, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBF, 0x82, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBF, 0xB2, FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1,
+               0xBE, 0xB7, FIL_, 0x03, 0xCC, 0x81, FIL_, 0xE1,
+               0xBF, 0x8E, FIL_, 0xCC, 0x80, FIL_, 0xE1, 0xBF,
+               0x8D, FIL_, 0xCD, 0x82, FIL_, 0xE1, 0xBF, 0x8F,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0x87,
+               FIL_, 0x01, 0xCD, 0x85, FIL_, 0xE1, 0xBF, 0xB7,
+               FIL_, 0x03, 0xCC, 0x80, FIL_, 0xE1, 0xBF, 0x9D,
+               FIL_, 0xCC, 0x81, FIL_, 0xE1, 0xBF, 0x9E, FIL_,
+               0xCD, 0x82, FIL_, 0xE1, 0xBF, 0x9F, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x86, 0x9A, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x86, 0x9B, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x86, 0xAE, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x87, 0x8D, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x87, 0x8F, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x87, 0x8E, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x88, 0x84, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x88, 0x89, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x88, 0x8C, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x88, 0xA4, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x88, 0xA6, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0x81, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0x84, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0x87, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0x89, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xAD, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xA2, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xB0, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xB1, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xB4, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xB5, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xB8, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x89, 0xB9, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0x80, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0x81, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xA0, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xA1, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0x84, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0x85, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0x88, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0x89, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xA2, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xA3, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0xAC, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0xAD, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0xAE, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8A, 0xAF, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xAA, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xAB, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xAC, FIL_, 0x01,
+               0xCC, 0xB8, FIL_, 0xE2, 0x8B, 0xAD, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82, 0x94, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0x8C,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81,
+               0x8E, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x81, 0x90, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x81, 0x92, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x81, 0x94, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x81, 0x96, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x81, 0x98, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0x9A, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0x9C,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81,
+               0x9E, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x81, 0xA0, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x81, 0xA2, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x81, 0xA5, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x81, 0xA7, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x81, 0xA9, FIL_, 0x02,
+               0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x81, 0xB1, FIL_,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0xB0, FIL_,
+               0x02, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81, 0xB3,
+               FIL_, 0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x81, 0xB4,
+               FIL_, 0x02, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x81,
+               0xB6, FIL_, 0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x81,
+               0xB7, FIL_, 0x02, 0xE3, 0x82, 0x9A, FIL_, 0xE3,
+               0x81, 0xBA, FIL_, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x81, 0xB9, FIL_, 0x02, 0xE3, 0x82, 0x9A, FIL_,
+               0xE3, 0x81, 0xBD, FIL_, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x81, 0xBC, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x82, 0x9E, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x83, 0xB4, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x82, 0xAC, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82, 0xAE, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82, 0xB0,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82,
+               0xB2, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x82, 0xB4, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x82, 0xB6, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x82, 0xB8, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x82, 0xBA, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x82, 0xBC, FIL_, 0x01,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x82, 0xBE, FIL_,
+               0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0x80,
+               FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83,
+               0x82, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x83, 0x85, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x83, 0x87, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x83, 0x89, FIL_, 0x02, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x83, 0x90, FIL_, 0xE3, 0x82,
+               0x9A, FIL_, 0xE3, 0x83, 0x91, FIL_, 0x02, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x83, 0x93, FIL_, 0xE3,
+               0x82, 0x9A, FIL_, 0xE3, 0x83, 0x94, FIL_, 0x02,
+               0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x83, 0x97, FIL_,
+               0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0x96, FIL_,
+               0x02, 0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x83, 0x9A,
+               FIL_, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83, 0x99,
+               FIL_, 0x02, 0xE3, 0x82, 0x99, FIL_, 0xE3, 0x83,
+               0x9C, FIL_, 0xE3, 0x82, 0x9A, FIL_, 0xE3, 0x83,
+               0x9D, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_, 0xE3,
+               0x83, 0xB7, FIL_, 0x01, 0xE3, 0x82, 0x99, FIL_,
+               0xE3, 0x83, 0xB8, FIL_, 0x01, 0xE3, 0x82, 0x99,
+               FIL_, 0xE3, 0x83, 0xB9, FIL_, 0x01, 0xE3, 0x82,
+               0x99, FIL_, 0xE3, 0x83, 0xBA, FIL_, 0x01, 0xE3,
+               0x82, 0x99, FIL_, 0xE3, 0x83, 0xBE, FIL_,
+       },
+};
+
+static const uchar_t u8_decomp_b2_tbl[2][2][256] = {
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       1,  2,  3,  4,  N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 5,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 6,  N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 7,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       1,  2,  3,  4,  N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 5,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, 6,  N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 7,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+
+};
+
+static const u8_displacement_t u8_decomp_b3_tbl[2][8][256] = {
+       {
+               {       /* Third byte table 0. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0, 0 },
+                       { 1, 35 }, { 2, 247 }, { 3, 474 },
+                       { 4, 693 }, { 5, 709 }, { 6, 951 },
+                       { N_, 0 }, { 7, 1139 }, { 8, 1152 },
+                       { N_, 0 }, { 9, 1177 }, { 10, 1199 },
+                       { 11, 1295 }, { 12, 1360 }, { 13, 1405 },
+                       { N_, 0 }, { 14, 1450 }, { N_, 0 },
+                       { N_, 0 }, { 15, 1620 }, { N_, 0 },
+                       { 16, 1624 }, { 17, 1649 }, { N_, 0 },
+                       { 18, 1665 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 19, 1680 },
+                       { 20, 1701 }, { N_, 0 }, { 21, 1757 },
+                       { 22, 1792 }, { 23, 1806 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 24, 1834 },
+                       { 25, 1869 }, { 26, 1876 }, { N_, 0 },
+                       { 27, 1897 }, { N_, 0 }, { 28, 1904 },
+                       { N_, 0 }, { 29, 1942 }, { N_, 0 },
+                       { 30, 1963 }, { 31, 1994 }, { N_, 0 },
+                       { 32, 2000 }, { 33, 2006 }, { 34, 2018 },
+                       { 35, 2021 }, { 36, 2109 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 37, 2158 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 0x8000, 2165 }, { 0x8001, 2445 },
+                       { 0x8002, 2741 }, { 0x8003, 3029 }, { 0x8004, 3337 },
+                       { 0x8005, 3725 }, { 0x8006, 4053 }, { 0x8007, 4536 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 38, 4895 },
+                       { 39, 4964 }, { 40, 4999 }, { N_, 0 },
+                       { 41, 5018 }, { 42, 5098 }, { 43, 5230 },
+                       { 44, 5248 }, { 45, 5266 }, { 46, 5326 },
+                       { 47, 5410 }, { 48, 5470 }, { 49, 5518 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 50, 5526 }, { 51, 5596 },
+                       { 52, 5767 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 53, 5810 }, { 54, 5822 }, { N_, 0 },
+                       { 55, 5830 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 56, 5836 }, { 57, 5839 }, { 58, 5842 },
+                       { 59, 6034 }, { 60, 6226 }, { 61, 6418 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 62, 6484 },
+                       { 63, 6497 }, { 64, 6672 }, { 65, 6770 },
+                       { 66, 6923 }, { 67, 6968 }, { 68, 7160 },
+                       { N_, 0 }, { 0x8008, 7247 }, { 69, 7597 },
+                       { 70, 7773 }, { 71, 7950 }, { 0x8009, 8142 },
+                       { 0x800A, 8919 }, { 72, 9351 }, { 73, 9522 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 5. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0x800B, 9743 },
+                       { 0x800C, 9999 }, { 0x800D, 10255 }, { 0x800E, 10511 },
+                       { 74, 10767 }, { 75, 10967 }, { N_, 0 },
+                       { N_, 0 }, { 76, 11139 }, { 77, 11303 },
+                       { 78, 11468 }, { 79, 11576 }, { 0x800F, 11740 },
+                       { 0x8010, 12006 }, { 0x8011, 12280 }, { 0x8012, 12546 },
+                       { 80, 12812 }, { 0x8013, 13060 }, { 0x8014, 13348 },
+                       { 81, 13720 }, { 82, 13898 }, { 83, 13933 },
+                       { 84, 14045 }, { 85, 14197 }, { 86, 14347 },
+                       { 87, 14410 }, { 88, 14540 }, { 89, 14729 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 6. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 90, 14829 }, { 91, 14912 },
+                       { 92, 14969 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 93, 14982 }, { 94, 15046 }, { 95, 15109 },
+                       { 96, 15163 }, { 97, 15225 }, { 98, 15282 },
+                       { 99, 15341 }, { 100, 15405 }, { 101, 15469 },
+                       { 102, 15533 }, { 103, 15597 }, { 104, 15681 },
+                       { 105, 15812 }, { 106, 15942 }, { 107, 16072 },
+                       { 108, 16202 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 7. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 0x8015, 16273 }, { 0x8016, 16536 },
+                       { 0x8017, 16799 }, { 0x8018, 17064 }, { 0x8019, 17329 },
+                       { 0x801A, 17601 }, { 0x801B, 17878 }, { 0x801C, 18147 },
+                       { 109, 18419 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+       },
+       {
+               {       /* Third byte table 0. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0, 0 },
+                       { 1, 35 }, { 2, 247 }, { 3, 474 },
+                       { 4, 693 }, { 5, 709 }, { 6, 951 },
+                       { N_, 0 }, { 7, 1139 }, { 8, 1152 },
+                       { N_, 0 }, { 9, 1177 }, { 10, 1199 },
+                       { 11, 1295 }, { 12, 1362 }, { 13, 1407 },
+                       { N_, 0 }, { 14, 1452 }, { N_, 0 },
+                       { N_, 0 }, { 15, 1622 }, { N_, 0 },
+                       { 16, 1626 }, { 17, 1651 }, { N_, 0 },
+                       { 18, 1667 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 19, 1682 },
+                       { 20, 1703 }, { N_, 0 }, { 21, 1759 },
+                       { 22, 1794 }, { 23, 1808 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 24, 1836 },
+                       { 25, 1871 }, { 26, 1878 }, { N_, 0 },
+                       { 27, 1899 }, { N_, 0 }, { 28, 1906 },
+                       { N_, 0 }, { 29, 1944 }, { N_, 0 },
+                       { 30, 1965 }, { 31, 1996 }, { N_, 0 },
+                       { 32, 2002 }, { 33, 2008 }, { 34, 2020 },
+                       { 35, 2023 }, { 36, 2111 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 37, 2160 },
+                       { N_, 0 }, { N_, 0 }, { 38, 2167 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 39, 2170 }, { 40, 2226 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 41, 2247 }, { 42, 2268 }, { 43, 2340 },
+                       { N_, 0 }, { 0x8000, 2414 }, { 0x8001, 2694 },
+                       { 0x8002, 2990 }, { 0x8003, 3278 }, { 0x8004, 3586 },
+                       { 0x8005, 3974 }, { 0x8006, 4302 }, { 0x8007, 4785 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 44, 5144 },
+                       { 45, 5213 }, { 46, 5248 }, { N_, 0 },
+                       { 47, 5273 }, { 48, 5358 }, { 49, 5490 },
+                       { 50, 5508 }, { 51, 5526 }, { 52, 5586 },
+                       { 53, 5670 }, { 54, 5730 }, { 55, 5778 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 56, 5786 }, { 57, 5856 },
+                       { 58, 6027 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 59, 6070 }, { 60, 6082 }, { N_, 0 },
+                       { 61, 6090 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 62, 6096 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 63, 6099 }, { 64, 6102 }, { 65, 6105 },
+                       { 66, 6297 }, { 67, 6489 }, { 68, 6681 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 69, 6747 },
+                       { 70, 6760 }, { 71, 6935 }, { 72, 7033 },
+                       { 73, 7186 }, { 74, 7231 }, { 75, 7423 },
+                       { N_, 0 }, { 0x8008, 7510 }, { 76, 7891 },
+                       { 77, 8103 }, { 78, 8280 }, { 0x8009, 8482 },
+                       { 0x800A, 9259 }, { 79, 9701 }, { 80, 9872 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 5. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0x800B, 10106 },
+                       { 0x800C, 10362 }, { 0x800D, 10618 }, { 0x800E, 10874 },
+                       { 81, 11130 }, { 82, 11330 }, { 0x800F, 11566 },
+                       { 83, 11822 }, { 84, 11932 }, { 85, 12096 },
+                       { 86, 12261 }, { 87, 12369 }, { 0x8010, 12533 },
+                       { 0x8011, 12799 }, { 0x8012, 13073 }, { 0x8013, 13339 },
+                       { 88, 13605 }, { 0x8014, 13853 }, { 0x8015, 14141 },
+                       { 89, 14513 }, { 90, 14691 }, { 91, 14746 },
+                       { 92, 14860 }, { 93, 15012 }, { 94, 15162 },
+                       { 95, 15225 }, { 96, 15355 }, { 97, 15544 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 6. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 98, 15644 }, { 99, 15727 },
+                       { 100, 15784 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 101, 15797 }, { 102, 15861 }, { 103, 15924 },
+                       { 104, 15978 }, { 105, 16041 }, { 106, 16098 },
+                       { 107, 16157 }, { 108, 16221 }, { 109, 16285 },
+                       { 110, 16349 }, { 111, 16413 }, { 112, 16501 },
+                       { 113, 16632 }, { 114, 16762 }, { 115, 16892 },
+                       { 116, 17022 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+               {       /* Third byte table 7. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 0x8016, 17097 }, { 0x8017, 17360 },
+                       { 0x8018, 17623 }, { 0x8019, 17888 }, { 0x801A, 18153 },
+                       { 0x801B, 18425 }, { 0x801C, 18702 }, { 0x801D, 18971 },
+                       { 117, 19243 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 },
+               },
+       },
+};
+
+static const uchar_t u8_decomp_b4_tbl[2][118][257] = {
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   1,   1,   1,   1,   1,   1,
+                       1,   4,   4,   5,   5,   5,   5,   5,
+                       8,   8,   8,   9,   10,  13,  15,  15,
+                       15,  18,  19,  20,  20,  25,  30,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  24,
+                       28,  32,  36,  40,  44,  48,  52,  56,
+                       60,  60,  64,  68,  72,  76,  80,  84,
+                       84,  84,  88,  92,  96,  100, 104, 104,
+                       104, 108, 112, 116, 120, 124, 128, 128,
+                       132, 136, 140, 144, 148, 152, 156, 160,
+                       164, 164, 168, 172, 176, 180, 184, 188,
+                       188, 188, 192, 196, 200, 204, 208, 208,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  64,  64,  68,  72,  76,  80,  84,
+                       88,  92,  96,  100, 104, 108, 112, 116,
+                       120, 124, 128, 132, 136, 140, 144, 144,
+                       144, 148, 152, 156, 160, 164, 168, 172,
+                       176, 180, 180, 182, 184, 188, 192, 196,
+                       200, 200, 204, 208, 212, 216, 220, 224,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   3,   7,   11,  15,  19,
+                       23,  27,  30,  30,  30,  34,  38,  42,
+                       46,  50,  54,  54,  54,  58,  62,  66,
+                       70,  74,  78,  82,  86,  90,  94,  98,
+                       102, 106, 110, 114, 118, 122, 126, 126,
+                       126, 130, 134, 138, 142, 146, 150, 154,
+                       158, 162, 166, 170, 174, 178, 182, 186,
+                       190, 194, 198, 202, 206, 210, 214, 218,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       12,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   4,   8,   12,
+                       14,  16,  18,  20,  22,  24,  28,  32,
+                       36,  40,  44,  48,  52,  56,  62,  68,
+                       74,  80,  86,  92,  98,  104, 104, 110,
+                       116, 122, 128, 133, 138, 138, 138, 142,
+                       146, 150, 154, 158, 162, 168, 174, 179,
+                       184, 188, 190, 192, 194, 198, 202, 202,
+                       202, 206, 210, 216, 222, 227, 232, 237,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 112, 112, 116,
+                       120, 120, 120, 120, 120, 120, 120, 124,
+                       128, 132, 136, 142, 148, 154, 160, 164,
+                       168, 174, 180, 184, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   3,   4,   5,   7,   9,   11,
+                       12,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  20,  21,  22,  23,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   6,   9,   14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  17,  17,  17,
+                       17,  17,  17,  20,  20,  20,  20,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   14,  19,
+                       22,  27,  32,  37,  37,  42,  42,  47,
+                       52,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  64,  69,  74,  79,  84,
+                       89,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   5,   10,  15,  20,  25,
+                       25,  27,  29,  31,  41,  51,  53,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  57,  59,  61,  61,  63,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,  65,  65,  65,  65,  65,  65,  65,
+                       65,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  10,  15,  15,  15,  15,
+                       20,  20,  20,  20,  20,  25,  30,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  10,  15,  15,  15,  15,
+                       20,  20,  20,  20,  20,  25,  30,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  40,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   5,   10,  10,  10,  10,  10,
+                       10,  10,  10,  10,  10,  10,  10,  10,
+                       10,  15,  20,  25,  30,  30,  30,  35,
+                       40,  40,  40,  45,  50,  55,  60,  65,
+                       70,  70,  70,  75,  80,  85,  90,  95,
+                       100, 100, 100, 105, 110, 115, 120, 125,
+                       130, 135, 140, 145, 150, 155, 160, 160,
+                       160, 165, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   5,   10,  15,  20,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   4,   8,
+                       12,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   5,   10,  10,  10,  10,  10,
+                       10,  10,  10,  10,  10,  10,  10,  10,
+                       10,  10,  10,  10,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   7,   7,   7,   7,   7,
+                       7,   7,   14,  14,  14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   14,  21,  28,  35,  42,  49,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  21,  28,  28,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   7,   7,   14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   14,  21,  21,  21,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   7,   14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  28,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   7,   7,   7,   7,   7,
+                       14,  21,  21,  28,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   7,   14,  24,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   6,   12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   14,  14,
+                       14,  14,  14,  21,  21,  21,  21,  21,
+                       28,  28,  28,  28,  28,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  49,  49,  56,  63,
+                       72,  79,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  21,  21,
+                       21,  21,  21,  28,  28,  28,  28,  28,
+                       35,  35,  35,  35,  35,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  13,  14,  15,  16,  17,
+                       18,  19,  20,  21,  21,  21,  21,  21,
+                       21,  21,  24,  24,  24,  24,  24,  24,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  28,  30,  33,
+                       33,  33,  33,  33,  33,  33,  33,  33,
+                       34,  34,  34,  34,  40,  49,  49,  55,
+                       64,  64,  64,  64,  64,  66,  66,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,
+               },
+               {       /* Fourth byte table 39. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       2,   4,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  20,  21,  21,  21,  22,  23,  24,
+                       25,  26,  27,  28,  31,  32,  33,  34,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 40. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  14,  15,  16,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  17,  17,  17,  17,  17,  17,  17,
+                       17,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,
+               },
+               {       /* Fourth byte table 41. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   7,   10,  10,  13,  16,
+                       18,  18,  21,  22,  23,  24,  25,  26,
+                       28,  29,  30,  31,  32,  32,  33,  35,
+                       35,  35,  36,  37,  38,  39,  40,  40,
+                       40,  42,  45,  47,  47,  48,  48,  51,
+                       51,  52,  52,  54,  58,  59,  60,  60,
+                       61,  62,  63,  63,  64,  65,  67,  69,
+                       71,  73,  74,  74,  74,  74,  76,  78,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,  80,  80,  80,  80,  80,  80,  80,
+                       80,
+               },
+               {       /* Fourth byte table 42. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   3,   3,   3,   4,   5,
+                       6,   7,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   13,  18,  23,  28,
+                       33,  38,  43,  48,  53,  58,  63,  68,
+                       72,  73,  75,  78,  80,  81,  83,  86,
+                       90,  92,  93,  95,  98,  99,  100, 101,
+                       102, 103, 105, 108, 110, 111, 113, 116,
+                       120, 122, 123, 125, 128, 129, 130, 131,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132,
+               },
+               {       /* Fourth byte table 43. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   6,   12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,
+               },
+               {       /* Fourth byte table 44. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   6,   12,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,
+               },
+               {       /* Fourth byte table 45. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   6,   6,   6,
+                       6,   6,   12,  12,  12,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  24,  24,  30,
+                       30,  30,  30,  30,  30,  36,  45,  45,
+                       51,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,
+               },
+               {       /* Fourth byte table 46. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   6,   6,   6,   12,  12,  12,
+                       18,  18,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  28,  28,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  40,  44,
+                       48,  54,  60,  60,  60,  66,  72,  72,
+                       72,  78,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,
+               },
+               {       /* Fourth byte table 47. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  12,  12,  18,  24,  24,
+                       24,  30,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  42,  48,  54,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,
+               },
+               {       /* Fourth byte table 48. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  18,  24,  24,  24,  24,
+                       24,  24,  24,  30,  36,  42,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 49. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   4,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,
+               },
+               {       /* Fourth byte table 50. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   11,  13,  15,  17,  19,  21,
+                       23,  25,  27,  29,  31,  34,  37,  40,
+                       43,  46,  49,  52,  55,  58,  62,  66,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,
+               },
+               {       /* Fourth byte table 51. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  53,  56,  59,  62,  65,  68,
+                       71,  74,  77,  80,  83,  86,  89,  92,
+                       95,  98,  101, 104, 107, 110, 113, 116,
+                       119, 122, 125, 128, 131, 134, 137, 140,
+                       143, 146, 149, 152, 155, 158, 161, 162,
+                       163, 164, 165, 166, 167, 168, 169, 170,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171,
+               },
+               {       /* Fourth byte table 52. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,
+               },
+               {       /* Fourth byte table 53. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,
+               },
+               {       /* Fourth byte table 54. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   5,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,
+               },
+               {       /* Fourth byte table 55. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,
+               },
+               {       /* Fourth byte table 56. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 57. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 58. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 59. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 60. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 61. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,
+               },
+               {       /* Fourth byte table 62. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   4,
+                       4,   7,   10,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,
+               },
+               {       /* Fourth byte table 63. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   7,   7,   14,
+                       14,  21,  21,  28,  28,  35,  35,  42,
+                       42,  49,  49,  56,  56,  63,  63,  70,
+                       70,  77,  77,  84,  84,  84,  91,  91,
+                       98,  98,  105, 105, 105, 105, 105, 105,
+                       105, 112, 119, 119, 126, 133, 133, 140,
+                       147, 147, 154, 161, 161, 168, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175,
+               },
+               {       /* Fourth byte table 64. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   7,   7,   7,
+                       7,   7,   7,   7,   11,  15,  15,  22,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  35,  35,  42,
+                       42,  49,  49,  56,  56,  63,  63,  70,
+                       70,  77,  77,  84,  84,  91,  91,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,
+               },
+               {       /* Fourth byte table 65. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   14,  14,  14,  21,  21,
+                       28,  28,  35,  35,  35,  35,  35,  35,
+                       35,  42,  49,  49,  56,  63,  63,  70,
+                       77,  77,  84,  91,  91,  98,  105, 105,
+                       105, 105, 105, 105, 105, 105, 105, 105,
+                       105, 105, 105, 105, 105, 105, 105, 105,
+                       105, 105, 105, 105, 105, 112, 112, 112,
+                       119, 126, 133, 140, 140, 140, 140, 147,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153,
+               },
+               {       /* Fourth byte table 66. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   6,   9,   12,  15,  18,
+                       21,  24,  27,  30,  33,  36,  39,  42,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,
+               },
+               {       /* Fourth byte table 67. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 68. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       45,  45,  45,  48,  51,  54,  57,  60,
+                       63,  66,  69,  72,  75,  78,  81,  84,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 69. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  15,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  22,  24,  26,  28,  30,  32,
+                       34,  36,  38,  40,  42,  44,  46,  48,
+                       50,  53,  56,  59,  62,  65,  68,  71,
+                       74,  77,  80,  83,  86,  89,  92,  98,
+                       104, 110, 116, 122, 128, 134, 140, 146,
+                       152, 158, 164, 170, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176, 176, 176, 176, 176, 176, 176, 176,
+                       176,
+               },
+               {       /* Fourth byte table 70. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 149, 151, 153, 155, 157, 159,
+                       161, 163, 165, 167, 169, 171, 173, 175,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177,
+               },
+               {       /* Fourth byte table 71. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  41,  46,  51,  51,  51,  51,
+                       51,  54,  57,  60,  63,  66,  69,  72,
+                       75,  78,  81,  84,  87,  90,  93,  96,
+                       99,  102, 105, 108, 111, 114, 117, 120,
+                       123, 126, 129, 132, 135, 138, 141, 144,
+                       147, 150, 153, 156, 159, 162, 165, 168,
+                       171, 174, 177, 180, 183, 186, 189, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 72. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   7,   9,   11,  13,  15,
+                       17,  20,  24,  26,  28,  31,  34,  36,
+                       38,  40,  43,  46,  49,  52,  55,  57,
+                       59,  61,  63,  65,  68,  70,  72,  74,
+                       77,  80,  82,  85,  88,  91,  93,  96,
+                       101, 107, 109, 112, 115, 118, 121, 128,
+                       136, 138, 140, 143, 145, 147, 149, 152,
+                       154, 156, 158, 160, 162, 165, 167, 169,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171,
+               },
+               {       /* Fourth byte table 73. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   10,  12,  14,  16,  22,
+                       25,  27,  29,  31,  33,  35,  37,  39,
+                       41,  43,  45,  48,  50,  52,  55,  58,
+                       60,  64,  67,  69,  71,  73,  75,  75,
+                       75,  79,  83,  87,  91,  95,  99,  103,
+                       107, 111, 116, 121, 126, 131, 136, 141,
+                       146, 151, 156, 161, 166, 171, 176, 181,
+                       186, 191, 196, 201, 206, 211, 216, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221, 221, 221, 221, 221, 221, 221, 221,
+                       221,
+               },
+               {       /* Fourth byte table 74. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  56,
+                       56,  60,  60,  64,  64,  64,  68,  72,
+                       76,  80,  84,  88,  92,  96,  100, 104,
+                       104, 108, 108, 112, 112, 112, 116, 120,
+                       120, 120, 120, 124, 128, 132, 136, 136,
+                       136, 140, 144, 148, 152, 156, 160, 164,
+                       168, 172, 176, 180, 184, 188, 192, 196,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200,
+               },
+               {       /* Fourth byte table 75. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 116, 120, 124,
+                       128, 132, 136, 140, 144, 148, 152, 156,
+                       160, 164, 168, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172, 172, 172, 172, 172, 172, 172, 172,
+                       172,
+               },
+               {       /* Fourth byte table 76. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   9,   12,  14,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  20,  24,  28,  32,
+                       36,  36,  36,  36,  36,  36,  41,  41,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       62,  64,  65,  70,  75,  82,  89,  94,
+                       99,  104, 109, 114, 119, 124, 129, 134,
+                       134, 139, 144, 149, 154, 159, 159, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164,
+               },
+               {       /* Fourth byte table 77. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  10,  15,  20,  20,  25,
+                       30,  35,  40,  45,  50,  55,  60,  65,
+                       69,  71,  73,  75,  77,  79,  81,  83,
+                       85,  87,  89,  91,  93,  95,  97,  99,
+                       101, 103, 105, 107, 109, 111, 113, 115,
+                       117, 119, 121, 123, 125, 127, 129, 131,
+                       133, 135, 137, 139, 141, 143, 145, 147,
+                       149, 151, 153, 155, 157, 159, 161, 163,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165,
+               },
+               {       /* Fourth byte table 78. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  66,  68,  70,  72,  76,  80,  82,
+                       84,  86,  88,  90,  92,  94,  96,  98,
+                       100, 104, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108,
+               },
+               {       /* Fourth byte table 79. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   2,   4,   6,   8,
+                       10,  12,  14,  16,  18,  20,  24,  26,
+                       28,  30,  32,  34,  36,  38,  40,  42,
+                       44,  46,  48,  54,  60,  66,  72,  78,
+                       84,  90,  96,  102, 108, 114, 120, 126,
+                       132, 138, 144, 150, 156, 158, 160, 162,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164,
+               },
+               {       /* Fourth byte table 80. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 116, 120, 124,
+                       128, 132, 136, 140, 144, 148, 152, 156,
+                       160, 164, 168, 172, 176, 180, 184, 188,
+                       192, 196, 200, 204, 208, 212, 216, 220,
+                       224, 228, 232, 236, 240, 244, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248,
+               },
+               {       /* Fourth byte table 81. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  18,  24,  30,  36,  42,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  54,  60,  68,  76,  84,  92,  100,
+                       108, 116, 122, 155, 170, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178,
+               },
+               {       /* Fourth byte table 82. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   5,   8,   9,   10,  11,  12,
+                       13,  14,  17,  20,  23,  26,  29,  32,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 83. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  15,  15,
+                       15,  15,  18,  21,  24,  27,  28,  29,
+                       30,  31,  34,  35,  35,  36,  37,  38,
+                       39,  42,  43,  44,  45,  46,  49,  52,
+                       53,  54,  55,  56,  57,  58,  59,  60,
+                       60,  61,  62,  63,  64,  64,  64,  64,
+                       64,  67,  71,  74,  74,  77,  77,  80,
+                       84,  87,  91,  94,  98,  101, 105, 108,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112,
+               },
+               {       /* Fourth byte table 84. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   6,   10,  14,  18,  22,  26,
+                       30,  34,  38,  42,  46,  50,  52,  54,
+                       56,  58,  60,  62,  64,  66,  68,  70,
+                       72,  74,  76,  78,  80,  82,  84,  86,
+                       88,  90,  92,  94,  96,  98,  100, 102,
+                       104, 106, 108, 110, 112, 114, 116, 118,
+                       120, 122, 124, 126, 128, 130, 132, 134,
+                       136, 138, 140, 142, 144, 146, 148, 150,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152,
+               },
+               {       /* Fourth byte table 85. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  66,  68,  70,  72,  74,  76,  78,
+                       80,  82,  84,  86,  88,  90,  92,  94,
+                       96,  98,  100, 102, 104, 106, 112, 118,
+                       124, 130, 136, 142, 146, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150,
+               },
+               {       /* Fourth byte table 86. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   1,   2,   3,   4,   5,   6,
+                       7,   8,   9,   10,  11,  12,  13,  14,
+                       15,  16,  17,  18,  19,  20,  21,  22,
+                       23,  24,  25,  26,  27,  28,  29,  30,
+                       31,  32,  33,  34,  35,  36,  37,  38,
+                       39,  40,  41,  42,  43,  44,  45,  46,
+                       47,  48,  49,  50,  51,  52,  53,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 87. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       34,  37,  40,  43,  46,  49,  52,  55,
+                       58,  61,  64,  67,  70,  73,  76,  79,
+                       82,  85,  88,  91,  94,  97,  100, 103,
+                       106, 109, 112, 115, 118, 121, 124, 127,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 88. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189,
+               },
+               {       /* Fourth byte table 89. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   3,   6,   9,   12,  15,
+                       18,  18,  18,  21,  24,  27,  30,  33,
+                       36,  36,  36,  39,  42,  45,  48,  51,
+                       54,  54,  54,  57,  60,  63,  63,  63,
+                       63,  65,  67,  69,  72,  74,  76,  79,
+                       79,  82,  85,  88,  91,  94,  97,  100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100,
+               },
+               {       /* Fourth byte table 90. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   9,
+                       18,  31,  44,  57,  70,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,
+               },
+               {       /* Fourth byte table 91. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   18,  31,  44,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,
+               },
+               {       /* Fourth byte table 92. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,
+               },
+               {       /* Fourth byte table 93. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 94. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  21,  22,
+                       23,  24,  25,  26,  27,  28,  29,  30,
+                       31,  32,  33,  34,  35,  36,  37,  38,
+                       39,  40,  41,  42,  43,  44,  45,  46,
+                       47,  48,  49,  50,  51,  52,  53,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 95. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  29,  30,
+                       31,  31,  31,  32,  32,  32,  33,  34,
+                       34,  34,  35,  36,  37,  38,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  50,  51,  51,  52,  53,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 96. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   1,   2,   3,   3,   4,   5,
+                       6,   7,   8,   9,   10,  11,  12,  13,
+                       14,  15,  16,  17,  18,  19,  20,  21,
+                       22,  23,  24,  25,  26,  27,  28,  29,
+                       30,  31,  32,  33,  34,  35,  36,  37,
+                       38,  39,  40,  41,  42,  43,  44,  45,
+                       46,  47,  48,  49,  50,  51,  52,  53,
+                       54,  55,  56,  57,  58,  59,  60,  61,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 97. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   6,
+                       7,   8,   9,   10,  10,  10,  11,  12,
+                       13,  14,  15,  16,  17,  18,  18,  19,
+                       20,  21,  22,  23,  24,  25,  25,  26,
+                       27,  28,  29,  30,  31,  32,  33,  34,
+                       35,  36,  37,  38,  39,  40,  41,  42,
+                       43,  44,  45,  46,  47,  48,  49,  50,
+                       51,  52,  53,  53,  54,  55,  56,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,
+               },
+               {       /* Fourth byte table 98. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   5,   6,
+                       6,   6,   6,   7,   8,   9,   10,  11,
+                       12,  13,  13,  14,  15,  16,  17,  18,
+                       19,  20,  21,  22,  23,  24,  25,  26,
+                       27,  28,  29,  30,  31,  32,  33,  34,
+                       35,  36,  37,  38,  39,  40,  41,  42,
+                       43,  44,  45,  46,  47,  48,  49,  50,
+                       51,  52,  53,  54,  55,  56,  57,  58,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,
+               },
+               {       /* Fourth byte table 99. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 100. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 101. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 102. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 103. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  36,  36,  36,
+                       36,  38,  40,  42,  44,  46,  48,  50,
+                       52,  54,  56,  58,  60,  62,  64,  66,
+                       68,  70,  72,  74,  76,  78,  80,  82,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,
+               },
+               {       /* Fourth byte table 104. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   5,   7,   9,   11,  13,  15,
+                       17,  19,  21,  23,  25,  27,  29,  31,
+                       33,  35,  37,  39,  41,  43,  45,  47,
+                       49,  51,  53,  55,  58,  60,  62,  64,
+                       66,  68,  70,  72,  74,  76,  78,  80,
+                       82,  84,  86,  88,  90,  92,  94,  96,
+                       98,  100, 102, 104, 106, 108, 110, 112,
+                       114, 116, 118, 120, 123, 125, 127, 129,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131,
+               },
+               {       /* Fourth byte table 105. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  45,  47,
+                       49,  51,  53,  55,  57,  59,  61,  63,
+                       65,  67,  69,  71,  73,  75,  77,  79,
+                       81,  83,  85,  87,  89,  91,  93,  95,
+                       97,  99,  101, 103, 105, 107, 110, 112,
+                       114, 116, 118, 120, 122, 124, 126, 128,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 106. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       33,  35,  37,  39,  41,  43,  45,  47,
+                       49,  51,  53,  55,  57,  59,  61,  63,
+                       65,  67,  69,  71,  73,  75,  77,  79,
+                       81,  83,  85,  87,  89,  91,  93,  95,
+                       98,  100, 102, 104, 106, 108, 110, 112,
+                       114, 116, 118, 120, 122, 124, 126, 128,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 107. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  21,  23,  25,  27,  29,  31,
+                       33,  35,  37,  39,  41,  43,  45,  47,
+                       49,  51,  53,  55,  57,  59,  61,  63,
+                       65,  67,  69,  71,  73,  75,  77,  79,
+                       81,  83,  86,  88,  90,  92,  94,  96,
+                       98,  100, 102, 104, 106, 108, 110, 112,
+                       114, 116, 118, 120, 122, 124, 126, 128,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 108. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   9,   11,  13,  15,
+                       17,  19,  21,  21,  21,  21,  21,  22,
+                       23,  24,  25,  26,  27,  28,  29,  30,
+                       31,  32,  33,  34,  35,  36,  37,  38,
+                       39,  40,  41,  42,  43,  44,  45,  46,
+                       47,  48,  49,  50,  51,  52,  53,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       63,  64,  65,  66,  67,  68,  69,  70,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,  71,  71,  71,  71,  71,  71,  71,
+                       71,
+               },
+               {       /* Fourth byte table 109. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   9,   13,  17,  21,  25,  29,
+                       33,  37,  42,  46,  50,  54,  58,  62,
+                       66,  71,  75,  80,  85,  90,  94,  98,
+                       102, 106, 110, 114, 118, 122, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127,
+               },
+               {       /* Fourth byte table 110. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 111. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 112. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 113. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 114. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 115. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 116. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 117. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+       },
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   1,   1,   1,   1,   1,   1,
+                       1,   4,   4,   5,   5,   5,   5,   5,
+                       8,   8,   8,   9,   10,  13,  15,  15,
+                       15,  18,  19,  20,  20,  25,  30,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  24,
+                       28,  32,  36,  40,  44,  48,  52,  56,
+                       60,  60,  64,  68,  72,  76,  80,  84,
+                       84,  84,  88,  92,  96,  100, 104, 104,
+                       104, 108, 112, 116, 120, 124, 128, 128,
+                       132, 136, 140, 144, 148, 152, 156, 160,
+                       164, 164, 168, 172, 176, 180, 184, 188,
+                       188, 188, 192, 196, 200, 204, 208, 208,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  64,  64,  68,  72,  76,  80,  84,
+                       88,  92,  96,  100, 104, 108, 112, 116,
+                       120, 124, 128, 132, 136, 140, 144, 144,
+                       144, 148, 152, 156, 160, 164, 168, 172,
+                       176, 180, 180, 182, 184, 188, 192, 196,
+                       200, 200, 204, 208, 212, 216, 220, 224,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227, 227, 227, 227, 227, 227, 227, 227,
+                       227,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   3,   7,   11,  15,  19,
+                       23,  27,  30,  30,  30,  34,  38,  42,
+                       46,  50,  54,  54,  54,  58,  62,  66,
+                       70,  74,  78,  82,  86,  90,  94,  98,
+                       102, 106, 110, 114, 118, 122, 126, 126,
+                       126, 130, 134, 138, 142, 146, 150, 154,
+                       158, 162, 166, 170, 174, 178, 182, 186,
+                       190, 194, 198, 202, 206, 210, 214, 218,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219, 219, 219, 219, 219, 219, 219, 219,
+                       219,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       12,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   4,   8,   12,
+                       14,  16,  18,  20,  22,  24,  28,  32,
+                       36,  40,  44,  48,  52,  56,  62,  68,
+                       74,  80,  86,  92,  98,  104, 104, 110,
+                       116, 122, 128, 133, 138, 138, 138, 142,
+                       146, 150, 154, 158, 162, 168, 174, 179,
+                       184, 188, 190, 192, 194, 198, 202, 202,
+                       202, 206, 210, 216, 222, 227, 232, 237,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242, 242, 242, 242, 242, 242, 242, 242,
+                       242,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 112, 112, 116,
+                       120, 120, 120, 120, 120, 120, 120, 124,
+                       128, 132, 136, 142, 148, 154, 160, 164,
+                       168, 174, 180, 184, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188, 188, 188, 188, 188, 188, 188, 188,
+                       188,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   3,   4,   5,   7,   9,   11,
+                       12,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  20,  21,  22,  23,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   6,   9,   14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  17,  17,  17,
+                       17,  17,  17,  20,  20,  20,  20,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   14,  19,
+                       22,  27,  32,  37,  37,  42,  42,  47,
+                       52,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  64,  69,  74,  79,  84,
+                       89,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   5,   10,  15,  20,  25,
+                       25,  27,  29,  31,  41,  51,  53,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  57,  59,  61,  61,  63,  65,  65,
+                       65,  65,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,  67,  67,  67,  67,  67,  67,  67,
+                       67,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  10,  15,  15,  15,  15,
+                       20,  20,  20,  20,  20,  25,  30,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  40,  40,  40,  40,  40,  40,
+                       40,  40,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  10,  15,  15,  15,  15,
+                       20,  20,  20,  20,  20,  25,  30,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  40,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   5,   10,  10,  10,  10,  10,
+                       10,  10,  10,  10,  10,  10,  10,  10,
+                       10,  15,  20,  25,  30,  30,  30,  35,
+                       40,  40,  40,  45,  50,  55,  60,  65,
+                       70,  70,  70,  75,  80,  85,  90,  95,
+                       100, 100, 100, 105, 110, 115, 120, 125,
+                       130, 135, 140, 145, 150, 155, 160, 160,
+                       160, 165, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170, 170, 170, 170, 170, 170, 170, 170,
+                       170,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,   4,   4,   4,   4,   4,   4,   4,
+                       4,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   5,   10,  15,  20,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   4,   8,
+                       12,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   5,   10,  10,  10,  10,  10,
+                       10,  10,  10,  10,  10,  10,  10,  10,
+                       10,  10,  10,  10,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   7,   7,   7,   7,   7,
+                       7,   7,   14,  14,  14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   14,  21,  28,  35,  42,  49,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  21,  28,  28,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   7,   7,   14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   14,  21,  21,  21,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   7,   14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  28,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   7,   7,   7,   7,   7,
+                       14,  21,  21,  28,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   14,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   7,   7,   14,  24,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,  31,  31,  31,  31,  31,  31,  31,
+                       31,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   6,   12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   14,  14,
+                       14,  14,  14,  21,  21,  21,  21,  21,
+                       28,  28,  28,  28,  28,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  49,  49,  56,  63,
+                       72,  79,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  21,  21,
+                       21,  21,  21,  28,  28,  28,  28,  28,
+                       35,  35,  35,  35,  35,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,  49,  49,  49,  49,  49,  49,  49,
+                       49,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,   7,   7,   7,   7,   7,   7,   7,
+                       7,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 39. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   7,
+                       7,   14,  14,  21,  21,  28,  28,  35,
+                       35,  35,  35,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  49,  49,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 40. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   14,  14,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 41. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   1,   3,   4,
+                       4,   5,   6,   8,   9,   10,  11,  12,
+                       13,  14,  15,  16,  16,  17,  19,  20,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 42. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   6,   8,   11,
+                       12,  13,  14,  16,  18,  20,  21,  21,
+                       22,  23,  25,  26,  28,  31,  34,  35,
+                       36,  37,  40,  42,  43,  46,  48,  50,
+                       52,  54,  56,  57,  58,  59,  60,  62,
+                       64,  66,  68,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,
+               },
+               {       /* Fourth byte table 43. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   2,   3,   5,   7,
+                       9,   10,  12,  14,  16,  18,  20,  22,
+                       25,  27,  29,  32,  34,  36,  38,  40,
+                       42,  44,  46,  48,  50,  52,  54,  56,
+                       58,  61,  63,  65,  66,  68,  70,  72,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,
+               },
+               {       /* Fourth byte table 44. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  13,  14,  15,  16,  17,
+                       18,  19,  20,  21,  21,  21,  21,  21,
+                       21,  21,  24,  24,  24,  24,  24,  24,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  28,  30,  33,
+                       33,  33,  33,  33,  33,  33,  33,  33,
+                       34,  34,  34,  34,  40,  49,  49,  55,
+                       64,  64,  64,  64,  64,  66,  66,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,  69,  69,  69,  69,  69,  69,  69,
+                       69,
+               },
+               {       /* Fourth byte table 45. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       2,   4,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  19,  19,
+                       19,  20,  21,  21,  21,  22,  23,  24,
+                       25,  26,  27,  28,  31,  32,  33,  34,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,  35,  35,  35,  35,  35,  35,  35,
+                       35,
+               },
+               {       /* Fourth byte table 46. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  14,  15,  16,  17,
+                       17,  18,  19,  20,  21,  23,  23,  23,
+                       23,  23,  23,  23,  23,  23,  23,  23,
+                       23,  23,  23,  23,  23,  23,  23,  23,
+                       23,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,  25,  25,  25,  25,  25,  25,  25,
+                       25,
+               },
+               {       /* Fourth byte table 47. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   7,   10,  10,  13,  16,
+                       18,  18,  21,  22,  23,  24,  25,  26,
+                       28,  29,  30,  31,  32,  32,  33,  35,
+                       35,  35,  36,  37,  38,  39,  40,  40,
+                       40,  42,  45,  47,  47,  48,  48,  51,
+                       51,  52,  52,  54,  58,  59,  60,  60,
+                       61,  62,  63,  63,  64,  65,  67,  69,
+                       71,  73,  74,  74,  77,  79,  81,  83,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,  85,  85,  85,  85,  85,  85,  85,
+                       85,
+               },
+               {       /* Fourth byte table 48. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   3,   3,   3,   4,   5,
+                       6,   7,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   13,  18,  23,  28,
+                       33,  38,  43,  48,  53,  58,  63,  68,
+                       72,  73,  75,  78,  80,  81,  83,  86,
+                       90,  92,  93,  95,  98,  99,  100, 101,
+                       102, 103, 105, 108, 110, 111, 113, 116,
+                       120, 122, 123, 125, 128, 129, 130, 131,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132, 132, 132, 132, 132, 132, 132, 132,
+                       132,
+               },
+               {       /* Fourth byte table 49. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   6,   12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,
+               },
+               {       /* Fourth byte table 50. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   6,   12,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,
+               },
+               {       /* Fourth byte table 51. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   6,   6,   6,
+                       6,   6,   12,  12,  12,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  24,  24,  30,
+                       30,  30,  30,  30,  30,  36,  45,  45,
+                       51,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,
+               },
+               {       /* Fourth byte table 52. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   6,   6,   6,   12,  12,  12,
+                       18,  18,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  28,  28,  34,  34,  34,  34,  34,
+                       34,  34,  34,  34,  34,  34,  40,  44,
+                       48,  54,  60,  60,  60,  66,  72,  72,
+                       72,  78,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,
+               },
+               {       /* Fourth byte table 53. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  12,  12,  18,  24,  24,
+                       24,  30,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  36,  36,  36,
+                       36,  36,  36,  36,  36,  42,  48,  54,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,
+               },
+               {       /* Fourth byte table 54. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  18,  24,  24,  24,  24,
+                       24,  24,  24,  30,  36,  42,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 55. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   4,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,
+               },
+               {       /* Fourth byte table 56. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   11,  13,  15,  17,  19,  21,
+                       23,  25,  27,  29,  31,  34,  37,  40,
+                       43,  46,  49,  52,  55,  58,  62,  66,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,
+               },
+               {       /* Fourth byte table 57. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  53,  56,  59,  62,  65,  68,
+                       71,  74,  77,  80,  83,  86,  89,  92,
+                       95,  98,  101, 104, 107, 110, 113, 116,
+                       119, 122, 125, 128, 131, 134, 137, 140,
+                       143, 146, 149, 152, 155, 158, 161, 162,
+                       163, 164, 165, 166, 167, 168, 169, 170,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171,
+               },
+               {       /* Fourth byte table 58. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,  43,  43,  43,  43,  43,  43,  43,
+                       43,
+               },
+               {       /* Fourth byte table 59. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,
+               },
+               {       /* Fourth byte table 60. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   5,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,
+               },
+               {       /* Fourth byte table 61. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,   6,   6,   6,   6,   6,   6,   6,
+                       6,
+               },
+               {       /* Fourth byte table 62. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 63. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 64. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 65. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 66. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 67. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 68. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,
+               },
+               {       /* Fourth byte table 69. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   1,
+                       1,   1,   1,   1,   1,   1,   1,   4,
+                       4,   7,   10,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,
+               },
+               {       /* Fourth byte table 70. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   7,   7,   14,
+                       14,  21,  21,  28,  28,  35,  35,  42,
+                       42,  49,  49,  56,  56,  63,  63,  70,
+                       70,  77,  77,  84,  84,  84,  91,  91,
+                       98,  98,  105, 105, 105, 105, 105, 105,
+                       105, 112, 119, 119, 126, 133, 133, 140,
+                       147, 147, 154, 161, 161, 168, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175, 175, 175, 175, 175, 175, 175, 175,
+                       175,
+               },
+               {       /* Fourth byte table 71. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   7,   7,   7,
+                       7,   7,   7,   7,   11,  15,  15,  22,
+                       28,  28,  28,  28,  28,  28,  28,  28,
+                       28,  28,  28,  28,  28,  35,  35,  42,
+                       42,  49,  49,  56,  56,  63,  63,  70,
+                       70,  77,  77,  84,  84,  91,  91,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,  98,  98,  98,  98,  98,  98,  98,
+                       98,
+               },
+               {       /* Fourth byte table 72. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   7,   7,   14,  14,  14,  21,  21,
+                       28,  28,  35,  35,  35,  35,  35,  35,
+                       35,  42,  49,  49,  56,  63,  63,  70,
+                       77,  77,  84,  91,  91,  98,  105, 105,
+                       105, 105, 105, 105, 105, 105, 105, 105,
+                       105, 105, 105, 105, 105, 105, 105, 105,
+                       105, 105, 105, 105, 105, 112, 112, 112,
+                       119, 126, 133, 140, 140, 140, 140, 147,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153, 153, 153, 153, 153, 153, 153, 153,
+                       153,
+               },
+               {       /* Fourth byte table 73. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   6,   9,   12,  15,  18,
+                       21,  24,  27,  30,  33,  36,  39,  42,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,  45,  45,  45,  45,  45,  45,  45,
+                       45,
+               },
+               {       /* Fourth byte table 74. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192, 192, 192, 192, 192, 192, 192, 192,
+                       192,
+               },
+               {       /* Fourth byte table 75. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       45,  45,  45,  48,  51,  54,  57,  60,
+                       63,  66,  69,  72,  75,  78,  81,  84,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 76. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  15,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  23,  25,  27,  29,  31,  33,  35,
+                       37,  39,  41,  43,  45,  47,  49,  51,
+                       53,  56,  59,  62,  65,  68,  71,  74,
+                       77,  80,  83,  86,  89,  92,  95,  101,
+                       107, 113, 119, 125, 131, 137, 143, 149,
+                       155, 161, 167, 173, 179, 194, 206, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212, 212, 212, 212, 212, 212, 212, 212,
+                       212,
+               },
+               {       /* Fourth byte table 77. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 149, 151, 153, 155, 157, 159,
+                       161, 163, 165, 167, 169, 171, 173, 175,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177, 177, 177, 177, 177, 177, 177, 177,
+                       177,
+               },
+               {       /* Fourth byte table 78. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  41,  46,  51,  53,  56,  58,
+                       61,  64,  67,  70,  73,  76,  79,  82,
+                       85,  88,  91,  94,  97,  100, 103, 106,
+                       109, 112, 115, 118, 121, 124, 127, 130,
+                       133, 136, 139, 142, 145, 148, 151, 154,
+                       157, 160, 163, 166, 169, 172, 175, 178,
+                       181, 184, 187, 190, 193, 196, 199, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202, 202, 202, 202, 202, 202, 202, 202,
+                       202,
+               },
+               {       /* Fourth byte table 79. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   7,   9,   11,  13,  15,
+                       17,  20,  24,  26,  28,  31,  34,  36,
+                       38,  40,  43,  46,  49,  52,  55,  57,
+                       59,  61,  63,  65,  68,  70,  72,  74,
+                       77,  80,  82,  85,  88,  91,  93,  96,
+                       101, 107, 109, 112, 115, 118, 121, 128,
+                       136, 138, 140, 143, 145, 147, 149, 152,
+                       154, 156, 158, 160, 162, 165, 167, 169,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171, 171, 171, 171, 171, 171, 171, 171,
+                       171,
+               },
+               {       /* Fourth byte table 80. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   10,  12,  14,  16,  22,
+                       25,  27,  29,  31,  33,  35,  37,  39,
+                       41,  43,  45,  48,  50,  52,  55,  58,
+                       60,  64,  67,  69,  71,  73,  75,  80,
+                       85,  89,  93,  97,  101, 105, 109, 113,
+                       117, 121, 126, 131, 136, 141, 146, 151,
+                       156, 161, 166, 171, 176, 181, 186, 191,
+                       196, 201, 206, 211, 216, 221, 226, 231,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234, 234, 234, 234, 234, 234, 234, 234,
+                       234,
+               },
+               {       /* Fourth byte table 81. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  56,
+                       56,  60,  60,  64,  64,  64,  68,  72,
+                       76,  80,  84,  88,  92,  96,  100, 104,
+                       104, 108, 108, 112, 112, 112, 116, 120,
+                       120, 120, 120, 124, 128, 132, 136, 136,
+                       136, 140, 144, 148, 152, 156, 160, 164,
+                       168, 172, 176, 180, 184, 188, 192, 196,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200, 200, 200, 200, 200, 200, 200, 200,
+                       200,
+               },
+               {       /* Fourth byte table 82. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 116, 120, 124,
+                       128, 132, 136, 140, 144, 148, 152, 156,
+                       160, 164, 168, 172, 172, 172, 172, 172,
+                       172, 176, 180, 184, 188, 192, 196, 200,
+                       204, 208, 212, 216, 220, 224, 228, 232,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236, 236, 236, 236, 236, 236, 236, 236,
+                       236,
+               },
+               {       /* Fourth byte table 83. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       65,  70,  75,  79,  83,  87,  92,  97,
+                       102, 106, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110, 110, 110, 110, 110, 110, 110, 110,
+                       110,
+               },
+               {       /* Fourth byte table 84. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   9,   12,  14,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  20,  24,  28,  32,
+                       36,  36,  36,  36,  36,  36,  41,  41,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       62,  64,  65,  70,  75,  82,  89,  94,
+                       99,  104, 109, 114, 119, 124, 129, 134,
+                       134, 139, 144, 149, 154, 159, 159, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164,
+               },
+               {       /* Fourth byte table 85. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   5,   10,  10,  15,  20,  20,  25,
+                       30,  35,  40,  45,  50,  55,  60,  65,
+                       69,  71,  73,  75,  77,  79,  81,  83,
+                       85,  87,  89,  91,  93,  95,  97,  99,
+                       101, 103, 105, 107, 109, 111, 113, 115,
+                       117, 119, 121, 123, 125, 127, 129, 131,
+                       133, 135, 137, 139, 141, 143, 145, 147,
+                       149, 151, 153, 155, 157, 159, 161, 163,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165, 165, 165, 165, 165, 165, 165, 165,
+                       165,
+               },
+               {       /* Fourth byte table 86. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  66,  68,  70,  72,  76,  80,  82,
+                       84,  86,  88,  90,  92,  94,  96,  98,
+                       100, 104, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108, 108, 108, 108, 108, 108, 108, 108,
+                       108,
+               },
+               {       /* Fourth byte table 87. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   2,   4,   6,   8,
+                       10,  12,  14,  16,  18,  20,  24,  26,
+                       28,  30,  32,  34,  36,  38,  40,  42,
+                       44,  46,  48,  54,  60,  66,  72,  78,
+                       84,  90,  96,  102, 108, 114, 120, 126,
+                       132, 138, 144, 150, 156, 158, 160, 162,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164, 164, 164, 164, 164, 164, 164, 164,
+                       164,
+               },
+               {       /* Fourth byte table 88. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 116, 120, 124,
+                       128, 132, 136, 140, 144, 148, 152, 156,
+                       160, 164, 168, 172, 176, 180, 184, 188,
+                       192, 196, 200, 204, 208, 212, 216, 220,
+                       224, 228, 232, 236, 240, 244, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248, 248, 248, 248, 248, 248, 248, 248,
+                       248,
+               },
+               {       /* Fourth byte table 89. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   6,   12,  18,  24,  30,  36,  42,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  54,  60,  68,  76,  84,  92,  100,
+                       108, 116, 122, 155, 170, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178, 178, 178, 178, 178, 178, 178, 178,
+                       178,
+               },
+               {       /* Fourth byte table 90. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   4,   7,   8,   9,   10,  11,
+                       14,  17,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  22,  25,  28,  29,  30,  31,  32,
+                       33,  34,  37,  40,  43,  46,  49,  52,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,  55,  55,  55,  55,  55,  55,  55,
+                       55,
+               },
+               {       /* Fourth byte table 91. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  15,  15,
+                       16,  17,  20,  23,  26,  29,  30,  31,
+                       32,  33,  36,  37,  37,  38,  39,  40,
+                       41,  44,  45,  46,  47,  48,  51,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       62,  63,  64,  65,  66,  66,  66,  66,
+                       66,  69,  73,  76,  76,  79,  79,  82,
+                       86,  89,  93,  96,  100, 103, 107, 110,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114,
+               },
+               {       /* Fourth byte table 92. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   6,   10,  14,  18,  22,  26,
+                       30,  34,  38,  42,  46,  50,  52,  54,
+                       56,  58,  60,  62,  64,  66,  68,  70,
+                       72,  74,  76,  78,  80,  82,  84,  86,
+                       88,  90,  92,  94,  96,  98,  100, 102,
+                       104, 106, 108, 110, 112, 114, 116, 118,
+                       120, 122, 124, 126, 128, 130, 132, 134,
+                       136, 138, 140, 142, 144, 146, 148, 150,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152,
+               },
+               {       /* Fourth byte table 93. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  66,  68,  70,  72,  74,  76,  78,
+                       80,  82,  84,  86,  88,  90,  92,  94,
+                       96,  98,  100, 102, 104, 106, 112, 118,
+                       124, 130, 136, 142, 146, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150, 150, 150, 150, 150, 150, 150, 150,
+                       150,
+               },
+               {       /* Fourth byte table 94. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   1,   2,   3,   4,   5,   6,
+                       7,   8,   9,   10,  11,  12,  13,  14,
+                       15,  16,  17,  18,  19,  20,  21,  22,
+                       23,  24,  25,  26,  27,  28,  29,  30,
+                       31,  32,  33,  34,  35,  36,  37,  38,
+                       39,  40,  41,  42,  43,  44,  45,  46,
+                       47,  48,  49,  50,  51,  52,  53,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 95. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       34,  37,  40,  43,  46,  49,  52,  55,
+                       58,  61,  64,  67,  70,  73,  76,  79,
+                       82,  85,  88,  91,  94,  97,  100, 103,
+                       106, 109, 112, 115, 118, 121, 124, 127,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 96. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       144, 147, 150, 153, 156, 159, 162, 165,
+                       168, 171, 174, 177, 180, 183, 186, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189, 189, 189, 189, 189, 189, 189, 189,
+                       189,
+               },
+               {       /* Fourth byte table 97. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   3,   6,   9,   12,  15,
+                       18,  18,  18,  21,  24,  27,  30,  33,
+                       36,  36,  36,  39,  42,  45,  48,  51,
+                       54,  54,  54,  57,  60,  63,  63,  63,
+                       63,  65,  67,  69,  72,  74,  76,  79,
+                       79,  82,  85,  88,  91,  94,  97,  100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100, 100, 100, 100, 100, 100, 100, 100,
+                       100,
+               },
+               {       /* Fourth byte table 98. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   9,
+                       18,  31,  44,  57,  70,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,
+               },
+               {       /* Fourth byte table 99. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   9,   18,  31,  44,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,
+               },
+               {       /* Fourth byte table 100. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,  13,  13,  13,  13,  13,  13,  13,
+                       13,
+               },
+               {       /* Fourth byte table 101. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 102. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  21,  22,
+                       23,  24,  25,  26,  27,  28,  29,  30,
+                       31,  32,  33,  34,  35,  36,  37,  38,
+                       39,  40,  41,  42,  43,  44,  45,  46,
+                       47,  48,  49,  50,  51,  52,  53,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 103. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  29,  30,
+                       31,  31,  31,  32,  32,  32,  33,  34,
+                       34,  34,  35,  36,  37,  38,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  50,  51,  51,  52,  53,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 104. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   4,   5,   6,
+                       7,   8,   9,   10,  11,  12,  13,  14,
+                       15,  16,  17,  18,  19,  20,  21,  22,
+                       23,  24,  25,  26,  27,  28,  29,  30,
+                       31,  32,  33,  34,  35,  36,  37,  38,
+                       39,  40,  41,  42,  43,  44,  45,  46,
+                       47,  48,  49,  50,  51,  52,  53,  54,
+                       55,  56,  57,  58,  59,  60,  61,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 105. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   6,
+                       7,   8,   9,   10,  10,  10,  11,  12,
+                       13,  14,  15,  16,  17,  18,  18,  19,
+                       20,  21,  22,  23,  24,  25,  25,  26,
+                       27,  28,  29,  30,  31,  32,  33,  34,
+                       35,  36,  37,  38,  39,  40,  41,  42,
+                       43,  44,  45,  46,  47,  48,  49,  50,
+                       51,  52,  53,  53,  54,  55,  56,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,
+               },
+               {       /* Fourth byte table 106. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   5,   6,
+                       6,   6,   6,   7,   8,   9,   10,  11,
+                       12,  13,  13,  14,  15,  16,  17,  18,
+                       19,  20,  21,  22,  23,  24,  25,  26,
+                       27,  28,  29,  30,  31,  32,  33,  34,
+                       35,  36,  37,  38,  39,  40,  41,  42,
+                       43,  44,  45,  46,  47,  48,  49,  50,
+                       51,  52,  53,  54,  55,  56,  57,  58,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,  59,  59,  59,  59,  59,  59,  59,
+                       59,
+               },
+               {       /* Fourth byte table 107. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 108. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 109. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 110. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  37,  38,  39,
+                       40,  41,  42,  43,  44,  45,  46,  47,
+                       48,  49,  50,  51,  52,  53,  54,  55,
+                       56,  57,  58,  59,  60,  61,  62,  63,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 111. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   1,   2,   3,   4,   5,   6,   7,
+                       8,   9,   10,  11,  12,  13,  14,  15,
+                       16,  17,  18,  19,  20,  21,  22,  23,
+                       24,  25,  26,  27,  28,  29,  30,  31,
+                       32,  33,  34,  35,  36,  38,  40,  40,
+                       40,  42,  44,  46,  48,  50,  52,  54,
+                       56,  58,  60,  62,  64,  66,  68,  70,
+                       72,  74,  76,  78,  80,  82,  84,  86,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,  88,  88,  88,  88,  88,  88,  88,
+                       88,
+               },
+               {       /* Fourth byte table 112. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   5,   7,   9,   11,  13,  15,
+                       17,  19,  21,  23,  25,  27,  29,  31,
+                       33,  35,  37,  39,  41,  43,  45,  47,
+                       49,  51,  53,  55,  58,  60,  62,  64,
+                       66,  68,  70,  72,  74,  76,  78,  80,
+                       82,  84,  86,  88,  90,  92,  94,  96,
+                       98,  100, 102, 104, 106, 108, 110, 112,
+                       114, 116, 118, 120, 123, 125, 127, 129,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131, 131, 131, 131, 131, 131, 131, 131,
+                       131,
+               },
+               {       /* Fourth byte table 113. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  45,  47,
+                       49,  51,  53,  55,  57,  59,  61,  63,
+                       65,  67,  69,  71,  73,  75,  77,  79,
+                       81,  83,  85,  87,  89,  91,  93,  95,
+                       97,  99,  101, 103, 105, 107, 110, 112,
+                       114, 116, 118, 120, 122, 124, 126, 128,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 114. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       33,  35,  37,  39,  41,  43,  45,  47,
+                       49,  51,  53,  55,  57,  59,  61,  63,
+                       65,  67,  69,  71,  73,  75,  77,  79,
+                       81,  83,  85,  87,  89,  91,  93,  95,
+                       98,  100, 102, 104, 106, 108, 110, 112,
+                       114, 116, 118, 120, 122, 124, 126, 128,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 115. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  21,  23,  25,  27,  29,  31,
+                       33,  35,  37,  39,  41,  43,  45,  47,
+                       49,  51,  53,  55,  57,  59,  61,  63,
+                       65,  67,  69,  71,  73,  75,  77,  79,
+                       81,  83,  86,  88,  90,  92,  94,  96,
+                       98,  100, 102, 104, 106, 108, 110, 112,
+                       114, 116, 118, 120, 122, 124, 126, 128,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130, 130, 130, 130, 130, 130, 130, 130,
+                       130,
+               },
+               {       /* Fourth byte table 116. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   9,   11,  13,  15,
+                       17,  19,  21,  23,  25,  25,  25,  26,
+                       27,  28,  29,  30,  31,  32,  33,  34,
+                       35,  36,  37,  38,  39,  40,  41,  42,
+                       43,  44,  45,  46,  47,  48,  49,  50,
+                       51,  52,  53,  54,  55,  56,  57,  58,
+                       59,  60,  61,  62,  63,  64,  65,  66,
+                       67,  68,  69,  70,  71,  72,  73,  74,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,  75,  75,  75,  75,  75,  75,  75,
+                       75,
+               },
+               {       /* Fourth byte table 117. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   9,   13,  17,  21,  25,  29,
+                       33,  37,  42,  46,  50,  54,  58,  62,
+                       66,  71,  75,  80,  85,  90,  94,  98,
+                       102, 106, 110, 114, 118, 122, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127, 127, 127, 127, 127, 127, 127, 127,
+                       127,
+               },
+       },
+};
+
+static const uint16_t u8_decomp_b4_16bit_tbl[2][30][257] = {
+       {
+               {       /* Fourth byte 16-bit table 0. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   38,   44,   48,   52,   56,   60,   64,
+                       68,   72,   76,   80,   84,   90,   96,   102,
+                       108,  112,  116,  120,  124,  130,  136,  140,
+                       144,  148,  152,  156,  160,  164,  168,  172,
+                       176,  180,  184,  188,  192,  196,  200,  206,
+                       212,  216,  220,  224,  228,  232,  236,  240,
+                       244,  250,  256,  260,  264,  268,  272,  276,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,
+               },
+               {       /* Fourth byte 16-bit table 1. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   54,   60,   66,
+                       72,   78,   84,   90,   96,   100,  104,  108,
+                       112,  116,  120,  124,  128,  134,  140,  144,
+                       148,  152,  156,  160,  164,  170,  176,  182,
+                       188,  194,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  262,  268,  274,  280,  284,  288,  292,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,
+               },
+               {       /* Fourth byte 16-bit table 2. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  107,  116,  116,  116,  116,
+                       116,  120,  124,  128,  132,  138,  144,  150,
+                       156,  162,  168,  174,  180,  186,  192,  198,
+                       204,  210,  216,  222,  228,  234,  240,  246,
+                       252,  256,  260,  264,  268,  272,  276,  282,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,
+               },
+               {       /* Fourth byte 16-bit table 3. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   36,   42,
+                       48,   52,   56,   60,   64,   68,   72,   76,
+                       80,   86,   92,   98,   104,  110,  116,  122,
+                       128,  134,  140,  146,  152,  158,  164,  170,
+                       176,  182,  188,  194,  200,  204,  208,  212,
+                       216,  222,  228,  234,  240,  246,  252,  258,
+                       264,  270,  276,  280,  284,  288,  292,  296,
+                       300,  304,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,
+               },
+               {       /* Fourth byte 16-bit table 4. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    10,   17,   24,   31,   38,   45,
+                       52,   57,   62,   69,   76,   83,   90,   97,
+                       104,  109,  114,  121,  128,  135,  142,  142,
+                       142,  147,  152,  159,  166,  173,  180,  180,
+                       180,  185,  190,  197,  204,  211,  218,  225,
+                       232,  237,  242,  249,  256,  263,  270,  277,
+                       284,  289,  294,  301,  308,  315,  322,  329,
+                       336,  341,  346,  353,  360,  367,  374,  381,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,
+               },
+               {       /* Fourth byte 16-bit table 5. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    10,   17,   24,   31,   38,   38,
+                       38,   43,   48,   55,   62,   69,   76,   76,
+                       76,   81,   86,   93,   100,  107,  114,  121,
+                       128,  128,  133,  133,  140,  140,  147,  147,
+                       154,  159,  164,  171,  178,  185,  192,  199,
+                       206,  211,  216,  223,  230,  237,  244,  251,
+                       258,  263,  268,  273,  278,  283,  288,  293,
+                       298,  303,  308,  313,  318,  323,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,
+               },
+               {       /* Fourth byte 16-bit table 6. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    7,    14,   23,   32,   41,   50,   59,
+                       68,   75,   82,   91,   100,  109,  118,  127,
+                       136,  143,  150,  159,  168,  177,  186,  195,
+                       204,  211,  218,  227,  236,  245,  254,  263,
+                       272,  279,  286,  295,  304,  313,  322,  331,
+                       340,  347,  354,  363,  372,  381,  390,  399,
+                       408,  413,  418,  425,  430,  437,  437,  442,
+                       449,  454,  459,  464,  469,  474,  477,  480,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,
+               },
+               {       /* Fourth byte 16-bit table 7. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    3,    14,   21,   26,   33,   33,   38,
+                       45,   50,   55,   60,   65,   70,   82,   94,
+                       106,  111,  116,  123,  130,  130,  130,  135,
+                       142,  147,  152,  157,  162,  162,  174,  186,
+                       198,  203,  208,  215,  222,  227,  232,  237,
+                       244,  249,  254,  259,  264,  269,  280,  291,
+                       293,  293,  293,  300,  305,  312,  312,  317,
+                       324,  329,  334,  339,  344,  349,  356,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,
+               },
+               {       /* Fourth byte 16-bit table 8. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    10,   15,   20,   25,   30,   35,
+                       40,   45,   50,   55,   60,   65,   70,   78,
+                       86,   94,   102,  110,  118,  126,  134,  142,
+                       150,  158,  166,  174,  182,  190,  190,  190,
+                       190,  195,  200,  205,  210,  215,  220,  225,
+                       230,  235,  240,  245,  250,  255,  260,  265,
+                       270,  275,  280,  285,  290,  295,  300,  305,
+                       310,  315,  320,  325,  330,  335,  340,  345,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,  350,  350,  350,  350,  350,  350,  350,
+                       350,
+               },
+               {       /* Fourth byte 16-bit table 9. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    15,   27,   42,   51,   66,   75,   84,
+                       102,  114,  123,  132,  141,  153,  165,  177,
+                       189,  201,  213,  225,  243,  249,  267,  285,
+                       300,  312,  330,  348,  360,  369,  378,  390,
+                       402,  417,  432,  441,  450,  462,  471,  480,
+                       486,  492,  501,  510,  528,  540,  555,  573,
+                       585,  594,  603,  621,  633,  651,  660,  675,
+                       684,  696,  705,  717,  732,  744,  759,  771,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,
+               },
+               {       /* Fourth byte 16-bit table 10. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    15,   24,   33,   45,   54,   63,   72,
+                       87,   99,   105,  123,  132,  147,  159,  171,
+                       180,  189,  201,  207,  219,  234,  240,  258,
+                       267,  271,  275,  279,  283,  287,  291,  295,
+                       299,  303,  307,  312,  317,  322,  327,  332,
+                       337,  342,  347,  352,  357,  362,  367,  372,
+                       377,  382,  385,  387,  389,  392,  394,  396,
+                       396,  396,  396,  396,  402,  408,  414,  420,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,  432,  432,  432,  432,  432,  432,  432,
+                       432,
+               },
+               {       /* Fourth byte 16-bit table 11. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 12. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 13. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 14. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 15. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   34,   38,
+                       42,   46,   50,   54,   58,   62,   66,   70,
+                       74,   78,   82,   86,   90,   94,   98,   102,
+                       106,  110,  114,  118,  122,  126,  130,  134,
+                       138,  142,  146,  150,  154,  158,  162,  166,
+                       170,  174,  178,  182,  186,  190,  194,  198,
+                       202,  206,  210,  214,  218,  222,  226,  230,
+                       234,  238,  242,  246,  250,  254,  258,  262,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,
+               },
+               {       /* Fourth byte 16-bit table 16. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  125,
+                       130,  135,  140,  145,  150,  156,  162,  168,
+                       174,  180,  186,  190,  194,  198,  202,  206,
+                       210,  214,  218,  222,  226,  230,  234,  238,
+                       242,  246,  250,  254,  258,  262,  266,  270,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,
+               },
+               {       /* Fourth byte 16-bit table 17. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       98,   104,  110,  116,  122,  126,  130,  134,
+                       138,  142,  146,  150,  154,  158,  162,  166,
+                       170,  174,  178,  182,  186,  190,  194,  198,
+                       202,  206,  210,  214,  218,  222,  226,  230,
+                       234,  238,  242,  246,  250,  254,  258,  262,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,
+               },
+               {       /* Fourth byte 16-bit table 18. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       130,  136,  140,  144,  148,  152,  156,  160,
+                       164,  168,  172,  176,  180,  184,  188,  192,
+                       196,  200,  204,  210,  216,  222,  226,  230,
+                       234,  238,  242,  246,  250,  254,  258,  262,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,
+               },
+               {       /* Fourth byte 16-bit table 19. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   36,   42,
+                       48,   54,   60,   66,   72,   78,   84,   90,
+                       96,   102,  108,  114,  120,  126,  132,  138,
+                       144,  150,  156,  162,  168,  174,  180,  186,
+                       192,  198,  204,  210,  216,  222,  228,  234,
+                       240,  246,  252,  258,  264,  270,  276,  282,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,
+               },
+               {       /* Fourth byte 16-bit table 20. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   36,   42,
+                       48,   54,   60,   66,   72,   78,   84,   90,
+                       96,   96,   96,   102,  108,  114,  120,  126,
+                       132,  138,  144,  150,  156,  162,  168,  174,
+                       180,  186,  192,  198,  204,  210,  216,  222,
+                       228,  234,  240,  246,  252,  258,  264,  270,
+                       276,  282,  288,  294,  300,  306,  312,  318,
+                       324,  330,  336,  342,  348,  354,  360,  366,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,
+               },
+               {       /* Fourth byte 16-bit table 21. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   17,   21,   25,   29,
+                       33,   37,   41,   45,   49,   53,   58,   62,
+                       66,   70,   74,   79,   83,   87,   91,   96,
+                       100,  104,  108,  112,  116,  121,  125,  129,
+                       133,  137,  141,  145,  149,  153,  157,  161,
+                       165,  169,  173,  177,  181,  185,  189,  193,
+                       197,  201,  205,  209,  213,  218,  222,  226,
+                       230,  235,  239,  243,  247,  251,  255,  259,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,
+               },
+               {       /* Fourth byte 16-bit table 22. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  105,  109,  113,  117,  121,  125,
+                       129,  134,  139,  143,  147,  151,  155,  159,
+                       163,  167,  171,  175,  179,  184,  188,  192,
+                       196,  200,  205,  209,  213,  217,  221,  225,
+                       229,  233,  237,  241,  246,  250,  255,  259,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,
+               },
+               {       /* Fourth byte 16-bit table 23. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   41,   45,   49,   53,   57,   61,
+                       66,   70,   75,   80,   84,   88,   92,   96,
+                       101,  106,  110,  114,  118,  122,  126,  130,
+                       134,  138,  142,  146,  150,  155,  159,  163,
+                       167,  171,  175,  179,  183,  187,  191,  195,
+                       199,  203,  207,  211,  215,  219,  223,  227,
+                       231,  236,  240,  244,  248,  252,  256,  261,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,
+               },
+               {       /* Fourth byte 16-bit table 24. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   45,   49,   53,   57,   61,
+                       65,   69,   73,   77,   81,   85,   89,   93,
+                       97,   101,  105,  109,  113,  117,  122,  126,
+                       130,  134,  138,  142,  147,  151,  155,  159,
+                       163,  167,  171,  175,  179,  184,  188,  192,
+                       196,  201,  205,  209,  213,  217,  221,  225,
+                       230,  235,  240,  244,  249,  253,  257,  261,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,
+               },
+               {       /* Fourth byte 16-bit table 25. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   29,
+                       33,   37,   41,   45,   49,   53,   58,   62,
+                       66,   71,   76,   80,   84,   88,   92,   96,
+                       100,  104,  108,  112,  117,  121,  126,  130,
+                       135,  139,  143,  147,  152,  156,  160,  165,
+                       170,  174,  178,  182,  186,  190,  194,  198,
+                       202,  206,  210,  214,  218,  222,  227,  231,
+                       236,  240,  245,  249,  254,  259,  264,  268,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,
+               },
+               {       /* Fourth byte 16-bit table 26. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    9,    14,   19,   24,   28,   32,
+                       36,   40,   44,   48,   52,   56,   61,   65,
+                       69,   73,   77,   82,   86,   91,   96,   100,
+                       104,  108,  112,  116,  120,  125,  130,  135,
+                       139,  143,  148,  152,  156,  160,  165,  169,
+                       173,  177,  181,  185,  190,  194,  198,  202,
+                       206,  210,  214,  219,  224,  228,  233,  237,
+                       242,  246,  250,  254,  259,  264,  268,  273,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,
+               },
+               {       /* Fourth byte 16-bit table 27. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    9,    13,   17,   21,   25,   29,
+                       34,   39,   44,   49,   53,   57,   61,   65,
+                       69,   73,   77,   81,   85,   89,   93,   97,
+                       102,  106,  110,  114,  118,  122,  126,  130,
+                       134,  138,  142,  146,  150,  155,  160,  165,
+                       169,  173,  177,  181,  186,  190,  195,  199,
+                       203,  208,  213,  217,  221,  225,  229,  233,
+                       237,  241,  245,  249,  253,  257,  261,  265,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,
+               },
+               {       /* Fourth byte 16-bit table 28. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   25,   29,
+                       33,   37,   41,   45,   50,   55,   59,   63,
+                       67,   71,   75,   79,   84,   88,   92,   96,
+                       100,  105,  110,  114,  118,  122,  127,  131,
+                       135,  140,  145,  149,  153,  157,  162,  166,
+                       170,  174,  178,  182,  186,  190,  195,  199,
+                       203,  207,  212,  216,  220,  224,  228,  233,
+                       238,  242,  246,  250,  255,  259,  264,  268,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,
+               },
+               {       /* Fourth byte 16-bit table 29. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,
+               },
+       },
+       {
+               {       /* Fourth byte 16-bit table 0. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   38,   44,   48,   52,   56,   60,   64,
+                       68,   72,   76,   80,   84,   90,   96,   102,
+                       108,  112,  116,  120,  124,  130,  136,  140,
+                       144,  148,  152,  156,  160,  164,  168,  172,
+                       176,  180,  184,  188,  192,  196,  200,  206,
+                       212,  216,  220,  224,  228,  232,  236,  240,
+                       244,  250,  256,  260,  264,  268,  272,  276,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,  280,  280,  280,  280,  280,  280,  280,
+                       280,
+               },
+               {       /* Fourth byte 16-bit table 1. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   54,   60,   66,
+                       72,   78,   84,   90,   96,   100,  104,  108,
+                       112,  116,  120,  124,  128,  134,  140,  144,
+                       148,  152,  156,  160,  164,  170,  176,  182,
+                       188,  194,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  262,  268,  274,  280,  284,  288,  292,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,  296,  296,  296,  296,  296,  296,  296,
+                       296,
+               },
+               {       /* Fourth byte 16-bit table 2. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  107,  116,  116,  116,  116,
+                       116,  120,  124,  128,  132,  138,  144,  150,
+                       156,  162,  168,  174,  180,  186,  192,  198,
+                       204,  210,  216,  222,  228,  234,  240,  246,
+                       252,  256,  260,  264,  268,  272,  276,  282,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,
+               },
+               {       /* Fourth byte 16-bit table 3. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   36,   42,
+                       48,   52,   56,   60,   64,   68,   72,   76,
+                       80,   86,   92,   98,   104,  110,  116,  122,
+                       128,  134,  140,  146,  152,  158,  164,  170,
+                       176,  182,  188,  194,  200,  204,  208,  212,
+                       216,  222,  228,  234,  240,  246,  252,  258,
+                       264,  270,  276,  280,  284,  288,  292,  296,
+                       300,  304,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,  308,  308,  308,  308,  308,  308,  308,
+                       308,
+               },
+               {       /* Fourth byte 16-bit table 4. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    10,   17,   24,   31,   38,   45,
+                       52,   57,   62,   69,   76,   83,   90,   97,
+                       104,  109,  114,  121,  128,  135,  142,  142,
+                       142,  147,  152,  159,  166,  173,  180,  180,
+                       180,  185,  190,  197,  204,  211,  218,  225,
+                       232,  237,  242,  249,  256,  263,  270,  277,
+                       284,  289,  294,  301,  308,  315,  322,  329,
+                       336,  341,  346,  353,  360,  367,  374,  381,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,  388,  388,  388,  388,  388,  388,  388,
+                       388,
+               },
+               {       /* Fourth byte 16-bit table 5. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    10,   17,   24,   31,   38,   38,
+                       38,   43,   48,   55,   62,   69,   76,   76,
+                       76,   81,   86,   93,   100,  107,  114,  121,
+                       128,  128,  133,  133,  140,  140,  147,  147,
+                       154,  159,  164,  171,  178,  185,  192,  199,
+                       206,  211,  216,  223,  230,  237,  244,  251,
+                       258,  263,  268,  273,  278,  283,  288,  293,
+                       298,  303,  308,  313,  318,  323,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,  328,  328,  328,  328,  328,  328,  328,
+                       328,
+               },
+               {       /* Fourth byte 16-bit table 6. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    7,    14,   23,   32,   41,   50,   59,
+                       68,   75,   82,   91,   100,  109,  118,  127,
+                       136,  143,  150,  159,  168,  177,  186,  195,
+                       204,  211,  218,  227,  236,  245,  254,  263,
+                       272,  279,  286,  295,  304,  313,  322,  331,
+                       340,  347,  354,  363,  372,  381,  390,  399,
+                       408,  413,  418,  425,  430,  437,  437,  442,
+                       449,  454,  459,  464,  469,  474,  477,  480,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,  483,  483,  483,  483,  483,  483,  483,
+                       483,
+               },
+               {       /* Fourth byte 16-bit table 7. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    3,    14,   21,   26,   33,   33,   38,
+                       45,   50,   55,   60,   65,   70,   82,   94,
+                       106,  111,  116,  123,  130,  130,  130,  135,
+                       142,  147,  152,  157,  162,  162,  174,  186,
+                       198,  203,  208,  215,  222,  227,  232,  237,
+                       244,  249,  254,  259,  264,  269,  280,  291,
+                       293,  293,  293,  300,  305,  312,  312,  317,
+                       324,  329,  334,  339,  344,  349,  356,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,  359,  359,  359,  359,  359,  359,  359,
+                       359,
+               },
+               {       /* Fourth byte 16-bit table 8. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    10,   15,   20,   25,   30,   35,
+                       40,   45,   50,   55,   60,   65,   70,   78,
+                       86,   94,   102,  110,  118,  126,  134,  142,
+                       150,  158,  166,  174,  182,  190,  207,  221,
+                       221,  226,  231,  236,  241,  246,  251,  256,
+                       261,  266,  271,  276,  281,  286,  291,  296,
+                       301,  306,  311,  316,  321,  326,  331,  336,
+                       341,  346,  351,  356,  361,  366,  371,  376,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,  381,  381,  381,  381,  381,  381,  381,
+                       381,
+               },
+               {       /* Fourth byte 16-bit table 9. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    15,   27,   42,   51,   66,   75,   84,
+                       102,  114,  123,  132,  141,  153,  165,  177,
+                       189,  201,  213,  225,  243,  249,  267,  285,
+                       300,  312,  330,  348,  360,  369,  378,  390,
+                       402,  417,  432,  441,  450,  462,  471,  480,
+                       486,  492,  501,  510,  528,  540,  555,  573,
+                       585,  594,  603,  621,  633,  651,  660,  675,
+                       684,  696,  705,  717,  732,  744,  759,  771,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,  777,  777,  777,  777,  777,  777,  777,
+                       777,
+               },
+               {       /* Fourth byte 16-bit table 10. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    15,   24,   33,   45,   54,   63,   72,
+                       87,   99,   105,  123,  132,  147,  159,  171,
+                       180,  189,  201,  207,  219,  234,  240,  258,
+                       267,  271,  275,  279,  283,  287,  291,  295,
+                       299,  303,  307,  312,  317,  322,  327,  332,
+                       337,  342,  347,  352,  357,  362,  367,  372,
+                       377,  382,  385,  387,  389,  392,  394,  396,
+                       398,  401,  404,  406,  412,  418,  424,  430,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,  442,  442,  442,  442,  442,  442,  442,
+                       442,
+               },
+               {       /* Fourth byte 16-bit table 11. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 12. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 13. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 14. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 15. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       128,  132,  136,  140,  144,  148,  152,  156,
+                       160,  164,  168,  172,  176,  180,  184,  188,
+                       192,  196,  200,  204,  208,  212,  216,  220,
+                       224,  228,  232,  236,  240,  244,  248,  252,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,  256,  256,  256,  256,  256,  256,  256,
+                       256,
+               },
+               {       /* Fourth byte 16-bit table 16. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   34,   38,
+                       42,   46,   50,   54,   58,   62,   66,   70,
+                       74,   78,   82,   86,   90,   94,   98,   102,
+                       106,  110,  114,  118,  122,  126,  130,  134,
+                       138,  142,  146,  150,  154,  158,  162,  166,
+                       170,  174,  178,  182,  186,  190,  194,  198,
+                       202,  206,  210,  214,  218,  222,  226,  230,
+                       234,  238,  242,  246,  250,  254,  258,  262,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,
+               },
+               {       /* Fourth byte 16-bit table 17. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  125,
+                       130,  135,  140,  145,  150,  156,  162,  168,
+                       174,  180,  186,  190,  194,  198,  202,  206,
+                       210,  214,  218,  222,  226,  230,  234,  238,
+                       242,  246,  250,  254,  258,  262,  266,  270,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,  274,  274,  274,  274,  274,  274,  274,
+                       274,
+               },
+               {       /* Fourth byte 16-bit table 18. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       98,   104,  110,  116,  122,  126,  130,  134,
+                       138,  142,  146,  150,  154,  158,  162,  166,
+                       170,  174,  178,  182,  186,  190,  194,  198,
+                       202,  206,  210,  214,  218,  222,  226,  230,
+                       234,  238,  242,  246,  250,  254,  258,  262,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,
+               },
+               {       /* Fourth byte 16-bit table 19. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  104,  108,  112,  116,  120,  124,
+                       130,  136,  140,  144,  148,  152,  156,  160,
+                       164,  168,  172,  176,  180,  184,  188,  192,
+                       196,  200,  204,  210,  216,  222,  226,  230,
+                       234,  238,  242,  246,  250,  254,  258,  262,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,  266,  266,  266,  266,  266,  266,  266,
+                       266,
+               },
+               {       /* Fourth byte 16-bit table 20. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   36,   42,
+                       48,   54,   60,   66,   72,   78,   84,   90,
+                       96,   102,  108,  114,  120,  126,  132,  138,
+                       144,  150,  156,  162,  168,  174,  180,  186,
+                       192,  198,  204,  210,  216,  222,  228,  234,
+                       240,  246,  252,  258,  264,  270,  276,  282,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,  288,  288,  288,  288,  288,  288,  288,
+                       288,
+               },
+               {       /* Fourth byte 16-bit table 21. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    6,    12,   18,   24,   30,   36,   42,
+                       48,   54,   60,   66,   72,   78,   84,   90,
+                       96,   96,   96,   102,  108,  114,  120,  126,
+                       132,  138,  144,  150,  156,  162,  168,  174,
+                       180,  186,  192,  198,  204,  210,  216,  222,
+                       228,  234,  240,  246,  252,  258,  264,  270,
+                       276,  282,  288,  294,  300,  306,  312,  318,
+                       324,  330,  336,  342,  348,  354,  360,  366,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,  372,  372,  372,  372,  372,  372,  372,
+                       372,
+               },
+               {       /* Fourth byte 16-bit table 22. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   17,   21,   25,   29,
+                       33,   37,   41,   45,   49,   53,   58,   62,
+                       66,   70,   74,   79,   83,   87,   91,   96,
+                       100,  104,  108,  112,  116,  121,  125,  129,
+                       133,  137,  141,  145,  149,  153,  157,  161,
+                       165,  169,  173,  177,  181,  185,  189,  193,
+                       197,  201,  205,  209,  213,  218,  222,  226,
+                       230,  235,  239,  243,  247,  251,  255,  259,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,
+               },
+               {       /* Fourth byte 16-bit table 23. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   44,   48,   52,   56,   60,
+                       64,   68,   72,   76,   80,   84,   88,   92,
+                       96,   100,  105,  109,  113,  117,  121,  125,
+                       129,  134,  139,  143,  147,  151,  155,  159,
+                       163,  167,  171,  175,  179,  184,  188,  192,
+                       196,  200,  205,  209,  213,  217,  221,  225,
+                       229,  233,  237,  241,  246,  250,  255,  259,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,  263,  263,  263,  263,  263,  263,  263,
+                       263,
+               },
+               {       /* Fourth byte 16-bit table 24. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   41,   45,   49,   53,   57,   61,
+                       66,   70,   75,   80,   84,   88,   92,   96,
+                       101,  106,  110,  114,  118,  122,  126,  130,
+                       134,  138,  142,  146,  150,  155,  159,  163,
+                       167,  171,  175,  179,  183,  187,  191,  195,
+                       199,  203,  207,  211,  215,  219,  223,  227,
+                       231,  236,  240,  244,  248,  252,  256,  261,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,
+               },
+               {       /* Fourth byte 16-bit table 25. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   28,
+                       32,   36,   40,   45,   49,   53,   57,   61,
+                       65,   69,   73,   77,   81,   85,   89,   93,
+                       97,   101,  105,  109,  113,  117,  122,  126,
+                       130,  134,  138,  142,  147,  151,  155,  159,
+                       163,  167,  171,  175,  179,  184,  188,  192,
+                       196,  201,  205,  209,  213,  217,  221,  225,
+                       230,  235,  240,  244,  249,  253,  257,  261,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,  265,  265,  265,  265,  265,  265,  265,
+                       265,
+               },
+               {       /* Fourth byte 16-bit table 26. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   24,   29,
+                       33,   37,   41,   45,   49,   53,   58,   62,
+                       66,   71,   76,   80,   84,   88,   92,   96,
+                       100,  104,  108,  112,  117,  121,  126,  130,
+                       135,  139,  143,  147,  152,  156,  160,  165,
+                       170,  174,  178,  182,  186,  190,  194,  198,
+                       202,  206,  210,  214,  218,  222,  227,  231,
+                       236,  240,  245,  249,  254,  259,  264,  268,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,
+               },
+               {       /* Fourth byte 16-bit table 27. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    9,    14,   19,   24,   28,   32,
+                       36,   40,   44,   48,   52,   56,   61,   65,
+                       69,   73,   77,   82,   86,   91,   96,   100,
+                       104,  108,  112,  116,  120,  125,  130,  135,
+                       139,  143,  148,  152,  156,  160,  165,  169,
+                       173,  177,  181,  185,  190,  194,  198,  202,
+                       206,  210,  214,  219,  224,  228,  233,  237,
+                       242,  246,  250,  254,  259,  264,  268,  273,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,  277,  277,  277,  277,  277,  277,  277,
+                       277,
+               },
+               {       /* Fourth byte 16-bit table 28. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    5,    9,    13,   17,   21,   25,   29,
+                       34,   39,   44,   49,   53,   57,   61,   65,
+                       69,   73,   77,   81,   85,   89,   93,   97,
+                       102,  106,  110,  114,  118,  122,  126,  130,
+                       134,  138,  142,  146,  150,  155,  160,  165,
+                       169,  173,  177,  181,  186,  190,  195,  199,
+                       203,  208,  213,  217,  221,  225,  229,  233,
+                       237,  241,  245,  249,  253,  257,  261,  265,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,  269,  269,  269,  269,  269,  269,  269,
+                       269,
+               },
+               {       /* Fourth byte 16-bit table 29. */
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    0,    0,    0,    0,    0,    0,    0,
+                       0,    4,    8,    12,   16,   20,   25,   29,
+                       33,   37,   41,   45,   50,   55,   59,   63,
+                       67,   71,   75,   79,   84,   88,   92,   96,
+                       100,  105,  110,  114,  118,  122,  127,  131,
+                       135,  140,  145,  149,  153,  157,  162,  166,
+                       170,  174,  178,  182,  186,  190,  195,  199,
+                       203,  207,  212,  216,  220,  224,  228,  233,
+                       238,  242,  246,  250,  255,  259,  264,  268,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,  272,  272,  272,  272,  272,  272,  272,
+                       272,
+               },
+       },
+};
+
+static const uchar_t u8_decomp_final_tbl[2][19370] = {
+       {
+               0x20, 0x20, 0xCC, 0x88, 0x61, 0x20, 0xCC, 0x84,
+               0x32, 0x33, 0x20, 0xCC, 0x81, 0xCE, 0xBC, 0x20,
+               0xCC, 0xA7, 0x31, 0x6F, 0x31, 0xE2, 0x81, 0x84,
+               0x34, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x33, 0xE2,
+               0x81, 0x84, 0x34, 0xF6, 0x41, 0xCC, 0x80, 0xF6,
+               0x41, 0xCC, 0x81, 0xF6, 0x41, 0xCC, 0x82, 0xF6,
+               0x41, 0xCC, 0x83, 0xF6, 0x41, 0xCC, 0x88, 0xF6,
+               0x41, 0xCC, 0x8A, 0xF6, 0x43, 0xCC, 0xA7, 0xF6,
+               0x45, 0xCC, 0x80, 0xF6, 0x45, 0xCC, 0x81, 0xF6,
+               0x45, 0xCC, 0x82, 0xF6, 0x45, 0xCC, 0x88, 0xF6,
+               0x49, 0xCC, 0x80, 0xF6, 0x49, 0xCC, 0x81, 0xF6,
+               0x49, 0xCC, 0x82, 0xF6, 0x49, 0xCC, 0x88, 0xF6,
+               0x4E, 0xCC, 0x83, 0xF6, 0x4F, 0xCC, 0x80, 0xF6,
+               0x4F, 0xCC, 0x81, 0xF6, 0x4F, 0xCC, 0x82, 0xF6,
+               0x4F, 0xCC, 0x83, 0xF6, 0x4F, 0xCC, 0x88, 0xF6,
+               0x55, 0xCC, 0x80, 0xF6, 0x55, 0xCC, 0x81, 0xF6,
+               0x55, 0xCC, 0x82, 0xF6, 0x55, 0xCC, 0x88, 0xF6,
+               0x59, 0xCC, 0x81, 0xF6, 0x61, 0xCC, 0x80, 0xF6,
+               0x61, 0xCC, 0x81, 0xF6, 0x61, 0xCC, 0x82, 0xF6,
+               0x61, 0xCC, 0x83, 0xF6, 0x61, 0xCC, 0x88, 0xF6,
+               0x61, 0xCC, 0x8A, 0xF6, 0x63, 0xCC, 0xA7, 0xF6,
+               0x65, 0xCC, 0x80, 0xF6, 0x65, 0xCC, 0x81, 0xF6,
+               0x65, 0xCC, 0x82, 0xF6, 0x65, 0xCC, 0x88, 0xF6,
+               0x69, 0xCC, 0x80, 0xF6, 0x69, 0xCC, 0x81, 0xF6,
+               0x69, 0xCC, 0x82, 0xF6, 0x69, 0xCC, 0x88, 0xF6,
+               0x6E, 0xCC, 0x83, 0xF6, 0x6F, 0xCC, 0x80, 0xF6,
+               0x6F, 0xCC, 0x81, 0xF6, 0x6F, 0xCC, 0x82, 0xF6,
+               0x6F, 0xCC, 0x83, 0xF6, 0x6F, 0xCC, 0x88, 0xF6,
+               0x75, 0xCC, 0x80, 0xF6, 0x75, 0xCC, 0x81, 0xF6,
+               0x75, 0xCC, 0x82, 0xF6, 0x75, 0xCC, 0x88, 0xF6,
+               0x79, 0xCC, 0x81, 0xF6, 0x79, 0xCC, 0x88, 0xF6,
+               0x41, 0xCC, 0x84, 0xF6, 0x61, 0xCC, 0x84, 0xF6,
+               0x41, 0xCC, 0x86, 0xF6, 0x61, 0xCC, 0x86, 0xF6,
+               0x41, 0xCC, 0xA8, 0xF6, 0x61, 0xCC, 0xA8, 0xF6,
+               0x43, 0xCC, 0x81, 0xF6, 0x63, 0xCC, 0x81, 0xF6,
+               0x43, 0xCC, 0x82, 0xF6, 0x63, 0xCC, 0x82, 0xF6,
+               0x43, 0xCC, 0x87, 0xF6, 0x63, 0xCC, 0x87, 0xF6,
+               0x43, 0xCC, 0x8C, 0xF6, 0x63, 0xCC, 0x8C, 0xF6,
+               0x44, 0xCC, 0x8C, 0xF6, 0x64, 0xCC, 0x8C, 0xF6,
+               0x45, 0xCC, 0x84, 0xF6, 0x65, 0xCC, 0x84, 0xF6,
+               0x45, 0xCC, 0x86, 0xF6, 0x65, 0xCC, 0x86, 0xF6,
+               0x45, 0xCC, 0x87, 0xF6, 0x65, 0xCC, 0x87, 0xF6,
+               0x45, 0xCC, 0xA8, 0xF6, 0x65, 0xCC, 0xA8, 0xF6,
+               0x45, 0xCC, 0x8C, 0xF6, 0x65, 0xCC, 0x8C, 0xF6,
+               0x47, 0xCC, 0x82, 0xF6, 0x67, 0xCC, 0x82, 0xF6,
+               0x47, 0xCC, 0x86, 0xF6, 0x67, 0xCC, 0x86, 0xF6,
+               0x47, 0xCC, 0x87, 0xF6, 0x67, 0xCC, 0x87, 0xF6,
+               0x47, 0xCC, 0xA7, 0xF6, 0x67, 0xCC, 0xA7, 0xF6,
+               0x48, 0xCC, 0x82, 0xF6, 0x68, 0xCC, 0x82, 0xF6,
+               0x49, 0xCC, 0x83, 0xF6, 0x69, 0xCC, 0x83, 0xF6,
+               0x49, 0xCC, 0x84, 0xF6, 0x69, 0xCC, 0x84, 0xF6,
+               0x49, 0xCC, 0x86, 0xF6, 0x69, 0xCC, 0x86, 0xF6,
+               0x49, 0xCC, 0xA8, 0xF6, 0x69, 0xCC, 0xA8, 0xF6,
+               0x49, 0xCC, 0x87, 0x49, 0x4A, 0x69, 0x6A, 0xF6,
+               0x4A, 0xCC, 0x82, 0xF6, 0x6A, 0xCC, 0x82, 0xF6,
+               0x4B, 0xCC, 0xA7, 0xF6, 0x6B, 0xCC, 0xA7, 0xF6,
+               0x4C, 0xCC, 0x81, 0xF6, 0x6C, 0xCC, 0x81, 0xF6,
+               0x4C, 0xCC, 0xA7, 0xF6, 0x6C, 0xCC, 0xA7, 0xF6,
+               0x4C, 0xCC, 0x8C, 0xF6, 0x6C, 0xCC, 0x8C, 0x4C,
+               0xC2, 0xB7, 0x6C, 0xC2, 0xB7, 0xF6, 0x4E, 0xCC,
+               0x81, 0xF6, 0x6E, 0xCC, 0x81, 0xF6, 0x4E, 0xCC,
+               0xA7, 0xF6, 0x6E, 0xCC, 0xA7, 0xF6, 0x4E, 0xCC,
+               0x8C, 0xF6, 0x6E, 0xCC, 0x8C, 0xCA, 0xBC, 0x6E,
+               0xF6, 0x4F, 0xCC, 0x84, 0xF6, 0x6F, 0xCC, 0x84,
+               0xF6, 0x4F, 0xCC, 0x86, 0xF6, 0x6F, 0xCC, 0x86,
+               0xF6, 0x4F, 0xCC, 0x8B, 0xF6, 0x6F, 0xCC, 0x8B,
+               0xF6, 0x52, 0xCC, 0x81, 0xF6, 0x72, 0xCC, 0x81,
+               0xF6, 0x52, 0xCC, 0xA7, 0xF6, 0x72, 0xCC, 0xA7,
+               0xF6, 0x52, 0xCC, 0x8C, 0xF6, 0x72, 0xCC, 0x8C,
+               0xF6, 0x53, 0xCC, 0x81, 0xF6, 0x73, 0xCC, 0x81,
+               0xF6, 0x53, 0xCC, 0x82, 0xF6, 0x73, 0xCC, 0x82,
+               0xF6, 0x53, 0xCC, 0xA7, 0xF6, 0x73, 0xCC, 0xA7,
+               0xF6, 0x53, 0xCC, 0x8C, 0xF6, 0x73, 0xCC, 0x8C,
+               0xF6, 0x54, 0xCC, 0xA7, 0xF6, 0x74, 0xCC, 0xA7,
+               0xF6, 0x54, 0xCC, 0x8C, 0xF6, 0x74, 0xCC, 0x8C,
+               0xF6, 0x55, 0xCC, 0x83, 0xF6, 0x75, 0xCC, 0x83,
+               0xF6, 0x55, 0xCC, 0x84, 0xF6, 0x75, 0xCC, 0x84,
+               0xF6, 0x55, 0xCC, 0x86, 0xF6, 0x75, 0xCC, 0x86,
+               0xF6, 0x55, 0xCC, 0x8A, 0xF6, 0x75, 0xCC, 0x8A,
+               0xF6, 0x55, 0xCC, 0x8B, 0xF6, 0x75, 0xCC, 0x8B,
+               0xF6, 0x55, 0xCC, 0xA8, 0xF6, 0x75, 0xCC, 0xA8,
+               0xF6, 0x57, 0xCC, 0x82, 0xF6, 0x77, 0xCC, 0x82,
+               0xF6, 0x59, 0xCC, 0x82, 0xF6, 0x79, 0xCC, 0x82,
+               0xF6, 0x59, 0xCC, 0x88, 0xF6, 0x5A, 0xCC, 0x81,
+               0xF6, 0x7A, 0xCC, 0x81, 0xF6, 0x5A, 0xCC, 0x87,
+               0xF6, 0x7A, 0xCC, 0x87, 0xF6, 0x5A, 0xCC, 0x8C,
+               0xF6, 0x7A, 0xCC, 0x8C, 0x73, 0xF6, 0x4F, 0xCC,
+               0x9B, 0xF6, 0x6F, 0xCC, 0x9B, 0xF6, 0x55, 0xCC,
+               0x9B, 0xF6, 0x75, 0xCC, 0x9B, 0x44, 0x5A, 0xCC,
+               0x8C, 0x44, 0x7A, 0xCC, 0x8C, 0x64, 0x7A, 0xCC,
+               0x8C, 0x4C, 0x4A, 0x4C, 0x6A, 0x6C, 0x6A, 0x4E,
+               0x4A, 0x4E, 0x6A, 0x6E, 0x6A, 0xF6, 0x41, 0xCC,
+               0x8C, 0xF6, 0x61, 0xCC, 0x8C, 0xF6, 0x49, 0xCC,
+               0x8C, 0xF6, 0x69, 0xCC, 0x8C, 0xF6, 0x4F, 0xCC,
+               0x8C, 0xF6, 0x6F, 0xCC, 0x8C, 0xF6, 0x55, 0xCC,
+               0x8C, 0xF6, 0x75, 0xCC, 0x8C, 0xF6, 0x55, 0xCC,
+               0x88, 0xCC, 0x84, 0xF6, 0x75, 0xCC, 0x88, 0xCC,
+               0x84, 0xF6, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0x75, 0xCC, 0x88, 0xCC, 0x81, 0xF6, 0x55, 0xCC,
+               0x88, 0xCC, 0x8C, 0xF6, 0x75, 0xCC, 0x88, 0xCC,
+               0x8C, 0xF6, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xF6,
+               0x75, 0xCC, 0x88, 0xCC, 0x80, 0xF6, 0x41, 0xCC,
+               0x88, 0xCC, 0x84, 0xF6, 0x61, 0xCC, 0x88, 0xCC,
+               0x84, 0xF6, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xF6,
+               0x61, 0xCC, 0x87, 0xCC, 0x84, 0xF6, 0xC3, 0x86,
+               0xCC, 0x84, 0xF6, 0xC3, 0xA6, 0xCC, 0x84, 0xF6,
+               0x47, 0xCC, 0x8C, 0xF6, 0x67, 0xCC, 0x8C, 0xF6,
+               0x4B, 0xCC, 0x8C, 0xF6, 0x6B, 0xCC, 0x8C, 0xF6,
+               0x4F, 0xCC, 0xA8, 0xF6, 0x6F, 0xCC, 0xA8, 0xF6,
+               0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xF6, 0x6F, 0xCC,
+               0xA8, 0xCC, 0x84, 0xF6, 0xC6, 0xB7, 0xCC, 0x8C,
+               0xF6, 0xCA, 0x92, 0xCC, 0x8C, 0xF6, 0x6A, 0xCC,
+               0x8C, 0x44, 0x5A, 0x44, 0x7A, 0x64, 0x7A, 0xF6,
+               0x47, 0xCC, 0x81, 0xF6, 0x67, 0xCC, 0x81, 0xF6,
+               0x4E, 0xCC, 0x80, 0xF6, 0x6E, 0xCC, 0x80, 0xF6,
+               0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xF6, 0x61, 0xCC,
+               0x8A, 0xCC, 0x81, 0xF6, 0xC3, 0x86, 0xCC, 0x81,
+               0xF6, 0xC3, 0xA6, 0xCC, 0x81, 0xF6, 0xC3, 0x98,
+               0xCC, 0x81, 0xF6, 0xC3, 0xB8, 0xCC, 0x81, 0xF6,
+               0x41, 0xCC, 0x8F, 0xF6, 0x61, 0xCC, 0x8F, 0xF6,
+               0x41, 0xCC, 0x91, 0xF6, 0x61, 0xCC, 0x91, 0xF6,
+               0x45, 0xCC, 0x8F, 0xF6, 0x65, 0xCC, 0x8F, 0xF6,
+               0x45, 0xCC, 0x91, 0xF6, 0x65, 0xCC, 0x91, 0xF6,
+               0x49, 0xCC, 0x8F, 0xF6, 0x69, 0xCC, 0x8F, 0xF6,
+               0x49, 0xCC, 0x91, 0xF6, 0x69, 0xCC, 0x91, 0xF6,
+               0x4F, 0xCC, 0x8F, 0xF6, 0x6F, 0xCC, 0x8F, 0xF6,
+               0x4F, 0xCC, 0x91, 0xF6, 0x6F, 0xCC, 0x91, 0xF6,
+               0x52, 0xCC, 0x8F, 0xF6, 0x72, 0xCC, 0x8F, 0xF6,
+               0x52, 0xCC, 0x91, 0xF6, 0x72, 0xCC, 0x91, 0xF6,
+               0x55, 0xCC, 0x8F, 0xF6, 0x75, 0xCC, 0x8F, 0xF6,
+               0x55, 0xCC, 0x91, 0xF6, 0x75, 0xCC, 0x91, 0xF6,
+               0x53, 0xCC, 0xA6, 0xF6, 0x73, 0xCC, 0xA6, 0xF6,
+               0x54, 0xCC, 0xA6, 0xF6, 0x74, 0xCC, 0xA6, 0xF6,
+               0x48, 0xCC, 0x8C, 0xF6, 0x68, 0xCC, 0x8C, 0xF6,
+               0x41, 0xCC, 0x87, 0xF6, 0x61, 0xCC, 0x87, 0xF6,
+               0x45, 0xCC, 0xA7, 0xF6, 0x65, 0xCC, 0xA7, 0xF6,
+               0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xF6, 0x6F, 0xCC,
+               0x88, 0xCC, 0x84, 0xF6, 0x4F, 0xCC, 0x83, 0xCC,
+               0x84, 0xF6, 0x6F, 0xCC, 0x83, 0xCC, 0x84, 0xF6,
+               0x4F, 0xCC, 0x87, 0xF6, 0x6F, 0xCC, 0x87, 0xF6,
+               0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xF6, 0x6F, 0xCC,
+               0x87, 0xCC, 0x84, 0xF6, 0x59, 0xCC, 0x84, 0xF6,
+               0x79, 0xCC, 0x84, 0x68, 0xC9, 0xA6, 0x6A, 0x72,
+               0xC9, 0xB9, 0xC9, 0xBB, 0xCA, 0x81, 0x77, 0x79,
+               0x20, 0xCC, 0x86, 0x20, 0xCC, 0x87, 0x20, 0xCC,
+               0x8A, 0x20, 0xCC, 0xA8, 0x20, 0xCC, 0x83, 0x20,
+               0xCC, 0x8B, 0xC9, 0xA3, 0x6C, 0x73, 0x78, 0xCA,
+               0x95, 0xF6, 0xCC, 0x80, 0xF6, 0xCC, 0x81, 0xF6,
+               0xCC, 0x93, 0xF6, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0xCA, 0xB9, 0x20, 0xCD, 0x85, 0xF6, 0x3B, 0x20,
+               0xCC, 0x81, 0xF5, 0x05, 0xC2, 0xA8, 0xCC, 0x81,
+               0x20, 0xCC, 0x88, 0xCC, 0x81, 0xF6, 0xCE, 0x91,
+               0xCC, 0x81, 0xF6, 0xC2, 0xB7, 0xF6, 0xCE, 0x95,
+               0xCC, 0x81, 0xF6, 0xCE, 0x97, 0xCC, 0x81, 0xF6,
+               0xCE, 0x99, 0xCC, 0x81, 0xF6, 0xCE, 0x9F, 0xCC,
+               0x81, 0xF6, 0xCE, 0xA5, 0xCC, 0x81, 0xF6, 0xCE,
+               0xA9, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC, 0x88,
+               0xCC, 0x81, 0xF6, 0xCE, 0x99, 0xCC, 0x88, 0xF6,
+               0xCE, 0xA5, 0xCC, 0x88, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x81, 0xF6, 0xCE, 0xB5, 0xCC, 0x81, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC, 0x81,
+               0xF6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0xCE, 0xB9, 0xCC, 0x88, 0xF6, 0xCF, 0x85, 0xCC,
+               0x88, 0xF6, 0xCE, 0xBF, 0xCC, 0x81, 0xF6, 0xCF,
+               0x85, 0xCC, 0x81, 0xF6, 0xCF, 0x89, 0xCC, 0x81,
+               0xCE, 0xB2, 0xCE, 0xB8, 0xCE, 0xA5, 0xF5, 0x05,
+               0xCF, 0x92, 0xCC, 0x81, 0xCE, 0xA5, 0xCC, 0x81,
+               0xF5, 0x05, 0xCF, 0x92, 0xCC, 0x88, 0xCE, 0xA5,
+               0xCC, 0x88, 0xCF, 0x86, 0xCF, 0x80, 0xCE, 0xBA,
+               0xCF, 0x81, 0xCF, 0x82, 0xCE, 0x98, 0xCE, 0xB5,
+               0xF6, 0xD0, 0x95, 0xCC, 0x80, 0xF6, 0xD0, 0x95,
+               0xCC, 0x88, 0xF6, 0xD0, 0x93, 0xCC, 0x81, 0xF6,
+               0xD0, 0x86, 0xCC, 0x88, 0xF6, 0xD0, 0x9A, 0xCC,
+               0x81, 0xF6, 0xD0, 0x98, 0xCC, 0x80, 0xF6, 0xD0,
+               0xA3, 0xCC, 0x86, 0xF6, 0xD0, 0x98, 0xCC, 0x86,
+               0xF6, 0xD0, 0xB8, 0xCC, 0x86, 0xF6, 0xD0, 0xB5,
+               0xCC, 0x80, 0xF6, 0xD0, 0xB5, 0xCC, 0x88, 0xF6,
+               0xD0, 0xB3, 0xCC, 0x81, 0xF6, 0xD1, 0x96, 0xCC,
+               0x88, 0xF6, 0xD0, 0xBA, 0xCC, 0x81, 0xF6, 0xD0,
+               0xB8, 0xCC, 0x80, 0xF6, 0xD1, 0x83, 0xCC, 0x86,
+               0xF6, 0xD1, 0xB4, 0xCC, 0x8F, 0xF6, 0xD1, 0xB5,
+               0xCC, 0x8F, 0xF6, 0xD0, 0x96, 0xCC, 0x86, 0xF6,
+               0xD0, 0xB6, 0xCC, 0x86, 0xF6, 0xD0, 0x90, 0xCC,
+               0x86, 0xF6, 0xD0, 0xB0, 0xCC, 0x86, 0xF6, 0xD0,
+               0x90, 0xCC, 0x88, 0xF6, 0xD0, 0xB0, 0xCC, 0x88,
+               0xF6, 0xD0, 0x95, 0xCC, 0x86, 0xF6, 0xD0, 0xB5,
+               0xCC, 0x86, 0xF6, 0xD3, 0x98, 0xCC, 0x88, 0xF6,
+               0xD3, 0x99, 0xCC, 0x88, 0xF6, 0xD0, 0x96, 0xCC,
+               0x88, 0xF6, 0xD0, 0xB6, 0xCC, 0x88, 0xF6, 0xD0,
+               0x97, 0xCC, 0x88, 0xF6, 0xD0, 0xB7, 0xCC, 0x88,
+               0xF6, 0xD0, 0x98, 0xCC, 0x84, 0xF6, 0xD0, 0xB8,
+               0xCC, 0x84, 0xF6, 0xD0, 0x98, 0xCC, 0x88, 0xF6,
+               0xD0, 0xB8, 0xCC, 0x88, 0xF6, 0xD0, 0x9E, 0xCC,
+               0x88, 0xF6, 0xD0, 0xBE, 0xCC, 0x88, 0xF6, 0xD3,
+               0xA8, 0xCC, 0x88, 0xF6, 0xD3, 0xA9, 0xCC, 0x88,
+               0xF6, 0xD0, 0xAD, 0xCC, 0x88, 0xF6, 0xD1, 0x8D,
+               0xCC, 0x88, 0xF6, 0xD0, 0xA3, 0xCC, 0x84, 0xF6,
+               0xD1, 0x83, 0xCC, 0x84, 0xF6, 0xD0, 0xA3, 0xCC,
+               0x88, 0xF6, 0xD1, 0x83, 0xCC, 0x88, 0xF6, 0xD0,
+               0xA3, 0xCC, 0x8B, 0xF6, 0xD1, 0x83, 0xCC, 0x8B,
+               0xF6, 0xD0, 0xA7, 0xCC, 0x88, 0xF6, 0xD1, 0x87,
+               0xCC, 0x88, 0xF6, 0xD0, 0xAB, 0xCC, 0x88, 0xF6,
+               0xD1, 0x8B, 0xCC, 0x88, 0xD5, 0xA5, 0xD6, 0x82,
+               0xF6, 0xD8, 0xA7, 0xD9, 0x93, 0xF6, 0xD8, 0xA7,
+               0xD9, 0x94, 0xF6, 0xD9, 0x88, 0xD9, 0x94, 0xF6,
+               0xD8, 0xA7, 0xD9, 0x95, 0xF6, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD8, 0xA7, 0xD9, 0xB4, 0xD9, 0x88, 0xD9,
+               0xB4, 0xDB, 0x87, 0xD9, 0xB4, 0xD9, 0x8A, 0xD9,
+               0xB4, 0xF6, 0xDB, 0x95, 0xD9, 0x94, 0xF6, 0xDB,
+               0x81, 0xD9, 0x94, 0xF6, 0xDB, 0x92, 0xD9, 0x94,
+               0xF6, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0xF6,
+               0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0,
+               0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA4,
+               0x95, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA4, 0x96,
+               0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA4, 0x97, 0xE0,
+               0xA4, 0xBC, 0xF6, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4,
+               0xBC, 0xF6, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4, 0xBC,
+               0xF6, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4, 0xBC, 0xF6,
+               0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0,
+               0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA7,
+               0x87, 0xE0, 0xA6, 0xBE, 0xF6, 0xE0, 0xA7, 0x87,
+               0xE0, 0xA7, 0x97, 0xF6, 0xE0, 0xA6, 0xA1, 0xE0,
+               0xA6, 0xBC, 0xF6, 0xE0, 0xA6, 0xA2, 0xE0, 0xA6,
+               0xBC, 0xF6, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6, 0xBC,
+               0xF6, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC, 0xF6,
+               0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0xF6, 0xE0,
+               0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0xF6, 0xE0, 0xA8,
+               0x97, 0xE0, 0xA8, 0xBC, 0xF6, 0xE0, 0xA8, 0x9C,
+               0xE0, 0xA8, 0xBC, 0xF6, 0xE0, 0xA8, 0xAB, 0xE0,
+               0xA8, 0xBC, 0xF6, 0xE0, 0xAD, 0x87, 0xE0, 0xAD,
+               0x96, 0xF6, 0xE0, 0xAD, 0x87, 0xE0, 0xAC, 0xBE,
+               0xF6, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0xF6,
+               0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC, 0xF6, 0xE0,
+               0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0xF6, 0xE0, 0xAE,
+               0x92, 0xE0, 0xAF, 0x97, 0xF6, 0xE0, 0xAF, 0x86,
+               0xE0, 0xAE, 0xBE, 0xF6, 0xE0, 0xAF, 0x87, 0xE0,
+               0xAE, 0xBE, 0xF6, 0xE0, 0xAF, 0x86, 0xE0, 0xAF,
+               0x97, 0xF6, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96,
+               0xF6, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0xF6,
+               0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0xF6, 0xE0,
+               0xB3, 0x86, 0xE0, 0xB3, 0x96, 0xF6, 0xE0, 0xB3,
+               0x86, 0xE0, 0xB3, 0x82, 0xF6, 0xE0, 0xB3, 0x86,
+               0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0xF6, 0xE0,
+               0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0xF6, 0xE0, 0xB5,
+               0x87, 0xE0, 0xB4, 0xBE, 0xF6, 0xE0, 0xB5, 0x86,
+               0xE0, 0xB5, 0x97, 0xF6, 0xE0, 0xB7, 0x99, 0xE0,
+               0xB7, 0x8A, 0xF6, 0xE0, 0xB7, 0x99, 0xE0, 0xB7,
+               0x8F, 0xF6, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F,
+               0xE0, 0xB7, 0x8A, 0xF6, 0xE0, 0xB7, 0x99, 0xE0,
+               0xB7, 0x9F, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2,
+               0xE0, 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0xE0, 0xBA,
+               0xAB, 0xE0, 0xBA, 0x99, 0xE0, 0xBA, 0xAB, 0xE0,
+               0xBA, 0xA1, 0xE0, 0xBC, 0x8B, 0xF6, 0xE0, 0xBD,
+               0x82, 0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBD, 0x8C,
+               0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBD, 0x91, 0xE0,
+               0xBE, 0xB7, 0xF6, 0xE0, 0xBD, 0x96, 0xE0, 0xBE,
+               0xB7, 0xF6, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7,
+               0xF6, 0xE0, 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0xF6,
+               0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0xF6, 0xE0,
+               0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xF6, 0xE0, 0xBE,
+               0xB2, 0xE0, 0xBE, 0x80, 0xE0, 0xBE, 0xB2, 0xE0,
+               0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xF6, 0xE0, 0xBE,
+               0xB3, 0xE0, 0xBE, 0x80, 0xE0, 0xBE, 0xB3, 0xE0,
+               0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xF6, 0xE0, 0xBD,
+               0xB1, 0xE0, 0xBE, 0x80, 0xF6, 0xE0, 0xBE, 0x92,
+               0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBE, 0x9C, 0xE0,
+               0xBE, 0xB7, 0xF6, 0xE0, 0xBE, 0xA1, 0xE0, 0xBE,
+               0xB7, 0xF6, 0xE0, 0xBE, 0xA6, 0xE0, 0xBE, 0xB7,
+               0xF6, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, 0xF6,
+               0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0xF6, 0xE1,
+               0x80, 0xA5, 0xE1, 0x80, 0xAE, 0xF6, 0x41, 0xCC,
+               0xA5, 0xF6, 0x61, 0xCC, 0xA5, 0xF6, 0x42, 0xCC,
+               0x87, 0xF6, 0x62, 0xCC, 0x87, 0xF6, 0x42, 0xCC,
+               0xA3, 0xF6, 0x62, 0xCC, 0xA3, 0xF6, 0x42, 0xCC,
+               0xB1, 0xF6, 0x62, 0xCC, 0xB1, 0xF6, 0x43, 0xCC,
+               0xA7, 0xCC, 0x81, 0xF6, 0x63, 0xCC, 0xA7, 0xCC,
+               0x81, 0xF6, 0x44, 0xCC, 0x87, 0xF6, 0x64, 0xCC,
+               0x87, 0xF6, 0x44, 0xCC, 0xA3, 0xF6, 0x64, 0xCC,
+               0xA3, 0xF6, 0x44, 0xCC, 0xB1, 0xF6, 0x64, 0xCC,
+               0xB1, 0xF6, 0x44, 0xCC, 0xA7, 0xF6, 0x64, 0xCC,
+               0xA7, 0xF6, 0x44, 0xCC, 0xAD, 0xF6, 0x64, 0xCC,
+               0xAD, 0xF6, 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xF6,
+               0x65, 0xCC, 0x84, 0xCC, 0x80, 0xF6, 0x45, 0xCC,
+               0x84, 0xCC, 0x81, 0xF6, 0x65, 0xCC, 0x84, 0xCC,
+               0x81, 0xF6, 0x45, 0xCC, 0xAD, 0xF6, 0x65, 0xCC,
+               0xAD, 0xF6, 0x45, 0xCC, 0xB0, 0xF6, 0x65, 0xCC,
+               0xB0, 0xF6, 0x45, 0xCC, 0xA7, 0xCC, 0x86, 0xF6,
+               0x65, 0xCC, 0xA7, 0xCC, 0x86, 0xF6, 0x46, 0xCC,
+               0x87, 0xF6, 0x66, 0xCC, 0x87, 0xF6, 0x47, 0xCC,
+               0x84, 0xF6, 0x67, 0xCC, 0x84, 0xF6, 0x48, 0xCC,
+               0x87, 0xF6, 0x68, 0xCC, 0x87, 0xF6, 0x48, 0xCC,
+               0xA3, 0xF6, 0x68, 0xCC, 0xA3, 0xF6, 0x48, 0xCC,
+               0x88, 0xF6, 0x68, 0xCC, 0x88, 0xF6, 0x48, 0xCC,
+               0xA7, 0xF6, 0x68, 0xCC, 0xA7, 0xF6, 0x48, 0xCC,
+               0xAE, 0xF6, 0x68, 0xCC, 0xAE, 0xF6, 0x49, 0xCC,
+               0xB0, 0xF6, 0x69, 0xCC, 0xB0, 0xF6, 0x49, 0xCC,
+               0x88, 0xCC, 0x81, 0xF6, 0x69, 0xCC, 0x88, 0xCC,
+               0x81, 0xF6, 0x4B, 0xCC, 0x81, 0xF6, 0x6B, 0xCC,
+               0x81, 0xF6, 0x4B, 0xCC, 0xA3, 0xF6, 0x6B, 0xCC,
+               0xA3, 0xF6, 0x4B, 0xCC, 0xB1, 0xF6, 0x6B, 0xCC,
+               0xB1, 0xF6, 0x4C, 0xCC, 0xA3, 0xF6, 0x6C, 0xCC,
+               0xA3, 0xF6, 0x4C, 0xCC, 0xA3, 0xCC, 0x84, 0xF6,
+               0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xF6, 0x4C, 0xCC,
+               0xB1, 0xF6, 0x6C, 0xCC, 0xB1, 0xF6, 0x4C, 0xCC,
+               0xAD, 0xF6, 0x6C, 0xCC, 0xAD, 0xF6, 0x4D, 0xCC,
+               0x81, 0xF6, 0x6D, 0xCC, 0x81, 0xF6, 0x4D, 0xCC,
+               0x87, 0xF6, 0x6D, 0xCC, 0x87, 0xF6, 0x4D, 0xCC,
+               0xA3, 0xF6, 0x6D, 0xCC, 0xA3, 0xF6, 0x4E, 0xCC,
+               0x87, 0xF6, 0x6E, 0xCC, 0x87, 0xF6, 0x4E, 0xCC,
+               0xA3, 0xF6, 0x6E, 0xCC, 0xA3, 0xF6, 0x4E, 0xCC,
+               0xB1, 0xF6, 0x6E, 0xCC, 0xB1, 0xF6, 0x4E, 0xCC,
+               0xAD, 0xF6, 0x6E, 0xCC, 0xAD, 0xF6, 0x4F, 0xCC,
+               0x83, 0xCC, 0x81, 0xF6, 0x6F, 0xCC, 0x83, 0xCC,
+               0x81, 0xF6, 0x4F, 0xCC, 0x83, 0xCC, 0x88, 0xF6,
+               0x6F, 0xCC, 0x83, 0xCC, 0x88, 0xF6, 0x4F, 0xCC,
+               0x84, 0xCC, 0x80, 0xF6, 0x6F, 0xCC, 0x84, 0xCC,
+               0x80, 0xF6, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xF6,
+               0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xF6, 0x50, 0xCC,
+               0x81, 0xF6, 0x70, 0xCC, 0x81, 0xF6, 0x50, 0xCC,
+               0x87, 0xF6, 0x70, 0xCC, 0x87, 0xF6, 0x52, 0xCC,
+               0x87, 0xF6, 0x72, 0xCC, 0x87, 0xF6, 0x52, 0xCC,
+               0xA3, 0xF6, 0x72, 0xCC, 0xA3, 0xF6, 0x52, 0xCC,
+               0xA3, 0xCC, 0x84, 0xF6, 0x72, 0xCC, 0xA3, 0xCC,
+               0x84, 0xF6, 0x52, 0xCC, 0xB1, 0xF6, 0x72, 0xCC,
+               0xB1, 0xF6, 0x53, 0xCC, 0x87, 0xF6, 0x73, 0xCC,
+               0x87, 0xF6, 0x53, 0xCC, 0xA3, 0xF6, 0x73, 0xCC,
+               0xA3, 0xF6, 0x53, 0xCC, 0x81, 0xCC, 0x87, 0xF6,
+               0x73, 0xCC, 0x81, 0xCC, 0x87, 0xF6, 0x53, 0xCC,
+               0x8C, 0xCC, 0x87, 0xF6, 0x73, 0xCC, 0x8C, 0xCC,
+               0x87, 0xF6, 0x53, 0xCC, 0xA3, 0xCC, 0x87, 0xF6,
+               0x73, 0xCC, 0xA3, 0xCC, 0x87, 0xF6, 0x54, 0xCC,
+               0x87, 0xF6, 0x74, 0xCC, 0x87, 0xF6, 0x54, 0xCC,
+               0xA3, 0xF6, 0x74, 0xCC, 0xA3, 0xF6, 0x54, 0xCC,
+               0xB1, 0xF6, 0x74, 0xCC, 0xB1, 0xF6, 0x54, 0xCC,
+               0xAD, 0xF6, 0x74, 0xCC, 0xAD, 0xF6, 0x55, 0xCC,
+               0xA4, 0xF6, 0x75, 0xCC, 0xA4, 0xF6, 0x55, 0xCC,
+               0xB0, 0xF6, 0x75, 0xCC, 0xB0, 0xF6, 0x55, 0xCC,
+               0xAD, 0xF6, 0x75, 0xCC, 0xAD, 0xF6, 0x55, 0xCC,
+               0x83, 0xCC, 0x81, 0xF6, 0x75, 0xCC, 0x83, 0xCC,
+               0x81, 0xF6, 0x55, 0xCC, 0x84, 0xCC, 0x88, 0xF6,
+               0x75, 0xCC, 0x84, 0xCC, 0x88, 0xF6, 0x56, 0xCC,
+               0x83, 0xF6, 0x76, 0xCC, 0x83, 0xF6, 0x56, 0xCC,
+               0xA3, 0xF6, 0x76, 0xCC, 0xA3, 0xF6, 0x57, 0xCC,
+               0x80, 0xF6, 0x77, 0xCC, 0x80, 0xF6, 0x57, 0xCC,
+               0x81, 0xF6, 0x77, 0xCC, 0x81, 0xF6, 0x57, 0xCC,
+               0x88, 0xF6, 0x77, 0xCC, 0x88, 0xF6, 0x57, 0xCC,
+               0x87, 0xF6, 0x77, 0xCC, 0x87, 0xF6, 0x57, 0xCC,
+               0xA3, 0xF6, 0x77, 0xCC, 0xA3, 0xF6, 0x58, 0xCC,
+               0x87, 0xF6, 0x78, 0xCC, 0x87, 0xF6, 0x58, 0xCC,
+               0x88, 0xF6, 0x78, 0xCC, 0x88, 0xF6, 0x59, 0xCC,
+               0x87, 0xF6, 0x79, 0xCC, 0x87, 0xF6, 0x5A, 0xCC,
+               0x82, 0xF6, 0x7A, 0xCC, 0x82, 0xF6, 0x5A, 0xCC,
+               0xA3, 0xF6, 0x7A, 0xCC, 0xA3, 0xF6, 0x5A, 0xCC,
+               0xB1, 0xF6, 0x7A, 0xCC, 0xB1, 0xF6, 0x68, 0xCC,
+               0xB1, 0xF6, 0x74, 0xCC, 0x88, 0xF6, 0x77, 0xCC,
+               0x8A, 0xF6, 0x79, 0xCC, 0x8A, 0x61, 0xCA, 0xBE,
+               0xF5, 0x05, 0xC5, 0xBF, 0xCC, 0x87, 0x73, 0xCC,
+               0x87, 0xF6, 0x41, 0xCC, 0xA3, 0xF6, 0x61, 0xCC,
+               0xA3, 0xF6, 0x41, 0xCC, 0x89, 0xF6, 0x61, 0xCC,
+               0x89, 0xF6, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xF6,
+               0x61, 0xCC, 0x82, 0xCC, 0x81, 0xF6, 0x41, 0xCC,
+               0x82, 0xCC, 0x80, 0xF6, 0x61, 0xCC, 0x82, 0xCC,
+               0x80, 0xF6, 0x41, 0xCC, 0x82, 0xCC, 0x89, 0xF6,
+               0x61, 0xCC, 0x82, 0xCC, 0x89, 0xF6, 0x41, 0xCC,
+               0x82, 0xCC, 0x83, 0xF6, 0x61, 0xCC, 0x82, 0xCC,
+               0x83, 0xF6, 0x41, 0xCC, 0xA3, 0xCC, 0x82, 0xF6,
+               0x61, 0xCC, 0xA3, 0xCC, 0x82, 0xF6, 0x41, 0xCC,
+               0x86, 0xCC, 0x81, 0xF6, 0x61, 0xCC, 0x86, 0xCC,
+               0x81, 0xF6, 0x41, 0xCC, 0x86, 0xCC, 0x80, 0xF6,
+               0x61, 0xCC, 0x86, 0xCC, 0x80, 0xF6, 0x41, 0xCC,
+               0x86, 0xCC, 0x89, 0xF6, 0x61, 0xCC, 0x86, 0xCC,
+               0x89, 0xF6, 0x41, 0xCC, 0x86, 0xCC, 0x83, 0xF6,
+               0x61, 0xCC, 0x86, 0xCC, 0x83, 0xF6, 0x41, 0xCC,
+               0xA3, 0xCC, 0x86, 0xF6, 0x61, 0xCC, 0xA3, 0xCC,
+               0x86, 0xF6, 0x45, 0xCC, 0xA3, 0xF6, 0x65, 0xCC,
+               0xA3, 0xF6, 0x45, 0xCC, 0x89, 0xF6, 0x65, 0xCC,
+               0x89, 0xF6, 0x45, 0xCC, 0x83, 0xF6, 0x65, 0xCC,
+               0x83, 0xF6, 0x45, 0xCC, 0x82, 0xCC, 0x81, 0xF6,
+               0x65, 0xCC, 0x82, 0xCC, 0x81, 0xF6, 0x45, 0xCC,
+               0x82, 0xCC, 0x80, 0xF6, 0x65, 0xCC, 0x82, 0xCC,
+               0x80, 0xF6, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xF6,
+               0x65, 0xCC, 0x82, 0xCC, 0x89, 0xF6, 0x45, 0xCC,
+               0x82, 0xCC, 0x83, 0xF6, 0x65, 0xCC, 0x82, 0xCC,
+               0x83, 0xF6, 0x45, 0xCC, 0xA3, 0xCC, 0x82, 0xF6,
+               0x65, 0xCC, 0xA3, 0xCC, 0x82, 0xF6, 0x49, 0xCC,
+               0x89, 0xF6, 0x69, 0xCC, 0x89, 0xF6, 0x49, 0xCC,
+               0xA3, 0xF6, 0x69, 0xCC, 0xA3, 0xF6, 0x4F, 0xCC,
+               0xA3, 0xF6, 0x6F, 0xCC, 0xA3, 0xF6, 0x4F, 0xCC,
+               0x89, 0xF6, 0x6F, 0xCC, 0x89, 0xF6, 0x4F, 0xCC,
+               0x82, 0xCC, 0x81, 0xF6, 0x6F, 0xCC, 0x82, 0xCC,
+               0x81, 0xF6, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xF6,
+               0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xF6, 0x4F, 0xCC,
+               0x82, 0xCC, 0x89, 0xF6, 0x6F, 0xCC, 0x82, 0xCC,
+               0x89, 0xF6, 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xF6,
+               0x6F, 0xCC, 0x82, 0xCC, 0x83, 0xF6, 0x4F, 0xCC,
+               0xA3, 0xCC, 0x82, 0xF6, 0x6F, 0xCC, 0xA3, 0xCC,
+               0x82, 0xF6, 0x4F, 0xCC, 0x9B, 0xCC, 0x81, 0xF6,
+               0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0xF6, 0x4F, 0xCC,
+               0x9B, 0xCC, 0x80, 0xF6, 0x6F, 0xCC, 0x9B, 0xCC,
+               0x80, 0xF6, 0x4F, 0xCC, 0x9B, 0xCC, 0x89, 0xF6,
+               0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0xF6, 0x4F, 0xCC,
+               0x9B, 0xCC, 0x83, 0xF6, 0x6F, 0xCC, 0x9B, 0xCC,
+               0x83, 0xF6, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3, 0xF6,
+               0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xF6, 0x55, 0xCC,
+               0xA3, 0xF6, 0x75, 0xCC, 0xA3, 0xF6, 0x55, 0xCC,
+               0x89, 0xF6, 0x75, 0xCC, 0x89, 0xF6, 0x55, 0xCC,
+               0x9B, 0xCC, 0x81, 0xF6, 0x75, 0xCC, 0x9B, 0xCC,
+               0x81, 0xF6, 0x55, 0xCC, 0x9B, 0xCC, 0x80, 0xF6,
+               0x75, 0xCC, 0x9B, 0xCC, 0x80, 0xF6, 0x55, 0xCC,
+               0x9B, 0xCC, 0x89, 0xF6, 0x75, 0xCC, 0x9B, 0xCC,
+               0x89, 0xF6, 0x55, 0xCC, 0x9B, 0xCC, 0x83, 0xF6,
+               0x75, 0xCC, 0x9B, 0xCC, 0x83, 0xF6, 0x55, 0xCC,
+               0x9B, 0xCC, 0xA3, 0xF6, 0x75, 0xCC, 0x9B, 0xCC,
+               0xA3, 0xF6, 0x59, 0xCC, 0x80, 0xF6, 0x79, 0xCC,
+               0x80, 0xF6, 0x59, 0xCC, 0xA3, 0xF6, 0x79, 0xCC,
+               0xA3, 0xF6, 0x59, 0xCC, 0x89, 0xF6, 0x79, 0xCC,
+               0x89, 0xF6, 0x59, 0xCC, 0x83, 0xF6, 0x79, 0xCC,
+               0x83, 0xF6, 0xCE, 0xB1, 0xCC, 0x93, 0xF6, 0xCE,
+               0xB1, 0xCC, 0x94, 0xF6, 0xCE, 0xB1, 0xCC, 0x93,
+               0xCC, 0x80, 0xF6, 0xCE, 0xB1, 0xCC, 0x94, 0xCC,
+               0x80, 0xF6, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81,
+               0xF6, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xF6, 0xCE,
+               0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE, 0x91,
+               0xCC, 0x93, 0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xF6,
+               0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE,
+               0x91, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE, 0x91,
+               0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0x91, 0xCC,
+               0x94, 0xCC, 0x81, 0xF6, 0xCE, 0x91, 0xCC, 0x93,
+               0xCD, 0x82, 0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xCD,
+               0x82, 0xF6, 0xCE, 0xB5, 0xCC, 0x93, 0xF6, 0xCE,
+               0xB5, 0xCC, 0x94, 0xF6, 0xCE, 0xB5, 0xCC, 0x93,
+               0xCC, 0x80, 0xF6, 0xCE, 0xB5, 0xCC, 0x94, 0xCC,
+               0x80, 0xF6, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81,
+               0xF6, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xF6,
+               0xCE, 0x95, 0xCC, 0x93, 0xF6, 0xCE, 0x95, 0xCC,
+               0x94, 0xF6, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80,
+               0xF6, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xF6,
+               0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE,
+               0x95, 0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x93, 0xF6, 0xCE, 0xB7, 0xCC, 0x94, 0xF6,
+               0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xB7, 0xCC,
+               0x94, 0xCC, 0x81, 0xF6, 0xCE, 0xB7, 0xCC, 0x93,
+               0xCD, 0x82, 0xF6, 0xCE, 0xB7, 0xCC, 0x94, 0xCD,
+               0x82, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xF6, 0xCE,
+               0x97, 0xCC, 0x94, 0xF6, 0xCE, 0x97, 0xCC, 0x93,
+               0xCC, 0x80, 0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
+               0x80, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81,
+               0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xF6,
+               0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xF6, 0xCE,
+               0x97, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE, 0xB9,
+               0xCC, 0x93, 0xF6, 0xCE, 0xB9, 0xCC, 0x94, 0xF6,
+               0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE,
+               0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE, 0xB9,
+               0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC,
+               0x94, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC, 0x93,
+               0xCD, 0x82, 0xF6, 0xCE, 0xB9, 0xCC, 0x94, 0xCD,
+               0x82, 0xF6, 0xCE, 0x99, 0xCC, 0x93, 0xF6, 0xCE,
+               0x99, 0xCC, 0x94, 0xF6, 0xCE, 0x99, 0xCC, 0x93,
+               0xCC, 0x80, 0xF6, 0xCE, 0x99, 0xCC, 0x94, 0xCC,
+               0x80, 0xF6, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81,
+               0xF6, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xF6,
+               0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xF6, 0xCE,
+               0x99, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE, 0xBF,
+               0xCC, 0x93, 0xF6, 0xCE, 0xBF, 0xCC, 0x94, 0xF6,
+               0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE,
+               0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE, 0xBF,
+               0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xBF, 0xCC,
+               0x94, 0xCC, 0x81, 0xF6, 0xCE, 0x9F, 0xCC, 0x93,
+               0xF6, 0xCE, 0x9F, 0xCC, 0x94, 0xF6, 0xCE, 0x9F,
+               0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE, 0x9F, 0xCC,
+               0x94, 0xCC, 0x80, 0xF6, 0xCE, 0x9F, 0xCC, 0x93,
+               0xCC, 0x81, 0xF6, 0xCE, 0x9F, 0xCC, 0x94, 0xCC,
+               0x81, 0xF6, 0xCF, 0x85, 0xCC, 0x93, 0xF6, 0xCF,
+               0x85, 0xCC, 0x94, 0xF6, 0xCF, 0x85, 0xCC, 0x93,
+               0xCC, 0x80, 0xF6, 0xCF, 0x85, 0xCC, 0x94, 0xCC,
+               0x80, 0xF6, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81,
+               0xF6, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xF6,
+               0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xF6, 0xCF,
+               0x85, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE, 0xA5,
+               0xCC, 0x94, 0xF6, 0xCE, 0xA5, 0xCC, 0x94, 0xCC,
+               0x80, 0xF6, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81,
+               0xF6, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xF6,
+               0xCF, 0x89, 0xCC, 0x93, 0xF6, 0xCF, 0x89, 0xCC,
+               0x94, 0xF6, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x80,
+               0xF6, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x80, 0xF6,
+               0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCF,
+               0x89, 0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCF, 0x89,
+               0xCC, 0x93, 0xCD, 0x82, 0xF6, 0xCF, 0x89, 0xCC,
+               0x94, 0xCD, 0x82, 0xF6, 0xCE, 0xA9, 0xCC, 0x93,
+               0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xF6, 0xCE, 0xA9,
+               0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE, 0xA9, 0xCC,
+               0x94, 0xCC, 0x80, 0xF6, 0xCE, 0xA9, 0xCC, 0x93,
+               0xCC, 0x81, 0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC,
+               0x81, 0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x82,
+               0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x80, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x81, 0xF6, 0xCE, 0xB5, 0xCC, 0x80, 0xF6, 0xCE,
+               0xB5, 0xCC, 0x81, 0xF6, 0xCE, 0xB7, 0xCC, 0x80,
+               0xF6, 0xCE, 0xB7, 0xCC, 0x81, 0xF6, 0xCE, 0xB9,
+               0xCC, 0x80, 0xF6, 0xCE, 0xB9, 0xCC, 0x81, 0xF6,
+               0xCE, 0xBF, 0xCC, 0x80, 0xF6, 0xCE, 0xBF, 0xCC,
+               0x81, 0xF6, 0xCF, 0x85, 0xCC, 0x80, 0xF6, 0xCF,
+               0x85, 0xCC, 0x81, 0xF6, 0xCF, 0x89, 0xCC, 0x80,
+               0xF6, 0xCF, 0x89, 0xCC, 0x81, 0xF6, 0xCE, 0xB1,
+               0xCC, 0x93, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x94, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCC, 0x93,
+               0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB1,
+               0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85,
+               0xF6, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD,
+               0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85,
+               0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xF6,
+               0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85,
+               0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD,
+               0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81,
+               0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x93,
+               0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC,
+               0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x93, 0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCC,
+               0x94, 0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCC, 0x93,
+               0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCC,
+               0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xF6,
+               0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85,
+               0xF6, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCD,
+               0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85,
+               0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xF6,
+               0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85,
+               0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCD,
+               0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81,
+               0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x93,
+               0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC,
+               0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCF, 0x89,
+               0xCC, 0x93, 0xCD, 0x85, 0xF6, 0xCF, 0x89, 0xCC,
+               0x94, 0xCD, 0x85, 0xF6, 0xCF, 0x89, 0xCC, 0x93,
+               0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCF, 0x89, 0xCC,
+               0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCF, 0x89,
+               0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF6, 0xCF,
+               0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xF6,
+               0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85,
+               0xF6, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD,
+               0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85,
+               0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xF6,
+               0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85,
+               0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD,
+               0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81,
+               0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x93,
+               0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC,
+               0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0xB1,
+               0xCC, 0x86, 0xF6, 0xCE, 0xB1, 0xCC, 0x84, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB1, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCC, 0x81,
+               0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCD, 0x82, 0xF6,
+               0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE,
+               0x91, 0xCC, 0x86, 0xF6, 0xCE, 0x91, 0xCC, 0x84,
+               0xF6, 0xCE, 0x91, 0xCC, 0x80, 0xF6, 0xCE, 0x91,
+               0xCC, 0x81, 0xF6, 0xCE, 0x91, 0xCD, 0x85, 0x20,
+               0xCC, 0x93, 0xF6, 0xCE, 0xB9, 0x20, 0xCC, 0x93,
+               0x20, 0xCD, 0x82, 0xF5, 0x05, 0xC2, 0xA8, 0xCD,
+               0x82, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB7,
+               0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCC, 0x81, 0xCD,
+               0x85, 0xF6, 0xCE, 0xB7, 0xCD, 0x82, 0xF6, 0xCE,
+               0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x95,
+               0xCC, 0x80, 0xF6, 0xCE, 0x95, 0xCC, 0x81, 0xF6,
+               0xCE, 0x97, 0xCC, 0x80, 0xF6, 0xCE, 0x97, 0xCC,
+               0x81, 0xF6, 0xCE, 0x97, 0xCD, 0x85, 0xF5, 0x06,
+               0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0x20, 0xCC, 0x93,
+               0xCC, 0x80, 0xF5, 0x06, 0xE1, 0xBE, 0xBF, 0xCC,
+               0x81, 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xF5, 0x06,
+               0xE1, 0xBE, 0xBF, 0xCD, 0x82, 0x20, 0xCC, 0x93,
+               0xCD, 0x82, 0xF6, 0xCE, 0xB9, 0xCC, 0x86, 0xF6,
+               0xCE, 0xB9, 0xCC, 0x84, 0xF6, 0xCE, 0xB9, 0xCC,
+               0x88, 0xCC, 0x80, 0xF6, 0xCE, 0xB9, 0xCC, 0x88,
+               0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCD, 0x82, 0xF6,
+               0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xF6, 0xCE,
+               0x99, 0xCC, 0x86, 0xF6, 0xCE, 0x99, 0xCC, 0x84,
+               0xF6, 0xCE, 0x99, 0xCC, 0x80, 0xF6, 0xCE, 0x99,
+               0xCC, 0x81, 0xF5, 0x06, 0xE1, 0xBF, 0xBE, 0xCC,
+               0x80, 0x20, 0xCC, 0x94, 0xCC, 0x80, 0xF5, 0x06,
+               0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x20, 0xCC, 0x94,
+               0xCC, 0x81, 0xF5, 0x06, 0xE1, 0xBF, 0xBE, 0xCD,
+               0x82, 0x20, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCF,
+               0x85, 0xCC, 0x86, 0xF6, 0xCF, 0x85, 0xCC, 0x84,
+               0xF6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xF6,
+               0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xF6, 0xCF,
+               0x81, 0xCC, 0x93, 0xF6, 0xCF, 0x81, 0xCC, 0x94,
+               0xF6, 0xCF, 0x85, 0xCD, 0x82, 0xF6, 0xCF, 0x85,
+               0xCC, 0x88, 0xCD, 0x82, 0xF6, 0xCE, 0xA5, 0xCC,
+               0x86, 0xF6, 0xCE, 0xA5, 0xCC, 0x84, 0xF6, 0xCE,
+               0xA5, 0xCC, 0x80, 0xF6, 0xCE, 0xA5, 0xCC, 0x81,
+               0xF6, 0xCE, 0xA1, 0xCC, 0x94, 0xF5, 0x05, 0xC2,
+               0xA8, 0xCC, 0x80, 0x20, 0xCC, 0x88, 0xCC, 0x80,
+               0xF5, 0x05, 0xC2, 0xA8, 0xCC, 0x81, 0x20, 0xCC,
+               0x88, 0xCC, 0x81, 0xF6, 0x60, 0xF6, 0xCF, 0x89,
+               0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCF, 0x89, 0xCD,
+               0x85, 0xF6, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85,
+               0xF6, 0xCF, 0x89, 0xCD, 0x82, 0xF6, 0xCF, 0x89,
+               0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x9F, 0xCC,
+               0x80, 0xF6, 0xCE, 0x9F, 0xCC, 0x81, 0xF6, 0xCE,
+               0xA9, 0xCC, 0x80, 0xF6, 0xCE, 0xA9, 0xCC, 0x81,
+               0xF6, 0xCE, 0xA9, 0xCD, 0x85, 0xF5, 0x03, 0xC2,
+               0xB4, 0x20, 0xCC, 0x81, 0x20, 0xCC, 0x94, 0xF5,
+               0x04, 0xE2, 0x80, 0x82, 0x20, 0xF5, 0x04, 0xE2,
+               0x80, 0x83, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+               0x20, 0x20, 0x20, 0x20, 0xE2, 0x80, 0x90, 0x20,
+               0xCC, 0xB3, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
+               0x20, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2,
+               0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+               0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80,
+               0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x21,
+               0x21, 0x20, 0xCC, 0x85, 0x3F, 0x3F, 0x3F, 0x21,
+               0x21, 0x3F, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+               0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x20, 0x30,
+               0x69, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B,
+               0xE2, 0x88, 0x92, 0x3D, 0x28, 0x29, 0x6E, 0x30,
+               0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0x2B, 0xE2, 0x88, 0x92, 0x3D, 0x28, 0x29,
+               0x52, 0x73, 0x61, 0x2F, 0x63, 0x61, 0x2F, 0x73,
+               0x43, 0xC2, 0xB0, 0x43, 0x63, 0x2F, 0x6F, 0x63,
+               0x2F, 0x75, 0xC6, 0x90, 0xC2, 0xB0, 0x46, 0x67,
+               0x48, 0x48, 0x48, 0x68, 0xC4, 0xA7, 0x49, 0x49,
+               0x4C, 0x6C, 0x4E, 0x4E, 0x6F, 0x50, 0x51, 0x52,
+               0x52, 0x52, 0x53, 0x4D, 0x54, 0x45, 0x4C, 0x54,
+               0x4D, 0x5A, 0xF6, 0xCE, 0xA9, 0x5A, 0xF6, 0x4B,
+               0xF6, 0x41, 0xCC, 0x8A, 0x42, 0x43, 0x65, 0x45,
+               0x46, 0x4D, 0x6F, 0xD7, 0x90, 0xD7, 0x91, 0xD7,
+               0x92, 0xD7, 0x93, 0x69, 0xCE, 0xB3, 0xCE, 0x93,
+               0xCE, 0xA0, 0xE2, 0x88, 0x91, 0x44, 0x64, 0x65,
+               0x69, 0x6A, 0x31, 0xE2, 0x81, 0x84, 0x33, 0x32,
+               0xE2, 0x81, 0x84, 0x33, 0x31, 0xE2, 0x81, 0x84,
+               0x35, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x33, 0xE2,
+               0x81, 0x84, 0x35, 0x34, 0xE2, 0x81, 0x84, 0x35,
+               0x31, 0xE2, 0x81, 0x84, 0x36, 0x35, 0xE2, 0x81,
+               0x84, 0x36, 0x31, 0xE2, 0x81, 0x84, 0x38, 0x33,
+               0xE2, 0x81, 0x84, 0x38, 0x35, 0xE2, 0x81, 0x84,
+               0x38, 0x37, 0xE2, 0x81, 0x84, 0x38, 0x31, 0xE2,
+               0x81, 0x84, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+               0x49, 0x56, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49,
+               0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x58,
+               0x49, 0x58, 0x49, 0x49, 0x4C, 0x43, 0x44, 0x4D,
+               0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76,
+               0x76, 0x76, 0x69, 0x76, 0x69, 0x69, 0x76, 0x69,
+               0x69, 0x69, 0x69, 0x78, 0x78, 0x78, 0x69, 0x78,
+               0x69, 0x69, 0x6C, 0x63, 0x64, 0x6D, 0xF6, 0xE2,
+               0x86, 0x90, 0xCC, 0xB8, 0xF6, 0xE2, 0x86, 0x92,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x86, 0x94, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x87, 0x94, 0xCC, 0xB8, 0xF6, 0xE2, 0x87, 0x92,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x88, 0x83, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x88, 0x8B, 0xCC, 0xB8, 0xF6, 0xE2, 0x88, 0xA3,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x88, 0xA5, 0xCC, 0xB8,
+               0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
+               0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2,
+               0x88, 0xAE, 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE,
+               0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0xF6, 0xE2,
+               0x88, 0xBC, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0x83,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0x85, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0x88, 0xCC, 0xB8, 0xF6, 0x3D,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xA1, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0x8D, 0xCC, 0xB8, 0xF6, 0x3C,
+               0xCC, 0xB8, 0xF6, 0x3E, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0xA4, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xA5,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xB2, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0xB3, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0xB6, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xB7,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xBA, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0x82, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0x83,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0x86, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0x87, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0xA2, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xA8,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xA9, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0xAB, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0xBC, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xBD,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0x91, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0xB2, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xB3,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0xF6, 0xE3,
+               0x80, 0x88, 0xF6, 0xE3, 0x80, 0x89, 0x31, 0x32,
+               0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x31,
+               0x30, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x31,
+               0x34, 0x31, 0x35, 0x31, 0x36, 0x31, 0x37, 0x31,
+               0x38, 0x31, 0x39, 0x32, 0x30, 0x28, 0x31, 0x29,
+               0x28, 0x32, 0x29, 0x28, 0x33, 0x29, 0x28, 0x34,
+               0x29, 0x28, 0x35, 0x29, 0x28, 0x36, 0x29, 0x28,
+               0x37, 0x29, 0x28, 0x38, 0x29, 0x28, 0x39, 0x29,
+               0x28, 0x31, 0x30, 0x29, 0x28, 0x31, 0x31, 0x29,
+               0x28, 0x31, 0x32, 0x29, 0x28, 0x31, 0x33, 0x29,
+               0x28, 0x31, 0x34, 0x29, 0x28, 0x31, 0x35, 0x29,
+               0x28, 0x31, 0x36, 0x29, 0x28, 0x31, 0x37, 0x29,
+               0x28, 0x31, 0x38, 0x29, 0x28, 0x31, 0x39, 0x29,
+               0x28, 0x32, 0x30, 0x29, 0x31, 0x2E, 0x32, 0x2E,
+               0x33, 0x2E, 0x34, 0x2E, 0x35, 0x2E, 0x36, 0x2E,
+               0x37, 0x2E, 0x38, 0x2E, 0x39, 0x2E, 0x31, 0x30,
+               0x2E, 0x31, 0x31, 0x2E, 0x31, 0x32, 0x2E, 0x31,
+               0x33, 0x2E, 0x31, 0x34, 0x2E, 0x31, 0x35, 0x2E,
+               0x31, 0x36, 0x2E, 0x31, 0x37, 0x2E, 0x31, 0x38,
+               0x2E, 0x31, 0x39, 0x2E, 0x32, 0x30, 0x2E, 0x28,
+               0x61, 0x29, 0x28, 0x62, 0x29, 0x28, 0x63, 0x29,
+               0x28, 0x64, 0x29, 0x28, 0x65, 0x29, 0x28, 0x66,
+               0x29, 0x28, 0x67, 0x29, 0x28, 0x68, 0x29, 0x28,
+               0x69, 0x29, 0x28, 0x6A, 0x29, 0x28, 0x6B, 0x29,
+               0x28, 0x6C, 0x29, 0x28, 0x6D, 0x29, 0x28, 0x6E,
+               0x29, 0x28, 0x6F, 0x29, 0x28, 0x70, 0x29, 0x28,
+               0x71, 0x29, 0x28, 0x72, 0x29, 0x28, 0x73, 0x29,
+               0x28, 0x74, 0x29, 0x28, 0x75, 0x29, 0x28, 0x76,
+               0x29, 0x28, 0x77, 0x29, 0x28, 0x78, 0x29, 0x28,
+               0x79, 0x29, 0x28, 0x7A, 0x29, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x30, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
+               0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x3A, 0x3A,
+               0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0xF6, 0xE2,
+               0xAB, 0x9D, 0xCC, 0xB8, 0xE6, 0xAF, 0x8D, 0xE9,
+               0xBE, 0x9F, 0xE4, 0xB8, 0x80, 0xE4, 0xB8, 0xA8,
+               0xE4, 0xB8, 0xB6, 0xE4, 0xB8, 0xBF, 0xE4, 0xB9,
+               0x99, 0xE4, 0xBA, 0x85, 0xE4, 0xBA, 0x8C, 0xE4,
+               0xBA, 0xA0, 0xE4, 0xBA, 0xBA, 0xE5, 0x84, 0xBF,
+               0xE5, 0x85, 0xA5, 0xE5, 0x85, 0xAB, 0xE5, 0x86,
+               0x82, 0xE5, 0x86, 0x96, 0xE5, 0x86, 0xAB, 0xE5,
+               0x87, 0xA0, 0xE5, 0x87, 0xB5, 0xE5, 0x88, 0x80,
+               0xE5, 0x8A, 0x9B, 0xE5, 0x8B, 0xB9, 0xE5, 0x8C,
+               0x95, 0xE5, 0x8C, 0x9A, 0xE5, 0x8C, 0xB8, 0xE5,
+               0x8D, 0x81, 0xE5, 0x8D, 0x9C, 0xE5, 0x8D, 0xA9,
+               0xE5, 0x8E, 0x82, 0xE5, 0x8E, 0xB6, 0xE5, 0x8F,
+               0x88, 0xE5, 0x8F, 0xA3, 0xE5, 0x9B, 0x97, 0xE5,
+               0x9C, 0x9F, 0xE5, 0xA3, 0xAB, 0xE5, 0xA4, 0x82,
+               0xE5, 0xA4, 0x8A, 0xE5, 0xA4, 0x95, 0xE5, 0xA4,
+               0xA7, 0xE5, 0xA5, 0xB3, 0xE5, 0xAD, 0x90, 0xE5,
+               0xAE, 0x80, 0xE5, 0xAF, 0xB8, 0xE5, 0xB0, 0x8F,
+               0xE5, 0xB0, 0xA2, 0xE5, 0xB0, 0xB8, 0xE5, 0xB1,
+               0xAE, 0xE5, 0xB1, 0xB1, 0xE5, 0xB7, 0x9B, 0xE5,
+               0xB7, 0xA5, 0xE5, 0xB7, 0xB1, 0xE5, 0xB7, 0xBE,
+               0xE5, 0xB9, 0xB2, 0xE5, 0xB9, 0xBA, 0xE5, 0xB9,
+               0xBF, 0xE5, 0xBB, 0xB4, 0xE5, 0xBB, 0xBE, 0xE5,
+               0xBC, 0x8B, 0xE5, 0xBC, 0x93, 0xE5, 0xBD, 0x90,
+               0xE5, 0xBD, 0xA1, 0xE5, 0xBD, 0xB3, 0xE5, 0xBF,
+               0x83, 0xE6, 0x88, 0x88, 0xE6, 0x88, 0xB6, 0xE6,
+               0x89, 0x8B, 0xE6, 0x94, 0xAF, 0xE6, 0x94, 0xB4,
+               0xE6, 0x96, 0x87, 0xE6, 0x96, 0x97, 0xE6, 0x96,
+               0xA4, 0xE6, 0x96, 0xB9, 0xE6, 0x97, 0xA0, 0xE6,
+               0x97, 0xA5, 0xE6, 0x9B, 0xB0, 0xE6, 0x9C, 0x88,
+               0xE6, 0x9C, 0xA8, 0xE6, 0xAC, 0xA0, 0xE6, 0xAD,
+               0xA2, 0xE6, 0xAD, 0xB9, 0xE6, 0xAE, 0xB3, 0xE6,
+               0xAF, 0x8B, 0xE6, 0xAF, 0x94, 0xE6, 0xAF, 0x9B,
+               0xE6, 0xB0, 0x8F, 0xE6, 0xB0, 0x94, 0xE6, 0xB0,
+               0xB4, 0xE7, 0x81, 0xAB, 0xE7, 0x88, 0xAA, 0xE7,
+               0x88, 0xB6, 0xE7, 0x88, 0xBB, 0xE7, 0x88, 0xBF,
+               0xE7, 0x89, 0x87, 0xE7, 0x89, 0x99, 0xE7, 0x89,
+               0x9B, 0xE7, 0x8A, 0xAC, 0xE7, 0x8E, 0x84, 0xE7,
+               0x8E, 0x89, 0xE7, 0x93, 0x9C, 0xE7, 0x93, 0xA6,
+               0xE7, 0x94, 0x98, 0xE7, 0x94, 0x9F, 0xE7, 0x94,
+               0xA8, 0xE7, 0x94, 0xB0, 0xE7, 0x96, 0x8B, 0xE7,
+               0x96, 0x92, 0xE7, 0x99, 0xB6, 0xE7, 0x99, 0xBD,
+               0xE7, 0x9A, 0xAE, 0xE7, 0x9A, 0xBF, 0xE7, 0x9B,
+               0xAE, 0xE7, 0x9F, 0x9B, 0xE7, 0x9F, 0xA2, 0xE7,
+               0x9F, 0xB3, 0xE7, 0xA4, 0xBA, 0xE7, 0xA6, 0xB8,
+               0xE7, 0xA6, 0xBE, 0xE7, 0xA9, 0xB4, 0xE7, 0xAB,
+               0x8B, 0xE7, 0xAB, 0xB9, 0xE7, 0xB1, 0xB3, 0xE7,
+               0xB3, 0xB8, 0xE7, 0xBC, 0xB6, 0xE7, 0xBD, 0x91,
+               0xE7, 0xBE, 0x8A, 0xE7, 0xBE, 0xBD, 0xE8, 0x80,
+               0x81, 0xE8, 0x80, 0x8C, 0xE8, 0x80, 0x92, 0xE8,
+               0x80, 0xB3, 0xE8, 0x81, 0xBF, 0xE8, 0x82, 0x89,
+               0xE8, 0x87, 0xA3, 0xE8, 0x87, 0xAA, 0xE8, 0x87,
+               0xB3, 0xE8, 0x87, 0xBC, 0xE8, 0x88, 0x8C, 0xE8,
+               0x88, 0x9B, 0xE8, 0x88, 0x9F, 0xE8, 0x89, 0xAE,
+               0xE8, 0x89, 0xB2, 0xE8, 0x89, 0xB8, 0xE8, 0x99,
+               0x8D, 0xE8, 0x99, 0xAB, 0xE8, 0xA1, 0x80, 0xE8,
+               0xA1, 0x8C, 0xE8, 0xA1, 0xA3, 0xE8, 0xA5, 0xBE,
+               0xE8, 0xA6, 0x8B, 0xE8, 0xA7, 0x92, 0xE8, 0xA8,
+               0x80, 0xE8, 0xB0, 0xB7, 0xE8, 0xB1, 0x86, 0xE8,
+               0xB1, 0x95, 0xE8, 0xB1, 0xB8, 0xE8, 0xB2, 0x9D,
+               0xE8, 0xB5, 0xA4, 0xE8, 0xB5, 0xB0, 0xE8, 0xB6,
+               0xB3, 0xE8, 0xBA, 0xAB, 0xE8, 0xBB, 0x8A, 0xE8,
+               0xBE, 0x9B, 0xE8, 0xBE, 0xB0, 0xE8, 0xBE, 0xB5,
+               0xE9, 0x82, 0x91, 0xE9, 0x85, 0x89, 0xE9, 0x87,
+               0x86, 0xE9, 0x87, 0x8C, 0xE9, 0x87, 0x91, 0xE9,
+               0x95, 0xB7, 0xE9, 0x96, 0x80, 0xE9, 0x98, 0x9C,
+               0xE9, 0x9A, 0xB6, 0xE9, 0x9A, 0xB9, 0xE9, 0x9B,
+               0xA8, 0xE9, 0x9D, 0x91, 0xE9, 0x9D, 0x9E, 0xE9,
+               0x9D, 0xA2, 0xE9, 0x9D, 0xA9, 0xE9, 0x9F, 0x8B,
+               0xE9, 0x9F, 0xAD, 0xE9, 0x9F, 0xB3, 0xE9, 0xA0,
+               0x81, 0xE9, 0xA2, 0xA8, 0xE9, 0xA3, 0x9B, 0xE9,
+               0xA3, 0x9F, 0xE9, 0xA6, 0x96, 0xE9, 0xA6, 0x99,
+               0xE9, 0xA6, 0xAC, 0xE9, 0xAA, 0xA8, 0xE9, 0xAB,
+               0x98, 0xE9, 0xAB, 0x9F, 0xE9, 0xAC, 0xA5, 0xE9,
+               0xAC, 0xAF, 0xE9, 0xAC, 0xB2, 0xE9, 0xAC, 0xBC,
+               0xE9, 0xAD, 0x9A, 0xE9, 0xB3, 0xA5, 0xE9, 0xB9,
+               0xB5, 0xE9, 0xB9, 0xBF, 0xE9, 0xBA, 0xA5, 0xE9,
+               0xBA, 0xBB, 0xE9, 0xBB, 0x83, 0xE9, 0xBB, 0x8D,
+               0xE9, 0xBB, 0x91, 0xE9, 0xBB, 0xB9, 0xE9, 0xBB,
+               0xBD, 0xE9, 0xBC, 0x8E, 0xE9, 0xBC, 0x93, 0xE9,
+               0xBC, 0xA0, 0xE9, 0xBC, 0xBB, 0xE9, 0xBD, 0x8A,
+               0xE9, 0xBD, 0x92, 0xE9, 0xBE, 0x8D, 0xE9, 0xBE,
+               0x9C, 0xE9, 0xBE, 0xA0, 0x20, 0xE3, 0x80, 0x92,
+               0xE5, 0x8D, 0x81, 0xE5, 0x8D, 0x84, 0xE5, 0x8D,
+               0x85, 0xF6, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x81, 0x91, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81,
+               0x93, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0x95,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0x97, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x81, 0x99, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x81, 0xA1, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81,
+               0xA4, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0xA6,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0xA8, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x81, 0xAF, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A,
+               0xF6, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0xF6, 0xE3,
+               0x81, 0xB5, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81,
+               0xB5, 0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x81, 0xB8,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0xB8, 0xE3,
+               0x82, 0x9A, 0xF6, 0xE3, 0x81, 0xBB, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A,
+               0xF6, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x20,
+               0xE3, 0x82, 0x99, 0x20, 0xE3, 0x82, 0x9A, 0xF6,
+               0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0xE3, 0x82,
+               0x88, 0xE3, 0x82, 0x8A, 0xF6, 0xE3, 0x82, 0xAB,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82, 0xAD, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x82, 0xAF, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x82, 0xB7, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82,
+               0xB9, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82, 0xBB,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82, 0xBD, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x82, 0xBF, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x83, 0x88, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83,
+               0x8F, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83, 0x8F,
+               0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x83, 0x92, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x83, 0x92, 0xE3, 0x82,
+               0x9A, 0xF6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0xF6,
+               0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x83, 0x98, 0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x83,
+               0x9B, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83, 0x9B,
+               0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x82, 0xA6, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x83, 0xAF, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x83, 0xBD, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB3,
+               0xE3, 0x83, 0x88, 0xE1, 0x84, 0x80, 0xE1, 0x84,
+               0x81, 0xE1, 0x86, 0xAA, 0xE1, 0x84, 0x82, 0xE1,
+               0x86, 0xAC, 0xE1, 0x86, 0xAD, 0xE1, 0x84, 0x83,
+               0xE1, 0x84, 0x84, 0xE1, 0x84, 0x85, 0xE1, 0x86,
+               0xB0, 0xE1, 0x86, 0xB1, 0xE1, 0x86, 0xB2, 0xE1,
+               0x86, 0xB3, 0xE1, 0x86, 0xB4, 0xE1, 0x86, 0xB5,
+               0xE1, 0x84, 0x9A, 0xE1, 0x84, 0x86, 0xE1, 0x84,
+               0x87, 0xE1, 0x84, 0x88, 0xE1, 0x84, 0xA1, 0xE1,
+               0x84, 0x89, 0xE1, 0x84, 0x8A, 0xE1, 0x84, 0x8B,
+               0xE1, 0x84, 0x8C, 0xE1, 0x84, 0x8D, 0xE1, 0x84,
+               0x8E, 0xE1, 0x84, 0x8F, 0xE1, 0x84, 0x90, 0xE1,
+               0x84, 0x91, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1,
+               0xE1, 0x85, 0xA2, 0xE1, 0x85, 0xA3, 0xE1, 0x85,
+               0xA4, 0xE1, 0x85, 0xA5, 0xE1, 0x85, 0xA6, 0xE1,
+               0x85, 0xA7, 0xE1, 0x85, 0xA8, 0xE1, 0x85, 0xA9,
+               0xE1, 0x85, 0xAA, 0xE1, 0x85, 0xAB, 0xE1, 0x85,
+               0xAC, 0xE1, 0x85, 0xAD, 0xE1, 0x85, 0xAE, 0xE1,
+               0x85, 0xAF, 0xE1, 0x85, 0xB0, 0xE1, 0x85, 0xB1,
+               0xE1, 0x85, 0xB2, 0xE1, 0x85, 0xB3, 0xE1, 0x85,
+               0xB4, 0xE1, 0x85, 0xB5, 0xE1, 0x85, 0xA0, 0xE1,
+               0x84, 0x94, 0xE1, 0x84, 0x95, 0xE1, 0x87, 0x87,
+               0xE1, 0x87, 0x88, 0xE1, 0x87, 0x8C, 0xE1, 0x87,
+               0x8E, 0xE1, 0x87, 0x93, 0xE1, 0x87, 0x97, 0xE1,
+               0x87, 0x99, 0xE1, 0x84, 0x9C, 0xE1, 0x87, 0x9D,
+               0xE1, 0x87, 0x9F, 0xE1, 0x84, 0x9D, 0xE1, 0x84,
+               0x9E, 0xE1, 0x84, 0xA0, 0xE1, 0x84, 0xA2, 0xE1,
+               0x84, 0xA3, 0xE1, 0x84, 0xA7, 0xE1, 0x84, 0xA9,
+               0xE1, 0x84, 0xAB, 0xE1, 0x84, 0xAC, 0xE1, 0x84,
+               0xAD, 0xE1, 0x84, 0xAE, 0xE1, 0x84, 0xAF, 0xE1,
+               0x84, 0xB2, 0xE1, 0x84, 0xB6, 0xE1, 0x85, 0x80,
+               0xE1, 0x85, 0x87, 0xE1, 0x85, 0x8C, 0xE1, 0x87,
+               0xB1, 0xE1, 0x87, 0xB2, 0xE1, 0x85, 0x97, 0xE1,
+               0x85, 0x98, 0xE1, 0x85, 0x99, 0xE1, 0x86, 0x84,
+               0xE1, 0x86, 0x85, 0xE1, 0x86, 0x88, 0xE1, 0x86,
+               0x91, 0xE1, 0x86, 0x92, 0xE1, 0x86, 0x94, 0xE1,
+               0x86, 0x9E, 0xE1, 0x86, 0xA1, 0xE4, 0xB8, 0x80,
+               0xE4, 0xBA, 0x8C, 0xE4, 0xB8, 0x89, 0xE5, 0x9B,
+               0x9B, 0xE4, 0xB8, 0x8A, 0xE4, 0xB8, 0xAD, 0xE4,
+               0xB8, 0x8B, 0xE7, 0x94, 0xB2, 0xE4, 0xB9, 0x99,
+               0xE4, 0xB8, 0x99, 0xE4, 0xB8, 0x81, 0xE5, 0xA4,
+               0xA9, 0xE5, 0x9C, 0xB0, 0xE4, 0xBA, 0xBA, 0x28,
+               0xE1, 0x84, 0x80, 0x29, 0x28, 0xE1, 0x84, 0x82,
+               0x29, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x28, 0xE1,
+               0x84, 0x85, 0x29, 0x28, 0xE1, 0x84, 0x86, 0x29,
+               0x28, 0xE1, 0x84, 0x87, 0x29, 0x28, 0xE1, 0x84,
+               0x89, 0x29, 0x28, 0xE1, 0x84, 0x8B, 0x29, 0x28,
+               0xE1, 0x84, 0x8C, 0x29, 0x28, 0xE1, 0x84, 0x8E,
+               0x29, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x28, 0xE1,
+               0x84, 0x90, 0x29, 0x28, 0xE1, 0x84, 0x91, 0x29,
+               0x28, 0xE1, 0x84, 0x92, 0x29, 0x28, 0xE1, 0x84,
+               0x80, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x82, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x83, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x85, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x86, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x87, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x89, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x8E, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x8F, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x90, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x91, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x92, 0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84,
+               0x8C, 0xE1, 0x85, 0xAE, 0x29, 0x28, 0xE4, 0xB8,
+               0x80, 0x29, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x28,
+               0xE4, 0xB8, 0x89, 0x29, 0x28, 0xE5, 0x9B, 0x9B,
+               0x29, 0x28, 0xE4, 0xBA, 0x94, 0x29, 0x28, 0xE5,
+               0x85, 0xAD, 0x29, 0x28, 0xE4, 0xB8, 0x83, 0x29,
+               0x28, 0xE5, 0x85, 0xAB, 0x29, 0x28, 0xE4, 0xB9,
+               0x9D, 0x29, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x28,
+               0xE6, 0x9C, 0x88, 0x29, 0x28, 0xE7, 0x81, 0xAB,
+               0x29, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x28, 0xE6,
+               0x9C, 0xA8, 0x29, 0x28, 0xE9, 0x87, 0x91, 0x29,
+               0x28, 0xE5, 0x9C, 0x9F, 0x29, 0x28, 0xE6, 0x97,
+               0xA5, 0x29, 0x28, 0xE6, 0xA0, 0xAA, 0x29, 0x28,
+               0xE6, 0x9C, 0x89, 0x29, 0x28, 0xE7, 0xA4, 0xBE,
+               0x29, 0x28, 0xE5, 0x90, 0x8D, 0x29, 0x28, 0xE7,
+               0x89, 0xB9, 0x29, 0x28, 0xE8, 0xB2, 0xA1, 0x29,
+               0x28, 0xE7, 0xA5, 0x9D, 0x29, 0x28, 0xE5, 0x8A,
+               0xB4, 0x29, 0x28, 0xE4, 0xBB, 0xA3, 0x29, 0x28,
+               0xE5, 0x91, 0xBC, 0x29, 0x28, 0xE5, 0xAD, 0xA6,
+               0x29, 0x28, 0xE7, 0x9B, 0xA3, 0x29, 0x28, 0xE4,
+               0xBC, 0x81, 0x29, 0x28, 0xE8, 0xB3, 0x87, 0x29,
+               0x28, 0xE5, 0x8D, 0x94, 0x29, 0x28, 0xE7, 0xA5,
+               0xAD, 0x29, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x28,
+               0xE8, 0x87, 0xAA, 0x29, 0x28, 0xE8, 0x87, 0xB3,
+               0x29, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33, 0x32,
+               0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32,
+               0x38, 0x32, 0x39, 0x33, 0x30, 0x33, 0x31, 0x33,
+               0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35, 0xE1,
+               0x84, 0x80, 0xE1, 0x84, 0x82, 0xE1, 0x84, 0x83,
+               0xE1, 0x84, 0x85, 0xE1, 0x84, 0x86, 0xE1, 0x84,
+               0x87, 0xE1, 0x84, 0x89, 0xE1, 0x84, 0x8B, 0xE1,
+               0x84, 0x8C, 0xE1, 0x84, 0x8E, 0xE1, 0x84, 0x8F,
+               0xE1, 0x84, 0x90, 0xE1, 0x84, 0x91, 0xE1, 0x84,
+               0x92, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0xE1,
+               0x84, 0x82, 0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x83,
+               0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x85, 0xE1, 0x85,
+               0xA1, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0xE1,
+               0x84, 0x87, 0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x89,
+               0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x8B, 0xE1, 0x85,
+               0xA1, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0xE1,
+               0x84, 0x8E, 0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x8F,
+               0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x90, 0xE1, 0x85,
+               0xA1, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0xE1,
+               0x84, 0x92, 0xE1, 0x85, 0xA1, 0xE4, 0xB8, 0x80,
+               0xE4, 0xBA, 0x8C, 0xE4, 0xB8, 0x89, 0xE5, 0x9B,
+               0x9B, 0xE4, 0xBA, 0x94, 0xE5, 0x85, 0xAD, 0xE4,
+               0xB8, 0x83, 0xE5, 0x85, 0xAB, 0xE4, 0xB9, 0x9D,
+               0xE5, 0x8D, 0x81, 0xE6, 0x9C, 0x88, 0xE7, 0x81,
+               0xAB, 0xE6, 0xB0, 0xB4, 0xE6, 0x9C, 0xA8, 0xE9,
+               0x87, 0x91, 0xE5, 0x9C, 0x9F, 0xE6, 0x97, 0xA5,
+               0xE6, 0xA0, 0xAA, 0xE6, 0x9C, 0x89, 0xE7, 0xA4,
+               0xBE, 0xE5, 0x90, 0x8D, 0xE7, 0x89, 0xB9, 0xE8,
+               0xB2, 0xA1, 0xE7, 0xA5, 0x9D, 0xE5, 0x8A, 0xB4,
+               0xE7, 0xA7, 0x98, 0xE7, 0x94, 0xB7, 0xE5, 0xA5,
+               0xB3, 0xE9, 0x81, 0xA9, 0xE5, 0x84, 0xAA, 0xE5,
+               0x8D, 0xB0, 0xE6, 0xB3, 0xA8, 0xE9, 0xA0, 0x85,
+               0xE4, 0xBC, 0x91, 0xE5, 0x86, 0x99, 0xE6, 0xAD,
+               0xA3, 0xE4, 0xB8, 0x8A, 0xE4, 0xB8, 0xAD, 0xE4,
+               0xB8, 0x8B, 0xE5, 0xB7, 0xA6, 0xE5, 0x8F, 0xB3,
+               0xE5, 0x8C, 0xBB, 0xE5, 0xAE, 0x97, 0xE5, 0xAD,
+               0xA6, 0xE7, 0x9B, 0xA3, 0xE4, 0xBC, 0x81, 0xE8,
+               0xB3, 0x87, 0xE5, 0x8D, 0x94, 0xE5, 0xA4, 0x9C,
+               0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39,
+               0x34, 0x30, 0x34, 0x31, 0x34, 0x32, 0x34, 0x33,
+               0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37,
+               0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x31, 0xE6,
+               0x9C, 0x88, 0x32, 0xE6, 0x9C, 0x88, 0x33, 0xE6,
+               0x9C, 0x88, 0x34, 0xE6, 0x9C, 0x88, 0x35, 0xE6,
+               0x9C, 0x88, 0x36, 0xE6, 0x9C, 0x88, 0x37, 0xE6,
+               0x9C, 0x88, 0x38, 0xE6, 0x9C, 0x88, 0x39, 0xE6,
+               0x9C, 0x88, 0x31, 0x30, 0xE6, 0x9C, 0x88, 0x31,
+               0x31, 0xE6, 0x9C, 0x88, 0x31, 0x32, 0xE6, 0x9C,
+               0x88, 0xE3, 0x82, 0xA2, 0xE3, 0x82, 0xA4, 0xE3,
+               0x82, 0xA6, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xAA,
+               0xE3, 0x82, 0xAB, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+               0xAF, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0xB3, 0xE3,
+               0x82, 0xB5, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0xB9,
+               0xE3, 0x82, 0xBB, 0xE3, 0x82, 0xBD, 0xE3, 0x82,
+               0xBF, 0xE3, 0x83, 0x81, 0xE3, 0x83, 0x84, 0xE3,
+               0x83, 0x86, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0x8A,
+               0xE3, 0x83, 0x8B, 0xE3, 0x83, 0x8C, 0xE3, 0x83,
+               0x8D, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x8F, 0xE3,
+               0x83, 0x92, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0x98,
+               0xE3, 0x83, 0x9B, 0xE3, 0x83, 0x9E, 0xE3, 0x83,
+               0x9F, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0xA1, 0xE3,
+               0x83, 0xA2, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xA6,
+               0xE3, 0x83, 0xA8, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
+               0xAA, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0xAC, 0xE3,
+               0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0xB0,
+               0xE3, 0x83, 0xB1, 0xE3, 0x83, 0xB2, 0xE3, 0x82,
+               0xA2, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3,
+               0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xA2,
+               0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+               0xA1, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xB3, 0xE3,
+               0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA2,
+               0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+               0xAB, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x8B, 0xE3,
+               0x83, 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+               0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0x81, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0xA9, 0xE3,
+               0x83, 0xB3, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9,
+               0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+               0x88, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xA8, 0xE3,
+               0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xBC,
+               0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+               0xB9, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3,
+               0x83, 0xA0, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0xA4,
+               0xE3, 0x83, 0xAA, 0xE3, 0x82, 0xAB, 0xE3, 0x83,
+               0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3,
+               0x82, 0xAB, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAA,
+               0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
+               0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0xE3,
+               0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3,
+               0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+               0x99, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3,
+               0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B,
+               0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAD, 0xE3, 0x83,
+               0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0xE3,
+               0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
+               0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0xBC, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3,
+               0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x82, 0xAF,
+               0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
+               0xA0, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3,
+               0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+               0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAD, 0xE3, 0x83,
+               0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3,
+               0x83, 0x88, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+               0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x82,
+               0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, 0xE3,
+               0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3,
+               0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0xE3, 0x82,
+               0xBB, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xA4, 0xE3,
+               0x83, 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD,
+               0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x8D, 0xE3, 0x82,
+               0xB1, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0xE3,
+               0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A,
+               0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+               0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB5, 0xE3,
+               0x82, 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB,
+               0xE3, 0x82, 0xB5, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0x81, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0xE3,
+               0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3,
+               0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x82,
+               0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3,
+               0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88,
+               0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0xBC, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x86, 0xE3,
+               0x82, 0x99, 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0x88,
+               0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83,
+               0x88, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x8A, 0xE3,
+               0x83, 0x8E, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83,
+               0xE3, 0x83, 0x88, 0xE3, 0x83, 0x8F, 0xE3, 0x82,
+               0xA4, 0xE3, 0x83, 0x84, 0xE3, 0x83, 0x8F, 0xE3,
+               0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBB,
+               0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+               0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
+               0x83, 0x84, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99,
+               0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAC, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3,
+               0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88,
+               0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92, 0xE3, 0x82,
+               0x9A, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0xE3,
+               0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3,
+               0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0xA1, 0xE3,
+               0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88,
+               0xE3, 0x82, 0x99, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+               0xA3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3,
+               0x83, 0x95, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x83,
+               0xE3, 0x82, 0xB7, 0xE3, 0x82, 0xA7, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0xAF,
+               0xE3, 0x82, 0xBF, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+               0x82, 0xBD, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A,
+               0xE3, 0x83, 0x8B, 0xE3, 0x83, 0x92, 0xE3, 0x83,
+               0x98, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0xE3,
+               0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3,
+               0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+               0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB7, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99,
+               0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF, 0xE3, 0x83,
+               0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0x9B,
+               0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83,
+               0x88, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0xE3,
+               0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3,
+               0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0xE3,
+               0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xB3,
+               0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82,
+               0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0x9E, 0xE3,
+               0x82, 0xA4, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x9E,
+               0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0xE3, 0x83,
+               0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF, 0xE3,
+               0x83, 0x9E, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7,
+               0xE3, 0x83, 0xA7, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0x9F, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA,
+               0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
+               0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3,
+               0x83, 0xAB, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB,
+               0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA1, 0xE3, 0x82,
+               0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x88, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0xE3, 0x83,
+               0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0xAB, 0xE3, 0x83, 0xA6, 0xE3, 0x82,
+               0xA2, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0xAA, 0xE3,
+               0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB,
+               0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3,
+               0x83, 0xBC, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xA0, 0xE3,
+               0x83, 0xAC, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88,
+               0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0xB3, 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3,
+               0x83, 0x88, 0x30, 0xE7, 0x82, 0xB9, 0x31, 0xE7,
+               0x82, 0xB9, 0x32, 0xE7, 0x82, 0xB9, 0x33, 0xE7,
+               0x82, 0xB9, 0x34, 0xE7, 0x82, 0xB9, 0x35, 0xE7,
+               0x82, 0xB9, 0x36, 0xE7, 0x82, 0xB9, 0x37, 0xE7,
+               0x82, 0xB9, 0x38, 0xE7, 0x82, 0xB9, 0x39, 0xE7,
+               0x82, 0xB9, 0x31, 0x30, 0xE7, 0x82, 0xB9, 0x31,
+               0x31, 0xE7, 0x82, 0xB9, 0x31, 0x32, 0xE7, 0x82,
+               0xB9, 0x31, 0x33, 0xE7, 0x82, 0xB9, 0x31, 0x34,
+               0xE7, 0x82, 0xB9, 0x31, 0x35, 0xE7, 0x82, 0xB9,
+               0x31, 0x36, 0xE7, 0x82, 0xB9, 0x31, 0x37, 0xE7,
+               0x82, 0xB9, 0x31, 0x38, 0xE7, 0x82, 0xB9, 0x31,
+               0x39, 0xE7, 0x82, 0xB9, 0x32, 0x30, 0xE7, 0x82,
+               0xB9, 0x32, 0x31, 0xE7, 0x82, 0xB9, 0x32, 0x32,
+               0xE7, 0x82, 0xB9, 0x32, 0x33, 0xE7, 0x82, 0xB9,
+               0x32, 0x34, 0xE7, 0x82, 0xB9, 0x68, 0x50, 0x61,
+               0x64, 0x61, 0x41, 0x55, 0x62, 0x61, 0x72, 0x6F,
+               0x56, 0x70, 0x63, 0xE5, 0xB9, 0xB3, 0xE6, 0x88,
+               0x90, 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0xE5,
+               0xA4, 0xA7, 0xE6, 0xAD, 0xA3, 0xE6, 0x98, 0x8E,
+               0xE6, 0xB2, 0xBB, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC,
+               0x8F, 0xE4, 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x70,
+               0x41, 0x6E, 0x41, 0xCE, 0xBC, 0x41, 0x6D, 0x41,
+               0x6B, 0x41, 0x4B, 0x42, 0x4D, 0x42, 0x47, 0x42,
+               0x63, 0x61, 0x6C, 0x6B, 0x63, 0x61, 0x6C, 0x70,
+               0x46, 0x6E, 0x46, 0xCE, 0xBC, 0x46, 0xCE, 0xBC,
+               0x67, 0x6D, 0x67, 0x6B, 0x67, 0x48, 0x7A, 0x6B,
+               0x48, 0x7A, 0x4D, 0x48, 0x7A, 0x47, 0x48, 0x7A,
+               0x54, 0x48, 0x7A, 0xCE, 0xBC, 0x6C, 0x6D, 0x6C,
+               0x64, 0x6C, 0x6B, 0x6C, 0x66, 0x6D, 0x6E, 0x6D,
+               0xCE, 0xBC, 0x6D, 0x6D, 0x6D, 0x63, 0x6D, 0x6B,
+               0x6D, 0x6D, 0x6D, 0x32, 0x63, 0x6D, 0x32, 0x6D,
+               0x32, 0x6B, 0x6D, 0x32, 0x6D, 0x6D, 0x33, 0x63,
+               0x6D, 0x33, 0x6D, 0x33, 0x6B, 0x6D, 0x33, 0x6D,
+               0xE2, 0x88, 0x95, 0x73, 0x6D, 0xE2, 0x88, 0x95,
+               0x73, 0x32, 0x50, 0x61, 0x6B, 0x50, 0x61, 0x4D,
+               0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64,
+               0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x72,
+               0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x70,
+               0x73, 0x6E, 0x73, 0xCE, 0xBC, 0x73, 0x6D, 0x73,
+               0x70, 0x56, 0x6E, 0x56, 0xCE, 0xBC, 0x56, 0x6D,
+               0x56, 0x6B, 0x56, 0x4D, 0x56, 0x70, 0x57, 0x6E,
+               0x57, 0xCE, 0xBC, 0x57, 0x6D, 0x57, 0x6B, 0x57,
+               0x4D, 0x57, 0x6B, 0xCE, 0xA9, 0x4D, 0xCE, 0xA9,
+               0x61, 0x2E, 0x6D, 0x2E, 0x42, 0x71, 0x63, 0x63,
+               0x63, 0x64, 0x43, 0xE2, 0x88, 0x95, 0x6B, 0x67,
+               0x43, 0x6F, 0x2E, 0x64, 0x42, 0x47, 0x79, 0x68,
+               0x61, 0x48, 0x50, 0x69, 0x6E, 0x4B, 0x4B, 0x4B,
+               0x4D, 0x6B, 0x74, 0x6C, 0x6D, 0x6C, 0x6E, 0x6C,
+               0x6F, 0x67, 0x6C, 0x78, 0x6D, 0x62, 0x6D, 0x69,
+               0x6C, 0x6D, 0x6F, 0x6C, 0x50, 0x48, 0x70, 0x2E,
+               0x6D, 0x2E, 0x50, 0x50, 0x4D, 0x50, 0x52, 0x73,
+               0x72, 0x53, 0x76, 0x57, 0x62, 0x31, 0xE6, 0x97,
+               0xA5, 0x32, 0xE6, 0x97, 0xA5, 0x33, 0xE6, 0x97,
+               0xA5, 0x34, 0xE6, 0x97, 0xA5, 0x35, 0xE6, 0x97,
+               0xA5, 0x36, 0xE6, 0x97, 0xA5, 0x37, 0xE6, 0x97,
+               0xA5, 0x38, 0xE6, 0x97, 0xA5, 0x39, 0xE6, 0x97,
+               0xA5, 0x31, 0x30, 0xE6, 0x97, 0xA5, 0x31, 0x31,
+               0xE6, 0x97, 0xA5, 0x31, 0x32, 0xE6, 0x97, 0xA5,
+               0x31, 0x33, 0xE6, 0x97, 0xA5, 0x31, 0x34, 0xE6,
+               0x97, 0xA5, 0x31, 0x35, 0xE6, 0x97, 0xA5, 0x31,
+               0x36, 0xE6, 0x97, 0xA5, 0x31, 0x37, 0xE6, 0x97,
+               0xA5, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x31, 0x39,
+               0xE6, 0x97, 0xA5, 0x32, 0x30, 0xE6, 0x97, 0xA5,
+               0x32, 0x31, 0xE6, 0x97, 0xA5, 0x32, 0x32, 0xE6,
+               0x97, 0xA5, 0x32, 0x33, 0xE6, 0x97, 0xA5, 0x32,
+               0x34, 0xE6, 0x97, 0xA5, 0x32, 0x35, 0xE6, 0x97,
+               0xA5, 0x32, 0x36, 0xE6, 0x97, 0xA5, 0x32, 0x37,
+               0xE6, 0x97, 0xA5, 0x32, 0x38, 0xE6, 0x97, 0xA5,
+               0x32, 0x39, 0xE6, 0x97, 0xA5, 0x33, 0x30, 0xE6,
+               0x97, 0xA5, 0x33, 0x31, 0xE6, 0x97, 0xA5, 0xF6,
+               0xE8, 0xB1, 0x88, 0xF6, 0xE6, 0x9B, 0xB4, 0xF6,
+               0xE8, 0xBB, 0x8A, 0xF6, 0xE8, 0xB3, 0x88, 0xF6,
+               0xE6, 0xBB, 0x91, 0xF6, 0xE4, 0xB8, 0xB2, 0xF6,
+               0xE5, 0x8F, 0xA5, 0xF6, 0xE9, 0xBE, 0x9C, 0xF6,
+               0xE9, 0xBE, 0x9C, 0xF6, 0xE5, 0xA5, 0x91, 0xF6,
+               0xE9, 0x87, 0x91, 0xF6, 0xE5, 0x96, 0x87, 0xF6,
+               0xE5, 0xA5, 0x88, 0xF6, 0xE6, 0x87, 0xB6, 0xF6,
+               0xE7, 0x99, 0xA9, 0xF6, 0xE7, 0xBE, 0x85, 0xF6,
+               0xE8, 0x98, 0xBF, 0xF6, 0xE8, 0x9E, 0xBA, 0xF6,
+               0xE8, 0xA3, 0xB8, 0xF6, 0xE9, 0x82, 0x8F, 0xF6,
+               0xE6, 0xA8, 0x82, 0xF6, 0xE6, 0xB4, 0x9B, 0xF6,
+               0xE7, 0x83, 0x99, 0xF6, 0xE7, 0x8F, 0x9E, 0xF6,
+               0xE8, 0x90, 0xBD, 0xF6, 0xE9, 0x85, 0xAA, 0xF6,
+               0xE9, 0xA7, 0xB1, 0xF6, 0xE4, 0xBA, 0x82, 0xF6,
+               0xE5, 0x8D, 0xB5, 0xF6, 0xE6, 0xAC, 0x84, 0xF6,
+               0xE7, 0x88, 0x9B, 0xF6, 0xE8, 0x98, 0xAD, 0xF6,
+               0xE9, 0xB8, 0x9E, 0xF6, 0xE5, 0xB5, 0x90, 0xF6,
+               0xE6, 0xBF, 0xAB, 0xF6, 0xE8, 0x97, 0x8D, 0xF6,
+               0xE8, 0xA5, 0xA4, 0xF6, 0xE6, 0x8B, 0x89, 0xF6,
+               0xE8, 0x87, 0x98, 0xF6, 0xE8, 0xA0, 0x9F, 0xF6,
+               0xE5, 0xBB, 0x8A, 0xF6, 0xE6, 0x9C, 0x97, 0xF6,
+               0xE6, 0xB5, 0xAA, 0xF6, 0xE7, 0x8B, 0xBC, 0xF6,
+               0xE9, 0x83, 0x8E, 0xF6, 0xE4, 0xBE, 0x86, 0xF6,
+               0xE5, 0x86, 0xB7, 0xF6, 0xE5, 0x8B, 0x9E, 0xF6,
+               0xE6, 0x93, 0x84, 0xF6, 0xE6, 0xAB, 0x93, 0xF6,
+               0xE7, 0x88, 0x90, 0xF6, 0xE7, 0x9B, 0xA7, 0xF6,
+               0xE8, 0x80, 0x81, 0xF6, 0xE8, 0x98, 0x86, 0xF6,
+               0xE8, 0x99, 0x9C, 0xF6, 0xE8, 0xB7, 0xAF, 0xF6,
+               0xE9, 0x9C, 0xB2, 0xF6, 0xE9, 0xAD, 0xAF, 0xF6,
+               0xE9, 0xB7, 0xBA, 0xF6, 0xE7, 0xA2, 0x8C, 0xF6,
+               0xE7, 0xA5, 0xBF, 0xF6, 0xE7, 0xB6, 0xA0, 0xF6,
+               0xE8, 0x8F, 0x89, 0xF6, 0xE9, 0x8C, 0x84, 0xF6,
+               0xE9, 0xB9, 0xBF, 0xF6, 0xE8, 0xAB, 0x96, 0xF6,
+               0xE5, 0xA3, 0x9F, 0xF6, 0xE5, 0xBC, 0x84, 0xF6,
+               0xE7, 0xB1, 0xA0, 0xF6, 0xE8, 0x81, 0xBE, 0xF6,
+               0xE7, 0x89, 0xA2, 0xF6, 0xE7, 0xA3, 0x8A, 0xF6,
+               0xE8, 0xB3, 0x82, 0xF6, 0xE9, 0x9B, 0xB7, 0xF6,
+               0xE5, 0xA3, 0x98, 0xF6, 0xE5, 0xB1, 0xA2, 0xF6,
+               0xE6, 0xA8, 0x93, 0xF6, 0xE6, 0xB7, 0x9A, 0xF6,
+               0xE6, 0xBC, 0x8F, 0xF6, 0xE7, 0xB4, 0xAF, 0xF6,
+               0xE7, 0xB8, 0xB7, 0xF6, 0xE9, 0x99, 0x8B, 0xF6,
+               0xE5, 0x8B, 0x92, 0xF6, 0xE8, 0x82, 0x8B, 0xF6,
+               0xE5, 0x87, 0x9C, 0xF6, 0xE5, 0x87, 0x8C, 0xF6,
+               0xE7, 0xA8, 0x9C, 0xF6, 0xE7, 0xB6, 0xBE, 0xF6,
+               0xE8, 0x8F, 0xB1, 0xF6, 0xE9, 0x99, 0xB5, 0xF6,
+               0xE8, 0xAE, 0x80, 0xF6, 0xE6, 0x8B, 0x8F, 0xF6,
+               0xE6, 0xA8, 0x82, 0xF6, 0xE8, 0xAB, 0xBE, 0xF6,
+               0xE4, 0xB8, 0xB9, 0xF6, 0xE5, 0xAF, 0xA7, 0xF6,
+               0xE6, 0x80, 0x92, 0xF6, 0xE7, 0x8E, 0x87, 0xF6,
+               0xE7, 0x95, 0xB0, 0xF6, 0xE5, 0x8C, 0x97, 0xF6,
+               0xE7, 0xA3, 0xBB, 0xF6, 0xE4, 0xBE, 0xBF, 0xF6,
+               0xE5, 0xBE, 0xA9, 0xF6, 0xE4, 0xB8, 0x8D, 0xF6,
+               0xE6, 0xB3, 0x8C, 0xF6, 0xE6, 0x95, 0xB8, 0xF6,
+               0xE7, 0xB4, 0xA2, 0xF6, 0xE5, 0x8F, 0x83, 0xF6,
+               0xE5, 0xA1, 0x9E, 0xF6, 0xE7, 0x9C, 0x81, 0xF6,
+               0xE8, 0x91, 0x89, 0xF6, 0xE8, 0xAA, 0xAA, 0xF6,
+               0xE6, 0xAE, 0xBA, 0xF6, 0xE8, 0xBE, 0xB0, 0xF6,
+               0xE6, 0xB2, 0x88, 0xF6, 0xE6, 0x8B, 0xBE, 0xF6,
+               0xE8, 0x8B, 0xA5, 0xF6, 0xE6, 0x8E, 0xA0, 0xF6,
+               0xE7, 0x95, 0xA5, 0xF6, 0xE4, 0xBA, 0xAE, 0xF6,
+               0xE5, 0x85, 0xA9, 0xF6, 0xE5, 0x87, 0x89, 0xF6,
+               0xE6, 0xA2, 0x81, 0xF6, 0xE7, 0xB3, 0xA7, 0xF6,
+               0xE8, 0x89, 0xAF, 0xF6, 0xE8, 0xAB, 0x92, 0xF6,
+               0xE9, 0x87, 0x8F, 0xF6, 0xE5, 0x8B, 0xB5, 0xF6,
+               0xE5, 0x91, 0x82, 0xF6, 0xE5, 0xA5, 0xB3, 0xF6,
+               0xE5, 0xBB, 0xAC, 0xF6, 0xE6, 0x97, 0x85, 0xF6,
+               0xE6, 0xBF, 0xBE, 0xF6, 0xE7, 0xA4, 0xAA, 0xF6,
+               0xE9, 0x96, 0xAD, 0xF6, 0xE9, 0xA9, 0xAA, 0xF6,
+               0xE9, 0xBA, 0x97, 0xF6, 0xE9, 0xBB, 0x8E, 0xF6,
+               0xE5, 0x8A, 0x9B, 0xF6, 0xE6, 0x9B, 0x86, 0xF6,
+               0xE6, 0xAD, 0xB7, 0xF6, 0xE8, 0xBD, 0xA2, 0xF6,
+               0xE5, 0xB9, 0xB4, 0xF6, 0xE6, 0x86, 0x90, 0xF6,
+               0xE6, 0x88, 0x80, 0xF6, 0xE6, 0x92, 0x9A, 0xF6,
+               0xE6, 0xBC, 0xA3, 0xF6, 0xE7, 0x85, 0x89, 0xF6,
+               0xE7, 0x92, 0x89, 0xF6, 0xE7, 0xA7, 0x8A, 0xF6,
+               0xE7, 0xB7, 0xB4, 0xF6, 0xE8, 0x81, 0xAF, 0xF6,
+               0xE8, 0xBC, 0xA6, 0xF6, 0xE8, 0x93, 0xAE, 0xF6,
+               0xE9, 0x80, 0xA3, 0xF6, 0xE9, 0x8D, 0x8A, 0xF6,
+               0xE5, 0x88, 0x97, 0xF6, 0xE5, 0x8A, 0xA3, 0xF6,
+               0xE5, 0x92, 0xBD, 0xF6, 0xE7, 0x83, 0x88, 0xF6,
+               0xE8, 0xA3, 0x82, 0xF6, 0xE8, 0xAA, 0xAA, 0xF6,
+               0xE5, 0xBB, 0x89, 0xF6, 0xE5, 0xBF, 0xB5, 0xF6,
+               0xE6, 0x8D, 0xBB, 0xF6, 0xE6, 0xAE, 0xAE, 0xF6,
+               0xE7, 0xB0, 0xBE, 0xF6, 0xE7, 0x8D, 0xB5, 0xF6,
+               0xE4, 0xBB, 0xA4, 0xF6, 0xE5, 0x9B, 0xB9, 0xF6,
+               0xE5, 0xAF, 0xA7, 0xF6, 0xE5, 0xB6, 0xBA, 0xF6,
+               0xE6, 0x80, 0x9C, 0xF6, 0xE7, 0x8E, 0xB2, 0xF6,
+               0xE7, 0x91, 0xA9, 0xF6, 0xE7, 0xBE, 0x9A, 0xF6,
+               0xE8, 0x81, 0x86, 0xF6, 0xE9, 0x88, 0xB4, 0xF6,
+               0xE9, 0x9B, 0xB6, 0xF6, 0xE9, 0x9D, 0x88, 0xF6,
+               0xE9, 0xA0, 0x98, 0xF6, 0xE4, 0xBE, 0x8B, 0xF6,
+               0xE7, 0xA6, 0xAE, 0xF6, 0xE9, 0x86, 0xB4, 0xF6,
+               0xE9, 0x9A, 0xB8, 0xF6, 0xE6, 0x83, 0xA1, 0xF6,
+               0xE4, 0xBA, 0x86, 0xF6, 0xE5, 0x83, 0x9A, 0xF6,
+               0xE5, 0xAF, 0xAE, 0xF6, 0xE5, 0xB0, 0xBF, 0xF6,
+               0xE6, 0x96, 0x99, 0xF6, 0xE6, 0xA8, 0x82, 0xF6,
+               0xE7, 0x87, 0x8E, 0xF6, 0xE7, 0x99, 0x82, 0xF6,
+               0xE8, 0x93, 0xBC, 0xF6, 0xE9, 0x81, 0xBC, 0xF6,
+               0xE9, 0xBE, 0x8D, 0xF6, 0xE6, 0x9A, 0x88, 0xF6,
+               0xE9, 0x98, 0xAE, 0xF6, 0xE5, 0x8A, 0x89, 0xF6,
+               0xE6, 0x9D, 0xBB, 0xF6, 0xE6, 0x9F, 0xB3, 0xF6,
+               0xE6, 0xB5, 0x81, 0xF6, 0xE6, 0xBA, 0x9C, 0xF6,
+               0xE7, 0x90, 0x89, 0xF6, 0xE7, 0x95, 0x99, 0xF6,
+               0xE7, 0xA1, 0xAB, 0xF6, 0xE7, 0xB4, 0x90, 0xF6,
+               0xE9, 0xA1, 0x9E, 0xF6, 0xE5, 0x85, 0xAD, 0xF6,
+               0xE6, 0x88, 0xAE, 0xF6, 0xE9, 0x99, 0xB8, 0xF6,
+               0xE5, 0x80, 0xAB, 0xF6, 0xE5, 0xB4, 0x99, 0xF6,
+               0xE6, 0xB7, 0xAA, 0xF6, 0xE8, 0xBC, 0xAA, 0xF6,
+               0xE5, 0xBE, 0x8B, 0xF6, 0xE6, 0x85, 0x84, 0xF6,
+               0xE6, 0xA0, 0x97, 0xF6, 0xE7, 0x8E, 0x87, 0xF6,
+               0xE9, 0x9A, 0x86, 0xF6, 0xE5, 0x88, 0xA9, 0xF6,
+               0xE5, 0x90, 0x8F, 0xF6, 0xE5, 0xB1, 0xA5, 0xF6,
+               0xE6, 0x98, 0x93, 0xF6, 0xE6, 0x9D, 0x8E, 0xF6,
+               0xE6, 0xA2, 0xA8, 0xF6, 0xE6, 0xB3, 0xA5, 0xF6,
+               0xE7, 0x90, 0x86, 0xF6, 0xE7, 0x97, 0xA2, 0xF6,
+               0xE7, 0xBD, 0xB9, 0xF6, 0xE8, 0xA3, 0x8F, 0xF6,
+               0xE8, 0xA3, 0xA1, 0xF6, 0xE9, 0x87, 0x8C, 0xF6,
+               0xE9, 0x9B, 0xA2, 0xF6, 0xE5, 0x8C, 0xBF, 0xF6,
+               0xE6, 0xBA, 0xBA, 0xF6, 0xE5, 0x90, 0x9D, 0xF6,
+               0xE7, 0x87, 0x90, 0xF6, 0xE7, 0x92, 0x98, 0xF6,
+               0xE8, 0x97, 0xBA, 0xF6, 0xE9, 0x9A, 0xA3, 0xF6,
+               0xE9, 0xB1, 0x97, 0xF6, 0xE9, 0xBA, 0x9F, 0xF6,
+               0xE6, 0x9E, 0x97, 0xF6, 0xE6, 0xB7, 0x8B, 0xF6,
+               0xE8, 0x87, 0xA8, 0xF6, 0xE7, 0xAB, 0x8B, 0xF6,
+               0xE7, 0xAC, 0xA0, 0xF6, 0xE7, 0xB2, 0x92, 0xF6,
+               0xE7, 0x8B, 0x80, 0xF6, 0xE7, 0x82, 0x99, 0xF6,
+               0xE8, 0xAD, 0x98, 0xF6, 0xE4, 0xBB, 0x80, 0xF6,
+               0xE8, 0x8C, 0xB6, 0xF6, 0xE5, 0x88, 0xBA, 0xF6,
+               0xE5, 0x88, 0x87, 0xF6, 0xE5, 0xBA, 0xA6, 0xF6,
+               0xE6, 0x8B, 0x93, 0xF6, 0xE7, 0xB3, 0x96, 0xF6,
+               0xE5, 0xAE, 0x85, 0xF6, 0xE6, 0xB4, 0x9E, 0xF6,
+               0xE6, 0x9A, 0xB4, 0xF6, 0xE8, 0xBC, 0xBB, 0xF6,
+               0xE8, 0xA1, 0x8C, 0xF6, 0xE9, 0x99, 0x8D, 0xF6,
+               0xE8, 0xA6, 0x8B, 0xF6, 0xE5, 0xBB, 0x93, 0xF6,
+               0xE5, 0x85, 0x80, 0xF6, 0xE5, 0x97, 0x80, 0xF6,
+               0xE5, 0xA1, 0x9A, 0xF6, 0xE6, 0x99, 0xB4, 0xF6,
+               0xE5, 0x87, 0x9E, 0xF6, 0xE7, 0x8C, 0xAA, 0xF6,
+               0xE7, 0x9B, 0x8A, 0xF6, 0xE7, 0xA4, 0xBC, 0xF6,
+               0xE7, 0xA5, 0x9E, 0xF6, 0xE7, 0xA5, 0xA5, 0xF6,
+               0xE7, 0xA6, 0x8F, 0xF6, 0xE9, 0x9D, 0x96, 0xF6,
+               0xE7, 0xB2, 0xBE, 0xF6, 0xE7, 0xBE, 0xBD, 0xF6,
+               0xE8, 0x98, 0x92, 0xF6, 0xE8, 0xAB, 0xB8, 0xF6,
+               0xE9, 0x80, 0xB8, 0xF6, 0xE9, 0x83, 0xBD, 0xF6,
+               0xE9, 0xA3, 0xAF, 0xF6, 0xE9, 0xA3, 0xBC, 0xF6,
+               0xE9, 0xA4, 0xA8, 0xF6, 0xE9, 0xB6, 0xB4, 0xF6,
+               0xE4, 0xBE, 0xAE, 0xF6, 0xE5, 0x83, 0xA7, 0xF6,
+               0xE5, 0x85, 0x8D, 0xF6, 0xE5, 0x8B, 0x89, 0xF6,
+               0xE5, 0x8B, 0xA4, 0xF6, 0xE5, 0x8D, 0x91, 0xF6,
+               0xE5, 0x96, 0x9D, 0xF6, 0xE5, 0x98, 0x86, 0xF6,
+               0xE5, 0x99, 0xA8, 0xF6, 0xE5, 0xA1, 0x80, 0xF6,
+               0xE5, 0xA2, 0xA8, 0xF6, 0xE5, 0xB1, 0xA4, 0xF6,
+               0xE5, 0xB1, 0xAE, 0xF6, 0xE6, 0x82, 0x94, 0xF6,
+               0xE6, 0x85, 0xA8, 0xF6, 0xE6, 0x86, 0x8E, 0xF6,
+               0xE6, 0x87, 0xB2, 0xF6, 0xE6, 0x95, 0x8F, 0xF6,
+               0xE6, 0x97, 0xA2, 0xF6, 0xE6, 0x9A, 0x91, 0xF6,
+               0xE6, 0xA2, 0x85, 0xF6, 0xE6, 0xB5, 0xB7, 0xF6,
+               0xE6, 0xB8, 0x9A, 0xF6, 0xE6, 0xBC, 0xA2, 0xF6,
+               0xE7, 0x85, 0xAE, 0xF6, 0xE7, 0x88, 0xAB, 0xF6,
+               0xE7, 0x90, 0xA2, 0xF6, 0xE7, 0xA2, 0x91, 0xF6,
+               0xE7, 0xA4, 0xBE, 0xF6, 0xE7, 0xA5, 0x89, 0xF6,
+               0xE7, 0xA5, 0x88, 0xF6, 0xE7, 0xA5, 0x90, 0xF6,
+               0xE7, 0xA5, 0x96, 0xF6, 0xE7, 0xA5, 0x9D, 0xF6,
+               0xE7, 0xA6, 0x8D, 0xF6, 0xE7, 0xA6, 0x8E, 0xF6,
+               0xE7, 0xA9, 0x80, 0xF6, 0xE7, 0xAA, 0x81, 0xF6,
+               0xE7, 0xAF, 0x80, 0xF6, 0xE7, 0xB7, 0xB4, 0xF6,
+               0xE7, 0xB8, 0x89, 0xF6, 0xE7, 0xB9, 0x81, 0xF6,
+               0xE7, 0xBD, 0xB2, 0xF6, 0xE8, 0x80, 0x85, 0xF6,
+               0xE8, 0x87, 0xAD, 0xF6, 0xE8, 0x89, 0xB9, 0xF6,
+               0xE8, 0x89, 0xB9, 0xF6, 0xE8, 0x91, 0x97, 0xF6,
+               0xE8, 0xA4, 0x90, 0xF6, 0xE8, 0xA6, 0x96, 0xF6,
+               0xE8, 0xAC, 0x81, 0xF6, 0xE8, 0xAC, 0xB9, 0xF6,
+               0xE8, 0xB3, 0x93, 0xF6, 0xE8, 0xB4, 0x88, 0xF6,
+               0xE8, 0xBE, 0xB6, 0xF6, 0xE9, 0x80, 0xB8, 0xF6,
+               0xE9, 0x9B, 0xA3, 0xF6, 0xE9, 0x9F, 0xBF, 0xF6,
+               0xE9, 0xA0, 0xBB, 0x66, 0x66, 0x66, 0x69, 0x66,
+               0x6C, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6C, 0x73,
+               0x74, 0x73, 0x74, 0xD5, 0xB4, 0xD5, 0xB6, 0xD5,
+               0xB4, 0xD5, 0xA5, 0xD5, 0xB4, 0xD5, 0xAB, 0xD5,
+               0xBE, 0xD5, 0xB6, 0xD5, 0xB4, 0xD5, 0xAD, 0xF6,
+               0xD7, 0x99, 0xD6, 0xB4, 0xF6, 0xD7, 0xB2, 0xD6,
+               0xB7, 0xD7, 0xA2, 0xD7, 0x90, 0xD7, 0x93, 0xD7,
+               0x94, 0xD7, 0x9B, 0xD7, 0x9C, 0xD7, 0x9D, 0xD7,
+               0xA8, 0xD7, 0xAA, 0x2B, 0xF6, 0xD7, 0xA9, 0xD7,
+               0x81, 0xF6, 0xD7, 0xA9, 0xD7, 0x82, 0xF6, 0xD7,
+               0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0xF6, 0xD7, 0xA9,
+               0xD6, 0xBC, 0xD7, 0x82, 0xF6, 0xD7, 0x90, 0xD6,
+               0xB7, 0xF6, 0xD7, 0x90, 0xD6, 0xB8, 0xF6, 0xD7,
+               0x90, 0xD6, 0xBC, 0xF6, 0xD7, 0x91, 0xD6, 0xBC,
+               0xF6, 0xD7, 0x92, 0xD6, 0xBC, 0xF6, 0xD7, 0x93,
+               0xD6, 0xBC, 0xF6, 0xD7, 0x94, 0xD6, 0xBC, 0xF6,
+               0xD7, 0x95, 0xD6, 0xBC, 0xF6, 0xD7, 0x96, 0xD6,
+               0xBC, 0xF6, 0xD7, 0x98, 0xD6, 0xBC, 0xF6, 0xD7,
+               0x99, 0xD6, 0xBC, 0xF6, 0xD7, 0x9A, 0xD6, 0xBC,
+               0xF6, 0xD7, 0x9B, 0xD6, 0xBC, 0xF6, 0xD7, 0x9C,
+               0xD6, 0xBC, 0xF6, 0xD7, 0x9E, 0xD6, 0xBC, 0xF6,
+               0xD7, 0xA0, 0xD6, 0xBC, 0xF6, 0xD7, 0xA1, 0xD6,
+               0xBC, 0xF6, 0xD7, 0xA3, 0xD6, 0xBC, 0xF6, 0xD7,
+               0xA4, 0xD6, 0xBC, 0xF6, 0xD7, 0xA6, 0xD6, 0xBC,
+               0xF6, 0xD7, 0xA7, 0xD6, 0xBC, 0xF6, 0xD7, 0xA8,
+               0xD6, 0xBC, 0xF6, 0xD7, 0xA9, 0xD6, 0xBC, 0xF6,
+               0xD7, 0xAA, 0xD6, 0xBC, 0xF6, 0xD7, 0x95, 0xD6,
+               0xB9, 0xF6, 0xD7, 0x91, 0xD6, 0xBF, 0xF6, 0xD7,
+               0x9B, 0xD6, 0xBF, 0xF6, 0xD7, 0xA4, 0xD6, 0xBF,
+               0xD7, 0x90, 0xD7, 0x9C, 0xD9, 0xB1, 0xD9, 0xB1,
+               0xD9, 0xBB, 0xD9, 0xBB, 0xD9, 0xBB, 0xD9, 0xBB,
+               0xD9, 0xBE, 0xD9, 0xBE, 0xD9, 0xBE, 0xD9, 0xBE,
+               0xDA, 0x80, 0xDA, 0x80, 0xDA, 0x80, 0xDA, 0x80,
+               0xD9, 0xBA, 0xD9, 0xBA, 0xD9, 0xBA, 0xD9, 0xBA,
+               0xD9, 0xBF, 0xD9, 0xBF, 0xD9, 0xBF, 0xD9, 0xBF,
+               0xD9, 0xB9, 0xD9, 0xB9, 0xD9, 0xB9, 0xD9, 0xB9,
+               0xDA, 0xA4, 0xDA, 0xA4, 0xDA, 0xA4, 0xDA, 0xA4,
+               0xDA, 0xA6, 0xDA, 0xA6, 0xDA, 0xA6, 0xDA, 0xA6,
+               0xDA, 0x84, 0xDA, 0x84, 0xDA, 0x84, 0xDA, 0x84,
+               0xDA, 0x83, 0xDA, 0x83, 0xDA, 0x83, 0xDA, 0x83,
+               0xDA, 0x86, 0xDA, 0x86, 0xDA, 0x86, 0xDA, 0x86,
+               0xDA, 0x87, 0xDA, 0x87, 0xDA, 0x87, 0xDA, 0x87,
+               0xDA, 0x8D, 0xDA, 0x8D, 0xDA, 0x8C, 0xDA, 0x8C,
+               0xDA, 0x8E, 0xDA, 0x8E, 0xDA, 0x88, 0xDA, 0x88,
+               0xDA, 0x98, 0xDA, 0x98, 0xDA, 0x91, 0xDA, 0x91,
+               0xDA, 0xA9, 0xDA, 0xA9, 0xDA, 0xA9, 0xDA, 0xA9,
+               0xDA, 0xAF, 0xDA, 0xAF, 0xDA, 0xAF, 0xDA, 0xAF,
+               0xDA, 0xB3, 0xDA, 0xB3, 0xDA, 0xB3, 0xDA, 0xB3,
+               0xDA, 0xB1, 0xDA, 0xB1, 0xDA, 0xB1, 0xDA, 0xB1,
+               0xDA, 0xBA, 0xDA, 0xBA, 0xDA, 0xBB, 0xDA, 0xBB,
+               0xDA, 0xBB, 0xDA, 0xBB, 0xDB, 0x95, 0xD9, 0x94,
+               0xDB, 0x95, 0xD9, 0x94, 0xDB, 0x81, 0xDB, 0x81,
+               0xDB, 0x81, 0xDB, 0x81, 0xDA, 0xBE, 0xDA, 0xBE,
+               0xDA, 0xBE, 0xDA, 0xBE, 0xDB, 0x92, 0xDB, 0x92,
+               0xDB, 0x92, 0xD9, 0x94, 0xDB, 0x92, 0xD9, 0x94,
+               0xDA, 0xAD, 0xDA, 0xAD, 0xDA, 0xAD, 0xDA, 0xAD,
+               0xDB, 0x87, 0xDB, 0x87, 0xDB, 0x86, 0xDB, 0x86,
+               0xDB, 0x88, 0xDB, 0x88, 0xDB, 0x87, 0xD9, 0xB4,
+               0xDB, 0x8B, 0xDB, 0x8B, 0xDB, 0x85, 0xDB, 0x85,
+               0xDB, 0x89, 0xDB, 0x89, 0xDB, 0x90, 0xDB, 0x90,
+               0xDB, 0x90, 0xDB, 0x90, 0xD9, 0x89, 0xD9, 0x89,
+               0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xA7, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD8, 0xA7, 0xD9, 0x8A, 0xD9, 0x94,
+               0xDB, 0x95, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x95,
+               0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x88, 0xD9, 0x8A, 0xD9, 0x94,
+               0xDB, 0x87, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x87,
+               0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0xD9, 0x8A,
+               0xD9, 0x94, 0xDB, 0x86, 0xD9, 0x8A, 0xD9, 0x94,
+               0xDB, 0x88, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x88,
+               0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x90, 0xD9, 0x8A,
+               0xD9, 0x94, 0xDB, 0x90, 0xD9, 0x8A, 0xD9, 0x94,
+               0xDB, 0x90, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89,
+               0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x89, 0xDB, 0x8C, 0xDB, 0x8C,
+               0xDB, 0x8C, 0xDB, 0x8C, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD8, 0xAC, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD,
+               0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x85, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x89, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD9, 0x8A, 0xD8, 0xA8, 0xD8, 0xAC, 0xD8, 0xA8,
+               0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xAE, 0xD8, 0xA8,
+               0xD9, 0x85, 0xD8, 0xA8, 0xD9, 0x89, 0xD8, 0xA8,
+               0xD9, 0x8A, 0xD8, 0xAA, 0xD8, 0xAC, 0xD8, 0xAA,
+               0xD8, 0xAD, 0xD8, 0xAA, 0xD8, 0xAE, 0xD8, 0xAA,
+               0xD9, 0x85, 0xD8, 0xAA, 0xD9, 0x89, 0xD8, 0xAA,
+               0xD9, 0x8A, 0xD8, 0xAB, 0xD8, 0xAC, 0xD8, 0xAB,
+               0xD9, 0x85, 0xD8, 0xAB, 0xD9, 0x89, 0xD8, 0xAB,
+               0xD9, 0x8A, 0xD8, 0xAC, 0xD8, 0xAD, 0xD8, 0xAC,
+               0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0xD8, 0xAD,
+               0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0xD8, 0xAE,
+               0xD8, 0xAD, 0xD8, 0xAE, 0xD9, 0x85, 0xD8, 0xB3,
+               0xD8, 0xAC, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8, 0xB3,
+               0xD8, 0xAE, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xB5,
+               0xD8, 0xAD, 0xD8, 0xB5, 0xD9, 0x85, 0xD8, 0xB6,
+               0xD8, 0xAC, 0xD8, 0xB6, 0xD8, 0xAD, 0xD8, 0xB6,
+               0xD8, 0xAE, 0xD8, 0xB6, 0xD9, 0x85, 0xD8, 0xB7,
+               0xD8, 0xAD, 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xB8,
+               0xD9, 0x85, 0xD8, 0xB9, 0xD8, 0xAC, 0xD8, 0xB9,
+               0xD9, 0x85, 0xD8, 0xBA, 0xD8, 0xAC, 0xD8, 0xBA,
+               0xD9, 0x85, 0xD9, 0x81, 0xD8, 0xAC, 0xD9, 0x81,
+               0xD8, 0xAD, 0xD9, 0x81, 0xD8, 0xAE, 0xD9, 0x81,
+               0xD9, 0x85, 0xD9, 0x81, 0xD9, 0x89, 0xD9, 0x81,
+               0xD9, 0x8A, 0xD9, 0x82, 0xD8, 0xAD, 0xD9, 0x82,
+               0xD9, 0x85, 0xD9, 0x82, 0xD9, 0x89, 0xD9, 0x82,
+               0xD9, 0x8A, 0xD9, 0x83, 0xD8, 0xA7, 0xD9, 0x83,
+               0xD8, 0xAC, 0xD9, 0x83, 0xD8, 0xAD, 0xD9, 0x83,
+               0xD8, 0xAE, 0xD9, 0x83, 0xD9, 0x84, 0xD9, 0x83,
+               0xD9, 0x85, 0xD9, 0x83, 0xD9, 0x89, 0xD9, 0x83,
+               0xD9, 0x8A, 0xD9, 0x84, 0xD8, 0xAC, 0xD9, 0x84,
+               0xD8, 0xAD, 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x84,
+               0xD9, 0x85, 0xD9, 0x84, 0xD9, 0x89, 0xD9, 0x84,
+               0xD9, 0x8A, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAE, 0xD9, 0x85,
+               0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x89, 0xD9, 0x85,
+               0xD9, 0x8A, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x86,
+               0xD8, 0xAD, 0xD9, 0x86, 0xD8, 0xAE, 0xD9, 0x86,
+               0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x89, 0xD9, 0x86,
+               0xD9, 0x8A, 0xD9, 0x87, 0xD8, 0xAC, 0xD9, 0x87,
+               0xD9, 0x85, 0xD9, 0x87, 0xD9, 0x89, 0xD9, 0x87,
+               0xD9, 0x8A, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xAD, 0xD9, 0x8A, 0xD8, 0xAE, 0xD9, 0x8A,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x89, 0xD9, 0x8A,
+               0xD9, 0x8A, 0xD8, 0xB0, 0xD9, 0xB0, 0xD8, 0xB1,
+               0xD9, 0xB0, 0xD9, 0x89, 0xD9, 0xB0, 0x20, 0xD9,
+               0x8C, 0xD9, 0x91, 0x20, 0xD9, 0x8D, 0xD9, 0x91,
+               0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x20, 0xD9, 0x8F,
+               0xD9, 0x91, 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x20,
+               0xD9, 0x91, 0xD9, 0xB0, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD8, 0xB1, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xB2,
+               0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x85, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x86, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD9, 0x89, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A,
+               0xD8, 0xA8, 0xD8, 0xB1, 0xD8, 0xA8, 0xD8, 0xB2,
+               0xD8, 0xA8, 0xD9, 0x85, 0xD8, 0xA8, 0xD9, 0x86,
+               0xD8, 0xA8, 0xD9, 0x89, 0xD8, 0xA8, 0xD9, 0x8A,
+               0xD8, 0xAA, 0xD8, 0xB1, 0xD8, 0xAA, 0xD8, 0xB2,
+               0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAA, 0xD9, 0x86,
+               0xD8, 0xAA, 0xD9, 0x89, 0xD8, 0xAA, 0xD9, 0x8A,
+               0xD8, 0xAB, 0xD8, 0xB1, 0xD8, 0xAB, 0xD8, 0xB2,
+               0xD8, 0xAB, 0xD9, 0x85, 0xD8, 0xAB, 0xD9, 0x86,
+               0xD8, 0xAB, 0xD9, 0x89, 0xD8, 0xAB, 0xD9, 0x8A,
+               0xD9, 0x81, 0xD9, 0x89, 0xD9, 0x81, 0xD9, 0x8A,
+               0xD9, 0x82, 0xD9, 0x89, 0xD9, 0x82, 0xD9, 0x8A,
+               0xD9, 0x83, 0xD8, 0xA7, 0xD9, 0x83, 0xD9, 0x84,
+               0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x83, 0xD9, 0x89,
+               0xD9, 0x83, 0xD9, 0x8A, 0xD9, 0x84, 0xD9, 0x85,
+               0xD9, 0x84, 0xD9, 0x89, 0xD9, 0x84, 0xD9, 0x8A,
+               0xD9, 0x85, 0xD8, 0xA7, 0xD9, 0x85, 0xD9, 0x85,
+               0xD9, 0x86, 0xD8, 0xB1, 0xD9, 0x86, 0xD8, 0xB2,
+               0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x86,
+               0xD9, 0x86, 0xD9, 0x89, 0xD9, 0x86, 0xD9, 0x8A,
+               0xD9, 0x89, 0xD9, 0xB0, 0xD9, 0x8A, 0xD8, 0xB1,
+               0xD9, 0x8A, 0xD8, 0xB2, 0xD9, 0x8A, 0xD9, 0x85,
+               0xD9, 0x8A, 0xD9, 0x86, 0xD9, 0x8A, 0xD9, 0x89,
+               0xD9, 0x8A, 0xD9, 0x8A, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD8, 0xAC, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD,
+               0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD9, 0x87, 0xD8, 0xA8, 0xD8, 0xAC, 0xD8, 0xA8,
+               0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xAE, 0xD8, 0xA8,
+               0xD9, 0x85, 0xD8, 0xA8, 0xD9, 0x87, 0xD8, 0xAA,
+               0xD8, 0xAC, 0xD8, 0xAA, 0xD8, 0xAD, 0xD8, 0xAA,
+               0xD8, 0xAE, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAA,
+               0xD9, 0x87, 0xD8, 0xAB, 0xD9, 0x85, 0xD8, 0xAC,
+               0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xAD,
+               0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAE,
+               0xD8, 0xAC, 0xD8, 0xAE, 0xD9, 0x85, 0xD8, 0xB3,
+               0xD8, 0xAC, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8, 0xB3,
+               0xD8, 0xAE, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xB5,
+               0xD8, 0xAD, 0xD8, 0xB5, 0xD8, 0xAE, 0xD8, 0xB5,
+               0xD9, 0x85, 0xD8, 0xB6, 0xD8, 0xAC, 0xD8, 0xB6,
+               0xD8, 0xAD, 0xD8, 0xB6, 0xD8, 0xAE, 0xD8, 0xB6,
+               0xD9, 0x85, 0xD8, 0xB7, 0xD8, 0xAD, 0xD8, 0xB8,
+               0xD9, 0x85, 0xD8, 0xB9, 0xD8, 0xAC, 0xD8, 0xB9,
+               0xD9, 0x85, 0xD8, 0xBA, 0xD8, 0xAC, 0xD8, 0xBA,
+               0xD9, 0x85, 0xD9, 0x81, 0xD8, 0xAC, 0xD9, 0x81,
+               0xD8, 0xAD, 0xD9, 0x81, 0xD8, 0xAE, 0xD9, 0x81,
+               0xD9, 0x85, 0xD9, 0x82, 0xD8, 0xAD, 0xD9, 0x82,
+               0xD9, 0x85, 0xD9, 0x83, 0xD8, 0xAC, 0xD9, 0x83,
+               0xD8, 0xAD, 0xD9, 0x83, 0xD8, 0xAE, 0xD9, 0x83,
+               0xD9, 0x84, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x84,
+               0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x84,
+               0xD8, 0xAE, 0xD9, 0x84, 0xD9, 0x85, 0xD9, 0x84,
+               0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAE, 0xD9, 0x85,
+               0xD9, 0x85, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x86,
+               0xD8, 0xAD, 0xD9, 0x86, 0xD8, 0xAE, 0xD9, 0x86,
+               0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x87, 0xD9, 0x87,
+               0xD8, 0xAC, 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x87,
+               0xD9, 0xB0, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xAD, 0xD9, 0x8A, 0xD8, 0xAE, 0xD9, 0x8A,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x87, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x94,
+               0xD9, 0x87, 0xD8, 0xA8, 0xD9, 0x85, 0xD8, 0xA8,
+               0xD9, 0x87, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAA,
+               0xD9, 0x87, 0xD8, 0xAB, 0xD9, 0x85, 0xD8, 0xAB,
+               0xD9, 0x87, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xB3,
+               0xD9, 0x87, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xB4,
+               0xD9, 0x87, 0xD9, 0x83, 0xD9, 0x84, 0xD9, 0x83,
+               0xD9, 0x85, 0xD9, 0x84, 0xD9, 0x85, 0xD9, 0x86,
+               0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x87, 0xD9, 0x8A,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x87, 0xD9, 0x80,
+               0xD9, 0x8E, 0xD9, 0x91, 0xD9, 0x80, 0xD9, 0x8F,
+               0xD9, 0x91, 0xD9, 0x80, 0xD9, 0x90, 0xD9, 0x91,
+               0xD8, 0xB7, 0xD9, 0x89, 0xD8, 0xB7, 0xD9, 0x8A,
+               0xD8, 0xB9, 0xD9, 0x89, 0xD8, 0xB9, 0xD9, 0x8A,
+               0xD8, 0xBA, 0xD9, 0x89, 0xD8, 0xBA, 0xD9, 0x8A,
+               0xD8, 0xB3, 0xD9, 0x89, 0xD8, 0xB3, 0xD9, 0x8A,
+               0xD8, 0xB4, 0xD9, 0x89, 0xD8, 0xB4, 0xD9, 0x8A,
+               0xD8, 0xAD, 0xD9, 0x89, 0xD8, 0xAD, 0xD9, 0x8A,
+               0xD8, 0xAC, 0xD9, 0x89, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xAE, 0xD9, 0x89, 0xD8, 0xAE, 0xD9, 0x8A,
+               0xD8, 0xB5, 0xD9, 0x89, 0xD8, 0xB5, 0xD9, 0x8A,
+               0xD8, 0xB6, 0xD9, 0x89, 0xD8, 0xB6, 0xD9, 0x8A,
+               0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8, 0xAD,
+               0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9, 0x85,
+               0xD8, 0xB4, 0xD8, 0xB1, 0xD8, 0xB3, 0xD8, 0xB1,
+               0xD8, 0xB5, 0xD8, 0xB1, 0xD8, 0xB6, 0xD8, 0xB1,
+               0xD8, 0xB7, 0xD9, 0x89, 0xD8, 0xB7, 0xD9, 0x8A,
+               0xD8, 0xB9, 0xD9, 0x89, 0xD8, 0xB9, 0xD9, 0x8A,
+               0xD8, 0xBA, 0xD9, 0x89, 0xD8, 0xBA, 0xD9, 0x8A,
+               0xD8, 0xB3, 0xD9, 0x89, 0xD8, 0xB3, 0xD9, 0x8A,
+               0xD8, 0xB4, 0xD9, 0x89, 0xD8, 0xB4, 0xD9, 0x8A,
+               0xD8, 0xAD, 0xD9, 0x89, 0xD8, 0xAD, 0xD9, 0x8A,
+               0xD8, 0xAC, 0xD9, 0x89, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xAE, 0xD9, 0x89, 0xD8, 0xAE, 0xD9, 0x8A,
+               0xD8, 0xB5, 0xD9, 0x89, 0xD8, 0xB5, 0xD9, 0x8A,
+               0xD8, 0xB6, 0xD9, 0x89, 0xD8, 0xB6, 0xD9, 0x8A,
+               0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8, 0xAD,
+               0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9, 0x85,
+               0xD8, 0xB4, 0xD8, 0xB1, 0xD8, 0xB3, 0xD8, 0xB1,
+               0xD8, 0xB5, 0xD8, 0xB1, 0xD8, 0xB6, 0xD8, 0xB1,
+               0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8, 0xAD,
+               0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9, 0x85,
+               0xD8, 0xB3, 0xD9, 0x87, 0xD8, 0xB4, 0xD9, 0x87,
+               0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xB3, 0xD8, 0xAC,
+               0xD8, 0xB3, 0xD8, 0xAD, 0xD8, 0xB3, 0xD8, 0xAE,
+               0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8, 0xAD,
+               0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB7, 0xD9, 0x85,
+               0xD8, 0xB8, 0xD9, 0x85, 0xD8, 0xA7, 0xD9, 0x8B,
+               0xD8, 0xA7, 0xD9, 0x8B, 0xD8, 0xAA, 0xD8, 0xAC,
+               0xD9, 0x85, 0xD8, 0xAA, 0xD8, 0xAD, 0xD8, 0xAC,
+               0xD8, 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0xD8, 0xAA,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAA, 0xD8, 0xAE,
+               0xD9, 0x85, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC,
+               0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAA,
+               0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xAD,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x8A, 0xD8, 0xAD,
+               0xD9, 0x85, 0xD9, 0x89, 0xD8, 0xB3, 0xD8, 0xAD,
+               0xD8, 0xAC, 0xD8, 0xB3, 0xD8, 0xAC, 0xD8, 0xAD,
+               0xD8, 0xB3, 0xD8, 0xAC, 0xD9, 0x89, 0xD8, 0xB3,
+               0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xB3, 0xD9, 0x85,
+               0xD8, 0xAD, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC,
+               0xD8, 0xB3, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB3,
+               0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB5, 0xD8, 0xAD,
+               0xD8, 0xAD, 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD,
+               0xD8, 0xB5, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB4,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xB4, 0xD8, 0xAD,
+               0xD9, 0x85, 0xD8, 0xB4, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xB4,
+               0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9, 0x85,
+               0xD9, 0x85, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85,
+               0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x89, 0xD8, 0xB6,
+               0xD8, 0xAE, 0xD9, 0x85, 0xD8, 0xB6, 0xD8, 0xAE,
+               0xD9, 0x85, 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD,
+               0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xB7,
+               0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB7, 0xD9, 0x85,
+               0xD9, 0x8A, 0xD8, 0xB9, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB9,
+               0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB9, 0xD9, 0x85,
+               0xD9, 0x89, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85,
+               0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0xD8, 0xBA,
+               0xD9, 0x85, 0xD9, 0x89, 0xD9, 0x81, 0xD8, 0xAE,
+               0xD9, 0x85, 0xD9, 0x81, 0xD8, 0xAE, 0xD9, 0x85,
+               0xD9, 0x82, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x82,
+               0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x84, 0xD8, 0xAD,
+               0xD9, 0x85, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A,
+               0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89, 0xD9, 0x84,
+               0xD8, 0xAC, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xAC,
+               0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85,
+               0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0xD9, 0x84,
+               0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x84, 0xD9, 0x85,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC,
+               0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x85,
+               0xD8, 0xAD, 0xD9, 0x8A, 0xD9, 0x85, 0xD8, 0xAC,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD8, 0xAE, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xAC,
+               0xD8, 0xAE, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC,
+               0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x86,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x86, 0xD8, 0xAD,
+               0xD9, 0x89, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85,
+               0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x86,
+               0xD8, 0xAC, 0xD9, 0x89, 0xD9, 0x86, 0xD9, 0x85,
+               0xD9, 0x8A, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x89,
+               0xD9, 0x8A, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x8A,
+               0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xA8, 0xD8, 0xAE,
+               0xD9, 0x8A, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0xD8, 0xAA,
+               0xD8, 0xAE, 0xD9, 0x8A, 0xD8, 0xAA, 0xD8, 0xAE,
+               0xD9, 0x89, 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x8A,
+               0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0xD8, 0xAC,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD8, 0xAC, 0xD8, 0xAD,
+               0xD9, 0x89, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89,
+               0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89, 0xD8, 0xB5,
+               0xD8, 0xAD, 0xD9, 0x8A, 0xD8, 0xB4, 0xD8, 0xAD,
+               0xD9, 0x8A, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A,
+               0xD9, 0x84, 0xD8, 0xAC, 0xD9, 0x8A, 0xD9, 0x84,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x8A, 0xD8, 0xAD,
+               0xD9, 0x8A, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD9, 0x8A, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x85,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x82, 0xD9, 0x85,
+               0xD9, 0x8A, 0xD9, 0x86, 0xD8, 0xAD, 0xD9, 0x8A,
+               0xD9, 0x82, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x84,
+               0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xB9, 0xD9, 0x85,
+               0xD9, 0x8A, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x8A,
+               0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x85,
+               0xD8, 0xAE, 0xD9, 0x8A, 0xD9, 0x84, 0xD8, 0xAC,
+               0xD9, 0x85, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85,
+               0xD9, 0x84, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x86,
+               0xD8, 0xAC, 0xD8, 0xAD, 0xD8, 0xAC, 0xD8, 0xAD,
+               0xD9, 0x8A, 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A, 0xD9, 0x81,
+               0xD9, 0x85, 0xD9, 0x8A, 0xD8, 0xA8, 0xD8, 0xAD,
+               0xD9, 0x8A, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85,
+               0xD8, 0xB9, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xB5,
+               0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB3, 0xD8, 0xAE,
+               0xD9, 0x8A, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x8A,
+               0xD8, 0xB5, 0xD9, 0x84, 0xDB, 0x92, 0xD9, 0x82,
+               0xD9, 0x84, 0xDB, 0x92, 0xD8, 0xA7, 0xD9, 0x84,
+               0xD9, 0x84, 0xD9, 0x87, 0xD8, 0xA7, 0xD9, 0x83,
+               0xD8, 0xA8, 0xD8, 0xB1, 0xD9, 0x85, 0xD8, 0xAD,
+               0xD9, 0x85, 0xD8, 0xAF, 0xD8, 0xB5, 0xD9, 0x84,
+               0xD8, 0xB9, 0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xB3,
+               0xD9, 0x88, 0xD9, 0x84, 0xD8, 0xB9, 0xD9, 0x84,
+               0xD9, 0x8A, 0xD9, 0x87, 0xD9, 0x88, 0xD8, 0xB3,
+               0xD9, 0x84, 0xD9, 0x85, 0xD8, 0xB5, 0xD9, 0x84,
+               0xD9, 0x89, 0xD8, 0xB5, 0xD9, 0x84, 0xD9, 0x89,
+               0x20, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9,
+               0x87, 0x20, 0xD8, 0xB9, 0xD9, 0x84, 0xD9, 0x8A,
+               0xD9, 0x87, 0x20, 0xD9, 0x88, 0xD8, 0xB3, 0xD9,
+               0x84, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x84, 0x20,
+               0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x84,
+               0xD9, 0x87, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7,
+               0xD9, 0x84, 0x2E, 0x2E, 0xE2, 0x80, 0x94, 0xE2,
+               0x80, 0x93, 0x5F, 0x5F, 0x28, 0x29, 0x7B, 0x7D,
+               0xE3, 0x80, 0x94, 0xE3, 0x80, 0x95, 0xE3, 0x80,
+               0x90, 0xE3, 0x80, 0x91, 0xE3, 0x80, 0x8A, 0xE3,
+               0x80, 0x8B, 0xE3, 0x80, 0x88, 0xE3, 0x80, 0x89,
+               0xE3, 0x80, 0x8C, 0xE3, 0x80, 0x8D, 0xE3, 0x80,
+               0x8E, 0xE3, 0x80, 0x8F, 0x20, 0xCC, 0x85, 0x20,
+               0xCC, 0x85, 0x20, 0xCC, 0x85, 0x20, 0xCC, 0x85,
+               0x5F, 0x5F, 0x5F, 0x2C, 0xE3, 0x80, 0x81, 0x2E,
+               0x3B, 0x3A, 0x3F, 0x21, 0xE2, 0x80, 0x94, 0x28,
+               0x29, 0x7B, 0x7D, 0xE3, 0x80, 0x94, 0xE3, 0x80,
+               0x95, 0x23, 0x26, 0x2A, 0x2B, 0x2D, 0x3C, 0x3E,
+               0x3D, 0x5C, 0x24, 0x25, 0x40, 0x20, 0xD9, 0x8B,
+               0xD9, 0x80, 0xD9, 0x8B, 0x20, 0xD9, 0x8C, 0x20,
+               0xD9, 0x8D, 0x20, 0xD9, 0x8E, 0xD9, 0x80, 0xD9,
+               0x8E, 0x20, 0xD9, 0x8F, 0xD9, 0x80, 0xD9, 0x8F,
+               0x20, 0xD9, 0x90, 0xD9, 0x80, 0xD9, 0x90, 0x20,
+               0xD9, 0x91, 0xD9, 0x80, 0xD9, 0x91, 0x20, 0xD9,
+               0x92, 0xD9, 0x80, 0xD9, 0x92, 0xD8, 0xA1, 0xD8,
+               0xA7, 0xD9, 0x93, 0xD8, 0xA7, 0xD9, 0x93, 0xD8,
+               0xA7, 0xD9, 0x94, 0xD8, 0xA7, 0xD9, 0x94, 0xD9,
+               0x88, 0xD9, 0x94, 0xD9, 0x88, 0xD9, 0x94, 0xD8,
+               0xA7, 0xD9, 0x95, 0xD8, 0xA7, 0xD9, 0x95, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
+               0xA7, 0xD8, 0xA7, 0xD8, 0xA8, 0xD8, 0xA8, 0xD8,
+               0xA8, 0xD8, 0xA8, 0xD8, 0xA9, 0xD8, 0xA9, 0xD8,
+               0xAA, 0xD8, 0xAA, 0xD8, 0xAA, 0xD8, 0xAA, 0xD8,
+               0xAB, 0xD8, 0xAB, 0xD8, 0xAB, 0xD8, 0xAB, 0xD8,
+               0xAC, 0xD8, 0xAC, 0xD8, 0xAC, 0xD8, 0xAC, 0xD8,
+               0xAD, 0xD8, 0xAD, 0xD8, 0xAD, 0xD8, 0xAD, 0xD8,
+               0xAE, 0xD8, 0xAE, 0xD8, 0xAE, 0xD8, 0xAE, 0xD8,
+               0xAF, 0xD8, 0xAF, 0xD8, 0xB0, 0xD8, 0xB0, 0xD8,
+               0xB1, 0xD8, 0xB1, 0xD8, 0xB2, 0xD8, 0xB2, 0xD8,
+               0xB3, 0xD8, 0xB3, 0xD8, 0xB3, 0xD8, 0xB3, 0xD8,
+               0xB4, 0xD8, 0xB4, 0xD8, 0xB4, 0xD8, 0xB4, 0xD8,
+               0xB5, 0xD8, 0xB5, 0xD8, 0xB5, 0xD8, 0xB5, 0xD8,
+               0xB6, 0xD8, 0xB6, 0xD8, 0xB6, 0xD8, 0xB6, 0xD8,
+               0xB7, 0xD8, 0xB7, 0xD8, 0xB7, 0xD8, 0xB7, 0xD8,
+               0xB8, 0xD8, 0xB8, 0xD8, 0xB8, 0xD8, 0xB8, 0xD8,
+               0xB9, 0xD8, 0xB9, 0xD8, 0xB9, 0xD8, 0xB9, 0xD8,
+               0xBA, 0xD8, 0xBA, 0xD8, 0xBA, 0xD8, 0xBA, 0xD9,
+               0x81, 0xD9, 0x81, 0xD9, 0x81, 0xD9, 0x81, 0xD9,
+               0x82, 0xD9, 0x82, 0xD9, 0x82, 0xD9, 0x82, 0xD9,
+               0x83, 0xD9, 0x83, 0xD9, 0x83, 0xD9, 0x83, 0xD9,
+               0x84, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x84, 0xD9,
+               0x85, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
+               0x86, 0xD9, 0x86, 0xD9, 0x86, 0xD9, 0x86, 0xD9,
+               0x87, 0xD9, 0x87, 0xD9, 0x87, 0xD9, 0x87, 0xD9,
+               0x88, 0xD9, 0x88, 0xD9, 0x89, 0xD9, 0x89, 0xD9,
+               0x8A, 0xD9, 0x8A, 0xD9, 0x8A, 0xD9, 0x8A, 0xD9,
+               0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xD9, 0x84, 0xD8,
+               0xA7, 0xD9, 0x93, 0xD9, 0x84, 0xD8, 0xA7, 0xD9,
+               0x94, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xD9,
+               0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xD9, 0x84, 0xD8,
+               0xA7, 0xD9, 0x95, 0xD9, 0x84, 0xD8, 0xA7, 0xD9,
+               0x84, 0xD8, 0xA7, 0x21, 0x22, 0x23, 0x24, 0x25,
+               0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+               0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+               0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D,
+               0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+               0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D,
+               0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
+               0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D,
+               0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D,
+               0x7E, 0xE2, 0xA6, 0x85, 0xE2, 0xA6, 0x86, 0xE3,
+               0x80, 0x82, 0xE3, 0x80, 0x8C, 0xE3, 0x80, 0x8D,
+               0xE3, 0x80, 0x81, 0xE3, 0x83, 0xBB, 0xE3, 0x83,
+               0xB2, 0xE3, 0x82, 0xA1, 0xE3, 0x82, 0xA3, 0xE3,
+               0x82, 0xA5, 0xE3, 0x82, 0xA7, 0xE3, 0x82, 0xA9,
+               0xE3, 0x83, 0xA3, 0xE3, 0x83, 0xA5, 0xE3, 0x83,
+               0xA7, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0xBC, 0xE3,
+               0x82, 0xA2, 0xE3, 0x82, 0xA4, 0xE3, 0x82, 0xA6,
+               0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xAA, 0xE3, 0x82,
+               0xAB, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0xAF, 0xE3,
+               0x82, 0xB1, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0xB5,
+               0xE3, 0x82, 0xB7, 0xE3, 0x82, 0xB9, 0xE3, 0x82,
+               0xBB, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0xBF, 0xE3,
+               0x83, 0x81, 0xE3, 0x83, 0x84, 0xE3, 0x83, 0x86,
+               0xE3, 0x83, 0x88, 0xE3, 0x83, 0x8A, 0xE3, 0x83,
+               0x8B, 0xE3, 0x83, 0x8C, 0xE3, 0x83, 0x8D, 0xE3,
+               0x83, 0x8E, 0xE3, 0x83, 0x8F, 0xE3, 0x83, 0x92,
+               0xE3, 0x83, 0x95, 0xE3, 0x83, 0x98, 0xE3, 0x83,
+               0x9B, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x9F, 0xE3,
+               0x83, 0xA0, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xA2,
+               0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xA6, 0xE3, 0x83,
+               0xA8, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xAA, 0xE3,
+               0x83, 0xAB, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xAD,
+               0xE3, 0x83, 0xAF, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+               0x99, 0xE3, 0x82, 0x9A, 0xE1, 0x85, 0xA0, 0xE1,
+               0x84, 0x80, 0xE1, 0x84, 0x81, 0xE1, 0x86, 0xAA,
+               0xE1, 0x84, 0x82, 0xE1, 0x86, 0xAC, 0xE1, 0x86,
+               0xAD, 0xE1, 0x84, 0x83, 0xE1, 0x84, 0x84, 0xE1,
+               0x84, 0x85, 0xE1, 0x86, 0xB0, 0xE1, 0x86, 0xB1,
+               0xE1, 0x86, 0xB2, 0xE1, 0x86, 0xB3, 0xE1, 0x86,
+               0xB4, 0xE1, 0x86, 0xB5, 0xE1, 0x84, 0x9A, 0xE1,
+               0x84, 0x86, 0xE1, 0x84, 0x87, 0xE1, 0x84, 0x88,
+               0xE1, 0x84, 0xA1, 0xE1, 0x84, 0x89, 0xE1, 0x84,
+               0x8A, 0xE1, 0x84, 0x8B, 0xE1, 0x84, 0x8C, 0xE1,
+               0x84, 0x8D, 0xE1, 0x84, 0x8E, 0xE1, 0x84, 0x8F,
+               0xE1, 0x84, 0x90, 0xE1, 0x84, 0x91, 0xE1, 0x84,
+               0x92, 0xE1, 0x85, 0xA1, 0xE1, 0x85, 0xA2, 0xE1,
+               0x85, 0xA3, 0xE1, 0x85, 0xA4, 0xE1, 0x85, 0xA5,
+               0xE1, 0x85, 0xA6, 0xE1, 0x85, 0xA7, 0xE1, 0x85,
+               0xA8, 0xE1, 0x85, 0xA9, 0xE1, 0x85, 0xAA, 0xE1,
+               0x85, 0xAB, 0xE1, 0x85, 0xAC, 0xE1, 0x85, 0xAD,
+               0xE1, 0x85, 0xAE, 0xE1, 0x85, 0xAF, 0xE1, 0x85,
+               0xB0, 0xE1, 0x85, 0xB1, 0xE1, 0x85, 0xB2, 0xE1,
+               0x85, 0xB3, 0xE1, 0x85, 0xB4, 0xE1, 0x85, 0xB5,
+               0xC2, 0xA2, 0xC2, 0xA3, 0xC2, 0xAC, 0x20, 0xCC,
+               0x84, 0xC2, 0xA6, 0xC2, 0xA5, 0xE2, 0x82, 0xA9,
+               0xE2, 0x94, 0x82, 0xE2, 0x86, 0x90, 0xE2, 0x86,
+               0x91, 0xE2, 0x86, 0x92, 0xE2, 0x86, 0x93, 0xE2,
+               0x96, 0xA0, 0xE2, 0x97, 0x8B, 0xF6, 0xF0, 0x9D,
+               0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0xF6, 0xF0,
+               0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF6,
+               0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
+               0xF0, 0x9D, 0x85, 0xAE, 0xF6, 0xF0, 0x9D, 0x85,
+               0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+               0xAF, 0xF6, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D,
+               0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0xF6, 0xF0,
+               0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
+               0x9D, 0x85, 0xB1, 0xF6, 0xF0, 0x9D, 0x85, 0x98,
+               0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2,
+               0xF6, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85,
+               0xA5, 0xF6, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D,
+               0x85, 0xA5, 0xF6, 0xF0, 0x9D, 0x86, 0xB9, 0xF0,
+               0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xF6,
+               0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5,
+               0xF0, 0x9D, 0x85, 0xAE, 0xF6, 0xF0, 0x9D, 0x86,
+               0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+               0xAF, 0xF6, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D,
+               0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x41, 0x42,
+               0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
+               0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
+               0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
+               0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+               0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+               0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+               0x79, 0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+               0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
+               0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+               0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64,
+               0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x43, 0x44, 0x47, 0x4A, 0x4B, 0x4E,
+               0x4F, 0x50, 0x51, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x66,
+               0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x44,
+               0x45, 0x46, 0x47, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
+               0x4F, 0x50, 0x51, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+               0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
+               0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+               0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x44, 0x45,
+               0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4F,
+               0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0xCE, 0x91, 0xCE, 0x92, 0xCE, 0x93, 0xCE,
+               0x94, 0xCE, 0x95, 0xCE, 0x96, 0xCE, 0x97, 0xCE,
+               0x98, 0xCE, 0x99, 0xCE, 0x9A, 0xCE, 0x9B, 0xCE,
+               0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE, 0x9F, 0xCE,
+               0xA0, 0xCE, 0xA1, 0xCE, 0x98, 0xCE, 0xA3, 0xCE,
+               0xA4, 0xCE, 0xA5, 0xCE, 0xA6, 0xCE, 0xA7, 0xCE,
+               0xA8, 0xCE, 0xA9, 0xE2, 0x88, 0x87, 0xCE, 0xB1,
+               0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4, 0xCE, 0xB5,
+               0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8, 0xCE, 0xB9,
+               0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC, 0xCE, 0xBD,
+               0xCE, 0xBE, 0xCE, 0xBF, 0xCF, 0x80, 0xCF, 0x81,
+               0xCF, 0x82, 0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85,
+               0xCF, 0x86, 0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89,
+               0xE2, 0x88, 0x82, 0xCE, 0xB5, 0xCE, 0xB8, 0xCE,
+               0xBA, 0xCF, 0x86, 0xCF, 0x81, 0xCF, 0x80, 0xCE,
+               0x91, 0xCE, 0x92, 0xCE, 0x93, 0xCE, 0x94, 0xCE,
+               0x95, 0xCE, 0x96, 0xCE, 0x97, 0xCE, 0x98, 0xCE,
+               0x99, 0xCE, 0x9A, 0xCE, 0x9B, 0xCE, 0x9C, 0xCE,
+               0x9D, 0xCE, 0x9E, 0xCE, 0x9F, 0xCE, 0xA0, 0xCE,
+               0xA1, 0xCE, 0x98, 0xCE, 0xA3, 0xCE, 0xA4, 0xCE,
+               0xA5, 0xCE, 0xA6, 0xCE, 0xA7, 0xCE, 0xA8, 0xCE,
+               0xA9, 0xE2, 0x88, 0x87, 0xCE, 0xB1, 0xCE, 0xB2,
+               0xCE, 0xB3, 0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6,
+               0xCE, 0xB7, 0xCE, 0xB8, 0xCE, 0xB9, 0xCE, 0xBA,
+               0xCE, 0xBB, 0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE,
+               0xCE, 0xBF, 0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x82,
+               0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85, 0xCF, 0x86,
+               0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89, 0xE2, 0x88,
+               0x82, 0xCE, 0xB5, 0xCE, 0xB8, 0xCE, 0xBA, 0xCF,
+               0x86, 0xCF, 0x81, 0xCF, 0x80, 0xCE, 0x91, 0xCE,
+               0x92, 0xCE, 0x93, 0xCE, 0x94, 0xCE, 0x95, 0xCE,
+               0x96, 0xCE, 0x97, 0xCE, 0x98, 0xCE, 0x99, 0xCE,
+               0x9A, 0xCE, 0x9B, 0xCE, 0x9C, 0xCE, 0x9D, 0xCE,
+               0x9E, 0xCE, 0x9F, 0xCE, 0xA0, 0xCE, 0xA1, 0xCE,
+               0x98, 0xCE, 0xA3, 0xCE, 0xA4, 0xCE, 0xA5, 0xCE,
+               0xA6, 0xCE, 0xA7, 0xCE, 0xA8, 0xCE, 0xA9, 0xE2,
+               0x88, 0x87, 0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3,
+               0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6, 0xCE, 0xB7,
+               0xCE, 0xB8, 0xCE, 0xB9, 0xCE, 0xBA, 0xCE, 0xBB,
+               0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE, 0xCE, 0xBF,
+               0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x82, 0xCF, 0x83,
+               0xCF, 0x84, 0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87,
+               0xCF, 0x88, 0xCF, 0x89, 0xE2, 0x88, 0x82, 0xCE,
+               0xB5, 0xCE, 0xB8, 0xCE, 0xBA, 0xCF, 0x86, 0xCF,
+               0x81, 0xCF, 0x80, 0xCE, 0x91, 0xCE, 0x92, 0xCE,
+               0x93, 0xCE, 0x94, 0xCE, 0x95, 0xCE, 0x96, 0xCE,
+               0x97, 0xCE, 0x98, 0xCE, 0x99, 0xCE, 0x9A, 0xCE,
+               0x9B, 0xCE, 0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE,
+               0x9F, 0xCE, 0xA0, 0xCE, 0xA1, 0xCE, 0x98, 0xCE,
+               0xA3, 0xCE, 0xA4, 0xCE, 0xA5, 0xCE, 0xA6, 0xCE,
+               0xA7, 0xCE, 0xA8, 0xCE, 0xA9, 0xE2, 0x88, 0x87,
+               0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4,
+               0xCE, 0xB5, 0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8,
+               0xCE, 0xB9, 0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC,
+               0xCE, 0xBD, 0xCE, 0xBE, 0xCE, 0xBF, 0xCF, 0x80,
+               0xCF, 0x81, 0xCF, 0x82, 0xCF, 0x83, 0xCF, 0x84,
+               0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87, 0xCF, 0x88,
+               0xCF, 0x89, 0xE2, 0x88, 0x82, 0xCE, 0xB5, 0xCE,
+               0xB8, 0xCE, 0xBA, 0xCF, 0x86, 0xCF, 0x81, 0xCF,
+               0x80, 0xCE, 0x91, 0xCE, 0x92, 0xCE, 0x93, 0xCE,
+               0x94, 0xCE, 0x95, 0xCE, 0x96, 0xCE, 0x97, 0xCE,
+               0x98, 0xCE, 0x99, 0xCE, 0x9A, 0xCE, 0x9B, 0xCE,
+               0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE, 0x9F, 0xCE,
+               0xA0, 0xCE, 0xA1, 0xCE, 0x98, 0xCE, 0xA3, 0xCE,
+               0xA4, 0xCE, 0xA5, 0xCE, 0xA6, 0xCE, 0xA7, 0xCE,
+               0xA8, 0xCE, 0xA9, 0xE2, 0x88, 0x87, 0xCE, 0xB1,
+               0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4, 0xCE, 0xB5,
+               0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8, 0xCE, 0xB9,
+               0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC, 0xCE, 0xBD,
+               0xCE, 0xBE, 0xCE, 0xBF, 0xCF, 0x80, 0xCF, 0x81,
+               0xCF, 0x82, 0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85,
+               0xCF, 0x86, 0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89,
+               0xE2, 0x88, 0x82, 0xCE, 0xB5, 0xCE, 0xB8, 0xCE,
+               0xBA, 0xCF, 0x86, 0xCF, 0x81, 0xCF, 0x80, 0x30,
+               0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+               0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
+               0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
+               0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
+               0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0xF6, 0xE4, 0xB8, 0xBD, 0xF6, 0xE4, 0xB8,
+               0xB8, 0xF6, 0xE4, 0xB9, 0x81, 0xF6, 0xF0, 0xA0,
+               0x84, 0xA2, 0xF6, 0xE4, 0xBD, 0xA0, 0xF6, 0xE4,
+               0xBE, 0xAE, 0xF6, 0xE4, 0xBE, 0xBB, 0xF6, 0xE5,
+               0x80, 0x82, 0xF6, 0xE5, 0x81, 0xBA, 0xF6, 0xE5,
+               0x82, 0x99, 0xF6, 0xE5, 0x83, 0xA7, 0xF6, 0xE5,
+               0x83, 0x8F, 0xF6, 0xE3, 0x92, 0x9E, 0xF6, 0xF0,
+               0xA0, 0x98, 0xBA, 0xF6, 0xE5, 0x85, 0x8D, 0xF6,
+               0xE5, 0x85, 0x94, 0xF6, 0xE5, 0x85, 0xA4, 0xF6,
+               0xE5, 0x85, 0xB7, 0xF6, 0xF0, 0xA0, 0x94, 0x9C,
+               0xF6, 0xE3, 0x92, 0xB9, 0xF6, 0xE5, 0x85, 0xA7,
+               0xF6, 0xE5, 0x86, 0x8D, 0xF6, 0xF0, 0xA0, 0x95,
+               0x8B, 0xF6, 0xE5, 0x86, 0x97, 0xF6, 0xE5, 0x86,
+               0xA4, 0xF6, 0xE4, 0xBB, 0x8C, 0xF6, 0xE5, 0x86,
+               0xAC, 0xF6, 0xE5, 0x86, 0xB5, 0xF6, 0xF0, 0xA9,
+               0x87, 0x9F, 0xF6, 0xE5, 0x87, 0xB5, 0xF6, 0xE5,
+               0x88, 0x83, 0xF6, 0xE3, 0x93, 0x9F, 0xF6, 0xE5,
+               0x88, 0xBB, 0xF6, 0xE5, 0x89, 0x86, 0xF6, 0xE5,
+               0x89, 0xB2, 0xF6, 0xE5, 0x89, 0xB7, 0xF6, 0xE3,
+               0x94, 0x95, 0xF6, 0xE5, 0x8B, 0x87, 0xF6, 0xE5,
+               0x8B, 0x89, 0xF6, 0xE5, 0x8B, 0xA4, 0xF6, 0xE5,
+               0x8B, 0xBA, 0xF6, 0xE5, 0x8C, 0x85, 0xF6, 0xE5,
+               0x8C, 0x86, 0xF6, 0xE5, 0x8C, 0x97, 0xF6, 0xE5,
+               0x8D, 0x89, 0xF6, 0xE5, 0x8D, 0x91, 0xF6, 0xE5,
+               0x8D, 0x9A, 0xF6, 0xE5, 0x8D, 0xB3, 0xF6, 0xE5,
+               0x8D, 0xBD, 0xF6, 0xE5, 0x8D, 0xBF, 0xF6, 0xE5,
+               0x8D, 0xBF, 0xF6, 0xE5, 0x8D, 0xBF, 0xF6, 0xF0,
+               0xA0, 0xA8, 0xAC, 0xF6, 0xE7, 0x81, 0xB0, 0xF6,
+               0xE5, 0x8F, 0x8A, 0xF6, 0xE5, 0x8F, 0x9F, 0xF6,
+               0xF0, 0xA0, 0xAD, 0xA3, 0xF6, 0xE5, 0x8F, 0xAB,
+               0xF6, 0xE5, 0x8F, 0xB1, 0xF6, 0xE5, 0x90, 0x86,
+               0xF6, 0xE5, 0x92, 0x9E, 0xF6, 0xE5, 0x90, 0xB8,
+               0xF6, 0xE5, 0x91, 0x88, 0xF6, 0xE5, 0x91, 0xA8,
+               0xF6, 0xE5, 0x92, 0xA2, 0xF6, 0xE5, 0x93, 0xB6,
+               0xF6, 0xE5, 0x94, 0x90, 0xF6, 0xE5, 0x95, 0x93,
+               0xF6, 0xE5, 0x95, 0xA3, 0xF6, 0xE5, 0x96, 0x84,
+               0xF6, 0xE5, 0x96, 0x84, 0xF6, 0xE5, 0x96, 0x99,
+               0xF6, 0xE5, 0x96, 0xAB, 0xF6, 0xE5, 0x96, 0xB3,
+               0xF6, 0xE5, 0x97, 0x82, 0xF6, 0xE5, 0x9C, 0x96,
+               0xF6, 0xE5, 0x98, 0x86, 0xF6, 0xE5, 0x9C, 0x97,
+               0xF6, 0xE5, 0x99, 0x91, 0xF6, 0xE5, 0x99, 0xB4,
+               0xF6, 0xE5, 0x88, 0x87, 0xF6, 0xE5, 0xA3, 0xAE,
+               0xF6, 0xE5, 0x9F, 0x8E, 0xF6, 0xE5, 0x9F, 0xB4,
+               0xF6, 0xE5, 0xA0, 0x8D, 0xF6, 0xE5, 0x9E, 0x8B,
+               0xF6, 0xE5, 0xA0, 0xB2, 0xF6, 0xE5, 0xA0, 0xB1,
+               0xF6, 0xE5, 0xA2, 0xAC, 0xF6, 0xF0, 0xA1, 0x93,
+               0xA4, 0xF6, 0xE5, 0xA3, 0xB2, 0xF6, 0xE5, 0xA3,
+               0xB7, 0xF6, 0xE5, 0xA4, 0x86, 0xF6, 0xE5, 0xA4,
+               0x9A, 0xF6, 0xE5, 0xA4, 0xA2, 0xF6, 0xE5, 0xA5,
+               0xA2, 0xF6, 0xF0, 0xA1, 0x9A, 0xA8, 0xF6, 0xF0,
+               0xA1, 0x9B, 0xAA, 0xF6, 0xE5, 0xA7, 0xAC, 0xF6,
+               0xE5, 0xA8, 0x9B, 0xF6, 0xE5, 0xA8, 0xA7, 0xF6,
+               0xE5, 0xA7, 0x98, 0xF6, 0xE5, 0xA9, 0xA6, 0xF6,
+               0xE3, 0x9B, 0xAE, 0xF6, 0xE3, 0x9B, 0xBC, 0xF6,
+               0xE5, 0xAC, 0x88, 0xF6, 0xE5, 0xAC, 0xBE, 0xF6,
+               0xE5, 0xAC, 0xBE, 0xF6, 0xF0, 0xA1, 0xA7, 0x88,
+               0xF6, 0xE5, 0xAF, 0x83, 0xF6, 0xE5, 0xAF, 0x98,
+               0xF6, 0xE5, 0xAF, 0xA7, 0xF6, 0xE5, 0xAF, 0xB3,
+               0xF6, 0xF0, 0xA1, 0xAC, 0x98, 0xF6, 0xE5, 0xAF,
+               0xBF, 0xF6, 0xE5, 0xB0, 0x86, 0xF6, 0xE5, 0xBD,
+               0x93, 0xF6, 0xE5, 0xB0, 0xA2, 0xF6, 0xE3, 0x9E,
+               0x81, 0xF6, 0xE5, 0xB1, 0xA0, 0xF6, 0xE5, 0xB1,
+               0xAE, 0xF6, 0xE5, 0xB3, 0x80, 0xF6, 0xE5, 0xB2,
+               0x8D, 0xF6, 0xF0, 0xA1, 0xB7, 0xA4, 0xF6, 0xE5,
+               0xB5, 0x83, 0xF6, 0xF0, 0xA1, 0xB7, 0xA6, 0xF6,
+               0xE5, 0xB5, 0xAE, 0xF6, 0xE5, 0xB5, 0xAB, 0xF6,
+               0xE5, 0xB5, 0xBC, 0xF6, 0xE5, 0xB7, 0xA1, 0xF6,
+               0xE5, 0xB7, 0xA2, 0xF6, 0xE3, 0xA0, 0xAF, 0xF6,
+               0xE5, 0xB7, 0xBD, 0xF6, 0xE5, 0xB8, 0xA8, 0xF6,
+               0xE5, 0xB8, 0xBD, 0xF6, 0xE5, 0xB9, 0xA9, 0xF6,
+               0xE3, 0xA1, 0xA2, 0xF6, 0xF0, 0xA2, 0x86, 0x83,
+               0xF6, 0xE3, 0xA1, 0xBC, 0xF6, 0xE5, 0xBA, 0xB0,
+               0xF6, 0xE5, 0xBA, 0xB3, 0xF6, 0xE5, 0xBA, 0xB6,
+               0xF6, 0xE5, 0xBB, 0x8A, 0xF6, 0xF0, 0xAA, 0x8E,
+               0x92, 0xF6, 0xE5, 0xBB, 0xBE, 0xF6, 0xF0, 0xA2,
+               0x8C, 0xB1, 0xF6, 0xF0, 0xA2, 0x8C, 0xB1, 0xF6,
+               0xE8, 0x88, 0x81, 0xF6, 0xE5, 0xBC, 0xA2, 0xF6,
+               0xE5, 0xBC, 0xA2, 0xF6, 0xE3, 0xA3, 0x87, 0xF6,
+               0xF0, 0xA3, 0x8A, 0xB8, 0xF6, 0xF0, 0xA6, 0x87,
+               0x9A, 0xF6, 0xE5, 0xBD, 0xA2, 0xF6, 0xE5, 0xBD,
+               0xAB, 0xF6, 0xE3, 0xA3, 0xA3, 0xF6, 0xE5, 0xBE,
+               0x9A, 0xF6, 0xE5, 0xBF, 0x8D, 0xF6, 0xE5, 0xBF,
+               0x97, 0xF6, 0xE5, 0xBF, 0xB9, 0xF6, 0xE6, 0x82,
+               0x81, 0xF6, 0xE3, 0xA4, 0xBA, 0xF6, 0xE3, 0xA4,
+               0x9C, 0xF6, 0xE6, 0x82, 0x94, 0xF6, 0xF0, 0xA2,
+               0x9B, 0x94, 0xF6, 0xE6, 0x83, 0x87, 0xF6, 0xE6,
+               0x85, 0x88, 0xF6, 0xE6, 0x85, 0x8C, 0xF6, 0xE6,
+               0x85, 0x8E, 0xF6, 0xE6, 0x85, 0x8C, 0xF6, 0xE6,
+               0x85, 0xBA, 0xF6, 0xE6, 0x86, 0x8E, 0xF6, 0xE6,
+               0x86, 0xB2, 0xF6, 0xE6, 0x86, 0xA4, 0xF6, 0xE6,
+               0x86, 0xAF, 0xF6, 0xE6, 0x87, 0x9E, 0xF6, 0xE6,
+               0x87, 0xB2, 0xF6, 0xE6, 0x87, 0xB6, 0xF6, 0xE6,
+               0x88, 0x90, 0xF6, 0xE6, 0x88, 0x9B, 0xF6, 0xE6,
+               0x89, 0x9D, 0xF6, 0xE6, 0x8A, 0xB1, 0xF6, 0xE6,
+               0x8B, 0x94, 0xF6, 0xE6, 0x8D, 0x90, 0xF6, 0xF0,
+               0xA2, 0xAC, 0x8C, 0xF6, 0xE6, 0x8C, 0xBD, 0xF6,
+               0xE6, 0x8B, 0xBC, 0xF6, 0xE6, 0x8D, 0xA8, 0xF6,
+               0xE6, 0x8E, 0x83, 0xF6, 0xE6, 0x8F, 0xA4, 0xF6,
+               0xF0, 0xA2, 0xAF, 0xB1, 0xF6, 0xE6, 0x90, 0xA2,
+               0xF6, 0xE6, 0x8F, 0x85, 0xF6, 0xE6, 0x8E, 0xA9,
+               0xF6, 0xE3, 0xA8, 0xAE, 0xF6, 0xE6, 0x91, 0xA9,
+               0xF6, 0xE6, 0x91, 0xBE, 0xF6, 0xE6, 0x92, 0x9D,
+               0xF6, 0xE6, 0x91, 0xB7, 0xF6, 0xE3, 0xA9, 0xAC,
+               0xF6, 0xE6, 0x95, 0x8F, 0xF6, 0xE6, 0x95, 0xAC,
+               0xF6, 0xF0, 0xA3, 0x80, 0x8A, 0xF6, 0xE6, 0x97,
+               0xA3, 0xF6, 0xE6, 0x9B, 0xB8, 0xF6, 0xE6, 0x99,
+               0x89, 0xF6, 0xE3, 0xAC, 0x99, 0xF6, 0xE6, 0x9A,
+               0x91, 0xF6, 0xE3, 0xAC, 0x88, 0xF6, 0xE3, 0xAB,
+               0xA4, 0xF6, 0xE5, 0x86, 0x92, 0xF6, 0xE5, 0x86,
+               0x95, 0xF6, 0xE6, 0x9C, 0x80, 0xF6, 0xE6, 0x9A,
+               0x9C, 0xF6, 0xE8, 0x82, 0xAD, 0xF6, 0xE4, 0x8F,
+               0x99, 0xF6, 0xE6, 0x9C, 0x97, 0xF6, 0xE6, 0x9C,
+               0x9B, 0xF6, 0xE6, 0x9C, 0xA1, 0xF6, 0xE6, 0x9D,
+               0x9E, 0xF6, 0xE6, 0x9D, 0x93, 0xF6, 0xF0, 0xA3,
+               0x8F, 0x83, 0xF6, 0xE3, 0xAD, 0x89, 0xF6, 0xE6,
+               0x9F, 0xBA, 0xF6, 0xE6, 0x9E, 0x85, 0xF6, 0xE6,
+               0xA1, 0x92, 0xF6, 0xE6, 0xA2, 0x85, 0xF6, 0xF0,
+               0xA3, 0x91, 0xAD, 0xF6, 0xE6, 0xA2, 0x8E, 0xF6,
+               0xE6, 0xA0, 0x9F, 0xF6, 0xE6, 0xA4, 0x94, 0xF6,
+               0xE3, 0xAE, 0x9D, 0xF6, 0xE6, 0xA5, 0x82, 0xF6,
+               0xE6, 0xA6, 0xA3, 0xF6, 0xE6, 0xA7, 0xAA, 0xF6,
+               0xE6, 0xAA, 0xA8, 0xF6, 0xF0, 0xA3, 0x9A, 0xA3,
+               0xF6, 0xE6, 0xAB, 0x9B, 0xF6, 0xE3, 0xB0, 0x98,
+               0xF6, 0xE6, 0xAC, 0xA1, 0xF6, 0xF0, 0xA3, 0xA2,
+               0xA7, 0xF6, 0xE6, 0xAD, 0x94, 0xF6, 0xE3, 0xB1,
+               0x8E, 0xF6, 0xE6, 0xAD, 0xB2, 0xF6, 0xE6, 0xAE,
+               0x9F, 0xF6, 0xE6, 0xAE, 0xBA, 0xF6, 0xE6, 0xAE,
+               0xBB, 0xF6, 0xF0, 0xA3, 0xAA, 0x8D, 0xF6, 0xF0,
+               0xA1, 0xB4, 0x8B, 0xF6, 0xF0, 0xA3, 0xAB, 0xBA,
+               0xF6, 0xE6, 0xB1, 0x8E, 0xF6, 0xF0, 0xA3, 0xB2,
+               0xBC, 0xF6, 0xE6, 0xB2, 0xBF, 0xF6, 0xE6, 0xB3,
+               0x8D, 0xF6, 0xE6, 0xB1, 0xA7, 0xF6, 0xE6, 0xB4,
+               0x96, 0xF6, 0xE6, 0xB4, 0xBE, 0xF6, 0xE6, 0xB5,
+               0xB7, 0xF6, 0xE6, 0xB5, 0x81, 0xF6, 0xE6, 0xB5,
+               0xA9, 0xF6, 0xE6, 0xB5, 0xB8, 0xF6, 0xE6, 0xB6,
+               0x85, 0xF6, 0xF0, 0xA3, 0xB4, 0x9E, 0xF6, 0xE6,
+               0xB4, 0xB4, 0xF6, 0xE6, 0xB8, 0xAF, 0xF6, 0xE6,
+               0xB9, 0xAE, 0xF6, 0xE3, 0xB4, 0xB3, 0xF6, 0xE6,
+               0xBB, 0x8B, 0xF6, 0xE6, 0xBB, 0x87, 0xF6, 0xF0,
+               0xA3, 0xBB, 0x91, 0xF6, 0xE6, 0xB7, 0xB9, 0xF6,
+               0xE6, 0xBD, 0xAE, 0xF6, 0xF0, 0xA3, 0xBD, 0x9E,
+               0xF6, 0xF0, 0xA3, 0xBE, 0x8E, 0xF6, 0xE6, 0xBF,
+               0x86, 0xF6, 0xE7, 0x80, 0xB9, 0xF6, 0xE7, 0x80,
+               0x9E, 0xF6, 0xE7, 0x80, 0x9B, 0xF6, 0xE3, 0xB6,
+               0x96, 0xF6, 0xE7, 0x81, 0x8A, 0xF6, 0xE7, 0x81,
+               0xBD, 0xF6, 0xE7, 0x81, 0xB7, 0xF6, 0xE7, 0x82,
+               0xAD, 0xF6, 0xF0, 0xA0, 0x94, 0xA5, 0xF6, 0xE7,
+               0x85, 0x85, 0xF6, 0xF0, 0xA4, 0x89, 0xA3, 0xF6,
+               0xE7, 0x86, 0x9C, 0xF6, 0xF0, 0xA4, 0x8E, 0xAB,
+               0xF6, 0xE7, 0x88, 0xA8, 0xF6, 0xE7, 0x88, 0xB5,
+               0xF6, 0xE7, 0x89, 0x90, 0xF6, 0xF0, 0xA4, 0x98,
+               0x88, 0xF6, 0xE7, 0x8A, 0x80, 0xF6, 0xE7, 0x8A,
+               0x95, 0xF6, 0xF0, 0xA4, 0x9C, 0xB5, 0xF6, 0xF0,
+               0xA4, 0xA0, 0x94, 0xF6, 0xE7, 0x8D, 0xBA, 0xF6,
+               0xE7, 0x8E, 0x8B, 0xF6, 0xE3, 0xBA, 0xAC, 0xF6,
+               0xE7, 0x8E, 0xA5, 0xF6, 0xE3, 0xBA, 0xB8, 0xF6,
+               0xE3, 0xBA, 0xB8, 0xF6, 0xE7, 0x91, 0x87, 0xF6,
+               0xE7, 0x91, 0x9C, 0xF6, 0xE7, 0x91, 0xB1, 0xF6,
+               0xE7, 0x92, 0x85, 0xF6, 0xE7, 0x93, 0x8A, 0xF6,
+               0xE3, 0xBC, 0x9B, 0xF6, 0xE7, 0x94, 0xA4, 0xF6,
+               0xF0, 0xA4, 0xB0, 0xB6, 0xF6, 0xE7, 0x94, 0xBE,
+               0xF6, 0xF0, 0xA4, 0xB2, 0x92, 0xF6, 0xE7, 0x95,
+               0xB0, 0xF6, 0xF0, 0xA2, 0x86, 0x9F, 0xF6, 0xE7,
+               0x98, 0x90, 0xF6, 0xF0, 0xA4, 0xBE, 0xA1, 0xF6,
+               0xF0, 0xA4, 0xBE, 0xB8, 0xF6, 0xF0, 0xA5, 0x81,
+               0x84, 0xF6, 0xE3, 0xBF, 0xBC, 0xF6, 0xE4, 0x80,
+               0x88, 0xF6, 0xE7, 0x9B, 0xB4, 0xF6, 0xF0, 0xA5,
+               0x83, 0xB3, 0xF6, 0xF0, 0xA5, 0x83, 0xB2, 0xF6,
+               0xF0, 0xA5, 0x84, 0x99, 0xF6, 0xF0, 0xA5, 0x84,
+               0xB3, 0xF6, 0xE7, 0x9C, 0x9E, 0xF6, 0xE7, 0x9C,
+               0x9F, 0xF6, 0xE7, 0x9C, 0x9F, 0xF6, 0xE7, 0x9D,
+               0x8A, 0xF6, 0xE4, 0x80, 0xB9, 0xF6, 0xE7, 0x9E,
+               0x8B, 0xF6, 0xE4, 0x81, 0x86, 0xF6, 0xE4, 0x82,
+               0x96, 0xF6, 0xF0, 0xA5, 0x90, 0x9D, 0xF6, 0xE7,
+               0xA1, 0x8E, 0xF6, 0xE7, 0xA2, 0x8C, 0xF6, 0xE7,
+               0xA3, 0x8C, 0xF6, 0xE4, 0x83, 0xA3, 0xF6, 0xF0,
+               0xA5, 0x98, 0xA6, 0xF6, 0xE7, 0xA5, 0x96, 0xF6,
+               0xF0, 0xA5, 0x9A, 0x9A, 0xF6, 0xF0, 0xA5, 0x9B,
+               0x85, 0xF6, 0xE7, 0xA6, 0x8F, 0xF6, 0xE7, 0xA7,
+               0xAB, 0xF6, 0xE4, 0x84, 0xAF, 0xF6, 0xE7, 0xA9,
+               0x80, 0xF6, 0xE7, 0xA9, 0x8A, 0xF6, 0xE7, 0xA9,
+               0x8F, 0xF6, 0xF0, 0xA5, 0xA5, 0xBC, 0xF6, 0xF0,
+               0xA5, 0xAA, 0xA7, 0xF6, 0xF0, 0xA5, 0xAA, 0xA7,
+               0xF6, 0xE7, 0xAB, 0xAE, 0xF6, 0xE4, 0x88, 0x82,
+               0xF6, 0xF0, 0xA5, 0xAE, 0xAB, 0xF6, 0xE7, 0xAF,
+               0x86, 0xF6, 0xE7, 0xAF, 0x89, 0xF6, 0xE4, 0x88,
+               0xA7, 0xF6, 0xF0, 0xA5, 0xB2, 0x80, 0xF6, 0xE7,
+               0xB3, 0x92, 0xF6, 0xE4, 0x8A, 0xA0, 0xF6, 0xE7,
+               0xB3, 0xA8, 0xF6, 0xE7, 0xB3, 0xA3, 0xF6, 0xE7,
+               0xB4, 0x80, 0xF6, 0xF0, 0xA5, 0xBE, 0x86, 0xF6,
+               0xE7, 0xB5, 0xA3, 0xF6, 0xE4, 0x8C, 0x81, 0xF6,
+               0xE7, 0xB7, 0x87, 0xF6, 0xE7, 0xB8, 0x82, 0xF6,
+               0xE7, 0xB9, 0x85, 0xF6, 0xE4, 0x8C, 0xB4, 0xF6,
+               0xF0, 0xA6, 0x88, 0xA8, 0xF6, 0xF0, 0xA6, 0x89,
+               0x87, 0xF6, 0xE4, 0x8D, 0x99, 0xF6, 0xF0, 0xA6,
+               0x8B, 0x99, 0xF6, 0xE7, 0xBD, 0xBA, 0xF6, 0xF0,
+               0xA6, 0x8C, 0xBE, 0xF6, 0xE7, 0xBE, 0x95, 0xF6,
+               0xE7, 0xBF, 0xBA, 0xF6, 0xE8, 0x80, 0x85, 0xF6,
+               0xF0, 0xA6, 0x93, 0x9A, 0xF6, 0xF0, 0xA6, 0x94,
+               0xA3, 0xF6, 0xE8, 0x81, 0xA0, 0xF6, 0xF0, 0xA6,
+               0x96, 0xA8, 0xF6, 0xE8, 0x81, 0xB0, 0xF6, 0xF0,
+               0xA3, 0x8D, 0x9F, 0xF6, 0xE4, 0x8F, 0x95, 0xF6,
+               0xE8, 0x82, 0xB2, 0xF6, 0xE8, 0x84, 0x83, 0xF6,
+               0xE4, 0x90, 0x8B, 0xF6, 0xE8, 0x84, 0xBE, 0xF6,
+               0xE5, 0xAA, 0xB5, 0xF6, 0xF0, 0xA6, 0x9E, 0xA7,
+               0xF6, 0xF0, 0xA6, 0x9E, 0xB5, 0xF6, 0xF0, 0xA3,
+               0x8E, 0x93, 0xF6, 0xF0, 0xA3, 0x8E, 0x9C, 0xF6,
+               0xE8, 0x88, 0x81, 0xF6, 0xE8, 0x88, 0x84, 0xF6,
+               0xE8, 0xBE, 0x9E, 0xF6, 0xE4, 0x91, 0xAB, 0xF6,
+               0xE8, 0x8A, 0x91, 0xF6, 0xE8, 0x8A, 0x8B, 0xF6,
+               0xE8, 0x8A, 0x9D, 0xF6, 0xE5, 0x8A, 0xB3, 0xF6,
+               0xE8, 0x8A, 0xB1, 0xF6, 0xE8, 0x8A, 0xB3, 0xF6,
+               0xE8, 0x8A, 0xBD, 0xF6, 0xE8, 0x8B, 0xA6, 0xF6,
+               0xF0, 0xA6, 0xAC, 0xBC, 0xF6, 0xE8, 0x8B, 0xA5,
+               0xF6, 0xE8, 0x8C, 0x9D, 0xF6, 0xE8, 0x8D, 0xA3,
+               0xF6, 0xE8, 0x8E, 0xAD, 0xF6, 0xE8, 0x8C, 0xA3,
+               0xF6, 0xE8, 0x8E, 0xBD, 0xF6, 0xE8, 0x8F, 0xA7,
+               0xF6, 0xE8, 0x91, 0x97, 0xF6, 0xE8, 0x8D, 0x93,
+               0xF6, 0xE8, 0x8F, 0x8A, 0xF6, 0xE8, 0x8F, 0x8C,
+               0xF6, 0xE8, 0x8F, 0x9C, 0xF6, 0xF0, 0xA6, 0xB0,
+               0xB6, 0xF6, 0xF0, 0xA6, 0xB5, 0xAB, 0xF6, 0xF0,
+               0xA6, 0xB3, 0x95, 0xF6, 0xE4, 0x94, 0xAB, 0xF6,
+               0xE8, 0x93, 0xB1, 0xF6, 0xE8, 0x93, 0xB3, 0xF6,
+               0xE8, 0x94, 0x96, 0xF6, 0xF0, 0xA7, 0x8F, 0x8A,
+               0xF6, 0xE8, 0x95, 0xA4, 0xF6, 0xF0, 0xA6, 0xBC,
+               0xAC, 0xF6, 0xE4, 0x95, 0x9D, 0xF6, 0xE4, 0x95,
+               0xA1, 0xF6, 0xF0, 0xA6, 0xBE, 0xB1, 0xF6, 0xF0,
+               0xA7, 0x83, 0x92, 0xF6, 0xE4, 0x95, 0xAB, 0xF6,
+               0xE8, 0x99, 0x90, 0xF6, 0xE8, 0x99, 0x9C, 0xF6,
+               0xE8, 0x99, 0xA7, 0xF6, 0xE8, 0x99, 0xA9, 0xF6,
+               0xE8, 0x9A, 0xA9, 0xF6, 0xE8, 0x9A, 0x88, 0xF6,
+               0xE8, 0x9C, 0x8E, 0xF6, 0xE8, 0x9B, 0xA2, 0xF6,
+               0xE8, 0x9D, 0xB9, 0xF6, 0xE8, 0x9C, 0xA8, 0xF6,
+               0xE8, 0x9D, 0xAB, 0xF6, 0xE8, 0x9E, 0x86, 0xF6,
+               0xE4, 0x97, 0x97, 0xF6, 0xE8, 0x9F, 0xA1, 0xF6,
+               0xE8, 0xA0, 0x81, 0xF6, 0xE4, 0x97, 0xB9, 0xF6,
+               0xE8, 0xA1, 0xA0, 0xF6, 0xE8, 0xA1, 0xA3, 0xF6,
+               0xF0, 0xA7, 0x99, 0xA7, 0xF6, 0xE8, 0xA3, 0x97,
+               0xF6, 0xE8, 0xA3, 0x9E, 0xF6, 0xE4, 0x98, 0xB5,
+               0xF6, 0xE8, 0xA3, 0xBA, 0xF6, 0xE3, 0x92, 0xBB,
+               0xF6, 0xF0, 0xA7, 0xA2, 0xAE, 0xF6, 0xF0, 0xA7,
+               0xA5, 0xA6, 0xF6, 0xE4, 0x9A, 0xBE, 0xF6, 0xE4,
+               0x9B, 0x87, 0xF6, 0xE8, 0xAA, 0xA0, 0xF6, 0xE8,
+               0xAB, 0xAD, 0xF6, 0xE8, 0xAE, 0x8A, 0xF6, 0xE8,
+               0xB1, 0x95, 0xF6, 0xF0, 0xA7, 0xB2, 0xA8, 0xF6,
+               0xE8, 0xB2, 0xAB, 0xF6, 0xE8, 0xB3, 0x81, 0xF6,
+               0xE8, 0xB4, 0x9B, 0xF6, 0xE8, 0xB5, 0xB7, 0xF6,
+               0xF0, 0xA7, 0xBC, 0xAF, 0xF6, 0xF0, 0xA0, 0xA0,
+               0x84, 0xF6, 0xE8, 0xB7, 0x8B, 0xF6, 0xE8, 0xB6,
+               0xBC, 0xF6, 0xE8, 0xB7, 0xB0, 0xF6, 0xF0, 0xA0,
+               0xA3, 0x9E, 0xF6, 0xE8, 0xBB, 0x94, 0xF6, 0xE8,
+               0xBC, 0xB8, 0xF6, 0xF0, 0xA8, 0x97, 0x92, 0xF6,
+               0xF0, 0xA8, 0x97, 0xAD, 0xF6, 0xE9, 0x82, 0x94,
+               0xF6, 0xE9, 0x83, 0xB1, 0xF6, 0xE9, 0x84, 0x91,
+               0xF6, 0xF0, 0xA8, 0x9C, 0xAE, 0xF6, 0xE9, 0x84,
+               0x9B, 0xF6, 0xE9, 0x88, 0xB8, 0xF6, 0xE9, 0x8B,
+               0x97, 0xF6, 0xE9, 0x8B, 0x98, 0xF6, 0xE9, 0x89,
+               0xBC, 0xF6, 0xE9, 0x8F, 0xB9, 0xF6, 0xE9, 0x90,
+               0x95, 0xF6, 0xF0, 0xA8, 0xAF, 0xBA, 0xF6, 0xE9,
+               0x96, 0x8B, 0xF6, 0xE4, 0xA6, 0x95, 0xF6, 0xE9,
+               0x96, 0xB7, 0xF6, 0xF0, 0xA8, 0xB5, 0xB7, 0xF6,
+               0xE4, 0xA7, 0xA6, 0xF6, 0xE9, 0x9B, 0x83, 0xF6,
+               0xE5, 0xB6, 0xB2, 0xF6, 0xE9, 0x9C, 0xA3, 0xF6,
+               0xF0, 0xA9, 0x85, 0x85, 0xF6, 0xF0, 0xA9, 0x88,
+               0x9A, 0xF6, 0xE4, 0xA9, 0xAE, 0xF6, 0xE4, 0xA9,
+               0xB6, 0xF6, 0xE9, 0x9F, 0xA0, 0xF6, 0xF0, 0xA9,
+               0x90, 0x8A, 0xF6, 0xE4, 0xAA, 0xB2, 0xF6, 0xF0,
+               0xA9, 0x92, 0x96, 0xF6, 0xE9, 0xA0, 0x8B, 0xF6,
+               0xE9, 0xA0, 0x8B, 0xF6, 0xE9, 0xA0, 0xA9, 0xF6,
+               0xF0, 0xA9, 0x96, 0xB6, 0xF6, 0xE9, 0xA3, 0xA2,
+               0xF6, 0xE4, 0xAC, 0xB3, 0xF6, 0xE9, 0xA4, 0xA9,
+               0xF6, 0xE9, 0xA6, 0xA7, 0xF6, 0xE9, 0xA7, 0x82,
+               0xF6, 0xE9, 0xA7, 0xBE, 0xF6, 0xE4, 0xAF, 0x8E,
+               0xF6, 0xF0, 0xA9, 0xAC, 0xB0, 0xF6, 0xE9, 0xAC,
+               0x92, 0xF6, 0xE9, 0xB1, 0x80, 0xF6, 0xE9, 0xB3,
+               0xBD, 0xF6, 0xE4, 0xB3, 0x8E, 0xF6, 0xE4, 0xB3,
+               0xAD, 0xF6, 0xE9, 0xB5, 0xA7, 0xF6, 0xF0, 0xAA,
+               0x83, 0x8E, 0xF6, 0xE4, 0xB3, 0xB8, 0xF6, 0xF0,
+               0xAA, 0x84, 0x85, 0xF6, 0xF0, 0xAA, 0x88, 0x8E,
+               0xF6, 0xF0, 0xAA, 0x8A, 0x91, 0xF6, 0xE9, 0xBA,
+               0xBB, 0xF6, 0xE4, 0xB5, 0x96, 0xF6, 0xE9, 0xBB,
+               0xB9, 0xF6, 0xE9, 0xBB, 0xBE, 0xF6, 0xE9, 0xBC,
+               0x85, 0xF6, 0xE9, 0xBC, 0x8F, 0xF6, 0xE9, 0xBC,
+               0x96, 0xF6, 0xE9, 0xBC, 0xBB, 0xF6, 0xF0, 0xAA,
+               0x98, 0x80, 0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,
+       },
+       {
+               0x20, 0x20, 0xCC, 0x88, 0x61, 0x20, 0xCC, 0x84,
+               0x32, 0x33, 0x20, 0xCC, 0x81, 0xCE, 0xBC, 0x20,
+               0xCC, 0xA7, 0x31, 0x6F, 0x31, 0xE2, 0x81, 0x84,
+               0x34, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x33, 0xE2,
+               0x81, 0x84, 0x34, 0xF6, 0x41, 0xCC, 0x80, 0xF6,
+               0x41, 0xCC, 0x81, 0xF6, 0x41, 0xCC, 0x82, 0xF6,
+               0x41, 0xCC, 0x83, 0xF6, 0x41, 0xCC, 0x88, 0xF6,
+               0x41, 0xCC, 0x8A, 0xF6, 0x43, 0xCC, 0xA7, 0xF6,
+               0x45, 0xCC, 0x80, 0xF6, 0x45, 0xCC, 0x81, 0xF6,
+               0x45, 0xCC, 0x82, 0xF6, 0x45, 0xCC, 0x88, 0xF6,
+               0x49, 0xCC, 0x80, 0xF6, 0x49, 0xCC, 0x81, 0xF6,
+               0x49, 0xCC, 0x82, 0xF6, 0x49, 0xCC, 0x88, 0xF6,
+               0x4E, 0xCC, 0x83, 0xF6, 0x4F, 0xCC, 0x80, 0xF6,
+               0x4F, 0xCC, 0x81, 0xF6, 0x4F, 0xCC, 0x82, 0xF6,
+               0x4F, 0xCC, 0x83, 0xF6, 0x4F, 0xCC, 0x88, 0xF6,
+               0x55, 0xCC, 0x80, 0xF6, 0x55, 0xCC, 0x81, 0xF6,
+               0x55, 0xCC, 0x82, 0xF6, 0x55, 0xCC, 0x88, 0xF6,
+               0x59, 0xCC, 0x81, 0xF6, 0x61, 0xCC, 0x80, 0xF6,
+               0x61, 0xCC, 0x81, 0xF6, 0x61, 0xCC, 0x82, 0xF6,
+               0x61, 0xCC, 0x83, 0xF6, 0x61, 0xCC, 0x88, 0xF6,
+               0x61, 0xCC, 0x8A, 0xF6, 0x63, 0xCC, 0xA7, 0xF6,
+               0x65, 0xCC, 0x80, 0xF6, 0x65, 0xCC, 0x81, 0xF6,
+               0x65, 0xCC, 0x82, 0xF6, 0x65, 0xCC, 0x88, 0xF6,
+               0x69, 0xCC, 0x80, 0xF6, 0x69, 0xCC, 0x81, 0xF6,
+               0x69, 0xCC, 0x82, 0xF6, 0x69, 0xCC, 0x88, 0xF6,
+               0x6E, 0xCC, 0x83, 0xF6, 0x6F, 0xCC, 0x80, 0xF6,
+               0x6F, 0xCC, 0x81, 0xF6, 0x6F, 0xCC, 0x82, 0xF6,
+               0x6F, 0xCC, 0x83, 0xF6, 0x6F, 0xCC, 0x88, 0xF6,
+               0x75, 0xCC, 0x80, 0xF6, 0x75, 0xCC, 0x81, 0xF6,
+               0x75, 0xCC, 0x82, 0xF6, 0x75, 0xCC, 0x88, 0xF6,
+               0x79, 0xCC, 0x81, 0xF6, 0x79, 0xCC, 0x88, 0xF6,
+               0x41, 0xCC, 0x84, 0xF6, 0x61, 0xCC, 0x84, 0xF6,
+               0x41, 0xCC, 0x86, 0xF6, 0x61, 0xCC, 0x86, 0xF6,
+               0x41, 0xCC, 0xA8, 0xF6, 0x61, 0xCC, 0xA8, 0xF6,
+               0x43, 0xCC, 0x81, 0xF6, 0x63, 0xCC, 0x81, 0xF6,
+               0x43, 0xCC, 0x82, 0xF6, 0x63, 0xCC, 0x82, 0xF6,
+               0x43, 0xCC, 0x87, 0xF6, 0x63, 0xCC, 0x87, 0xF6,
+               0x43, 0xCC, 0x8C, 0xF6, 0x63, 0xCC, 0x8C, 0xF6,
+               0x44, 0xCC, 0x8C, 0xF6, 0x64, 0xCC, 0x8C, 0xF6,
+               0x45, 0xCC, 0x84, 0xF6, 0x65, 0xCC, 0x84, 0xF6,
+               0x45, 0xCC, 0x86, 0xF6, 0x65, 0xCC, 0x86, 0xF6,
+               0x45, 0xCC, 0x87, 0xF6, 0x65, 0xCC, 0x87, 0xF6,
+               0x45, 0xCC, 0xA8, 0xF6, 0x65, 0xCC, 0xA8, 0xF6,
+               0x45, 0xCC, 0x8C, 0xF6, 0x65, 0xCC, 0x8C, 0xF6,
+               0x47, 0xCC, 0x82, 0xF6, 0x67, 0xCC, 0x82, 0xF6,
+               0x47, 0xCC, 0x86, 0xF6, 0x67, 0xCC, 0x86, 0xF6,
+               0x47, 0xCC, 0x87, 0xF6, 0x67, 0xCC, 0x87, 0xF6,
+               0x47, 0xCC, 0xA7, 0xF6, 0x67, 0xCC, 0xA7, 0xF6,
+               0x48, 0xCC, 0x82, 0xF6, 0x68, 0xCC, 0x82, 0xF6,
+               0x49, 0xCC, 0x83, 0xF6, 0x69, 0xCC, 0x83, 0xF6,
+               0x49, 0xCC, 0x84, 0xF6, 0x69, 0xCC, 0x84, 0xF6,
+               0x49, 0xCC, 0x86, 0xF6, 0x69, 0xCC, 0x86, 0xF6,
+               0x49, 0xCC, 0xA8, 0xF6, 0x69, 0xCC, 0xA8, 0xF6,
+               0x49, 0xCC, 0x87, 0x49, 0x4A, 0x69, 0x6A, 0xF6,
+               0x4A, 0xCC, 0x82, 0xF6, 0x6A, 0xCC, 0x82, 0xF6,
+               0x4B, 0xCC, 0xA7, 0xF6, 0x6B, 0xCC, 0xA7, 0xF6,
+               0x4C, 0xCC, 0x81, 0xF6, 0x6C, 0xCC, 0x81, 0xF6,
+               0x4C, 0xCC, 0xA7, 0xF6, 0x6C, 0xCC, 0xA7, 0xF6,
+               0x4C, 0xCC, 0x8C, 0xF6, 0x6C, 0xCC, 0x8C, 0x4C,
+               0xC2, 0xB7, 0x6C, 0xC2, 0xB7, 0xF6, 0x4E, 0xCC,
+               0x81, 0xF6, 0x6E, 0xCC, 0x81, 0xF6, 0x4E, 0xCC,
+               0xA7, 0xF6, 0x6E, 0xCC, 0xA7, 0xF6, 0x4E, 0xCC,
+               0x8C, 0xF6, 0x6E, 0xCC, 0x8C, 0xCA, 0xBC, 0x6E,
+               0xF6, 0x4F, 0xCC, 0x84, 0xF6, 0x6F, 0xCC, 0x84,
+               0xF6, 0x4F, 0xCC, 0x86, 0xF6, 0x6F, 0xCC, 0x86,
+               0xF6, 0x4F, 0xCC, 0x8B, 0xF6, 0x6F, 0xCC, 0x8B,
+               0xF6, 0x52, 0xCC, 0x81, 0xF6, 0x72, 0xCC, 0x81,
+               0xF6, 0x52, 0xCC, 0xA7, 0xF6, 0x72, 0xCC, 0xA7,
+               0xF6, 0x52, 0xCC, 0x8C, 0xF6, 0x72, 0xCC, 0x8C,
+               0xF6, 0x53, 0xCC, 0x81, 0xF6, 0x73, 0xCC, 0x81,
+               0xF6, 0x53, 0xCC, 0x82, 0xF6, 0x73, 0xCC, 0x82,
+               0xF6, 0x53, 0xCC, 0xA7, 0xF6, 0x73, 0xCC, 0xA7,
+               0xF6, 0x53, 0xCC, 0x8C, 0xF6, 0x73, 0xCC, 0x8C,
+               0xF6, 0x54, 0xCC, 0xA7, 0xF6, 0x74, 0xCC, 0xA7,
+               0xF6, 0x54, 0xCC, 0x8C, 0xF6, 0x74, 0xCC, 0x8C,
+               0xF6, 0x55, 0xCC, 0x83, 0xF6, 0x75, 0xCC, 0x83,
+               0xF6, 0x55, 0xCC, 0x84, 0xF6, 0x75, 0xCC, 0x84,
+               0xF6, 0x55, 0xCC, 0x86, 0xF6, 0x75, 0xCC, 0x86,
+               0xF6, 0x55, 0xCC, 0x8A, 0xF6, 0x75, 0xCC, 0x8A,
+               0xF6, 0x55, 0xCC, 0x8B, 0xF6, 0x75, 0xCC, 0x8B,
+               0xF6, 0x55, 0xCC, 0xA8, 0xF6, 0x75, 0xCC, 0xA8,
+               0xF6, 0x57, 0xCC, 0x82, 0xF6, 0x77, 0xCC, 0x82,
+               0xF6, 0x59, 0xCC, 0x82, 0xF6, 0x79, 0xCC, 0x82,
+               0xF6, 0x59, 0xCC, 0x88, 0xF6, 0x5A, 0xCC, 0x81,
+               0xF6, 0x7A, 0xCC, 0x81, 0xF6, 0x5A, 0xCC, 0x87,
+               0xF6, 0x7A, 0xCC, 0x87, 0xF6, 0x5A, 0xCC, 0x8C,
+               0xF6, 0x7A, 0xCC, 0x8C, 0x73, 0xF6, 0x4F, 0xCC,
+               0x9B, 0xF6, 0x6F, 0xCC, 0x9B, 0xF6, 0x55, 0xCC,
+               0x9B, 0xF6, 0x75, 0xCC, 0x9B, 0x44, 0x5A, 0xCC,
+               0x8C, 0x44, 0x7A, 0xCC, 0x8C, 0x64, 0x7A, 0xCC,
+               0x8C, 0x4C, 0x4A, 0x4C, 0x6A, 0x6C, 0x6A, 0x4E,
+               0x4A, 0x4E, 0x6A, 0x6E, 0x6A, 0xF6, 0x41, 0xCC,
+               0x8C, 0xF6, 0x61, 0xCC, 0x8C, 0xF6, 0x49, 0xCC,
+               0x8C, 0xF6, 0x69, 0xCC, 0x8C, 0xF6, 0x4F, 0xCC,
+               0x8C, 0xF6, 0x6F, 0xCC, 0x8C, 0xF6, 0x55, 0xCC,
+               0x8C, 0xF6, 0x75, 0xCC, 0x8C, 0xF6, 0x55, 0xCC,
+               0x88, 0xCC, 0x84, 0xF6, 0x75, 0xCC, 0x88, 0xCC,
+               0x84, 0xF6, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0x75, 0xCC, 0x88, 0xCC, 0x81, 0xF6, 0x55, 0xCC,
+               0x88, 0xCC, 0x8C, 0xF6, 0x75, 0xCC, 0x88, 0xCC,
+               0x8C, 0xF6, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xF6,
+               0x75, 0xCC, 0x88, 0xCC, 0x80, 0xF6, 0x41, 0xCC,
+               0x88, 0xCC, 0x84, 0xF6, 0x61, 0xCC, 0x88, 0xCC,
+               0x84, 0xF6, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xF6,
+               0x61, 0xCC, 0x87, 0xCC, 0x84, 0xF6, 0xC3, 0x86,
+               0xCC, 0x84, 0xF6, 0xC3, 0xA6, 0xCC, 0x84, 0xF6,
+               0x47, 0xCC, 0x8C, 0xF6, 0x67, 0xCC, 0x8C, 0xF6,
+               0x4B, 0xCC, 0x8C, 0xF6, 0x6B, 0xCC, 0x8C, 0xF6,
+               0x4F, 0xCC, 0xA8, 0xF6, 0x6F, 0xCC, 0xA8, 0xF6,
+               0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xF6, 0x6F, 0xCC,
+               0xA8, 0xCC, 0x84, 0xF6, 0xC6, 0xB7, 0xCC, 0x8C,
+               0xF6, 0xCA, 0x92, 0xCC, 0x8C, 0xF6, 0x6A, 0xCC,
+               0x8C, 0x44, 0x5A, 0x44, 0x7A, 0x64, 0x7A, 0xF6,
+               0x47, 0xCC, 0x81, 0xF6, 0x67, 0xCC, 0x81, 0xF6,
+               0x4E, 0xCC, 0x80, 0xF6, 0x6E, 0xCC, 0x80, 0xF6,
+               0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xF6, 0x61, 0xCC,
+               0x8A, 0xCC, 0x81, 0xF6, 0xC3, 0x86, 0xCC, 0x81,
+               0xF6, 0xC3, 0xA6, 0xCC, 0x81, 0xF6, 0xC3, 0x98,
+               0xCC, 0x81, 0xF6, 0xC3, 0xB8, 0xCC, 0x81, 0xF6,
+               0x41, 0xCC, 0x8F, 0xF6, 0x61, 0xCC, 0x8F, 0xF6,
+               0x41, 0xCC, 0x91, 0xF6, 0x61, 0xCC, 0x91, 0xF6,
+               0x45, 0xCC, 0x8F, 0xF6, 0x65, 0xCC, 0x8F, 0xF6,
+               0x45, 0xCC, 0x91, 0xF6, 0x65, 0xCC, 0x91, 0xF6,
+               0x49, 0xCC, 0x8F, 0xF6, 0x69, 0xCC, 0x8F, 0xF6,
+               0x49, 0xCC, 0x91, 0xF6, 0x69, 0xCC, 0x91, 0xF6,
+               0x4F, 0xCC, 0x8F, 0xF6, 0x6F, 0xCC, 0x8F, 0xF6,
+               0x4F, 0xCC, 0x91, 0xF6, 0x6F, 0xCC, 0x91, 0xF6,
+               0x52, 0xCC, 0x8F, 0xF6, 0x72, 0xCC, 0x8F, 0xF6,
+               0x52, 0xCC, 0x91, 0xF6, 0x72, 0xCC, 0x91, 0xF6,
+               0x55, 0xCC, 0x8F, 0xF6, 0x75, 0xCC, 0x8F, 0xF6,
+               0x55, 0xCC, 0x91, 0xF6, 0x75, 0xCC, 0x91, 0xF6,
+               0x53, 0xCC, 0xA6, 0xF6, 0x73, 0xCC, 0xA6, 0xF6,
+               0x54, 0xCC, 0xA6, 0xF6, 0x74, 0xCC, 0xA6, 0xF6,
+               0x48, 0xCC, 0x8C, 0xF6, 0x68, 0xCC, 0x8C, 0xF6,
+               0x41, 0xCC, 0x87, 0xF6, 0x61, 0xCC, 0x87, 0xF6,
+               0x45, 0xCC, 0xA7, 0xF6, 0x65, 0xCC, 0xA7, 0xF6,
+               0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xF6, 0x6F, 0xCC,
+               0x88, 0xCC, 0x84, 0xF6, 0x4F, 0xCC, 0x83, 0xCC,
+               0x84, 0xF6, 0x6F, 0xCC, 0x83, 0xCC, 0x84, 0xF6,
+               0x4F, 0xCC, 0x87, 0xF6, 0x6F, 0xCC, 0x87, 0xF6,
+               0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xF6, 0x6F, 0xCC,
+               0x87, 0xCC, 0x84, 0xF6, 0x59, 0xCC, 0x84, 0xF6,
+               0x79, 0xCC, 0x84, 0x68, 0xC9, 0xA6, 0x6A, 0x72,
+               0xC9, 0xB9, 0xC9, 0xBB, 0xCA, 0x81, 0x77, 0x79,
+               0x20, 0xCC, 0x86, 0x20, 0xCC, 0x87, 0x20, 0xCC,
+               0x8A, 0x20, 0xCC, 0xA8, 0x20, 0xCC, 0x83, 0x20,
+               0xCC, 0x8B, 0xC9, 0xA3, 0x6C, 0x73, 0x78, 0xCA,
+               0x95, 0xF6, 0xCC, 0x80, 0xF6, 0xCC, 0x81, 0xF6,
+               0xCC, 0x93, 0xF6, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0xCA, 0xB9, 0x20, 0xCD, 0x85, 0xF6, 0x3B, 0x20,
+               0xCC, 0x81, 0xF5, 0x05, 0xC2, 0xA8, 0xCC, 0x81,
+               0x20, 0xCC, 0x88, 0xCC, 0x81, 0xF6, 0xCE, 0x91,
+               0xCC, 0x81, 0xF6, 0xC2, 0xB7, 0xF6, 0xCE, 0x95,
+               0xCC, 0x81, 0xF6, 0xCE, 0x97, 0xCC, 0x81, 0xF6,
+               0xCE, 0x99, 0xCC, 0x81, 0xF6, 0xCE, 0x9F, 0xCC,
+               0x81, 0xF6, 0xCE, 0xA5, 0xCC, 0x81, 0xF6, 0xCE,
+               0xA9, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC, 0x88,
+               0xCC, 0x81, 0xF6, 0xCE, 0x99, 0xCC, 0x88, 0xF6,
+               0xCE, 0xA5, 0xCC, 0x88, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x81, 0xF6, 0xCE, 0xB5, 0xCC, 0x81, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC, 0x81,
+               0xF6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0xCE, 0xB9, 0xCC, 0x88, 0xF6, 0xCF, 0x85, 0xCC,
+               0x88, 0xF6, 0xCE, 0xBF, 0xCC, 0x81, 0xF6, 0xCF,
+               0x85, 0xCC, 0x81, 0xF6, 0xCF, 0x89, 0xCC, 0x81,
+               0xCE, 0xB2, 0xCE, 0xB8, 0xCE, 0xA5, 0xF5, 0x05,
+               0xCF, 0x92, 0xCC, 0x81, 0xCE, 0xA5, 0xCC, 0x81,
+               0xF5, 0x05, 0xCF, 0x92, 0xCC, 0x88, 0xCE, 0xA5,
+               0xCC, 0x88, 0xCF, 0x86, 0xCF, 0x80, 0xCE, 0xBA,
+               0xCF, 0x81, 0xCF, 0x82, 0xCE, 0x98, 0xCE, 0xB5,
+               0xCE, 0xA3, 0xF6, 0xD0, 0x95, 0xCC, 0x80, 0xF6,
+               0xD0, 0x95, 0xCC, 0x88, 0xF6, 0xD0, 0x93, 0xCC,
+               0x81, 0xF6, 0xD0, 0x86, 0xCC, 0x88, 0xF6, 0xD0,
+               0x9A, 0xCC, 0x81, 0xF6, 0xD0, 0x98, 0xCC, 0x80,
+               0xF6, 0xD0, 0xA3, 0xCC, 0x86, 0xF6, 0xD0, 0x98,
+               0xCC, 0x86, 0xF6, 0xD0, 0xB8, 0xCC, 0x86, 0xF6,
+               0xD0, 0xB5, 0xCC, 0x80, 0xF6, 0xD0, 0xB5, 0xCC,
+               0x88, 0xF6, 0xD0, 0xB3, 0xCC, 0x81, 0xF6, 0xD1,
+               0x96, 0xCC, 0x88, 0xF6, 0xD0, 0xBA, 0xCC, 0x81,
+               0xF6, 0xD0, 0xB8, 0xCC, 0x80, 0xF6, 0xD1, 0x83,
+               0xCC, 0x86, 0xF6, 0xD1, 0xB4, 0xCC, 0x8F, 0xF6,
+               0xD1, 0xB5, 0xCC, 0x8F, 0xF6, 0xD0, 0x96, 0xCC,
+               0x86, 0xF6, 0xD0, 0xB6, 0xCC, 0x86, 0xF6, 0xD0,
+               0x90, 0xCC, 0x86, 0xF6, 0xD0, 0xB0, 0xCC, 0x86,
+               0xF6, 0xD0, 0x90, 0xCC, 0x88, 0xF6, 0xD0, 0xB0,
+               0xCC, 0x88, 0xF6, 0xD0, 0x95, 0xCC, 0x86, 0xF6,
+               0xD0, 0xB5, 0xCC, 0x86, 0xF6, 0xD3, 0x98, 0xCC,
+               0x88, 0xF6, 0xD3, 0x99, 0xCC, 0x88, 0xF6, 0xD0,
+               0x96, 0xCC, 0x88, 0xF6, 0xD0, 0xB6, 0xCC, 0x88,
+               0xF6, 0xD0, 0x97, 0xCC, 0x88, 0xF6, 0xD0, 0xB7,
+               0xCC, 0x88, 0xF6, 0xD0, 0x98, 0xCC, 0x84, 0xF6,
+               0xD0, 0xB8, 0xCC, 0x84, 0xF6, 0xD0, 0x98, 0xCC,
+               0x88, 0xF6, 0xD0, 0xB8, 0xCC, 0x88, 0xF6, 0xD0,
+               0x9E, 0xCC, 0x88, 0xF6, 0xD0, 0xBE, 0xCC, 0x88,
+               0xF6, 0xD3, 0xA8, 0xCC, 0x88, 0xF6, 0xD3, 0xA9,
+               0xCC, 0x88, 0xF6, 0xD0, 0xAD, 0xCC, 0x88, 0xF6,
+               0xD1, 0x8D, 0xCC, 0x88, 0xF6, 0xD0, 0xA3, 0xCC,
+               0x84, 0xF6, 0xD1, 0x83, 0xCC, 0x84, 0xF6, 0xD0,
+               0xA3, 0xCC, 0x88, 0xF6, 0xD1, 0x83, 0xCC, 0x88,
+               0xF6, 0xD0, 0xA3, 0xCC, 0x8B, 0xF6, 0xD1, 0x83,
+               0xCC, 0x8B, 0xF6, 0xD0, 0xA7, 0xCC, 0x88, 0xF6,
+               0xD1, 0x87, 0xCC, 0x88, 0xF6, 0xD0, 0xAB, 0xCC,
+               0x88, 0xF6, 0xD1, 0x8B, 0xCC, 0x88, 0xD5, 0xA5,
+               0xD6, 0x82, 0xF6, 0xD8, 0xA7, 0xD9, 0x93, 0xF6,
+               0xD8, 0xA7, 0xD9, 0x94, 0xF6, 0xD9, 0x88, 0xD9,
+               0x94, 0xF6, 0xD8, 0xA7, 0xD9, 0x95, 0xF6, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD8, 0xA7, 0xD9, 0xB4, 0xD9,
+               0x88, 0xD9, 0xB4, 0xDB, 0x87, 0xD9, 0xB4, 0xD9,
+               0x8A, 0xD9, 0xB4, 0xF6, 0xDB, 0x95, 0xD9, 0x94,
+               0xF6, 0xDB, 0x81, 0xD9, 0x94, 0xF6, 0xDB, 0x92,
+               0xD9, 0x94, 0xF6, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4,
+               0xBC, 0xF6, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC,
+               0xF6, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0xF6,
+               0xE0, 0xA4, 0x95, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0,
+               0xA4, 0x96, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA4,
+               0x97, 0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA4, 0x9C,
+               0xE0, 0xA4, 0xBC, 0xF6, 0xE0, 0xA4, 0xA1, 0xE0,
+               0xA4, 0xBC, 0xF6, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4,
+               0xBC, 0xF6, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC,
+               0xF6, 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0xF6,
+               0xE0, 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0xF6, 0xE0,
+               0xA7, 0x87, 0xE0, 0xA7, 0x97, 0xF6, 0xE0, 0xA6,
+               0xA1, 0xE0, 0xA6, 0xBC, 0xF6, 0xE0, 0xA6, 0xA2,
+               0xE0, 0xA6, 0xBC, 0xF6, 0xE0, 0xA6, 0xAF, 0xE0,
+               0xA6, 0xBC, 0xF6, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8,
+               0xBC, 0xF6, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC,
+               0xF6, 0xE0, 0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0xF6,
+               0xE0, 0xA8, 0x97, 0xE0, 0xA8, 0xBC, 0xF6, 0xE0,
+               0xA8, 0x9C, 0xE0, 0xA8, 0xBC, 0xF6, 0xE0, 0xA8,
+               0xAB, 0xE0, 0xA8, 0xBC, 0xF6, 0xE0, 0xAD, 0x87,
+               0xE0, 0xAD, 0x96, 0xF6, 0xE0, 0xAD, 0x87, 0xE0,
+               0xAC, 0xBE, 0xF6, 0xE0, 0xAD, 0x87, 0xE0, 0xAD,
+               0x97, 0xF6, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC,
+               0xF6, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0xF6,
+               0xE0, 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0xF6, 0xE0,
+               0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0xF6, 0xE0, 0xAF,
+               0x87, 0xE0, 0xAE, 0xBE, 0xF6, 0xE0, 0xAF, 0x86,
+               0xE0, 0xAF, 0x97, 0xF6, 0xE0, 0xB1, 0x86, 0xE0,
+               0xB1, 0x96, 0xF6, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3,
+               0x95, 0xF6, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95,
+               0xF6, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0xF6,
+               0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xF6, 0xE0,
+               0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95,
+               0xF6, 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0xF6,
+               0xE0, 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0xF6, 0xE0,
+               0xB5, 0x86, 0xE0, 0xB5, 0x97, 0xF6, 0xE0, 0xB7,
+               0x99, 0xE0, 0xB7, 0x8A, 0xF6, 0xE0, 0xB7, 0x99,
+               0xE0, 0xB7, 0x8F, 0xF6, 0xE0, 0xB7, 0x99, 0xE0,
+               0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0xF6, 0xE0, 0xB7,
+               0x99, 0xE0, 0xB7, 0x9F, 0xE0, 0xB9, 0x8D, 0xE0,
+               0xB8, 0xB2, 0xE0, 0xBB, 0x8D, 0xE0, 0xBA, 0xB2,
+               0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0xE0, 0xBA,
+               0xAB, 0xE0, 0xBA, 0xA1, 0xE0, 0xBC, 0x8B, 0xF6,
+               0xE0, 0xBD, 0x82, 0xE0, 0xBE, 0xB7, 0xF6, 0xE0,
+               0xBD, 0x8C, 0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBD,
+               0x91, 0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBD, 0x96,
+               0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBD, 0x9B, 0xE0,
+               0xBE, 0xB7, 0xF6, 0xE0, 0xBD, 0x80, 0xE0, 0xBE,
+               0xB5, 0xF6, 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB2,
+               0xF6, 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0xF6,
+               0xE0, 0xBE, 0xB2, 0xE0, 0xBE, 0x80, 0xE0, 0xBE,
+               0xB2, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xF6,
+               0xE0, 0xBE, 0xB3, 0xE0, 0xBE, 0x80, 0xE0, 0xBE,
+               0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xF6,
+               0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0xF6, 0xE0,
+               0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBE,
+               0x9C, 0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBE, 0xA1,
+               0xE0, 0xBE, 0xB7, 0xF6, 0xE0, 0xBE, 0xA6, 0xE0,
+               0xBE, 0xB7, 0xF6, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE,
+               0xB7, 0xF6, 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5,
+               0xF6, 0xE1, 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0xE1,
+               0x83, 0x9C, 0xF6, 0xE1, 0xAC, 0x85, 0xE1, 0xAC,
+               0xB5, 0xF6, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5,
+               0xF6, 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0xF6,
+               0xE1, 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0xF6, 0xE1,
+               0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0xF6, 0xE1, 0xAC,
+               0x91, 0xE1, 0xAC, 0xB5, 0xF6, 0xE1, 0xAC, 0xBA,
+               0xE1, 0xAC, 0xB5, 0xF6, 0xE1, 0xAC, 0xBC, 0xE1,
+               0xAC, 0xB5, 0xF6, 0xE1, 0xAC, 0xBE, 0xE1, 0xAC,
+               0xB5, 0xF6, 0xE1, 0xAC, 0xBF, 0xE1, 0xAC, 0xB5,
+               0xF6, 0xE1, 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x41,
+               0xC3, 0x86, 0x42, 0x44, 0x45, 0xC6, 0x8E, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0xC8, 0xA2, 0x50, 0x52, 0x54, 0x55, 0x57, 0x61,
+               0xC9, 0x90, 0xC9, 0x91, 0xE1, 0xB4, 0x82, 0x62,
+               0x64, 0x65, 0xC9, 0x99, 0xC9, 0x9B, 0xC9, 0x9C,
+               0x67, 0x6B, 0x6D, 0xC5, 0x8B, 0x6F, 0xC9, 0x94,
+               0xE1, 0xB4, 0x96, 0xE1, 0xB4, 0x97, 0x70, 0x74,
+               0x75, 0xE1, 0xB4, 0x9D, 0xC9, 0xAF, 0x76, 0xE1,
+               0xB4, 0xA5, 0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4,
+               0xCF, 0x86, 0xCF, 0x87, 0x69, 0x72, 0x75, 0x76,
+               0xCE, 0xB2, 0xCE, 0xB3, 0xCF, 0x81, 0xCF, 0x86,
+               0xCF, 0x87, 0xD0, 0xBD, 0xC9, 0x92, 0x63, 0xC9,
+               0x95, 0xC3, 0xB0, 0xC9, 0x9C, 0x66, 0xC9, 0x9F,
+               0xC9, 0xA1, 0xC9, 0xA5, 0xC9, 0xA8, 0xC9, 0xA9,
+               0xC9, 0xAA, 0xE1, 0xB5, 0xBB, 0xCA, 0x9D, 0xC9,
+               0xAD, 0xE1, 0xB6, 0x85, 0xCA, 0x9F, 0xC9, 0xB1,
+               0xC9, 0xB0, 0xC9, 0xB2, 0xC9, 0xB3, 0xC9, 0xB4,
+               0xC9, 0xB5, 0xC9, 0xB8, 0xCA, 0x82, 0xCA, 0x83,
+               0xC6, 0xAB, 0xCA, 0x89, 0xCA, 0x8A, 0xE1, 0xB4,
+               0x9C, 0xCA, 0x8B, 0xCA, 0x8C, 0x7A, 0xCA, 0x90,
+               0xCA, 0x91, 0xCA, 0x92, 0xCE, 0xB8, 0xF6, 0x41,
+               0xCC, 0xA5, 0xF6, 0x61, 0xCC, 0xA5, 0xF6, 0x42,
+               0xCC, 0x87, 0xF6, 0x62, 0xCC, 0x87, 0xF6, 0x42,
+               0xCC, 0xA3, 0xF6, 0x62, 0xCC, 0xA3, 0xF6, 0x42,
+               0xCC, 0xB1, 0xF6, 0x62, 0xCC, 0xB1, 0xF6, 0x43,
+               0xCC, 0xA7, 0xCC, 0x81, 0xF6, 0x63, 0xCC, 0xA7,
+               0xCC, 0x81, 0xF6, 0x44, 0xCC, 0x87, 0xF6, 0x64,
+               0xCC, 0x87, 0xF6, 0x44, 0xCC, 0xA3, 0xF6, 0x64,
+               0xCC, 0xA3, 0xF6, 0x44, 0xCC, 0xB1, 0xF6, 0x64,
+               0xCC, 0xB1, 0xF6, 0x44, 0xCC, 0xA7, 0xF6, 0x64,
+               0xCC, 0xA7, 0xF6, 0x44, 0xCC, 0xAD, 0xF6, 0x64,
+               0xCC, 0xAD, 0xF6, 0x45, 0xCC, 0x84, 0xCC, 0x80,
+               0xF6, 0x65, 0xCC, 0x84, 0xCC, 0x80, 0xF6, 0x45,
+               0xCC, 0x84, 0xCC, 0x81, 0xF6, 0x65, 0xCC, 0x84,
+               0xCC, 0x81, 0xF6, 0x45, 0xCC, 0xAD, 0xF6, 0x65,
+               0xCC, 0xAD, 0xF6, 0x45, 0xCC, 0xB0, 0xF6, 0x65,
+               0xCC, 0xB0, 0xF6, 0x45, 0xCC, 0xA7, 0xCC, 0x86,
+               0xF6, 0x65, 0xCC, 0xA7, 0xCC, 0x86, 0xF6, 0x46,
+               0xCC, 0x87, 0xF6, 0x66, 0xCC, 0x87, 0xF6, 0x47,
+               0xCC, 0x84, 0xF6, 0x67, 0xCC, 0x84, 0xF6, 0x48,
+               0xCC, 0x87, 0xF6, 0x68, 0xCC, 0x87, 0xF6, 0x48,
+               0xCC, 0xA3, 0xF6, 0x68, 0xCC, 0xA3, 0xF6, 0x48,
+               0xCC, 0x88, 0xF6, 0x68, 0xCC, 0x88, 0xF6, 0x48,
+               0xCC, 0xA7, 0xF6, 0x68, 0xCC, 0xA7, 0xF6, 0x48,
+               0xCC, 0xAE, 0xF6, 0x68, 0xCC, 0xAE, 0xF6, 0x49,
+               0xCC, 0xB0, 0xF6, 0x69, 0xCC, 0xB0, 0xF6, 0x49,
+               0xCC, 0x88, 0xCC, 0x81, 0xF6, 0x69, 0xCC, 0x88,
+               0xCC, 0x81, 0xF6, 0x4B, 0xCC, 0x81, 0xF6, 0x6B,
+               0xCC, 0x81, 0xF6, 0x4B, 0xCC, 0xA3, 0xF6, 0x6B,
+               0xCC, 0xA3, 0xF6, 0x4B, 0xCC, 0xB1, 0xF6, 0x6B,
+               0xCC, 0xB1, 0xF6, 0x4C, 0xCC, 0xA3, 0xF6, 0x6C,
+               0xCC, 0xA3, 0xF6, 0x4C, 0xCC, 0xA3, 0xCC, 0x84,
+               0xF6, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xF6, 0x4C,
+               0xCC, 0xB1, 0xF6, 0x6C, 0xCC, 0xB1, 0xF6, 0x4C,
+               0xCC, 0xAD, 0xF6, 0x6C, 0xCC, 0xAD, 0xF6, 0x4D,
+               0xCC, 0x81, 0xF6, 0x6D, 0xCC, 0x81, 0xF6, 0x4D,
+               0xCC, 0x87, 0xF6, 0x6D, 0xCC, 0x87, 0xF6, 0x4D,
+               0xCC, 0xA3, 0xF6, 0x6D, 0xCC, 0xA3, 0xF6, 0x4E,
+               0xCC, 0x87, 0xF6, 0x6E, 0xCC, 0x87, 0xF6, 0x4E,
+               0xCC, 0xA3, 0xF6, 0x6E, 0xCC, 0xA3, 0xF6, 0x4E,
+               0xCC, 0xB1, 0xF6, 0x6E, 0xCC, 0xB1, 0xF6, 0x4E,
+               0xCC, 0xAD, 0xF6, 0x6E, 0xCC, 0xAD, 0xF6, 0x4F,
+               0xCC, 0x83, 0xCC, 0x81, 0xF6, 0x6F, 0xCC, 0x83,
+               0xCC, 0x81, 0xF6, 0x4F, 0xCC, 0x83, 0xCC, 0x88,
+               0xF6, 0x6F, 0xCC, 0x83, 0xCC, 0x88, 0xF6, 0x4F,
+               0xCC, 0x84, 0xCC, 0x80, 0xF6, 0x6F, 0xCC, 0x84,
+               0xCC, 0x80, 0xF6, 0x4F, 0xCC, 0x84, 0xCC, 0x81,
+               0xF6, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xF6, 0x50,
+               0xCC, 0x81, 0xF6, 0x70, 0xCC, 0x81, 0xF6, 0x50,
+               0xCC, 0x87, 0xF6, 0x70, 0xCC, 0x87, 0xF6, 0x52,
+               0xCC, 0x87, 0xF6, 0x72, 0xCC, 0x87, 0xF6, 0x52,
+               0xCC, 0xA3, 0xF6, 0x72, 0xCC, 0xA3, 0xF6, 0x52,
+               0xCC, 0xA3, 0xCC, 0x84, 0xF6, 0x72, 0xCC, 0xA3,
+               0xCC, 0x84, 0xF6, 0x52, 0xCC, 0xB1, 0xF6, 0x72,
+               0xCC, 0xB1, 0xF6, 0x53, 0xCC, 0x87, 0xF6, 0x73,
+               0xCC, 0x87, 0xF6, 0x53, 0xCC, 0xA3, 0xF6, 0x73,
+               0xCC, 0xA3, 0xF6, 0x53, 0xCC, 0x81, 0xCC, 0x87,
+               0xF6, 0x73, 0xCC, 0x81, 0xCC, 0x87, 0xF6, 0x53,
+               0xCC, 0x8C, 0xCC, 0x87, 0xF6, 0x73, 0xCC, 0x8C,
+               0xCC, 0x87, 0xF6, 0x53, 0xCC, 0xA3, 0xCC, 0x87,
+               0xF6, 0x73, 0xCC, 0xA3, 0xCC, 0x87, 0xF6, 0x54,
+               0xCC, 0x87, 0xF6, 0x74, 0xCC, 0x87, 0xF6, 0x54,
+               0xCC, 0xA3, 0xF6, 0x74, 0xCC, 0xA3, 0xF6, 0x54,
+               0xCC, 0xB1, 0xF6, 0x74, 0xCC, 0xB1, 0xF6, 0x54,
+               0xCC, 0xAD, 0xF6, 0x74, 0xCC, 0xAD, 0xF6, 0x55,
+               0xCC, 0xA4, 0xF6, 0x75, 0xCC, 0xA4, 0xF6, 0x55,
+               0xCC, 0xB0, 0xF6, 0x75, 0xCC, 0xB0, 0xF6, 0x55,
+               0xCC, 0xAD, 0xF6, 0x75, 0xCC, 0xAD, 0xF6, 0x55,
+               0xCC, 0x83, 0xCC, 0x81, 0xF6, 0x75, 0xCC, 0x83,
+               0xCC, 0x81, 0xF6, 0x55, 0xCC, 0x84, 0xCC, 0x88,
+               0xF6, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xF6, 0x56,
+               0xCC, 0x83, 0xF6, 0x76, 0xCC, 0x83, 0xF6, 0x56,
+               0xCC, 0xA3, 0xF6, 0x76, 0xCC, 0xA3, 0xF6, 0x57,
+               0xCC, 0x80, 0xF6, 0x77, 0xCC, 0x80, 0xF6, 0x57,
+               0xCC, 0x81, 0xF6, 0x77, 0xCC, 0x81, 0xF6, 0x57,
+               0xCC, 0x88, 0xF6, 0x77, 0xCC, 0x88, 0xF6, 0x57,
+               0xCC, 0x87, 0xF6, 0x77, 0xCC, 0x87, 0xF6, 0x57,
+               0xCC, 0xA3, 0xF6, 0x77, 0xCC, 0xA3, 0xF6, 0x58,
+               0xCC, 0x87, 0xF6, 0x78, 0xCC, 0x87, 0xF6, 0x58,
+               0xCC, 0x88, 0xF6, 0x78, 0xCC, 0x88, 0xF6, 0x59,
+               0xCC, 0x87, 0xF6, 0x79, 0xCC, 0x87, 0xF6, 0x5A,
+               0xCC, 0x82, 0xF6, 0x7A, 0xCC, 0x82, 0xF6, 0x5A,
+               0xCC, 0xA3, 0xF6, 0x7A, 0xCC, 0xA3, 0xF6, 0x5A,
+               0xCC, 0xB1, 0xF6, 0x7A, 0xCC, 0xB1, 0xF6, 0x68,
+               0xCC, 0xB1, 0xF6, 0x74, 0xCC, 0x88, 0xF6, 0x77,
+               0xCC, 0x8A, 0xF6, 0x79, 0xCC, 0x8A, 0x61, 0xCA,
+               0xBE, 0xF5, 0x05, 0xC5, 0xBF, 0xCC, 0x87, 0x73,
+               0xCC, 0x87, 0xF6, 0x41, 0xCC, 0xA3, 0xF6, 0x61,
+               0xCC, 0xA3, 0xF6, 0x41, 0xCC, 0x89, 0xF6, 0x61,
+               0xCC, 0x89, 0xF6, 0x41, 0xCC, 0x82, 0xCC, 0x81,
+               0xF6, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xF6, 0x41,
+               0xCC, 0x82, 0xCC, 0x80, 0xF6, 0x61, 0xCC, 0x82,
+               0xCC, 0x80, 0xF6, 0x41, 0xCC, 0x82, 0xCC, 0x89,
+               0xF6, 0x61, 0xCC, 0x82, 0xCC, 0x89, 0xF6, 0x41,
+               0xCC, 0x82, 0xCC, 0x83, 0xF6, 0x61, 0xCC, 0x82,
+               0xCC, 0x83, 0xF6, 0x41, 0xCC, 0xA3, 0xCC, 0x82,
+               0xF6, 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0xF6, 0x41,
+               0xCC, 0x86, 0xCC, 0x81, 0xF6, 0x61, 0xCC, 0x86,
+               0xCC, 0x81, 0xF6, 0x41, 0xCC, 0x86, 0xCC, 0x80,
+               0xF6, 0x61, 0xCC, 0x86, 0xCC, 0x80, 0xF6, 0x41,
+               0xCC, 0x86, 0xCC, 0x89, 0xF6, 0x61, 0xCC, 0x86,
+               0xCC, 0x89, 0xF6, 0x41, 0xCC, 0x86, 0xCC, 0x83,
+               0xF6, 0x61, 0xCC, 0x86, 0xCC, 0x83, 0xF6, 0x41,
+               0xCC, 0xA3, 0xCC, 0x86, 0xF6, 0x61, 0xCC, 0xA3,
+               0xCC, 0x86, 0xF6, 0x45, 0xCC, 0xA3, 0xF6, 0x65,
+               0xCC, 0xA3, 0xF6, 0x45, 0xCC, 0x89, 0xF6, 0x65,
+               0xCC, 0x89, 0xF6, 0x45, 0xCC, 0x83, 0xF6, 0x65,
+               0xCC, 0x83, 0xF6, 0x45, 0xCC, 0x82, 0xCC, 0x81,
+               0xF6, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xF6, 0x45,
+               0xCC, 0x82, 0xCC, 0x80, 0xF6, 0x65, 0xCC, 0x82,
+               0xCC, 0x80, 0xF6, 0x45, 0xCC, 0x82, 0xCC, 0x89,
+               0xF6, 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xF6, 0x45,
+               0xCC, 0x82, 0xCC, 0x83, 0xF6, 0x65, 0xCC, 0x82,
+               0xCC, 0x83, 0xF6, 0x45, 0xCC, 0xA3, 0xCC, 0x82,
+               0xF6, 0x65, 0xCC, 0xA3, 0xCC, 0x82, 0xF6, 0x49,
+               0xCC, 0x89, 0xF6, 0x69, 0xCC, 0x89, 0xF6, 0x49,
+               0xCC, 0xA3, 0xF6, 0x69, 0xCC, 0xA3, 0xF6, 0x4F,
+               0xCC, 0xA3, 0xF6, 0x6F, 0xCC, 0xA3, 0xF6, 0x4F,
+               0xCC, 0x89, 0xF6, 0x6F, 0xCC, 0x89, 0xF6, 0x4F,
+               0xCC, 0x82, 0xCC, 0x81, 0xF6, 0x6F, 0xCC, 0x82,
+               0xCC, 0x81, 0xF6, 0x4F, 0xCC, 0x82, 0xCC, 0x80,
+               0xF6, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xF6, 0x4F,
+               0xCC, 0x82, 0xCC, 0x89, 0xF6, 0x6F, 0xCC, 0x82,
+               0xCC, 0x89, 0xF6, 0x4F, 0xCC, 0x82, 0xCC, 0x83,
+               0xF6, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0xF6, 0x4F,
+               0xCC, 0xA3, 0xCC, 0x82, 0xF6, 0x6F, 0xCC, 0xA3,
+               0xCC, 0x82, 0xF6, 0x4F, 0xCC, 0x9B, 0xCC, 0x81,
+               0xF6, 0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0xF6, 0x4F,
+               0xCC, 0x9B, 0xCC, 0x80, 0xF6, 0x6F, 0xCC, 0x9B,
+               0xCC, 0x80, 0xF6, 0x4F, 0xCC, 0x9B, 0xCC, 0x89,
+               0xF6, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0xF6, 0x4F,
+               0xCC, 0x9B, 0xCC, 0x83, 0xF6, 0x6F, 0xCC, 0x9B,
+               0xCC, 0x83, 0xF6, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3,
+               0xF6, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xF6, 0x55,
+               0xCC, 0xA3, 0xF6, 0x75, 0xCC, 0xA3, 0xF6, 0x55,
+               0xCC, 0x89, 0xF6, 0x75, 0xCC, 0x89, 0xF6, 0x55,
+               0xCC, 0x9B, 0xCC, 0x81, 0xF6, 0x75, 0xCC, 0x9B,
+               0xCC, 0x81, 0xF6, 0x55, 0xCC, 0x9B, 0xCC, 0x80,
+               0xF6, 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0xF6, 0x55,
+               0xCC, 0x9B, 0xCC, 0x89, 0xF6, 0x75, 0xCC, 0x9B,
+               0xCC, 0x89, 0xF6, 0x55, 0xCC, 0x9B, 0xCC, 0x83,
+               0xF6, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0xF6, 0x55,
+               0xCC, 0x9B, 0xCC, 0xA3, 0xF6, 0x75, 0xCC, 0x9B,
+               0xCC, 0xA3, 0xF6, 0x59, 0xCC, 0x80, 0xF6, 0x79,
+               0xCC, 0x80, 0xF6, 0x59, 0xCC, 0xA3, 0xF6, 0x79,
+               0xCC, 0xA3, 0xF6, 0x59, 0xCC, 0x89, 0xF6, 0x79,
+               0xCC, 0x89, 0xF6, 0x59, 0xCC, 0x83, 0xF6, 0x79,
+               0xCC, 0x83, 0xF6, 0xCE, 0xB1, 0xCC, 0x93, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x94, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x93, 0xCC, 0x80, 0xF6, 0xCE, 0xB1, 0xCC, 0x94,
+               0xCC, 0x80, 0xF6, 0xCE, 0xB1, 0xCC, 0x93, 0xCC,
+               0x81, 0xF6, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81,
+               0xF6, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE,
+               0x91, 0xCC, 0x93, 0xF6, 0xCE, 0x91, 0xCC, 0x94,
+               0xF6, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xF6,
+               0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE,
+               0x91, 0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0x91,
+               0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCE, 0x91, 0xCC,
+               0x93, 0xCD, 0x82, 0xF6, 0xCE, 0x91, 0xCC, 0x94,
+               0xCD, 0x82, 0xF6, 0xCE, 0xB5, 0xCC, 0x93, 0xF6,
+               0xCE, 0xB5, 0xCC, 0x94, 0xF6, 0xCE, 0xB5, 0xCC,
+               0x93, 0xCC, 0x80, 0xF6, 0xCE, 0xB5, 0xCC, 0x94,
+               0xCC, 0x80, 0xF6, 0xCE, 0xB5, 0xCC, 0x93, 0xCC,
+               0x81, 0xF6, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81,
+               0xF6, 0xCE, 0x95, 0xCC, 0x93, 0xF6, 0xCE, 0x95,
+               0xCC, 0x94, 0xF6, 0xCE, 0x95, 0xCC, 0x93, 0xCC,
+               0x80, 0xF6, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80,
+               0xF6, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xF6,
+               0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x93, 0xF6, 0xCE, 0xB7, 0xCC, 0x94,
+               0xF6, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xF6,
+               0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCE, 0xB7, 0xCC,
+               0x93, 0xCD, 0x82, 0xF6, 0xCE, 0xB7, 0xCC, 0x94,
+               0xCD, 0x82, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xF6,
+               0xCE, 0x97, 0xCC, 0x94, 0xF6, 0xCE, 0x97, 0xCC,
+               0x93, 0xCC, 0x80, 0xF6, 0xCE, 0x97, 0xCC, 0x94,
+               0xCC, 0x80, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCC,
+               0x81, 0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81,
+               0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xF6,
+               0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE,
+               0xB9, 0xCC, 0x93, 0xF6, 0xCE, 0xB9, 0xCC, 0x94,
+               0xF6, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xF6,
+               0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE,
+               0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xB9,
+               0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCC,
+               0x93, 0xCD, 0x82, 0xF6, 0xCE, 0xB9, 0xCC, 0x94,
+               0xCD, 0x82, 0xF6, 0xCE, 0x99, 0xCC, 0x93, 0xF6,
+               0xCE, 0x99, 0xCC, 0x94, 0xF6, 0xCE, 0x99, 0xCC,
+               0x93, 0xCC, 0x80, 0xF6, 0xCE, 0x99, 0xCC, 0x94,
+               0xCC, 0x80, 0xF6, 0xCE, 0x99, 0xCC, 0x93, 0xCC,
+               0x81, 0xF6, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81,
+               0xF6, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xF6,
+               0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE,
+               0xBF, 0xCC, 0x93, 0xF6, 0xCE, 0xBF, 0xCC, 0x94,
+               0xF6, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xF6,
+               0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE,
+               0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xBF,
+               0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCE, 0x9F, 0xCC,
+               0x93, 0xF6, 0xCE, 0x9F, 0xCC, 0x94, 0xF6, 0xCE,
+               0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE, 0x9F,
+               0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE, 0x9F, 0xCC,
+               0x93, 0xCC, 0x81, 0xF6, 0xCE, 0x9F, 0xCC, 0x94,
+               0xCC, 0x81, 0xF6, 0xCF, 0x85, 0xCC, 0x93, 0xF6,
+               0xCF, 0x85, 0xCC, 0x94, 0xF6, 0xCF, 0x85, 0xCC,
+               0x93, 0xCC, 0x80, 0xF6, 0xCF, 0x85, 0xCC, 0x94,
+               0xCC, 0x80, 0xF6, 0xCF, 0x85, 0xCC, 0x93, 0xCC,
+               0x81, 0xF6, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81,
+               0xF6, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xF6,
+               0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE,
+               0xA5, 0xCC, 0x94, 0xF6, 0xCE, 0xA5, 0xCC, 0x94,
+               0xCC, 0x80, 0xF6, 0xCE, 0xA5, 0xCC, 0x94, 0xCC,
+               0x81, 0xF6, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82,
+               0xF6, 0xCF, 0x89, 0xCC, 0x93, 0xF6, 0xCF, 0x89,
+               0xCC, 0x94, 0xF6, 0xCF, 0x89, 0xCC, 0x93, 0xCC,
+               0x80, 0xF6, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x80,
+               0xF6, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xF6,
+               0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xF6, 0xCF,
+               0x89, 0xCC, 0x93, 0xCD, 0x82, 0xF6, 0xCF, 0x89,
+               0xCC, 0x94, 0xCD, 0x82, 0xF6, 0xCE, 0xA9, 0xCC,
+               0x93, 0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xF6, 0xCE,
+               0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xF6, 0xCE, 0xA9,
+               0xCC, 0x94, 0xCC, 0x80, 0xF6, 0xCE, 0xA9, 0xCC,
+               0x93, 0xCC, 0x81, 0xF6, 0xCE, 0xA9, 0xCC, 0x94,
+               0xCC, 0x81, 0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD,
+               0x82, 0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x82,
+               0xF6, 0xCE, 0xB1, 0xCC, 0x80, 0xF6, 0xCE, 0xB1,
+               0xCC, 0x81, 0xF6, 0xCE, 0xB5, 0xCC, 0x80, 0xF6,
+               0xCE, 0xB5, 0xCC, 0x81, 0xF6, 0xCE, 0xB7, 0xCC,
+               0x80, 0xF6, 0xCE, 0xB7, 0xCC, 0x81, 0xF6, 0xCE,
+               0xB9, 0xCC, 0x80, 0xF6, 0xCE, 0xB9, 0xCC, 0x81,
+               0xF6, 0xCE, 0xBF, 0xCC, 0x80, 0xF6, 0xCE, 0xBF,
+               0xCC, 0x81, 0xF6, 0xCF, 0x85, 0xCC, 0x80, 0xF6,
+               0xCF, 0x85, 0xCC, 0x81, 0xF6, 0xCF, 0x89, 0xCC,
+               0x80, 0xF6, 0xCF, 0x89, 0xCC, 0x81, 0xF6, 0xCE,
+               0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xF6, 0xCE, 0xB1,
+               0xCC, 0x94, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x93, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB1,
+               0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF6,
+               0xCE, 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85,
+               0xF6, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+               0x85, 0xF6, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82,
+               0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x93, 0xCD,
+               0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85,
+               0xF6, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+               0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80,
+               0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x93, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC, 0x94,
+               0xCC, 0x81, 0xCD, 0x85, 0xF6, 0xCE, 0x91, 0xCC,
+               0x93, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x91,
+               0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x94, 0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCC,
+               0x93, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE, 0xB7,
+               0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB7, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF6,
+               0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85,
+               0xF6, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+               0x85, 0xF6, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82,
+               0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCD,
+               0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85,
+               0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+               0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80,
+               0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x93, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC, 0x94,
+               0xCC, 0x81, 0xCD, 0x85, 0xF6, 0xCE, 0x97, 0xCC,
+               0x93, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x97,
+               0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCF,
+               0x89, 0xCC, 0x93, 0xCD, 0x85, 0xF6, 0xCF, 0x89,
+               0xCC, 0x94, 0xCD, 0x85, 0xF6, 0xCF, 0x89, 0xCC,
+               0x93, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCF, 0x89,
+               0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCF,
+               0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF6,
+               0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85,
+               0xF6, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+               0x85, 0xF6, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82,
+               0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCD,
+               0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85,
+               0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+               0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80,
+               0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x93, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC, 0x94,
+               0xCC, 0x81, 0xCD, 0x85, 0xF6, 0xCE, 0xA9, 0xCC,
+               0x93, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0xA9,
+               0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB1, 0xCC, 0x86, 0xF6, 0xCE, 0xB1, 0xCC, 0x84,
+               0xF6, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xF6,
+               0xCE, 0xB1, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCC,
+               0x81, 0xCD, 0x85, 0xF6, 0xCE, 0xB1, 0xCD, 0x82,
+               0xF6, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xF6,
+               0xCE, 0x91, 0xCC, 0x86, 0xF6, 0xCE, 0x91, 0xCC,
+               0x84, 0xF6, 0xCE, 0x91, 0xCC, 0x80, 0xF6, 0xCE,
+               0x91, 0xCC, 0x81, 0xF6, 0xCE, 0x91, 0xCD, 0x85,
+               0x20, 0xCC, 0x93, 0xF6, 0xCE, 0xB9, 0x20, 0xCC,
+               0x93, 0x20, 0xCD, 0x82, 0xF5, 0x05, 0xC2, 0xA8,
+               0xCD, 0x82, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xF6,
+               0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCE,
+               0xB7, 0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCC, 0x81,
+               0xCD, 0x85, 0xF6, 0xCE, 0xB7, 0xCD, 0x82, 0xF6,
+               0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE,
+               0x95, 0xCC, 0x80, 0xF6, 0xCE, 0x95, 0xCC, 0x81,
+               0xF6, 0xCE, 0x97, 0xCC, 0x80, 0xF6, 0xCE, 0x97,
+               0xCC, 0x81, 0xF6, 0xCE, 0x97, 0xCD, 0x85, 0xF5,
+               0x06, 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0x20, 0xCC,
+               0x93, 0xCC, 0x80, 0xF5, 0x06, 0xE1, 0xBE, 0xBF,
+               0xCC, 0x81, 0x20, 0xCC, 0x93, 0xCC, 0x81, 0xF5,
+               0x06, 0xE1, 0xBE, 0xBF, 0xCD, 0x82, 0x20, 0xCC,
+               0x93, 0xCD, 0x82, 0xF6, 0xCE, 0xB9, 0xCC, 0x86,
+               0xF6, 0xCE, 0xB9, 0xCC, 0x84, 0xF6, 0xCE, 0xB9,
+               0xCC, 0x88, 0xCC, 0x80, 0xF6, 0xCE, 0xB9, 0xCC,
+               0x88, 0xCC, 0x81, 0xF6, 0xCE, 0xB9, 0xCD, 0x82,
+               0xF6, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xF6,
+               0xCE, 0x99, 0xCC, 0x86, 0xF6, 0xCE, 0x99, 0xCC,
+               0x84, 0xF6, 0xCE, 0x99, 0xCC, 0x80, 0xF6, 0xCE,
+               0x99, 0xCC, 0x81, 0xF5, 0x06, 0xE1, 0xBF, 0xBE,
+               0xCC, 0x80, 0x20, 0xCC, 0x94, 0xCC, 0x80, 0xF5,
+               0x06, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x20, 0xCC,
+               0x94, 0xCC, 0x81, 0xF5, 0x06, 0xE1, 0xBF, 0xBE,
+               0xCD, 0x82, 0x20, 0xCC, 0x94, 0xCD, 0x82, 0xF6,
+               0xCF, 0x85, 0xCC, 0x86, 0xF6, 0xCF, 0x85, 0xCC,
+               0x84, 0xF6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80,
+               0xF6, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xF6,
+               0xCF, 0x81, 0xCC, 0x93, 0xF6, 0xCF, 0x81, 0xCC,
+               0x94, 0xF6, 0xCF, 0x85, 0xCD, 0x82, 0xF6, 0xCF,
+               0x85, 0xCC, 0x88, 0xCD, 0x82, 0xF6, 0xCE, 0xA5,
+               0xCC, 0x86, 0xF6, 0xCE, 0xA5, 0xCC, 0x84, 0xF6,
+               0xCE, 0xA5, 0xCC, 0x80, 0xF6, 0xCE, 0xA5, 0xCC,
+               0x81, 0xF6, 0xCE, 0xA1, 0xCC, 0x94, 0xF5, 0x05,
+               0xC2, 0xA8, 0xCC, 0x80, 0x20, 0xCC, 0x88, 0xCC,
+               0x80, 0xF5, 0x05, 0xC2, 0xA8, 0xCC, 0x81, 0x20,
+               0xCC, 0x88, 0xCC, 0x81, 0xF6, 0x60, 0xF6, 0xCF,
+               0x89, 0xCC, 0x80, 0xCD, 0x85, 0xF6, 0xCF, 0x89,
+               0xCD, 0x85, 0xF6, 0xCF, 0x89, 0xCC, 0x81, 0xCD,
+               0x85, 0xF6, 0xCF, 0x89, 0xCD, 0x82, 0xF6, 0xCF,
+               0x89, 0xCD, 0x82, 0xCD, 0x85, 0xF6, 0xCE, 0x9F,
+               0xCC, 0x80, 0xF6, 0xCE, 0x9F, 0xCC, 0x81, 0xF6,
+               0xCE, 0xA9, 0xCC, 0x80, 0xF6, 0xCE, 0xA9, 0xCC,
+               0x81, 0xF6, 0xCE, 0xA9, 0xCD, 0x85, 0xF5, 0x03,
+               0xC2, 0xB4, 0x20, 0xCC, 0x81, 0x20, 0xCC, 0x94,
+               0xF5, 0x04, 0xE2, 0x80, 0x82, 0x20, 0xF5, 0x04,
+               0xE2, 0x80, 0x83, 0x20, 0x20, 0x20, 0x20, 0x20,
+               0x20, 0x20, 0x20, 0x20, 0x20, 0xE2, 0x80, 0x90,
+               0x20, 0xCC, 0xB3, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
+               0x2E, 0x20, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+               0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80,
+               0xB2, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2,
+               0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5,
+               0x21, 0x21, 0x20, 0xCC, 0x85, 0x3F, 0x3F, 0x3F,
+               0x21, 0x21, 0x3F, 0xE2, 0x80, 0xB2, 0xE2, 0x80,
+               0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x20,
+               0x30, 0x69, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+               0x2B, 0xE2, 0x88, 0x92, 0x3D, 0x28, 0x29, 0x6E,
+               0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+               0x38, 0x39, 0x2B, 0xE2, 0x88, 0x92, 0x3D, 0x28,
+               0x29, 0x61, 0x65, 0x6F, 0x78, 0xC9, 0x99, 0x52,
+               0x73, 0x61, 0x2F, 0x63, 0x61, 0x2F, 0x73, 0x43,
+               0xC2, 0xB0, 0x43, 0x63, 0x2F, 0x6F, 0x63, 0x2F,
+               0x75, 0xC6, 0x90, 0xC2, 0xB0, 0x46, 0x67, 0x48,
+               0x48, 0x48, 0x68, 0xC4, 0xA7, 0x49, 0x49, 0x4C,
+               0x6C, 0x4E, 0x4E, 0x6F, 0x50, 0x51, 0x52, 0x52,
+               0x52, 0x53, 0x4D, 0x54, 0x45, 0x4C, 0x54, 0x4D,
+               0x5A, 0xF6, 0xCE, 0xA9, 0x5A, 0xF6, 0x4B, 0xF6,
+               0x41, 0xCC, 0x8A, 0x42, 0x43, 0x65, 0x45, 0x46,
+               0x4D, 0x6F, 0xD7, 0x90, 0xD7, 0x91, 0xD7, 0x92,
+               0xD7, 0x93, 0x69, 0x46, 0x41, 0x58, 0xCF, 0x80,
+               0xCE, 0xB3, 0xCE, 0x93, 0xCE, 0xA0, 0xE2, 0x88,
+               0x91, 0x44, 0x64, 0x65, 0x69, 0x6A, 0x31, 0xE2,
+               0x81, 0x84, 0x33, 0x32, 0xE2, 0x81, 0x84, 0x33,
+               0x31, 0xE2, 0x81, 0x84, 0x35, 0x32, 0xE2, 0x81,
+               0x84, 0x35, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x34,
+               0xE2, 0x81, 0x84, 0x35, 0x31, 0xE2, 0x81, 0x84,
+               0x36, 0x35, 0xE2, 0x81, 0x84, 0x36, 0x31, 0xE2,
+               0x81, 0x84, 0x38, 0x33, 0xE2, 0x81, 0x84, 0x38,
+               0x35, 0xE2, 0x81, 0x84, 0x38, 0x37, 0xE2, 0x81,
+               0x84, 0x38, 0x31, 0xE2, 0x81, 0x84, 0x49, 0x49,
+               0x49, 0x49, 0x49, 0x49, 0x49, 0x56, 0x56, 0x56,
+               0x49, 0x56, 0x49, 0x49, 0x56, 0x49, 0x49, 0x49,
+               0x49, 0x58, 0x58, 0x58, 0x49, 0x58, 0x49, 0x49,
+               0x4C, 0x43, 0x44, 0x4D, 0x69, 0x69, 0x69, 0x69,
+               0x69, 0x69, 0x69, 0x76, 0x76, 0x76, 0x69, 0x76,
+               0x69, 0x69, 0x76, 0x69, 0x69, 0x69, 0x69, 0x78,
+               0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6C, 0x63,
+               0x64, 0x6D, 0xF6, 0xE2, 0x86, 0x90, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x86, 0x94, 0xCC, 0xB8, 0xF6, 0xE2, 0x87, 0x90,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x87, 0x94, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x87, 0x92, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x88, 0x83, 0xCC, 0xB8, 0xF6, 0xE2, 0x88, 0x88,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x88, 0x8B, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x88, 0xA5, 0xCC, 0xB8, 0xE2, 0x88, 0xAB, 0xE2,
+               0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
+               0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAE, 0xE2, 0x88,
+               0xAE, 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0xE2,
+               0x88, 0xAE, 0xF6, 0xE2, 0x88, 0xBC, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0x83, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0x85, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0x88,
+               0xCC, 0xB8, 0xF6, 0x3D, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0xA1, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0x8D,
+               0xCC, 0xB8, 0xF6, 0x3C, 0xCC, 0xB8, 0xF6, 0x3E,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xA4, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0xB2, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xB3,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xB6, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0xB7, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x89, 0xBA, 0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xBB,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0x82, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0x86, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0x87,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0xA9, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xAB,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x89, 0xBC, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0x91, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0x92,
+               0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xB2, 0xCC, 0xB8,
+               0xF6, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, 0xF6, 0xE2,
+               0x8A, 0xB4, 0xCC, 0xB8, 0xF6, 0xE2, 0x8A, 0xB5,
+               0xCC, 0xB8, 0xF6, 0xE3, 0x80, 0x88, 0xF6, 0xE3,
+               0x80, 0x89, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+               0x37, 0x38, 0x39, 0x31, 0x30, 0x31, 0x31, 0x31,
+               0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, 0x31,
+               0x36, 0x31, 0x37, 0x31, 0x38, 0x31, 0x39, 0x32,
+               0x30, 0x28, 0x31, 0x29, 0x28, 0x32, 0x29, 0x28,
+               0x33, 0x29, 0x28, 0x34, 0x29, 0x28, 0x35, 0x29,
+               0x28, 0x36, 0x29, 0x28, 0x37, 0x29, 0x28, 0x38,
+               0x29, 0x28, 0x39, 0x29, 0x28, 0x31, 0x30, 0x29,
+               0x28, 0x31, 0x31, 0x29, 0x28, 0x31, 0x32, 0x29,
+               0x28, 0x31, 0x33, 0x29, 0x28, 0x31, 0x34, 0x29,
+               0x28, 0x31, 0x35, 0x29, 0x28, 0x31, 0x36, 0x29,
+               0x28, 0x31, 0x37, 0x29, 0x28, 0x31, 0x38, 0x29,
+               0x28, 0x31, 0x39, 0x29, 0x28, 0x32, 0x30, 0x29,
+               0x31, 0x2E, 0x32, 0x2E, 0x33, 0x2E, 0x34, 0x2E,
+               0x35, 0x2E, 0x36, 0x2E, 0x37, 0x2E, 0x38, 0x2E,
+               0x39, 0x2E, 0x31, 0x30, 0x2E, 0x31, 0x31, 0x2E,
+               0x31, 0x32, 0x2E, 0x31, 0x33, 0x2E, 0x31, 0x34,
+               0x2E, 0x31, 0x35, 0x2E, 0x31, 0x36, 0x2E, 0x31,
+               0x37, 0x2E, 0x31, 0x38, 0x2E, 0x31, 0x39, 0x2E,
+               0x32, 0x30, 0x2E, 0x28, 0x61, 0x29, 0x28, 0x62,
+               0x29, 0x28, 0x63, 0x29, 0x28, 0x64, 0x29, 0x28,
+               0x65, 0x29, 0x28, 0x66, 0x29, 0x28, 0x67, 0x29,
+               0x28, 0x68, 0x29, 0x28, 0x69, 0x29, 0x28, 0x6A,
+               0x29, 0x28, 0x6B, 0x29, 0x28, 0x6C, 0x29, 0x28,
+               0x6D, 0x29, 0x28, 0x6E, 0x29, 0x28, 0x6F, 0x29,
+               0x28, 0x70, 0x29, 0x28, 0x71, 0x29, 0x28, 0x72,
+               0x29, 0x28, 0x73, 0x29, 0x28, 0x74, 0x29, 0x28,
+               0x75, 0x29, 0x28, 0x76, 0x29, 0x28, 0x77, 0x29,
+               0x28, 0x78, 0x29, 0x28, 0x79, 0x29, 0x28, 0x7A,
+               0x29, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x30, 0xE2, 0x88,
+               0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2,
+               0x88, 0xAB, 0x3A, 0x3A, 0x3D, 0x3D, 0x3D, 0x3D,
+               0x3D, 0x3D, 0xF6, 0xE2, 0xAB, 0x9D, 0xCC, 0xB8,
+               0xE2, 0xB5, 0xA1, 0xE6, 0xAF, 0x8D, 0xE9, 0xBE,
+               0x9F, 0xE4, 0xB8, 0x80, 0xE4, 0xB8, 0xA8, 0xE4,
+               0xB8, 0xB6, 0xE4, 0xB8, 0xBF, 0xE4, 0xB9, 0x99,
+               0xE4, 0xBA, 0x85, 0xE4, 0xBA, 0x8C, 0xE4, 0xBA,
+               0xA0, 0xE4, 0xBA, 0xBA, 0xE5, 0x84, 0xBF, 0xE5,
+               0x85, 0xA5, 0xE5, 0x85, 0xAB, 0xE5, 0x86, 0x82,
+               0xE5, 0x86, 0x96, 0xE5, 0x86, 0xAB, 0xE5, 0x87,
+               0xA0, 0xE5, 0x87, 0xB5, 0xE5, 0x88, 0x80, 0xE5,
+               0x8A, 0x9B, 0xE5, 0x8B, 0xB9, 0xE5, 0x8C, 0x95,
+               0xE5, 0x8C, 0x9A, 0xE5, 0x8C, 0xB8, 0xE5, 0x8D,
+               0x81, 0xE5, 0x8D, 0x9C, 0xE5, 0x8D, 0xA9, 0xE5,
+               0x8E, 0x82, 0xE5, 0x8E, 0xB6, 0xE5, 0x8F, 0x88,
+               0xE5, 0x8F, 0xA3, 0xE5, 0x9B, 0x97, 0xE5, 0x9C,
+               0x9F, 0xE5, 0xA3, 0xAB, 0xE5, 0xA4, 0x82, 0xE5,
+               0xA4, 0x8A, 0xE5, 0xA4, 0x95, 0xE5, 0xA4, 0xA7,
+               0xE5, 0xA5, 0xB3, 0xE5, 0xAD, 0x90, 0xE5, 0xAE,
+               0x80, 0xE5, 0xAF, 0xB8, 0xE5, 0xB0, 0x8F, 0xE5,
+               0xB0, 0xA2, 0xE5, 0xB0, 0xB8, 0xE5, 0xB1, 0xAE,
+               0xE5, 0xB1, 0xB1, 0xE5, 0xB7, 0x9B, 0xE5, 0xB7,
+               0xA5, 0xE5, 0xB7, 0xB1, 0xE5, 0xB7, 0xBE, 0xE5,
+               0xB9, 0xB2, 0xE5, 0xB9, 0xBA, 0xE5, 0xB9, 0xBF,
+               0xE5, 0xBB, 0xB4, 0xE5, 0xBB, 0xBE, 0xE5, 0xBC,
+               0x8B, 0xE5, 0xBC, 0x93, 0xE5, 0xBD, 0x90, 0xE5,
+               0xBD, 0xA1, 0xE5, 0xBD, 0xB3, 0xE5, 0xBF, 0x83,
+               0xE6, 0x88, 0x88, 0xE6, 0x88, 0xB6, 0xE6, 0x89,
+               0x8B, 0xE6, 0x94, 0xAF, 0xE6, 0x94, 0xB4, 0xE6,
+               0x96, 0x87, 0xE6, 0x96, 0x97, 0xE6, 0x96, 0xA4,
+               0xE6, 0x96, 0xB9, 0xE6, 0x97, 0xA0, 0xE6, 0x97,
+               0xA5, 0xE6, 0x9B, 0xB0, 0xE6, 0x9C, 0x88, 0xE6,
+               0x9C, 0xA8, 0xE6, 0xAC, 0xA0, 0xE6, 0xAD, 0xA2,
+               0xE6, 0xAD, 0xB9, 0xE6, 0xAE, 0xB3, 0xE6, 0xAF,
+               0x8B, 0xE6, 0xAF, 0x94, 0xE6, 0xAF, 0x9B, 0xE6,
+               0xB0, 0x8F, 0xE6, 0xB0, 0x94, 0xE6, 0xB0, 0xB4,
+               0xE7, 0x81, 0xAB, 0xE7, 0x88, 0xAA, 0xE7, 0x88,
+               0xB6, 0xE7, 0x88, 0xBB, 0xE7, 0x88, 0xBF, 0xE7,
+               0x89, 0x87, 0xE7, 0x89, 0x99, 0xE7, 0x89, 0x9B,
+               0xE7, 0x8A, 0xAC, 0xE7, 0x8E, 0x84, 0xE7, 0x8E,
+               0x89, 0xE7, 0x93, 0x9C, 0xE7, 0x93, 0xA6, 0xE7,
+               0x94, 0x98, 0xE7, 0x94, 0x9F, 0xE7, 0x94, 0xA8,
+               0xE7, 0x94, 0xB0, 0xE7, 0x96, 0x8B, 0xE7, 0x96,
+               0x92, 0xE7, 0x99, 0xB6, 0xE7, 0x99, 0xBD, 0xE7,
+               0x9A, 0xAE, 0xE7, 0x9A, 0xBF, 0xE7, 0x9B, 0xAE,
+               0xE7, 0x9F, 0x9B, 0xE7, 0x9F, 0xA2, 0xE7, 0x9F,
+               0xB3, 0xE7, 0xA4, 0xBA, 0xE7, 0xA6, 0xB8, 0xE7,
+               0xA6, 0xBE, 0xE7, 0xA9, 0xB4, 0xE7, 0xAB, 0x8B,
+               0xE7, 0xAB, 0xB9, 0xE7, 0xB1, 0xB3, 0xE7, 0xB3,
+               0xB8, 0xE7, 0xBC, 0xB6, 0xE7, 0xBD, 0x91, 0xE7,
+               0xBE, 0x8A, 0xE7, 0xBE, 0xBD, 0xE8, 0x80, 0x81,
+               0xE8, 0x80, 0x8C, 0xE8, 0x80, 0x92, 0xE8, 0x80,
+               0xB3, 0xE8, 0x81, 0xBF, 0xE8, 0x82, 0x89, 0xE8,
+               0x87, 0xA3, 0xE8, 0x87, 0xAA, 0xE8, 0x87, 0xB3,
+               0xE8, 0x87, 0xBC, 0xE8, 0x88, 0x8C, 0xE8, 0x88,
+               0x9B, 0xE8, 0x88, 0x9F, 0xE8, 0x89, 0xAE, 0xE8,
+               0x89, 0xB2, 0xE8, 0x89, 0xB8, 0xE8, 0x99, 0x8D,
+               0xE8, 0x99, 0xAB, 0xE8, 0xA1, 0x80, 0xE8, 0xA1,
+               0x8C, 0xE8, 0xA1, 0xA3, 0xE8, 0xA5, 0xBE, 0xE8,
+               0xA6, 0x8B, 0xE8, 0xA7, 0x92, 0xE8, 0xA8, 0x80,
+               0xE8, 0xB0, 0xB7, 0xE8, 0xB1, 0x86, 0xE8, 0xB1,
+               0x95, 0xE8, 0xB1, 0xB8, 0xE8, 0xB2, 0x9D, 0xE8,
+               0xB5, 0xA4, 0xE8, 0xB5, 0xB0, 0xE8, 0xB6, 0xB3,
+               0xE8, 0xBA, 0xAB, 0xE8, 0xBB, 0x8A, 0xE8, 0xBE,
+               0x9B, 0xE8, 0xBE, 0xB0, 0xE8, 0xBE, 0xB5, 0xE9,
+               0x82, 0x91, 0xE9, 0x85, 0x89, 0xE9, 0x87, 0x86,
+               0xE9, 0x87, 0x8C, 0xE9, 0x87, 0x91, 0xE9, 0x95,
+               0xB7, 0xE9, 0x96, 0x80, 0xE9, 0x98, 0x9C, 0xE9,
+               0x9A, 0xB6, 0xE9, 0x9A, 0xB9, 0xE9, 0x9B, 0xA8,
+               0xE9, 0x9D, 0x91, 0xE9, 0x9D, 0x9E, 0xE9, 0x9D,
+               0xA2, 0xE9, 0x9D, 0xA9, 0xE9, 0x9F, 0x8B, 0xE9,
+               0x9F, 0xAD, 0xE9, 0x9F, 0xB3, 0xE9, 0xA0, 0x81,
+               0xE9, 0xA2, 0xA8, 0xE9, 0xA3, 0x9B, 0xE9, 0xA3,
+               0x9F, 0xE9, 0xA6, 0x96, 0xE9, 0xA6, 0x99, 0xE9,
+               0xA6, 0xAC, 0xE9, 0xAA, 0xA8, 0xE9, 0xAB, 0x98,
+               0xE9, 0xAB, 0x9F, 0xE9, 0xAC, 0xA5, 0xE9, 0xAC,
+               0xAF, 0xE9, 0xAC, 0xB2, 0xE9, 0xAC, 0xBC, 0xE9,
+               0xAD, 0x9A, 0xE9, 0xB3, 0xA5, 0xE9, 0xB9, 0xB5,
+               0xE9, 0xB9, 0xBF, 0xE9, 0xBA, 0xA5, 0xE9, 0xBA,
+               0xBB, 0xE9, 0xBB, 0x83, 0xE9, 0xBB, 0x8D, 0xE9,
+               0xBB, 0x91, 0xE9, 0xBB, 0xB9, 0xE9, 0xBB, 0xBD,
+               0xE9, 0xBC, 0x8E, 0xE9, 0xBC, 0x93, 0xE9, 0xBC,
+               0xA0, 0xE9, 0xBC, 0xBB, 0xE9, 0xBD, 0x8A, 0xE9,
+               0xBD, 0x92, 0xE9, 0xBE, 0x8D, 0xE9, 0xBE, 0x9C,
+               0xE9, 0xBE, 0xA0, 0x20, 0xE3, 0x80, 0x92, 0xE5,
+               0x8D, 0x81, 0xE5, 0x8D, 0x84, 0xE5, 0x8D, 0x85,
+               0xF6, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x81, 0x8F, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81,
+               0x91, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0x93,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0x95, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x81, 0x97, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x81, 0x9F, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81,
+               0xA1, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0xA4,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0xA6, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x81, 0xA8, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0xF6,
+               0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x81, 0xB2, 0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x81,
+               0xB5, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x81, 0xB5,
+               0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x81, 0xB8, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x81, 0xB8, 0xE3, 0x82,
+               0x9A, 0xF6, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0xF6,
+               0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x20, 0xE3,
+               0x82, 0x99, 0x20, 0xE3, 0x82, 0x9A, 0xF6, 0xE3,
+               0x82, 0x9D, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0x88,
+               0xE3, 0x82, 0x8A, 0xF6, 0xE3, 0x82, 0xAB, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x82, 0xB5, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82,
+               0xB7, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82, 0xB9,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x82, 0xBB, 0xE3,
+               0x82, 0x99, 0xF6, 0xE3, 0x82, 0xBD, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x83, 0x86, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83,
+               0x88, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83, 0x8F,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83, 0x8F, 0xE3,
+               0x82, 0x9A, 0xF6, 0xE3, 0x83, 0x92, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
+               0xF6, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0xF6, 0xE3,
+               0x83, 0x98, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83,
+               0x98, 0xE3, 0x82, 0x9A, 0xF6, 0xE3, 0x83, 0x9B,
+               0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83, 0x9B, 0xE3,
+               0x82, 0x9A, 0xF6, 0xE3, 0x82, 0xA6, 0xE3, 0x82,
+               0x99, 0xF6, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99,
+               0xF6, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0xF6,
+               0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0xF6, 0xE3,
+               0x83, 0xB2, 0xE3, 0x82, 0x99, 0xF6, 0xE3, 0x83,
+               0xBD, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB3, 0xE3,
+               0x83, 0x88, 0xE1, 0x84, 0x80, 0xE1, 0x84, 0x81,
+               0xE1, 0x86, 0xAA, 0xE1, 0x84, 0x82, 0xE1, 0x86,
+               0xAC, 0xE1, 0x86, 0xAD, 0xE1, 0x84, 0x83, 0xE1,
+               0x84, 0x84, 0xE1, 0x84, 0x85, 0xE1, 0x86, 0xB0,
+               0xE1, 0x86, 0xB1, 0xE1, 0x86, 0xB2, 0xE1, 0x86,
+               0xB3, 0xE1, 0x86, 0xB4, 0xE1, 0x86, 0xB5, 0xE1,
+               0x84, 0x9A, 0xE1, 0x84, 0x86, 0xE1, 0x84, 0x87,
+               0xE1, 0x84, 0x88, 0xE1, 0x84, 0xA1, 0xE1, 0x84,
+               0x89, 0xE1, 0x84, 0x8A, 0xE1, 0x84, 0x8B, 0xE1,
+               0x84, 0x8C, 0xE1, 0x84, 0x8D, 0xE1, 0x84, 0x8E,
+               0xE1, 0x84, 0x8F, 0xE1, 0x84, 0x90, 0xE1, 0x84,
+               0x91, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0xE1,
+               0x85, 0xA2, 0xE1, 0x85, 0xA3, 0xE1, 0x85, 0xA4,
+               0xE1, 0x85, 0xA5, 0xE1, 0x85, 0xA6, 0xE1, 0x85,
+               0xA7, 0xE1, 0x85, 0xA8, 0xE1, 0x85, 0xA9, 0xE1,
+               0x85, 0xAA, 0xE1, 0x85, 0xAB, 0xE1, 0x85, 0xAC,
+               0xE1, 0x85, 0xAD, 0xE1, 0x85, 0xAE, 0xE1, 0x85,
+               0xAF, 0xE1, 0x85, 0xB0, 0xE1, 0x85, 0xB1, 0xE1,
+               0x85, 0xB2, 0xE1, 0x85, 0xB3, 0xE1, 0x85, 0xB4,
+               0xE1, 0x85, 0xB5, 0xE1, 0x85, 0xA0, 0xE1, 0x84,
+               0x94, 0xE1, 0x84, 0x95, 0xE1, 0x87, 0x87, 0xE1,
+               0x87, 0x88, 0xE1, 0x87, 0x8C, 0xE1, 0x87, 0x8E,
+               0xE1, 0x87, 0x93, 0xE1, 0x87, 0x97, 0xE1, 0x87,
+               0x99, 0xE1, 0x84, 0x9C, 0xE1, 0x87, 0x9D, 0xE1,
+               0x87, 0x9F, 0xE1, 0x84, 0x9D, 0xE1, 0x84, 0x9E,
+               0xE1, 0x84, 0xA0, 0xE1, 0x84, 0xA2, 0xE1, 0x84,
+               0xA3, 0xE1, 0x84, 0xA7, 0xE1, 0x84, 0xA9, 0xE1,
+               0x84, 0xAB, 0xE1, 0x84, 0xAC, 0xE1, 0x84, 0xAD,
+               0xE1, 0x84, 0xAE, 0xE1, 0x84, 0xAF, 0xE1, 0x84,
+               0xB2, 0xE1, 0x84, 0xB6, 0xE1, 0x85, 0x80, 0xE1,
+               0x85, 0x87, 0xE1, 0x85, 0x8C, 0xE1, 0x87, 0xB1,
+               0xE1, 0x87, 0xB2, 0xE1, 0x85, 0x97, 0xE1, 0x85,
+               0x98, 0xE1, 0x85, 0x99, 0xE1, 0x86, 0x84, 0xE1,
+               0x86, 0x85, 0xE1, 0x86, 0x88, 0xE1, 0x86, 0x91,
+               0xE1, 0x86, 0x92, 0xE1, 0x86, 0x94, 0xE1, 0x86,
+               0x9E, 0xE1, 0x86, 0xA1, 0xE4, 0xB8, 0x80, 0xE4,
+               0xBA, 0x8C, 0xE4, 0xB8, 0x89, 0xE5, 0x9B, 0x9B,
+               0xE4, 0xB8, 0x8A, 0xE4, 0xB8, 0xAD, 0xE4, 0xB8,
+               0x8B, 0xE7, 0x94, 0xB2, 0xE4, 0xB9, 0x99, 0xE4,
+               0xB8, 0x99, 0xE4, 0xB8, 0x81, 0xE5, 0xA4, 0xA9,
+               0xE5, 0x9C, 0xB0, 0xE4, 0xBA, 0xBA, 0x28, 0xE1,
+               0x84, 0x80, 0x29, 0x28, 0xE1, 0x84, 0x82, 0x29,
+               0x28, 0xE1, 0x84, 0x83, 0x29, 0x28, 0xE1, 0x84,
+               0x85, 0x29, 0x28, 0xE1, 0x84, 0x86, 0x29, 0x28,
+               0xE1, 0x84, 0x87, 0x29, 0x28, 0xE1, 0x84, 0x89,
+               0x29, 0x28, 0xE1, 0x84, 0x8B, 0x29, 0x28, 0xE1,
+               0x84, 0x8C, 0x29, 0x28, 0xE1, 0x84, 0x8E, 0x29,
+               0x28, 0xE1, 0x84, 0x8F, 0x29, 0x28, 0xE1, 0x84,
+               0x90, 0x29, 0x28, 0xE1, 0x84, 0x91, 0x29, 0x28,
+               0xE1, 0x84, 0x92, 0x29, 0x28, 0xE1, 0x84, 0x80,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x82,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x83,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x85,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x86,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x87,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x89,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x8B,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x8C,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x8E,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x8F,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x90,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x91,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x92,
+               0xE1, 0x85, 0xA1, 0x29, 0x28, 0xE1, 0x84, 0x8C,
+               0xE1, 0x85, 0xAE, 0x29, 0x28, 0xE1, 0x84, 0x8B,
+               0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, 0x85,
+               0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x28, 0xE1, 0x84,
+               0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92, 0xE1,
+               0x85, 0xAE, 0x29, 0x28, 0xE4, 0xB8, 0x80, 0x29,
+               0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x28, 0xE4, 0xB8,
+               0x89, 0x29, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x28,
+               0xE4, 0xBA, 0x94, 0x29, 0x28, 0xE5, 0x85, 0xAD,
+               0x29, 0x28, 0xE4, 0xB8, 0x83, 0x29, 0x28, 0xE5,
+               0x85, 0xAB, 0x29, 0x28, 0xE4, 0xB9, 0x9D, 0x29,
+               0x28, 0xE5, 0x8D, 0x81, 0x29, 0x28, 0xE6, 0x9C,
+               0x88, 0x29, 0x28, 0xE7, 0x81, 0xAB, 0x29, 0x28,
+               0xE6, 0xB0, 0xB4, 0x29, 0x28, 0xE6, 0x9C, 0xA8,
+               0x29, 0x28, 0xE9, 0x87, 0x91, 0x29, 0x28, 0xE5,
+               0x9C, 0x9F, 0x29, 0x28, 0xE6, 0x97, 0xA5, 0x29,
+               0x28, 0xE6, 0xA0, 0xAA, 0x29, 0x28, 0xE6, 0x9C,
+               0x89, 0x29, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x28,
+               0xE5, 0x90, 0x8D, 0x29, 0x28, 0xE7, 0x89, 0xB9,
+               0x29, 0x28, 0xE8, 0xB2, 0xA1, 0x29, 0x28, 0xE7,
+               0xA5, 0x9D, 0x29, 0x28, 0xE5, 0x8A, 0xB4, 0x29,
+               0x28, 0xE4, 0xBB, 0xA3, 0x29, 0x28, 0xE5, 0x91,
+               0xBC, 0x29, 0x28, 0xE5, 0xAD, 0xA6, 0x29, 0x28,
+               0xE7, 0x9B, 0xA3, 0x29, 0x28, 0xE4, 0xBC, 0x81,
+               0x29, 0x28, 0xE8, 0xB3, 0x87, 0x29, 0x28, 0xE5,
+               0x8D, 0x94, 0x29, 0x28, 0xE7, 0xA5, 0xAD, 0x29,
+               0x28, 0xE4, 0xBC, 0x91, 0x29, 0x28, 0xE8, 0x87,
+               0xAA, 0x29, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x50,
+               0x54, 0x45, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33,
+               0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37,
+               0x32, 0x38, 0x32, 0x39, 0x33, 0x30, 0x33, 0x31,
+               0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35,
+               0xE1, 0x84, 0x80, 0xE1, 0x84, 0x82, 0xE1, 0x84,
+               0x83, 0xE1, 0x84, 0x85, 0xE1, 0x84, 0x86, 0xE1,
+               0x84, 0x87, 0xE1, 0x84, 0x89, 0xE1, 0x84, 0x8B,
+               0xE1, 0x84, 0x8C, 0xE1, 0x84, 0x8E, 0xE1, 0x84,
+               0x8F, 0xE1, 0x84, 0x90, 0xE1, 0x84, 0x91, 0xE1,
+               0x84, 0x92, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1,
+               0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0xE1, 0x84,
+               0x83, 0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x85, 0xE1,
+               0x85, 0xA1, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1,
+               0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0xE1, 0x84,
+               0x89, 0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x8B, 0xE1,
+               0x85, 0xA1, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1,
+               0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0xE1, 0x84,
+               0x8F, 0xE1, 0x85, 0xA1, 0xE1, 0x84, 0x90, 0xE1,
+               0x85, 0xA1, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1,
+               0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0xE1, 0x84,
+               0x8E, 0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1,
+               0x84, 0x80, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C,
+               0xE1, 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85,
+               0xB4, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0xE4,
+               0xB8, 0x80, 0xE4, 0xBA, 0x8C, 0xE4, 0xB8, 0x89,
+               0xE5, 0x9B, 0x9B, 0xE4, 0xBA, 0x94, 0xE5, 0x85,
+               0xAD, 0xE4, 0xB8, 0x83, 0xE5, 0x85, 0xAB, 0xE4,
+               0xB9, 0x9D, 0xE5, 0x8D, 0x81, 0xE6, 0x9C, 0x88,
+               0xE7, 0x81, 0xAB, 0xE6, 0xB0, 0xB4, 0xE6, 0x9C,
+               0xA8, 0xE9, 0x87, 0x91, 0xE5, 0x9C, 0x9F, 0xE6,
+               0x97, 0xA5, 0xE6, 0xA0, 0xAA, 0xE6, 0x9C, 0x89,
+               0xE7, 0xA4, 0xBE, 0xE5, 0x90, 0x8D, 0xE7, 0x89,
+               0xB9, 0xE8, 0xB2, 0xA1, 0xE7, 0xA5, 0x9D, 0xE5,
+               0x8A, 0xB4, 0xE7, 0xA7, 0x98, 0xE7, 0x94, 0xB7,
+               0xE5, 0xA5, 0xB3, 0xE9, 0x81, 0xA9, 0xE5, 0x84,
+               0xAA, 0xE5, 0x8D, 0xB0, 0xE6, 0xB3, 0xA8, 0xE9,
+               0xA0, 0x85, 0xE4, 0xBC, 0x91, 0xE5, 0x86, 0x99,
+               0xE6, 0xAD, 0xA3, 0xE4, 0xB8, 0x8A, 0xE4, 0xB8,
+               0xAD, 0xE4, 0xB8, 0x8B, 0xE5, 0xB7, 0xA6, 0xE5,
+               0x8F, 0xB3, 0xE5, 0x8C, 0xBB, 0xE5, 0xAE, 0x97,
+               0xE5, 0xAD, 0xA6, 0xE7, 0x9B, 0xA3, 0xE4, 0xBC,
+               0x81, 0xE8, 0xB3, 0x87, 0xE5, 0x8D, 0x94, 0xE5,
+               0xA4, 0x9C, 0x33, 0x36, 0x33, 0x37, 0x33, 0x38,
+               0x33, 0x39, 0x34, 0x30, 0x34, 0x31, 0x34, 0x32,
+               0x34, 0x33, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36,
+               0x34, 0x37, 0x34, 0x38, 0x34, 0x39, 0x35, 0x30,
+               0x31, 0xE6, 0x9C, 0x88, 0x32, 0xE6, 0x9C, 0x88,
+               0x33, 0xE6, 0x9C, 0x88, 0x34, 0xE6, 0x9C, 0x88,
+               0x35, 0xE6, 0x9C, 0x88, 0x36, 0xE6, 0x9C, 0x88,
+               0x37, 0xE6, 0x9C, 0x88, 0x38, 0xE6, 0x9C, 0x88,
+               0x39, 0xE6, 0x9C, 0x88, 0x31, 0x30, 0xE6, 0x9C,
+               0x88, 0x31, 0x31, 0xE6, 0x9C, 0x88, 0x31, 0x32,
+               0xE6, 0x9C, 0x88, 0x48, 0x67, 0x65, 0x72, 0x67,
+               0x65, 0x56, 0x4C, 0x54, 0x44, 0xE3, 0x82, 0xA2,
+               0xE3, 0x82, 0xA4, 0xE3, 0x82, 0xA6, 0xE3, 0x82,
+               0xA8, 0xE3, 0x82, 0xAA, 0xE3, 0x82, 0xAB, 0xE3,
+               0x82, 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xB1,
+               0xE3, 0x82, 0xB3, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
+               0xB7, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0xBB, 0xE3,
+               0x82, 0xBD, 0xE3, 0x82, 0xBF, 0xE3, 0x83, 0x81,
+               0xE3, 0x83, 0x84, 0xE3, 0x83, 0x86, 0xE3, 0x83,
+               0x88, 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8B, 0xE3,
+               0x83, 0x8C, 0xE3, 0x83, 0x8D, 0xE3, 0x83, 0x8E,
+               0xE3, 0x83, 0x8F, 0xE3, 0x83, 0x92, 0xE3, 0x83,
+               0x95, 0xE3, 0x83, 0x98, 0xE3, 0x83, 0x9B, 0xE3,
+               0x83, 0x9E, 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xA0,
+               0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xA2, 0xE3, 0x83,
+               0xA4, 0xE3, 0x83, 0xA6, 0xE3, 0x83, 0xA8, 0xE3,
+               0x83, 0xA9, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xAB,
+               0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xAD, 0xE3, 0x83,
+               0xAF, 0xE3, 0x83, 0xB0, 0xE3, 0x83, 0xB1, 0xE3,
+               0x83, 0xB2, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0x8F,
+               0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+               0x88, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3,
+               0x83, 0x95, 0xE3, 0x82, 0xA1, 0xE3, 0x82, 0xA2,
+               0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+               0x9A, 0xE3, 0x82, 0xA2, 0xE3, 0x82, 0xA2, 0xE3,
+               0x83, 0xBC, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xA4,
+               0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+               0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xA4, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0xA6,
+               0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+               0xA8, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0xAF, 0xE3,
+               0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99,
+               0xE3, 0x82, 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82,
+               0xAB, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAA, 0xE3,
+               0x83, 0xB3, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0xAA,
+               0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0xE3, 0x82,
+               0xAB, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAA, 0xE3,
+               0x82, 0xAB, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83,
+               0xE3, 0x83, 0x88, 0xE3, 0x82, 0xAB, 0xE3, 0x83,
+               0xAD, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0xE3,
+               0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAD,
+               0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
+               0x99, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x9E, 0xE3,
+               0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xAB,
+               0xE3, 0x82, 0x99, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+               0x99, 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xBC, 0xE3,
+               0x82, 0xAD, 0xE3, 0x83, 0xA5, 0xE3, 0x83, 0xAA,
+               0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+               0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xBF, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAD,
+               0xE3, 0x83, 0xAD, 0xE3, 0x82, 0xAD, 0xE3, 0x83,
+               0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3,
+               0x83, 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x82, 0xAD,
+               0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83,
+               0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0xE3,
+               0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF,
+               0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+               0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, 0xE3,
+               0x83, 0xA0, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+               0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83,
+               0x88, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xAF, 0xE3,
+               0x83, 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99,
+               0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0xE3, 0x82,
+               0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3,
+               0x83, 0x8D, 0xE3, 0x82, 0xB1, 0xE3, 0x83, 0xBC,
+               0xE3, 0x82, 0xB9, 0xE3, 0x82, 0xB3, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x8A, 0xE3, 0x82, 0xB3, 0xE3,
+               0x83, 0xBC, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A,
+               0xE3, 0x82, 0xB5, 0xE3, 0x82, 0xA4, 0xE3, 0x82,
+               0xAF, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xB5, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0xA0, 0xE3, 0x82, 0xB7, 0xE3, 0x83,
+               0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xAF, 0xE3,
+               0x82, 0x99, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3,
+               0xE3, 0x83, 0x81, 0xE3, 0x82, 0xBB, 0xE3, 0x83,
+               0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xBF, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9,
+               0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0xE3, 0x82,
+               0xB7, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3,
+               0x83, 0xAB, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3,
+               0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0xE3, 0x83,
+               0x8E, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3,
+               0x83, 0x8F, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x84,
+               0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
+               0xBC, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3,
+               0x83, 0x88, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A,
+               0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x84, 0xE3, 0x83,
+               0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3,
+               0x83, 0xAC, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92,
+               0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA2, 0xE3, 0x82,
+               0xB9, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0xE3,
+               0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xAF,
+               0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92, 0xE3, 0x82,
+               0x9A, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x92, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95,
+               0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
+               0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3,
+               0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0x88, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+               0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, 0xE3,
+               0x82, 0xA7, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95,
+               0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0x98, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3,
+               0x83, 0xBC, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x98,
+               0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xBD, 0xE3, 0x83,
+               0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0x8B, 0xE3,
+               0x83, 0x92, 0xE3, 0x83, 0x98, 0xE3, 0x83, 0xAB,
+               0xE3, 0x83, 0x84, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+               0x9A, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9, 0xE3,
+               0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+               0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0x98, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3,
+               0x82, 0xBF, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A,
+               0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0x88, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0xE3,
+               0x83, 0xAB, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0x9B,
+               0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+               0x9A, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x9B, 0xE3, 0x83,
+               0xBC, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x9E, 0xE3,
+               0x82, 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD,
+               0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x83, 0xE3,
+               0x83, 0x8F, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0xAB,
+               0xE3, 0x82, 0xAF, 0xE3, 0x83, 0x9E, 0xE3, 0x83,
+               0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xA7, 0xE3,
+               0x83, 0xB3, 0xE3, 0x83, 0x9F, 0xE3, 0x82, 0xAF,
+               0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x9F, 0xE3,
+               0x83, 0xAA, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99,
+               0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0xE3, 0x83,
+               0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3,
+               0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99,
+               0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+               0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3,
+               0x83, 0xAB, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC,
+               0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+               0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0xE3,
+               0x83, 0xA6, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xB3,
+               0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+               0x88, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0xAA, 0xE3,
+               0x83, 0xA9, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92,
+               0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0xAC,
+               0xE3, 0x83, 0xA0, 0xE3, 0x83, 0xAC, 0xE3, 0x83,
+               0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3,
+               0x82, 0x99, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0xAF,
+               0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x30, 0xE7,
+               0x82, 0xB9, 0x31, 0xE7, 0x82, 0xB9, 0x32, 0xE7,
+               0x82, 0xB9, 0x33, 0xE7, 0x82, 0xB9, 0x34, 0xE7,
+               0x82, 0xB9, 0x35, 0xE7, 0x82, 0xB9, 0x36, 0xE7,
+               0x82, 0xB9, 0x37, 0xE7, 0x82, 0xB9, 0x38, 0xE7,
+               0x82, 0xB9, 0x39, 0xE7, 0x82, 0xB9, 0x31, 0x30,
+               0xE7, 0x82, 0xB9, 0x31, 0x31, 0xE7, 0x82, 0xB9,
+               0x31, 0x32, 0xE7, 0x82, 0xB9, 0x31, 0x33, 0xE7,
+               0x82, 0xB9, 0x31, 0x34, 0xE7, 0x82, 0xB9, 0x31,
+               0x35, 0xE7, 0x82, 0xB9, 0x31, 0x36, 0xE7, 0x82,
+               0xB9, 0x31, 0x37, 0xE7, 0x82, 0xB9, 0x31, 0x38,
+               0xE7, 0x82, 0xB9, 0x31, 0x39, 0xE7, 0x82, 0xB9,
+               0x32, 0x30, 0xE7, 0x82, 0xB9, 0x32, 0x31, 0xE7,
+               0x82, 0xB9, 0x32, 0x32, 0xE7, 0x82, 0xB9, 0x32,
+               0x33, 0xE7, 0x82, 0xB9, 0x32, 0x34, 0xE7, 0x82,
+               0xB9, 0x68, 0x50, 0x61, 0x64, 0x61, 0x41, 0x55,
+               0x62, 0x61, 0x72, 0x6F, 0x56, 0x70, 0x63, 0x64,
+               0x6D, 0x64, 0x6D, 0x32, 0x64, 0x6D, 0x33, 0x49,
+               0x55, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, 0xE6,
+               0x98, 0xAD, 0xE5, 0x92, 0x8C, 0xE5, 0xA4, 0xA7,
+               0xE6, 0xAD, 0xA3, 0xE6, 0x98, 0x8E, 0xE6, 0xB2,
+               0xBB, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4,
+               0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x70, 0x41, 0x6E,
+               0x41, 0xCE, 0xBC, 0x41, 0x6D, 0x41, 0x6B, 0x41,
+               0x4B, 0x42, 0x4D, 0x42, 0x47, 0x42, 0x63, 0x61,
+               0x6C, 0x6B, 0x63, 0x61, 0x6C, 0x70, 0x46, 0x6E,
+               0x46, 0xCE, 0xBC, 0x46, 0xCE, 0xBC, 0x67, 0x6D,
+               0x67, 0x6B, 0x67, 0x48, 0x7A, 0x6B, 0x48, 0x7A,
+               0x4D, 0x48, 0x7A, 0x47, 0x48, 0x7A, 0x54, 0x48,
+               0x7A, 0xCE, 0xBC, 0x6C, 0x6D, 0x6C, 0x64, 0x6C,
+               0x6B, 0x6C, 0x66, 0x6D, 0x6E, 0x6D, 0xCE, 0xBC,
+               0x6D, 0x6D, 0x6D, 0x63, 0x6D, 0x6B, 0x6D, 0x6D,
+               0x6D, 0x32, 0x63, 0x6D, 0x32, 0x6D, 0x32, 0x6B,
+               0x6D, 0x32, 0x6D, 0x6D, 0x33, 0x63, 0x6D, 0x33,
+               0x6D, 0x33, 0x6B, 0x6D, 0x33, 0x6D, 0xE2, 0x88,
+               0x95, 0x73, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x32,
+               0x50, 0x61, 0x6B, 0x50, 0x61, 0x4D, 0x50, 0x61,
+               0x47, 0x50, 0x61, 0x72, 0x61, 0x64, 0x72, 0x61,
+               0x64, 0xE2, 0x88, 0x95, 0x73, 0x72, 0x61, 0x64,
+               0xE2, 0x88, 0x95, 0x73, 0x32, 0x70, 0x73, 0x6E,
+               0x73, 0xCE, 0xBC, 0x73, 0x6D, 0x73, 0x70, 0x56,
+               0x6E, 0x56, 0xCE, 0xBC, 0x56, 0x6D, 0x56, 0x6B,
+               0x56, 0x4D, 0x56, 0x70, 0x57, 0x6E, 0x57, 0xCE,
+               0xBC, 0x57, 0x6D, 0x57, 0x6B, 0x57, 0x4D, 0x57,
+               0x6B, 0xCE, 0xA9, 0x4D, 0xCE, 0xA9, 0x61, 0x2E,
+               0x6D, 0x2E, 0x42, 0x71, 0x63, 0x63, 0x63, 0x64,
+               0x43, 0xE2, 0x88, 0x95, 0x6B, 0x67, 0x43, 0x6F,
+               0x2E, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61, 0x48,
+               0x50, 0x69, 0x6E, 0x4B, 0x4B, 0x4B, 0x4D, 0x6B,
+               0x74, 0x6C, 0x6D, 0x6C, 0x6E, 0x6C, 0x6F, 0x67,
+               0x6C, 0x78, 0x6D, 0x62, 0x6D, 0x69, 0x6C, 0x6D,
+               0x6F, 0x6C, 0x50, 0x48, 0x70, 0x2E, 0x6D, 0x2E,
+               0x50, 0x50, 0x4D, 0x50, 0x52, 0x73, 0x72, 0x53,
+               0x76, 0x57, 0x62, 0x56, 0xE2, 0x88, 0x95, 0x6D,
+               0x41, 0xE2, 0x88, 0x95, 0x6D, 0x31, 0xE6, 0x97,
+               0xA5, 0x32, 0xE6, 0x97, 0xA5, 0x33, 0xE6, 0x97,
+               0xA5, 0x34, 0xE6, 0x97, 0xA5, 0x35, 0xE6, 0x97,
+               0xA5, 0x36, 0xE6, 0x97, 0xA5, 0x37, 0xE6, 0x97,
+               0xA5, 0x38, 0xE6, 0x97, 0xA5, 0x39, 0xE6, 0x97,
+               0xA5, 0x31, 0x30, 0xE6, 0x97, 0xA5, 0x31, 0x31,
+               0xE6, 0x97, 0xA5, 0x31, 0x32, 0xE6, 0x97, 0xA5,
+               0x31, 0x33, 0xE6, 0x97, 0xA5, 0x31, 0x34, 0xE6,
+               0x97, 0xA5, 0x31, 0x35, 0xE6, 0x97, 0xA5, 0x31,
+               0x36, 0xE6, 0x97, 0xA5, 0x31, 0x37, 0xE6, 0x97,
+               0xA5, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x31, 0x39,
+               0xE6, 0x97, 0xA5, 0x32, 0x30, 0xE6, 0x97, 0xA5,
+               0x32, 0x31, 0xE6, 0x97, 0xA5, 0x32, 0x32, 0xE6,
+               0x97, 0xA5, 0x32, 0x33, 0xE6, 0x97, 0xA5, 0x32,
+               0x34, 0xE6, 0x97, 0xA5, 0x32, 0x35, 0xE6, 0x97,
+               0xA5, 0x32, 0x36, 0xE6, 0x97, 0xA5, 0x32, 0x37,
+               0xE6, 0x97, 0xA5, 0x32, 0x38, 0xE6, 0x97, 0xA5,
+               0x32, 0x39, 0xE6, 0x97, 0xA5, 0x33, 0x30, 0xE6,
+               0x97, 0xA5, 0x33, 0x31, 0xE6, 0x97, 0xA5, 0x67,
+               0x61, 0x6C, 0xF6, 0xE8, 0xB1, 0x88, 0xF6, 0xE6,
+               0x9B, 0xB4, 0xF6, 0xE8, 0xBB, 0x8A, 0xF6, 0xE8,
+               0xB3, 0x88, 0xF6, 0xE6, 0xBB, 0x91, 0xF6, 0xE4,
+               0xB8, 0xB2, 0xF6, 0xE5, 0x8F, 0xA5, 0xF6, 0xE9,
+               0xBE, 0x9C, 0xF6, 0xE9, 0xBE, 0x9C, 0xF6, 0xE5,
+               0xA5, 0x91, 0xF6, 0xE9, 0x87, 0x91, 0xF6, 0xE5,
+               0x96, 0x87, 0xF6, 0xE5, 0xA5, 0x88, 0xF6, 0xE6,
+               0x87, 0xB6, 0xF6, 0xE7, 0x99, 0xA9, 0xF6, 0xE7,
+               0xBE, 0x85, 0xF6, 0xE8, 0x98, 0xBF, 0xF6, 0xE8,
+               0x9E, 0xBA, 0xF6, 0xE8, 0xA3, 0xB8, 0xF6, 0xE9,
+               0x82, 0x8F, 0xF6, 0xE6, 0xA8, 0x82, 0xF6, 0xE6,
+               0xB4, 0x9B, 0xF6, 0xE7, 0x83, 0x99, 0xF6, 0xE7,
+               0x8F, 0x9E, 0xF6, 0xE8, 0x90, 0xBD, 0xF6, 0xE9,
+               0x85, 0xAA, 0xF6, 0xE9, 0xA7, 0xB1, 0xF6, 0xE4,
+               0xBA, 0x82, 0xF6, 0xE5, 0x8D, 0xB5, 0xF6, 0xE6,
+               0xAC, 0x84, 0xF6, 0xE7, 0x88, 0x9B, 0xF6, 0xE8,
+               0x98, 0xAD, 0xF6, 0xE9, 0xB8, 0x9E, 0xF6, 0xE5,
+               0xB5, 0x90, 0xF6, 0xE6, 0xBF, 0xAB, 0xF6, 0xE8,
+               0x97, 0x8D, 0xF6, 0xE8, 0xA5, 0xA4, 0xF6, 0xE6,
+               0x8B, 0x89, 0xF6, 0xE8, 0x87, 0x98, 0xF6, 0xE8,
+               0xA0, 0x9F, 0xF6, 0xE5, 0xBB, 0x8A, 0xF6, 0xE6,
+               0x9C, 0x97, 0xF6, 0xE6, 0xB5, 0xAA, 0xF6, 0xE7,
+               0x8B, 0xBC, 0xF6, 0xE9, 0x83, 0x8E, 0xF6, 0xE4,
+               0xBE, 0x86, 0xF6, 0xE5, 0x86, 0xB7, 0xF6, 0xE5,
+               0x8B, 0x9E, 0xF6, 0xE6, 0x93, 0x84, 0xF6, 0xE6,
+               0xAB, 0x93, 0xF6, 0xE7, 0x88, 0x90, 0xF6, 0xE7,
+               0x9B, 0xA7, 0xF6, 0xE8, 0x80, 0x81, 0xF6, 0xE8,
+               0x98, 0x86, 0xF6, 0xE8, 0x99, 0x9C, 0xF6, 0xE8,
+               0xB7, 0xAF, 0xF6, 0xE9, 0x9C, 0xB2, 0xF6, 0xE9,
+               0xAD, 0xAF, 0xF6, 0xE9, 0xB7, 0xBA, 0xF6, 0xE7,
+               0xA2, 0x8C, 0xF6, 0xE7, 0xA5, 0xBF, 0xF6, 0xE7,
+               0xB6, 0xA0, 0xF6, 0xE8, 0x8F, 0x89, 0xF6, 0xE9,
+               0x8C, 0x84, 0xF6, 0xE9, 0xB9, 0xBF, 0xF6, 0xE8,
+               0xAB, 0x96, 0xF6, 0xE5, 0xA3, 0x9F, 0xF6, 0xE5,
+               0xBC, 0x84, 0xF6, 0xE7, 0xB1, 0xA0, 0xF6, 0xE8,
+               0x81, 0xBE, 0xF6, 0xE7, 0x89, 0xA2, 0xF6, 0xE7,
+               0xA3, 0x8A, 0xF6, 0xE8, 0xB3, 0x82, 0xF6, 0xE9,
+               0x9B, 0xB7, 0xF6, 0xE5, 0xA3, 0x98, 0xF6, 0xE5,
+               0xB1, 0xA2, 0xF6, 0xE6, 0xA8, 0x93, 0xF6, 0xE6,
+               0xB7, 0x9A, 0xF6, 0xE6, 0xBC, 0x8F, 0xF6, 0xE7,
+               0xB4, 0xAF, 0xF6, 0xE7, 0xB8, 0xB7, 0xF6, 0xE9,
+               0x99, 0x8B, 0xF6, 0xE5, 0x8B, 0x92, 0xF6, 0xE8,
+               0x82, 0x8B, 0xF6, 0xE5, 0x87, 0x9C, 0xF6, 0xE5,
+               0x87, 0x8C, 0xF6, 0xE7, 0xA8, 0x9C, 0xF6, 0xE7,
+               0xB6, 0xBE, 0xF6, 0xE8, 0x8F, 0xB1, 0xF6, 0xE9,
+               0x99, 0xB5, 0xF6, 0xE8, 0xAE, 0x80, 0xF6, 0xE6,
+               0x8B, 0x8F, 0xF6, 0xE6, 0xA8, 0x82, 0xF6, 0xE8,
+               0xAB, 0xBE, 0xF6, 0xE4, 0xB8, 0xB9, 0xF6, 0xE5,
+               0xAF, 0xA7, 0xF6, 0xE6, 0x80, 0x92, 0xF6, 0xE7,
+               0x8E, 0x87, 0xF6, 0xE7, 0x95, 0xB0, 0xF6, 0xE5,
+               0x8C, 0x97, 0xF6, 0xE7, 0xA3, 0xBB, 0xF6, 0xE4,
+               0xBE, 0xBF, 0xF6, 0xE5, 0xBE, 0xA9, 0xF6, 0xE4,
+               0xB8, 0x8D, 0xF6, 0xE6, 0xB3, 0x8C, 0xF6, 0xE6,
+               0x95, 0xB8, 0xF6, 0xE7, 0xB4, 0xA2, 0xF6, 0xE5,
+               0x8F, 0x83, 0xF6, 0xE5, 0xA1, 0x9E, 0xF6, 0xE7,
+               0x9C, 0x81, 0xF6, 0xE8, 0x91, 0x89, 0xF6, 0xE8,
+               0xAA, 0xAA, 0xF6, 0xE6, 0xAE, 0xBA, 0xF6, 0xE8,
+               0xBE, 0xB0, 0xF6, 0xE6, 0xB2, 0x88, 0xF6, 0xE6,
+               0x8B, 0xBE, 0xF6, 0xE8, 0x8B, 0xA5, 0xF6, 0xE6,
+               0x8E, 0xA0, 0xF6, 0xE7, 0x95, 0xA5, 0xF6, 0xE4,
+               0xBA, 0xAE, 0xF6, 0xE5, 0x85, 0xA9, 0xF6, 0xE5,
+               0x87, 0x89, 0xF6, 0xE6, 0xA2, 0x81, 0xF6, 0xE7,
+               0xB3, 0xA7, 0xF6, 0xE8, 0x89, 0xAF, 0xF6, 0xE8,
+               0xAB, 0x92, 0xF6, 0xE9, 0x87, 0x8F, 0xF6, 0xE5,
+               0x8B, 0xB5, 0xF6, 0xE5, 0x91, 0x82, 0xF6, 0xE5,
+               0xA5, 0xB3, 0xF6, 0xE5, 0xBB, 0xAC, 0xF6, 0xE6,
+               0x97, 0x85, 0xF6, 0xE6, 0xBF, 0xBE, 0xF6, 0xE7,
+               0xA4, 0xAA, 0xF6, 0xE9, 0x96, 0xAD, 0xF6, 0xE9,
+               0xA9, 0xAA, 0xF6, 0xE9, 0xBA, 0x97, 0xF6, 0xE9,
+               0xBB, 0x8E, 0xF6, 0xE5, 0x8A, 0x9B, 0xF6, 0xE6,
+               0x9B, 0x86, 0xF6, 0xE6, 0xAD, 0xB7, 0xF6, 0xE8,
+               0xBD, 0xA2, 0xF6, 0xE5, 0xB9, 0xB4, 0xF6, 0xE6,
+               0x86, 0x90, 0xF6, 0xE6, 0x88, 0x80, 0xF6, 0xE6,
+               0x92, 0x9A, 0xF6, 0xE6, 0xBC, 0xA3, 0xF6, 0xE7,
+               0x85, 0x89, 0xF6, 0xE7, 0x92, 0x89, 0xF6, 0xE7,
+               0xA7, 0x8A, 0xF6, 0xE7, 0xB7, 0xB4, 0xF6, 0xE8,
+               0x81, 0xAF, 0xF6, 0xE8, 0xBC, 0xA6, 0xF6, 0xE8,
+               0x93, 0xAE, 0xF6, 0xE9, 0x80, 0xA3, 0xF6, 0xE9,
+               0x8D, 0x8A, 0xF6, 0xE5, 0x88, 0x97, 0xF6, 0xE5,
+               0x8A, 0xA3, 0xF6, 0xE5, 0x92, 0xBD, 0xF6, 0xE7,
+               0x83, 0x88, 0xF6, 0xE8, 0xA3, 0x82, 0xF6, 0xE8,
+               0xAA, 0xAA, 0xF6, 0xE5, 0xBB, 0x89, 0xF6, 0xE5,
+               0xBF, 0xB5, 0xF6, 0xE6, 0x8D, 0xBB, 0xF6, 0xE6,
+               0xAE, 0xAE, 0xF6, 0xE7, 0xB0, 0xBE, 0xF6, 0xE7,
+               0x8D, 0xB5, 0xF6, 0xE4, 0xBB, 0xA4, 0xF6, 0xE5,
+               0x9B, 0xB9, 0xF6, 0xE5, 0xAF, 0xA7, 0xF6, 0xE5,
+               0xB6, 0xBA, 0xF6, 0xE6, 0x80, 0x9C, 0xF6, 0xE7,
+               0x8E, 0xB2, 0xF6, 0xE7, 0x91, 0xA9, 0xF6, 0xE7,
+               0xBE, 0x9A, 0xF6, 0xE8, 0x81, 0x86, 0xF6, 0xE9,
+               0x88, 0xB4, 0xF6, 0xE9, 0x9B, 0xB6, 0xF6, 0xE9,
+               0x9D, 0x88, 0xF6, 0xE9, 0xA0, 0x98, 0xF6, 0xE4,
+               0xBE, 0x8B, 0xF6, 0xE7, 0xA6, 0xAE, 0xF6, 0xE9,
+               0x86, 0xB4, 0xF6, 0xE9, 0x9A, 0xB8, 0xF6, 0xE6,
+               0x83, 0xA1, 0xF6, 0xE4, 0xBA, 0x86, 0xF6, 0xE5,
+               0x83, 0x9A, 0xF6, 0xE5, 0xAF, 0xAE, 0xF6, 0xE5,
+               0xB0, 0xBF, 0xF6, 0xE6, 0x96, 0x99, 0xF6, 0xE6,
+               0xA8, 0x82, 0xF6, 0xE7, 0x87, 0x8E, 0xF6, 0xE7,
+               0x99, 0x82, 0xF6, 0xE8, 0x93, 0xBC, 0xF6, 0xE9,
+               0x81, 0xBC, 0xF6, 0xE9, 0xBE, 0x8D, 0xF6, 0xE6,
+               0x9A, 0x88, 0xF6, 0xE9, 0x98, 0xAE, 0xF6, 0xE5,
+               0x8A, 0x89, 0xF6, 0xE6, 0x9D, 0xBB, 0xF6, 0xE6,
+               0x9F, 0xB3, 0xF6, 0xE6, 0xB5, 0x81, 0xF6, 0xE6,
+               0xBA, 0x9C, 0xF6, 0xE7, 0x90, 0x89, 0xF6, 0xE7,
+               0x95, 0x99, 0xF6, 0xE7, 0xA1, 0xAB, 0xF6, 0xE7,
+               0xB4, 0x90, 0xF6, 0xE9, 0xA1, 0x9E, 0xF6, 0xE5,
+               0x85, 0xAD, 0xF6, 0xE6, 0x88, 0xAE, 0xF6, 0xE9,
+               0x99, 0xB8, 0xF6, 0xE5, 0x80, 0xAB, 0xF6, 0xE5,
+               0xB4, 0x99, 0xF6, 0xE6, 0xB7, 0xAA, 0xF6, 0xE8,
+               0xBC, 0xAA, 0xF6, 0xE5, 0xBE, 0x8B, 0xF6, 0xE6,
+               0x85, 0x84, 0xF6, 0xE6, 0xA0, 0x97, 0xF6, 0xE7,
+               0x8E, 0x87, 0xF6, 0xE9, 0x9A, 0x86, 0xF6, 0xE5,
+               0x88, 0xA9, 0xF6, 0xE5, 0x90, 0x8F, 0xF6, 0xE5,
+               0xB1, 0xA5, 0xF6, 0xE6, 0x98, 0x93, 0xF6, 0xE6,
+               0x9D, 0x8E, 0xF6, 0xE6, 0xA2, 0xA8, 0xF6, 0xE6,
+               0xB3, 0xA5, 0xF6, 0xE7, 0x90, 0x86, 0xF6, 0xE7,
+               0x97, 0xA2, 0xF6, 0xE7, 0xBD, 0xB9, 0xF6, 0xE8,
+               0xA3, 0x8F, 0xF6, 0xE8, 0xA3, 0xA1, 0xF6, 0xE9,
+               0x87, 0x8C, 0xF6, 0xE9, 0x9B, 0xA2, 0xF6, 0xE5,
+               0x8C, 0xBF, 0xF6, 0xE6, 0xBA, 0xBA, 0xF6, 0xE5,
+               0x90, 0x9D, 0xF6, 0xE7, 0x87, 0x90, 0xF6, 0xE7,
+               0x92, 0x98, 0xF6, 0xE8, 0x97, 0xBA, 0xF6, 0xE9,
+               0x9A, 0xA3, 0xF6, 0xE9, 0xB1, 0x97, 0xF6, 0xE9,
+               0xBA, 0x9F, 0xF6, 0xE6, 0x9E, 0x97, 0xF6, 0xE6,
+               0xB7, 0x8B, 0xF6, 0xE8, 0x87, 0xA8, 0xF6, 0xE7,
+               0xAB, 0x8B, 0xF6, 0xE7, 0xAC, 0xA0, 0xF6, 0xE7,
+               0xB2, 0x92, 0xF6, 0xE7, 0x8B, 0x80, 0xF6, 0xE7,
+               0x82, 0x99, 0xF6, 0xE8, 0xAD, 0x98, 0xF6, 0xE4,
+               0xBB, 0x80, 0xF6, 0xE8, 0x8C, 0xB6, 0xF6, 0xE5,
+               0x88, 0xBA, 0xF6, 0xE5, 0x88, 0x87, 0xF6, 0xE5,
+               0xBA, 0xA6, 0xF6, 0xE6, 0x8B, 0x93, 0xF6, 0xE7,
+               0xB3, 0x96, 0xF6, 0xE5, 0xAE, 0x85, 0xF6, 0xE6,
+               0xB4, 0x9E, 0xF6, 0xE6, 0x9A, 0xB4, 0xF6, 0xE8,
+               0xBC, 0xBB, 0xF6, 0xE8, 0xA1, 0x8C, 0xF6, 0xE9,
+               0x99, 0x8D, 0xF6, 0xE8, 0xA6, 0x8B, 0xF6, 0xE5,
+               0xBB, 0x93, 0xF6, 0xE5, 0x85, 0x80, 0xF6, 0xE5,
+               0x97, 0x80, 0xF6, 0xE5, 0xA1, 0x9A, 0xF6, 0xE6,
+               0x99, 0xB4, 0xF6, 0xE5, 0x87, 0x9E, 0xF6, 0xE7,
+               0x8C, 0xAA, 0xF6, 0xE7, 0x9B, 0x8A, 0xF6, 0xE7,
+               0xA4, 0xBC, 0xF6, 0xE7, 0xA5, 0x9E, 0xF6, 0xE7,
+               0xA5, 0xA5, 0xF6, 0xE7, 0xA6, 0x8F, 0xF6, 0xE9,
+               0x9D, 0x96, 0xF6, 0xE7, 0xB2, 0xBE, 0xF6, 0xE7,
+               0xBE, 0xBD, 0xF6, 0xE8, 0x98, 0x92, 0xF6, 0xE8,
+               0xAB, 0xB8, 0xF6, 0xE9, 0x80, 0xB8, 0xF6, 0xE9,
+               0x83, 0xBD, 0xF6, 0xE9, 0xA3, 0xAF, 0xF6, 0xE9,
+               0xA3, 0xBC, 0xF6, 0xE9, 0xA4, 0xA8, 0xF6, 0xE9,
+               0xB6, 0xB4, 0xF6, 0xE4, 0xBE, 0xAE, 0xF6, 0xE5,
+               0x83, 0xA7, 0xF6, 0xE5, 0x85, 0x8D, 0xF6, 0xE5,
+               0x8B, 0x89, 0xF6, 0xE5, 0x8B, 0xA4, 0xF6, 0xE5,
+               0x8D, 0x91, 0xF6, 0xE5, 0x96, 0x9D, 0xF6, 0xE5,
+               0x98, 0x86, 0xF6, 0xE5, 0x99, 0xA8, 0xF6, 0xE5,
+               0xA1, 0x80, 0xF6, 0xE5, 0xA2, 0xA8, 0xF6, 0xE5,
+               0xB1, 0xA4, 0xF6, 0xE5, 0xB1, 0xAE, 0xF6, 0xE6,
+               0x82, 0x94, 0xF6, 0xE6, 0x85, 0xA8, 0xF6, 0xE6,
+               0x86, 0x8E, 0xF6, 0xE6, 0x87, 0xB2, 0xF6, 0xE6,
+               0x95, 0x8F, 0xF6, 0xE6, 0x97, 0xA2, 0xF6, 0xE6,
+               0x9A, 0x91, 0xF6, 0xE6, 0xA2, 0x85, 0xF6, 0xE6,
+               0xB5, 0xB7, 0xF6, 0xE6, 0xB8, 0x9A, 0xF6, 0xE6,
+               0xBC, 0xA2, 0xF6, 0xE7, 0x85, 0xAE, 0xF6, 0xE7,
+               0x88, 0xAB, 0xF6, 0xE7, 0x90, 0xA2, 0xF6, 0xE7,
+               0xA2, 0x91, 0xF6, 0xE7, 0xA4, 0xBE, 0xF6, 0xE7,
+               0xA5, 0x89, 0xF6, 0xE7, 0xA5, 0x88, 0xF6, 0xE7,
+               0xA5, 0x90, 0xF6, 0xE7, 0xA5, 0x96, 0xF6, 0xE7,
+               0xA5, 0x9D, 0xF6, 0xE7, 0xA6, 0x8D, 0xF6, 0xE7,
+               0xA6, 0x8E, 0xF6, 0xE7, 0xA9, 0x80, 0xF6, 0xE7,
+               0xAA, 0x81, 0xF6, 0xE7, 0xAF, 0x80, 0xF6, 0xE7,
+               0xB7, 0xB4, 0xF6, 0xE7, 0xB8, 0x89, 0xF6, 0xE7,
+               0xB9, 0x81, 0xF6, 0xE7, 0xBD, 0xB2, 0xF6, 0xE8,
+               0x80, 0x85, 0xF6, 0xE8, 0x87, 0xAD, 0xF6, 0xE8,
+               0x89, 0xB9, 0xF6, 0xE8, 0x89, 0xB9, 0xF6, 0xE8,
+               0x91, 0x97, 0xF6, 0xE8, 0xA4, 0x90, 0xF6, 0xE8,
+               0xA6, 0x96, 0xF6, 0xE8, 0xAC, 0x81, 0xF6, 0xE8,
+               0xAC, 0xB9, 0xF6, 0xE8, 0xB3, 0x93, 0xF6, 0xE8,
+               0xB4, 0x88, 0xF6, 0xE8, 0xBE, 0xB6, 0xF6, 0xE9,
+               0x80, 0xB8, 0xF6, 0xE9, 0x9B, 0xA3, 0xF6, 0xE9,
+               0x9F, 0xBF, 0xF6, 0xE9, 0xA0, 0xBB, 0xF6, 0xE4,
+               0xB8, 0xA6, 0xF6, 0xE5, 0x86, 0xB5, 0xF6, 0xE5,
+               0x85, 0xA8, 0xF6, 0xE4, 0xBE, 0x80, 0xF6, 0xE5,
+               0x85, 0x85, 0xF6, 0xE5, 0x86, 0x80, 0xF6, 0xE5,
+               0x8B, 0x87, 0xF6, 0xE5, 0x8B, 0xBA, 0xF6, 0xE5,
+               0x96, 0x9D, 0xF6, 0xE5, 0x95, 0x95, 0xF6, 0xE5,
+               0x96, 0x99, 0xF6, 0xE5, 0x97, 0xA2, 0xF6, 0xE5,
+               0xA1, 0x9A, 0xF6, 0xE5, 0xA2, 0xB3, 0xF6, 0xE5,
+               0xA5, 0x84, 0xF6, 0xE5, 0xA5, 0x94, 0xF6, 0xE5,
+               0xA9, 0xA2, 0xF6, 0xE5, 0xAC, 0xA8, 0xF6, 0xE5,
+               0xBB, 0x92, 0xF6, 0xE5, 0xBB, 0x99, 0xF6, 0xE5,
+               0xBD, 0xA9, 0xF6, 0xE5, 0xBE, 0xAD, 0xF6, 0xE6,
+               0x83, 0x98, 0xF6, 0xE6, 0x85, 0x8E, 0xF6, 0xE6,
+               0x84, 0x88, 0xF6, 0xE6, 0x86, 0x8E, 0xF6, 0xE6,
+               0x85, 0xA0, 0xF6, 0xE6, 0x87, 0xB2, 0xF6, 0xE6,
+               0x88, 0xB4, 0xF6, 0xE6, 0x8F, 0x84, 0xF6, 0xE6,
+               0x90, 0x9C, 0xF6, 0xE6, 0x91, 0x92, 0xF6, 0xE6,
+               0x95, 0x96, 0xF6, 0xE6, 0x99, 0xB4, 0xF6, 0xE6,
+               0x9C, 0x97, 0xF6, 0xE6, 0x9C, 0x9B, 0xF6, 0xE6,
+               0x9D, 0x96, 0xF6, 0xE6, 0xAD, 0xB9, 0xF6, 0xE6,
+               0xAE, 0xBA, 0xF6, 0xE6, 0xB5, 0x81, 0xF6, 0xE6,
+               0xBB, 0x9B, 0xF6, 0xE6, 0xBB, 0x8B, 0xF6, 0xE6,
+               0xBC, 0xA2, 0xF6, 0xE7, 0x80, 0x9E, 0xF6, 0xE7,
+               0x85, 0xAE, 0xF6, 0xE7, 0x9E, 0xA7, 0xF6, 0xE7,
+               0x88, 0xB5, 0xF6, 0xE7, 0x8A, 0xAF, 0xF6, 0xE7,
+               0x8C, 0xAA, 0xF6, 0xE7, 0x91, 0xB1, 0xF6, 0xE7,
+               0x94, 0x86, 0xF6, 0xE7, 0x94, 0xBB, 0xF6, 0xE7,
+               0x98, 0x9D, 0xF6, 0xE7, 0x98, 0x9F, 0xF6, 0xE7,
+               0x9B, 0x8A, 0xF6, 0xE7, 0x9B, 0x9B, 0xF6, 0xE7,
+               0x9B, 0xB4, 0xF6, 0xE7, 0x9D, 0x8A, 0xF6, 0xE7,
+               0x9D, 0x80, 0xF6, 0xE7, 0xA3, 0x8C, 0xF6, 0xE7,
+               0xAA, 0xB1, 0xF6, 0xE7, 0xAF, 0x80, 0xF6, 0xE7,
+               0xB1, 0xBB, 0xF6, 0xE7, 0xB5, 0x9B, 0xF6, 0xE7,
+               0xB7, 0xB4, 0xF6, 0xE7, 0xBC, 0xBE, 0xF6, 0xE8,
+               0x80, 0x85, 0xF6, 0xE8, 0x8D, 0x92, 0xF6, 0xE8,
+               0x8F, 0xAF, 0xF6, 0xE8, 0x9D, 0xB9, 0xF6, 0xE8,
+               0xA5, 0x81, 0xF6, 0xE8, 0xA6, 0x86, 0xF6, 0xE8,
+               0xA6, 0x96, 0xF6, 0xE8, 0xAA, 0xBF, 0xF6, 0xE8,
+               0xAB, 0xB8, 0xF6, 0xE8, 0xAB, 0x8B, 0xF6, 0xE8,
+               0xAC, 0x81, 0xF6, 0xE8, 0xAB, 0xBE, 0xF6, 0xE8,
+               0xAB, 0xAD, 0xF6, 0xE8, 0xAC, 0xB9, 0xF6, 0xE8,
+               0xAE, 0x8A, 0xF6, 0xE8, 0xB4, 0x88, 0xF6, 0xE8,
+               0xBC, 0xB8, 0xF6, 0xE9, 0x81, 0xB2, 0xF6, 0xE9,
+               0x86, 0x99, 0xF6, 0xE9, 0x89, 0xB6, 0xF6, 0xE9,
+               0x99, 0xBC, 0xF6, 0xE9, 0x9B, 0xA3, 0xF6, 0xE9,
+               0x9D, 0x96, 0xF6, 0xE9, 0x9F, 0x9B, 0xF6, 0xE9,
+               0x9F, 0xBF, 0xF6, 0xE9, 0xA0, 0x8B, 0xF6, 0xE9,
+               0xA0, 0xBB, 0xF6, 0xE9, 0xAC, 0x92, 0xF6, 0xE9,
+               0xBE, 0x9C, 0xF6, 0xF0, 0xA2, 0xA1, 0x8A, 0xF6,
+               0xF0, 0xA2, 0xA1, 0x84, 0xF6, 0xF0, 0xA3, 0x8F,
+               0x95, 0xF6, 0xE3, 0xAE, 0x9D, 0xF6, 0xE4, 0x80,
+               0x98, 0xF6, 0xE4, 0x80, 0xB9, 0xF6, 0xF0, 0xA5,
+               0x89, 0x89, 0xF6, 0xF0, 0xA5, 0xB3, 0x90, 0xF6,
+               0xF0, 0xA7, 0xBB, 0x93, 0xF6, 0xE9, 0xBD, 0x83,
+               0xF6, 0xE9, 0xBE, 0x8E, 0x66, 0x66, 0x66, 0x69,
+               0x66, 0x6C, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6C,
+               0x73, 0x74, 0x73, 0x74, 0xD5, 0xB4, 0xD5, 0xB6,
+               0xD5, 0xB4, 0xD5, 0xA5, 0xD5, 0xB4, 0xD5, 0xAB,
+               0xD5, 0xBE, 0xD5, 0xB6, 0xD5, 0xB4, 0xD5, 0xAD,
+               0xF6, 0xD7, 0x99, 0xD6, 0xB4, 0xF6, 0xD7, 0xB2,
+               0xD6, 0xB7, 0xD7, 0xA2, 0xD7, 0x90, 0xD7, 0x93,
+               0xD7, 0x94, 0xD7, 0x9B, 0xD7, 0x9C, 0xD7, 0x9D,
+               0xD7, 0xA8, 0xD7, 0xAA, 0x2B, 0xF6, 0xD7, 0xA9,
+               0xD7, 0x81, 0xF6, 0xD7, 0xA9, 0xD7, 0x82, 0xF6,
+               0xD7, 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0xF6, 0xD7,
+               0xA9, 0xD6, 0xBC, 0xD7, 0x82, 0xF6, 0xD7, 0x90,
+               0xD6, 0xB7, 0xF6, 0xD7, 0x90, 0xD6, 0xB8, 0xF6,
+               0xD7, 0x90, 0xD6, 0xBC, 0xF6, 0xD7, 0x91, 0xD6,
+               0xBC, 0xF6, 0xD7, 0x92, 0xD6, 0xBC, 0xF6, 0xD7,
+               0x93, 0xD6, 0xBC, 0xF6, 0xD7, 0x94, 0xD6, 0xBC,
+               0xF6, 0xD7, 0x95, 0xD6, 0xBC, 0xF6, 0xD7, 0x96,
+               0xD6, 0xBC, 0xF6, 0xD7, 0x98, 0xD6, 0xBC, 0xF6,
+               0xD7, 0x99, 0xD6, 0xBC, 0xF6, 0xD7, 0x9A, 0xD6,
+               0xBC, 0xF6, 0xD7, 0x9B, 0xD6, 0xBC, 0xF6, 0xD7,
+               0x9C, 0xD6, 0xBC, 0xF6, 0xD7, 0x9E, 0xD6, 0xBC,
+               0xF6, 0xD7, 0xA0, 0xD6, 0xBC, 0xF6, 0xD7, 0xA1,
+               0xD6, 0xBC, 0xF6, 0xD7, 0xA3, 0xD6, 0xBC, 0xF6,
+               0xD7, 0xA4, 0xD6, 0xBC, 0xF6, 0xD7, 0xA6, 0xD6,
+               0xBC, 0xF6, 0xD7, 0xA7, 0xD6, 0xBC, 0xF6, 0xD7,
+               0xA8, 0xD6, 0xBC, 0xF6, 0xD7, 0xA9, 0xD6, 0xBC,
+               0xF6, 0xD7, 0xAA, 0xD6, 0xBC, 0xF6, 0xD7, 0x95,
+               0xD6, 0xB9, 0xF6, 0xD7, 0x91, 0xD6, 0xBF, 0xF6,
+               0xD7, 0x9B, 0xD6, 0xBF, 0xF6, 0xD7, 0xA4, 0xD6,
+               0xBF, 0xD7, 0x90, 0xD7, 0x9C, 0xD9, 0xB1, 0xD9,
+               0xB1, 0xD9, 0xBB, 0xD9, 0xBB, 0xD9, 0xBB, 0xD9,
+               0xBB, 0xD9, 0xBE, 0xD9, 0xBE, 0xD9, 0xBE, 0xD9,
+               0xBE, 0xDA, 0x80, 0xDA, 0x80, 0xDA, 0x80, 0xDA,
+               0x80, 0xD9, 0xBA, 0xD9, 0xBA, 0xD9, 0xBA, 0xD9,
+               0xBA, 0xD9, 0xBF, 0xD9, 0xBF, 0xD9, 0xBF, 0xD9,
+               0xBF, 0xD9, 0xB9, 0xD9, 0xB9, 0xD9, 0xB9, 0xD9,
+               0xB9, 0xDA, 0xA4, 0xDA, 0xA4, 0xDA, 0xA4, 0xDA,
+               0xA4, 0xDA, 0xA6, 0xDA, 0xA6, 0xDA, 0xA6, 0xDA,
+               0xA6, 0xDA, 0x84, 0xDA, 0x84, 0xDA, 0x84, 0xDA,
+               0x84, 0xDA, 0x83, 0xDA, 0x83, 0xDA, 0x83, 0xDA,
+               0x83, 0xDA, 0x86, 0xDA, 0x86, 0xDA, 0x86, 0xDA,
+               0x86, 0xDA, 0x87, 0xDA, 0x87, 0xDA, 0x87, 0xDA,
+               0x87, 0xDA, 0x8D, 0xDA, 0x8D, 0xDA, 0x8C, 0xDA,
+               0x8C, 0xDA, 0x8E, 0xDA, 0x8E, 0xDA, 0x88, 0xDA,
+               0x88, 0xDA, 0x98, 0xDA, 0x98, 0xDA, 0x91, 0xDA,
+               0x91, 0xDA, 0xA9, 0xDA, 0xA9, 0xDA, 0xA9, 0xDA,
+               0xA9, 0xDA, 0xAF, 0xDA, 0xAF, 0xDA, 0xAF, 0xDA,
+               0xAF, 0xDA, 0xB3, 0xDA, 0xB3, 0xDA, 0xB3, 0xDA,
+               0xB3, 0xDA, 0xB1, 0xDA, 0xB1, 0xDA, 0xB1, 0xDA,
+               0xB1, 0xDA, 0xBA, 0xDA, 0xBA, 0xDA, 0xBB, 0xDA,
+               0xBB, 0xDA, 0xBB, 0xDA, 0xBB, 0xDB, 0x95, 0xD9,
+               0x94, 0xDB, 0x95, 0xD9, 0x94, 0xDB, 0x81, 0xDB,
+               0x81, 0xDB, 0x81, 0xDB, 0x81, 0xDA, 0xBE, 0xDA,
+               0xBE, 0xDA, 0xBE, 0xDA, 0xBE, 0xDB, 0x92, 0xDB,
+               0x92, 0xDB, 0x92, 0xD9, 0x94, 0xDB, 0x92, 0xD9,
+               0x94, 0xDA, 0xAD, 0xDA, 0xAD, 0xDA, 0xAD, 0xDA,
+               0xAD, 0xDB, 0x87, 0xDB, 0x87, 0xDB, 0x86, 0xDB,
+               0x86, 0xDB, 0x88, 0xDB, 0x88, 0xDB, 0x87, 0xD9,
+               0xB4, 0xDB, 0x8B, 0xDB, 0x8B, 0xDB, 0x85, 0xDB,
+               0x85, 0xDB, 0x89, 0xDB, 0x89, 0xDB, 0x90, 0xDB,
+               0x90, 0xDB, 0x90, 0xDB, 0x90, 0xD9, 0x89, 0xD9,
+               0x89, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xA7, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD8, 0xA7, 0xD9, 0x8A, 0xD9,
+               0x94, 0xDB, 0x95, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
+               0x95, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x88, 0xD9, 0x8A, 0xD9,
+               0x94, 0xDB, 0x87, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
+               0x87, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0xD9,
+               0x8A, 0xD9, 0x94, 0xDB, 0x86, 0xD9, 0x8A, 0xD9,
+               0x94, 0xDB, 0x88, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
+               0x88, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x90, 0xD9,
+               0x8A, 0xD9, 0x94, 0xDB, 0x90, 0xD9, 0x8A, 0xD9,
+               0x94, 0xDB, 0x90, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+               0x89, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x89, 0xDB, 0x8C, 0xDB,
+               0x8C, 0xDB, 0x8C, 0xDB, 0x8C, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD8, 0xAC, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
+               0xAD, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x85, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x89, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD9, 0x8A, 0xD8, 0xA8, 0xD8, 0xAC, 0xD8,
+               0xA8, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xAE, 0xD8,
+               0xA8, 0xD9, 0x85, 0xD8, 0xA8, 0xD9, 0x89, 0xD8,
+               0xA8, 0xD9, 0x8A, 0xD8, 0xAA, 0xD8, 0xAC, 0xD8,
+               0xAA, 0xD8, 0xAD, 0xD8, 0xAA, 0xD8, 0xAE, 0xD8,
+               0xAA, 0xD9, 0x85, 0xD8, 0xAA, 0xD9, 0x89, 0xD8,
+               0xAA, 0xD9, 0x8A, 0xD8, 0xAB, 0xD8, 0xAC, 0xD8,
+               0xAB, 0xD9, 0x85, 0xD8, 0xAB, 0xD9, 0x89, 0xD8,
+               0xAB, 0xD9, 0x8A, 0xD8, 0xAC, 0xD8, 0xAD, 0xD8,
+               0xAC, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0xD8,
+               0xAD, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0xD8,
+               0xAE, 0xD8, 0xAD, 0xD8, 0xAE, 0xD9, 0x85, 0xD8,
+               0xB3, 0xD8, 0xAC, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8,
+               0xB3, 0xD8, 0xAE, 0xD8, 0xB3, 0xD9, 0x85, 0xD8,
+               0xB5, 0xD8, 0xAD, 0xD8, 0xB5, 0xD9, 0x85, 0xD8,
+               0xB6, 0xD8, 0xAC, 0xD8, 0xB6, 0xD8, 0xAD, 0xD8,
+               0xB6, 0xD8, 0xAE, 0xD8, 0xB6, 0xD9, 0x85, 0xD8,
+               0xB7, 0xD8, 0xAD, 0xD8, 0xB7, 0xD9, 0x85, 0xD8,
+               0xB8, 0xD9, 0x85, 0xD8, 0xB9, 0xD8, 0xAC, 0xD8,
+               0xB9, 0xD9, 0x85, 0xD8, 0xBA, 0xD8, 0xAC, 0xD8,
+               0xBA, 0xD9, 0x85, 0xD9, 0x81, 0xD8, 0xAC, 0xD9,
+               0x81, 0xD8, 0xAD, 0xD9, 0x81, 0xD8, 0xAE, 0xD9,
+               0x81, 0xD9, 0x85, 0xD9, 0x81, 0xD9, 0x89, 0xD9,
+               0x81, 0xD9, 0x8A, 0xD9, 0x82, 0xD8, 0xAD, 0xD9,
+               0x82, 0xD9, 0x85, 0xD9, 0x82, 0xD9, 0x89, 0xD9,
+               0x82, 0xD9, 0x8A, 0xD9, 0x83, 0xD8, 0xA7, 0xD9,
+               0x83, 0xD8, 0xAC, 0xD9, 0x83, 0xD8, 0xAD, 0xD9,
+               0x83, 0xD8, 0xAE, 0xD9, 0x83, 0xD9, 0x84, 0xD9,
+               0x83, 0xD9, 0x85, 0xD9, 0x83, 0xD9, 0x89, 0xD9,
+               0x83, 0xD9, 0x8A, 0xD9, 0x84, 0xD8, 0xAC, 0xD9,
+               0x84, 0xD8, 0xAD, 0xD9, 0x84, 0xD8, 0xAE, 0xD9,
+               0x84, 0xD9, 0x85, 0xD9, 0x84, 0xD9, 0x89, 0xD9,
+               0x84, 0xD9, 0x8A, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAE, 0xD9,
+               0x85, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x89, 0xD9,
+               0x85, 0xD9, 0x8A, 0xD9, 0x86, 0xD8, 0xAC, 0xD9,
+               0x86, 0xD8, 0xAD, 0xD9, 0x86, 0xD8, 0xAE, 0xD9,
+               0x86, 0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x89, 0xD9,
+               0x86, 0xD9, 0x8A, 0xD9, 0x87, 0xD8, 0xAC, 0xD9,
+               0x87, 0xD9, 0x85, 0xD9, 0x87, 0xD9, 0x89, 0xD9,
+               0x87, 0xD9, 0x8A, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xAD, 0xD9, 0x8A, 0xD8, 0xAE, 0xD9,
+               0x8A, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x89, 0xD9,
+               0x8A, 0xD9, 0x8A, 0xD8, 0xB0, 0xD9, 0xB0, 0xD8,
+               0xB1, 0xD9, 0xB0, 0xD9, 0x89, 0xD9, 0xB0, 0x20,
+               0xD9, 0x8C, 0xD9, 0x91, 0x20, 0xD9, 0x8D, 0xD9,
+               0x91, 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x20, 0xD9,
+               0x8F, 0xD9, 0x91, 0x20, 0xD9, 0x90, 0xD9, 0x91,
+               0x20, 0xD9, 0x91, 0xD9, 0xB0, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD8, 0xB1, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
+               0xB2, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x85, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x86, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD9, 0x89, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+               0x8A, 0xD8, 0xA8, 0xD8, 0xB1, 0xD8, 0xA8, 0xD8,
+               0xB2, 0xD8, 0xA8, 0xD9, 0x85, 0xD8, 0xA8, 0xD9,
+               0x86, 0xD8, 0xA8, 0xD9, 0x89, 0xD8, 0xA8, 0xD9,
+               0x8A, 0xD8, 0xAA, 0xD8, 0xB1, 0xD8, 0xAA, 0xD8,
+               0xB2, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAA, 0xD9,
+               0x86, 0xD8, 0xAA, 0xD9, 0x89, 0xD8, 0xAA, 0xD9,
+               0x8A, 0xD8, 0xAB, 0xD8, 0xB1, 0xD8, 0xAB, 0xD8,
+               0xB2, 0xD8, 0xAB, 0xD9, 0x85, 0xD8, 0xAB, 0xD9,
+               0x86, 0xD8, 0xAB, 0xD9, 0x89, 0xD8, 0xAB, 0xD9,
+               0x8A, 0xD9, 0x81, 0xD9, 0x89, 0xD9, 0x81, 0xD9,
+               0x8A, 0xD9, 0x82, 0xD9, 0x89, 0xD9, 0x82, 0xD9,
+               0x8A, 0xD9, 0x83, 0xD8, 0xA7, 0xD9, 0x83, 0xD9,
+               0x84, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x83, 0xD9,
+               0x89, 0xD9, 0x83, 0xD9, 0x8A, 0xD9, 0x84, 0xD9,
+               0x85, 0xD9, 0x84, 0xD9, 0x89, 0xD9, 0x84, 0xD9,
+               0x8A, 0xD9, 0x85, 0xD8, 0xA7, 0xD9, 0x85, 0xD9,
+               0x85, 0xD9, 0x86, 0xD8, 0xB1, 0xD9, 0x86, 0xD8,
+               0xB2, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x86, 0xD9,
+               0x86, 0xD9, 0x86, 0xD9, 0x89, 0xD9, 0x86, 0xD9,
+               0x8A, 0xD9, 0x89, 0xD9, 0xB0, 0xD9, 0x8A, 0xD8,
+               0xB1, 0xD9, 0x8A, 0xD8, 0xB2, 0xD9, 0x8A, 0xD9,
+               0x85, 0xD9, 0x8A, 0xD9, 0x86, 0xD9, 0x8A, 0xD9,
+               0x89, 0xD9, 0x8A, 0xD9, 0x8A, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD8, 0xAC, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
+               0xAD, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x85, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD9, 0x87, 0xD8, 0xA8, 0xD8, 0xAC, 0xD8,
+               0xA8, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xAE, 0xD8,
+               0xA8, 0xD9, 0x85, 0xD8, 0xA8, 0xD9, 0x87, 0xD8,
+               0xAA, 0xD8, 0xAC, 0xD8, 0xAA, 0xD8, 0xAD, 0xD8,
+               0xAA, 0xD8, 0xAE, 0xD8, 0xAA, 0xD9, 0x85, 0xD8,
+               0xAA, 0xD9, 0x87, 0xD8, 0xAB, 0xD9, 0x85, 0xD8,
+               0xAC, 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
+               0xAD, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x85, 0xD8,
+               0xAE, 0xD8, 0xAC, 0xD8, 0xAE, 0xD9, 0x85, 0xD8,
+               0xB3, 0xD8, 0xAC, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8,
+               0xB3, 0xD8, 0xAE, 0xD8, 0xB3, 0xD9, 0x85, 0xD8,
+               0xB5, 0xD8, 0xAD, 0xD8, 0xB5, 0xD8, 0xAE, 0xD8,
+               0xB5, 0xD9, 0x85, 0xD8, 0xB6, 0xD8, 0xAC, 0xD8,
+               0xB6, 0xD8, 0xAD, 0xD8, 0xB6, 0xD8, 0xAE, 0xD8,
+               0xB6, 0xD9, 0x85, 0xD8, 0xB7, 0xD8, 0xAD, 0xD8,
+               0xB8, 0xD9, 0x85, 0xD8, 0xB9, 0xD8, 0xAC, 0xD8,
+               0xB9, 0xD9, 0x85, 0xD8, 0xBA, 0xD8, 0xAC, 0xD8,
+               0xBA, 0xD9, 0x85, 0xD9, 0x81, 0xD8, 0xAC, 0xD9,
+               0x81, 0xD8, 0xAD, 0xD9, 0x81, 0xD8, 0xAE, 0xD9,
+               0x81, 0xD9, 0x85, 0xD9, 0x82, 0xD8, 0xAD, 0xD9,
+               0x82, 0xD9, 0x85, 0xD9, 0x83, 0xD8, 0xAC, 0xD9,
+               0x83, 0xD8, 0xAD, 0xD9, 0x83, 0xD8, 0xAE, 0xD9,
+               0x83, 0xD9, 0x84, 0xD9, 0x83, 0xD9, 0x85, 0xD9,
+               0x84, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
+               0x84, 0xD8, 0xAE, 0xD9, 0x84, 0xD9, 0x85, 0xD9,
+               0x84, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAE, 0xD9,
+               0x85, 0xD9, 0x85, 0xD9, 0x86, 0xD8, 0xAC, 0xD9,
+               0x86, 0xD8, 0xAD, 0xD9, 0x86, 0xD8, 0xAE, 0xD9,
+               0x86, 0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x87, 0xD9,
+               0x87, 0xD8, 0xAC, 0xD9, 0x87, 0xD9, 0x85, 0xD9,
+               0x87, 0xD9, 0xB0, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xAD, 0xD9, 0x8A, 0xD8, 0xAE, 0xD9,
+               0x8A, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x87, 0xD9,
+               0x8A, 0xD9, 0x94, 0xD9, 0x85, 0xD9, 0x8A, 0xD9,
+               0x94, 0xD9, 0x87, 0xD8, 0xA8, 0xD9, 0x85, 0xD8,
+               0xA8, 0xD9, 0x87, 0xD8, 0xAA, 0xD9, 0x85, 0xD8,
+               0xAA, 0xD9, 0x87, 0xD8, 0xAB, 0xD9, 0x85, 0xD8,
+               0xAB, 0xD9, 0x87, 0xD8, 0xB3, 0xD9, 0x85, 0xD8,
+               0xB3, 0xD9, 0x87, 0xD8, 0xB4, 0xD9, 0x85, 0xD8,
+               0xB4, 0xD9, 0x87, 0xD9, 0x83, 0xD9, 0x84, 0xD9,
+               0x83, 0xD9, 0x85, 0xD9, 0x84, 0xD9, 0x85, 0xD9,
+               0x86, 0xD9, 0x85, 0xD9, 0x86, 0xD9, 0x87, 0xD9,
+               0x8A, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x87, 0xD9,
+               0x80, 0xD9, 0x8E, 0xD9, 0x91, 0xD9, 0x80, 0xD9,
+               0x8F, 0xD9, 0x91, 0xD9, 0x80, 0xD9, 0x90, 0xD9,
+               0x91, 0xD8, 0xB7, 0xD9, 0x89, 0xD8, 0xB7, 0xD9,
+               0x8A, 0xD8, 0xB9, 0xD9, 0x89, 0xD8, 0xB9, 0xD9,
+               0x8A, 0xD8, 0xBA, 0xD9, 0x89, 0xD8, 0xBA, 0xD9,
+               0x8A, 0xD8, 0xB3, 0xD9, 0x89, 0xD8, 0xB3, 0xD9,
+               0x8A, 0xD8, 0xB4, 0xD9, 0x89, 0xD8, 0xB4, 0xD9,
+               0x8A, 0xD8, 0xAD, 0xD9, 0x89, 0xD8, 0xAD, 0xD9,
+               0x8A, 0xD8, 0xAC, 0xD9, 0x89, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xAE, 0xD9, 0x89, 0xD8, 0xAE, 0xD9,
+               0x8A, 0xD8, 0xB5, 0xD9, 0x89, 0xD8, 0xB5, 0xD9,
+               0x8A, 0xD8, 0xB6, 0xD9, 0x89, 0xD8, 0xB6, 0xD9,
+               0x8A, 0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8,
+               0xAD, 0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9,
+               0x85, 0xD8, 0xB4, 0xD8, 0xB1, 0xD8, 0xB3, 0xD8,
+               0xB1, 0xD8, 0xB5, 0xD8, 0xB1, 0xD8, 0xB6, 0xD8,
+               0xB1, 0xD8, 0xB7, 0xD9, 0x89, 0xD8, 0xB7, 0xD9,
+               0x8A, 0xD8, 0xB9, 0xD9, 0x89, 0xD8, 0xB9, 0xD9,
+               0x8A, 0xD8, 0xBA, 0xD9, 0x89, 0xD8, 0xBA, 0xD9,
+               0x8A, 0xD8, 0xB3, 0xD9, 0x89, 0xD8, 0xB3, 0xD9,
+               0x8A, 0xD8, 0xB4, 0xD9, 0x89, 0xD8, 0xB4, 0xD9,
+               0x8A, 0xD8, 0xAD, 0xD9, 0x89, 0xD8, 0xAD, 0xD9,
+               0x8A, 0xD8, 0xAC, 0xD9, 0x89, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xAE, 0xD9, 0x89, 0xD8, 0xAE, 0xD9,
+               0x8A, 0xD8, 0xB5, 0xD9, 0x89, 0xD8, 0xB5, 0xD9,
+               0x8A, 0xD8, 0xB6, 0xD9, 0x89, 0xD8, 0xB6, 0xD9,
+               0x8A, 0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8,
+               0xAD, 0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9,
+               0x85, 0xD8, 0xB4, 0xD8, 0xB1, 0xD8, 0xB3, 0xD8,
+               0xB1, 0xD8, 0xB5, 0xD8, 0xB1, 0xD8, 0xB6, 0xD8,
+               0xB1, 0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8,
+               0xAD, 0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9,
+               0x85, 0xD8, 0xB3, 0xD9, 0x87, 0xD8, 0xB4, 0xD9,
+               0x87, 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xB3, 0xD8,
+               0xAC, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8, 0xB3, 0xD8,
+               0xAE, 0xD8, 0xB4, 0xD8, 0xAC, 0xD8, 0xB4, 0xD8,
+               0xAD, 0xD8, 0xB4, 0xD8, 0xAE, 0xD8, 0xB7, 0xD9,
+               0x85, 0xD8, 0xB8, 0xD9, 0x85, 0xD8, 0xA7, 0xD9,
+               0x8B, 0xD8, 0xA7, 0xD9, 0x8B, 0xD8, 0xAA, 0xD8,
+               0xAC, 0xD9, 0x85, 0xD8, 0xAA, 0xD8, 0xAD, 0xD8,
+               0xAC, 0xD8, 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0xD8,
+               0xAA, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAA, 0xD8,
+               0xAE, 0xD9, 0x85, 0xD8, 0xAA, 0xD9, 0x85, 0xD8,
+               0xAC, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0xD8,
+               0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
+               0xAD, 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x8A, 0xD8,
+               0xAD, 0xD9, 0x85, 0xD9, 0x89, 0xD8, 0xB3, 0xD8,
+               0xAD, 0xD8, 0xAC, 0xD8, 0xB3, 0xD8, 0xAC, 0xD8,
+               0xAD, 0xD8, 0xB3, 0xD8, 0xAC, 0xD9, 0x89, 0xD8,
+               0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xB3, 0xD9,
+               0x85, 0xD8, 0xAD, 0xD8, 0xB3, 0xD9, 0x85, 0xD8,
+               0xAC, 0xD8, 0xB3, 0xD9, 0x85, 0xD9, 0x85, 0xD8,
+               0xB3, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB5, 0xD8,
+               0xAD, 0xD8, 0xAD, 0xD8, 0xB5, 0xD8, 0xAD, 0xD8,
+               0xAD, 0xD8, 0xB5, 0xD9, 0x85, 0xD9, 0x85, 0xD8,
+               0xB4, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xB4, 0xD8,
+               0xAD, 0xD9, 0x85, 0xD8, 0xB4, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE, 0xD8,
+               0xB4, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xB4, 0xD9,
+               0x85, 0xD9, 0x85, 0xD8, 0xB4, 0xD9, 0x85, 0xD9,
+               0x85, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x89, 0xD8,
+               0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0xD8, 0xB6, 0xD8,
+               0xAE, 0xD9, 0x85, 0xD8, 0xB7, 0xD9, 0x85, 0xD8,
+               0xAD, 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0xD8,
+               0xB7, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB7, 0xD9,
+               0x85, 0xD9, 0x8A, 0xD8, 0xB9, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x85, 0xD8,
+               0xB9, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB9, 0xD9,
+               0x85, 0xD9, 0x89, 0xD8, 0xBA, 0xD9, 0x85, 0xD9,
+               0x85, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0xD8,
+               0xBA, 0xD9, 0x85, 0xD9, 0x89, 0xD9, 0x81, 0xD8,
+               0xAE, 0xD9, 0x85, 0xD9, 0x81, 0xD8, 0xAE, 0xD9,
+               0x85, 0xD9, 0x82, 0xD9, 0x85, 0xD8, 0xAD, 0xD9,
+               0x82, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x84, 0xD8,
+               0xAD, 0xD9, 0x85, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
+               0x8A, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89, 0xD9,
+               0x84, 0xD8, 0xAC, 0xD8, 0xAC, 0xD9, 0x84, 0xD8,
+               0xAC, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xAE, 0xD9,
+               0x85, 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0xD9,
+               0x84, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x84, 0xD9,
+               0x85, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAD, 0xD8,
+               0xAC, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0xD9,
+               0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0xD9, 0x85, 0xD8,
+               0xAC, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD8, 0xAE, 0xD9, 0x85, 0xD9, 0x85, 0xD8,
+               0xAC, 0xD8, 0xAE, 0xD9, 0x87, 0xD9, 0x85, 0xD8,
+               0xAC, 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
+               0x86, 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x86, 0xD8,
+               0xAD, 0xD9, 0x89, 0xD9, 0x86, 0xD8, 0xAC, 0xD9,
+               0x85, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0xD9,
+               0x86, 0xD8, 0xAC, 0xD9, 0x89, 0xD9, 0x86, 0xD9,
+               0x85, 0xD9, 0x8A, 0xD9, 0x86, 0xD9, 0x85, 0xD9,
+               0x89, 0xD9, 0x8A, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
+               0x8A, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xA8, 0xD8,
+               0xAE, 0xD9, 0x8A, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0xD8,
+               0xAA, 0xD8, 0xAE, 0xD9, 0x8A, 0xD8, 0xAA, 0xD8,
+               0xAE, 0xD9, 0x89, 0xD8, 0xAA, 0xD9, 0x85, 0xD9,
+               0x8A, 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0xD8,
+               0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0xD8, 0xAC, 0xD8,
+               0xAD, 0xD9, 0x89, 0xD8, 0xAC, 0xD9, 0x85, 0xD9,
+               0x89, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89, 0xD8,
+               0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0xD8, 0xB4, 0xD8,
+               0xAD, 0xD9, 0x8A, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9,
+               0x8A, 0xD9, 0x84, 0xD8, 0xAC, 0xD9, 0x8A, 0xD9,
+               0x84, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x8A, 0xD8,
+               0xAD, 0xD9, 0x8A, 0xD9, 0x8A, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD9, 0x8A, 0xD9, 0x85, 0xD9, 0x8A, 0xD9,
+               0x85, 0xD9, 0x85, 0xD9, 0x8A, 0xD9, 0x82, 0xD9,
+               0x85, 0xD9, 0x8A, 0xD9, 0x86, 0xD8, 0xAD, 0xD9,
+               0x8A, 0xD9, 0x82, 0xD9, 0x85, 0xD8, 0xAD, 0xD9,
+               0x84, 0xD8, 0xAD, 0xD9, 0x85, 0xD8, 0xB9, 0xD9,
+               0x85, 0xD9, 0x8A, 0xD9, 0x83, 0xD9, 0x85, 0xD9,
+               0x8A, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9,
+               0x85, 0xD8, 0xAE, 0xD9, 0x8A, 0xD9, 0x84, 0xD8,
+               0xAC, 0xD9, 0x85, 0xD9, 0x83, 0xD9, 0x85, 0xD9,
+               0x85, 0xD9, 0x84, 0xD8, 0xAC, 0xD9, 0x85, 0xD9,
+               0x86, 0xD8, 0xAC, 0xD8, 0xAD, 0xD8, 0xAC, 0xD8,
+               0xAD, 0xD9, 0x8A, 0xD8, 0xAD, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A, 0xD9,
+               0x81, 0xD9, 0x85, 0xD9, 0x8A, 0xD8, 0xA8, 0xD8,
+               0xAD, 0xD9, 0x8A, 0xD9, 0x83, 0xD9, 0x85, 0xD9,
+               0x85, 0xD8, 0xB9, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
+               0xB5, 0xD9, 0x85, 0xD9, 0x85, 0xD8, 0xB3, 0xD8,
+               0xAE, 0xD9, 0x8A, 0xD9, 0x86, 0xD8, 0xAC, 0xD9,
+               0x8A, 0xD8, 0xB5, 0xD9, 0x84, 0xDB, 0x92, 0xD9,
+               0x82, 0xD9, 0x84, 0xDB, 0x92, 0xD8, 0xA7, 0xD9,
+               0x84, 0xD9, 0x84, 0xD9, 0x87, 0xD8, 0xA7, 0xD9,
+               0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0xD9, 0x85, 0xD8,
+               0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0xD8, 0xB5, 0xD9,
+               0x84, 0xD8, 0xB9, 0xD9, 0x85, 0xD8, 0xB1, 0xD8,
+               0xB3, 0xD9, 0x88, 0xD9, 0x84, 0xD8, 0xB9, 0xD9,
+               0x84, 0xD9, 0x8A, 0xD9, 0x87, 0xD9, 0x88, 0xD8,
+               0xB3, 0xD9, 0x84, 0xD9, 0x85, 0xD8, 0xB5, 0xD9,
+               0x84, 0xD9, 0x89, 0xD8, 0xB5, 0xD9, 0x84, 0xD9,
+               0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84,
+               0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9, 0x84, 0xD9,
+               0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88, 0xD8, 0xB3,
+               0xD9, 0x84, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x84,
+               0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7, 0xD9,
+               0x84, 0xD9, 0x87, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8,
+               0xA7, 0xD9, 0x84, 0x2C, 0xE3, 0x80, 0x81, 0xE3,
+               0x80, 0x82, 0x3A, 0x3B, 0x21, 0x3F, 0xE3, 0x80,
+               0x96, 0xE3, 0x80, 0x97, 0x2E, 0x2E, 0x2E, 0x2E,
+               0x2E, 0xE2, 0x80, 0x94, 0xE2, 0x80, 0x93, 0x5F,
+               0x5F, 0x28, 0x29, 0x7B, 0x7D, 0xE3, 0x80, 0x94,
+               0xE3, 0x80, 0x95, 0xE3, 0x80, 0x90, 0xE3, 0x80,
+               0x91, 0xE3, 0x80, 0x8A, 0xE3, 0x80, 0x8B, 0xE3,
+               0x80, 0x88, 0xE3, 0x80, 0x89, 0xE3, 0x80, 0x8C,
+               0xE3, 0x80, 0x8D, 0xE3, 0x80, 0x8E, 0xE3, 0x80,
+               0x8F, 0x5B, 0x5D, 0x20, 0xCC, 0x85, 0x20, 0xCC,
+               0x85, 0x20, 0xCC, 0x85, 0x20, 0xCC, 0x85, 0x5F,
+               0x5F, 0x5F, 0x2C, 0xE3, 0x80, 0x81, 0x2E, 0x3B,
+               0x3A, 0x3F, 0x21, 0xE2, 0x80, 0x94, 0x28, 0x29,
+               0x7B, 0x7D, 0xE3, 0x80, 0x94, 0xE3, 0x80, 0x95,
+               0x23, 0x26, 0x2A, 0x2B, 0x2D, 0x3C, 0x3E, 0x3D,
+               0x5C, 0x24, 0x25, 0x40, 0x20, 0xD9, 0x8B, 0xD9,
+               0x80, 0xD9, 0x8B, 0x20, 0xD9, 0x8C, 0x20, 0xD9,
+               0x8D, 0x20, 0xD9, 0x8E, 0xD9, 0x80, 0xD9, 0x8E,
+               0x20, 0xD9, 0x8F, 0xD9, 0x80, 0xD9, 0x8F, 0x20,
+               0xD9, 0x90, 0xD9, 0x80, 0xD9, 0x90, 0x20, 0xD9,
+               0x91, 0xD9, 0x80, 0xD9, 0x91, 0x20, 0xD9, 0x92,
+               0xD9, 0x80, 0xD9, 0x92, 0xD8, 0xA1, 0xD8, 0xA7,
+               0xD9, 0x93, 0xD8, 0xA7, 0xD9, 0x93, 0xD8, 0xA7,
+               0xD9, 0x94, 0xD8, 0xA7, 0xD9, 0x94, 0xD9, 0x88,
+               0xD9, 0x94, 0xD9, 0x88, 0xD9, 0x94, 0xD8, 0xA7,
+               0xD9, 0x95, 0xD8, 0xA7, 0xD9, 0x95, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A,
+               0xD9, 0x94, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xA7,
+               0xD8, 0xA7, 0xD8, 0xA8, 0xD8, 0xA8, 0xD8, 0xA8,
+               0xD8, 0xA8, 0xD8, 0xA9, 0xD8, 0xA9, 0xD8, 0xAA,
+               0xD8, 0xAA, 0xD8, 0xAA, 0xD8, 0xAA, 0xD8, 0xAB,
+               0xD8, 0xAB, 0xD8, 0xAB, 0xD8, 0xAB, 0xD8, 0xAC,
+               0xD8, 0xAC, 0xD8, 0xAC, 0xD8, 0xAC, 0xD8, 0xAD,
+               0xD8, 0xAD, 0xD8, 0xAD, 0xD8, 0xAD, 0xD8, 0xAE,
+               0xD8, 0xAE, 0xD8, 0xAE, 0xD8, 0xAE, 0xD8, 0xAF,
+               0xD8, 0xAF, 0xD8, 0xB0, 0xD8, 0xB0, 0xD8, 0xB1,
+               0xD8, 0xB1, 0xD8, 0xB2, 0xD8, 0xB2, 0xD8, 0xB3,
+               0xD8, 0xB3, 0xD8, 0xB3, 0xD8, 0xB3, 0xD8, 0xB4,
+               0xD8, 0xB4, 0xD8, 0xB4, 0xD8, 0xB4, 0xD8, 0xB5,
+               0xD8, 0xB5, 0xD8, 0xB5, 0xD8, 0xB5, 0xD8, 0xB6,
+               0xD8, 0xB6, 0xD8, 0xB6, 0xD8, 0xB6, 0xD8, 0xB7,
+               0xD8, 0xB7, 0xD8, 0xB7, 0xD8, 0xB7, 0xD8, 0xB8,
+               0xD8, 0xB8, 0xD8, 0xB8, 0xD8, 0xB8, 0xD8, 0xB9,
+               0xD8, 0xB9, 0xD8, 0xB9, 0xD8, 0xB9, 0xD8, 0xBA,
+               0xD8, 0xBA, 0xD8, 0xBA, 0xD8, 0xBA, 0xD9, 0x81,
+               0xD9, 0x81, 0xD9, 0x81, 0xD9, 0x81, 0xD9, 0x82,
+               0xD9, 0x82, 0xD9, 0x82, 0xD9, 0x82, 0xD9, 0x83,
+               0xD9, 0x83, 0xD9, 0x83, 0xD9, 0x83, 0xD9, 0x84,
+               0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x85,
+               0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x86,
+               0xD9, 0x86, 0xD9, 0x86, 0xD9, 0x86, 0xD9, 0x87,
+               0xD9, 0x87, 0xD9, 0x87, 0xD9, 0x87, 0xD9, 0x88,
+               0xD9, 0x88, 0xD9, 0x89, 0xD9, 0x89, 0xD9, 0x8A,
+               0xD9, 0x8A, 0xD9, 0x8A, 0xD9, 0x8A, 0xD9, 0x84,
+               0xD8, 0xA7, 0xD9, 0x93, 0xD9, 0x84, 0xD8, 0xA7,
+               0xD9, 0x93, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94,
+               0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xD9, 0x84,
+               0xD8, 0xA7, 0xD9, 0x95, 0xD9, 0x84, 0xD8, 0xA7,
+               0xD9, 0x95, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x84,
+               0xD8, 0xA7, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+               0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
+               0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+               0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E,
+               0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+               0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
+               0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+               0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
+               0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+               0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
+               0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+               0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E,
+               0xE2, 0xA6, 0x85, 0xE2, 0xA6, 0x86, 0xE3, 0x80,
+               0x82, 0xE3, 0x80, 0x8C, 0xE3, 0x80, 0x8D, 0xE3,
+               0x80, 0x81, 0xE3, 0x83, 0xBB, 0xE3, 0x83, 0xB2,
+               0xE3, 0x82, 0xA1, 0xE3, 0x82, 0xA3, 0xE3, 0x82,
+               0xA5, 0xE3, 0x82, 0xA7, 0xE3, 0x82, 0xA9, 0xE3,
+               0x83, 0xA3, 0xE3, 0x83, 0xA5, 0xE3, 0x83, 0xA7,
+               0xE3, 0x83, 0x83, 0xE3, 0x83, 0xBC, 0xE3, 0x82,
+               0xA2, 0xE3, 0x82, 0xA4, 0xE3, 0x82, 0xA6, 0xE3,
+               0x82, 0xA8, 0xE3, 0x82, 0xAA, 0xE3, 0x82, 0xAB,
+               0xE3, 0x82, 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82,
+               0xB1, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0xB5, 0xE3,
+               0x82, 0xB7, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0xBB,
+               0xE3, 0x82, 0xBD, 0xE3, 0x82, 0xBF, 0xE3, 0x83,
+               0x81, 0xE3, 0x83, 0x84, 0xE3, 0x83, 0x86, 0xE3,
+               0x83, 0x88, 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8B,
+               0xE3, 0x83, 0x8C, 0xE3, 0x83, 0x8D, 0xE3, 0x83,
+               0x8E, 0xE3, 0x83, 0x8F, 0xE3, 0x83, 0x92, 0xE3,
+               0x83, 0x95, 0xE3, 0x83, 0x98, 0xE3, 0x83, 0x9B,
+               0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x9F, 0xE3, 0x83,
+               0xA0, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xA2, 0xE3,
+               0x83, 0xA4, 0xE3, 0x83, 0xA6, 0xE3, 0x83, 0xA8,
+               0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
+               0xAB, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xAD, 0xE3,
+               0x83, 0xAF, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0x99,
+               0xE3, 0x82, 0x9A, 0xE1, 0x85, 0xA0, 0xE1, 0x84,
+               0x80, 0xE1, 0x84, 0x81, 0xE1, 0x86, 0xAA, 0xE1,
+               0x84, 0x82, 0xE1, 0x86, 0xAC, 0xE1, 0x86, 0xAD,
+               0xE1, 0x84, 0x83, 0xE1, 0x84, 0x84, 0xE1, 0x84,
+               0x85, 0xE1, 0x86, 0xB0, 0xE1, 0x86, 0xB1, 0xE1,
+               0x86, 0xB2, 0xE1, 0x86, 0xB3, 0xE1, 0x86, 0xB4,
+               0xE1, 0x86, 0xB5, 0xE1, 0x84, 0x9A, 0xE1, 0x84,
+               0x86, 0xE1, 0x84, 0x87, 0xE1, 0x84, 0x88, 0xE1,
+               0x84, 0xA1, 0xE1, 0x84, 0x89, 0xE1, 0x84, 0x8A,
+               0xE1, 0x84, 0x8B, 0xE1, 0x84, 0x8C, 0xE1, 0x84,
+               0x8D, 0xE1, 0x84, 0x8E, 0xE1, 0x84, 0x8F, 0xE1,
+               0x84, 0x90, 0xE1, 0x84, 0x91, 0xE1, 0x84, 0x92,
+               0xE1, 0x85, 0xA1, 0xE1, 0x85, 0xA2, 0xE1, 0x85,
+               0xA3, 0xE1, 0x85, 0xA4, 0xE1, 0x85, 0xA5, 0xE1,
+               0x85, 0xA6, 0xE1, 0x85, 0xA7, 0xE1, 0x85, 0xA8,
+               0xE1, 0x85, 0xA9, 0xE1, 0x85, 0xAA, 0xE1, 0x85,
+               0xAB, 0xE1, 0x85, 0xAC, 0xE1, 0x85, 0xAD, 0xE1,
+               0x85, 0xAE, 0xE1, 0x85, 0xAF, 0xE1, 0x85, 0xB0,
+               0xE1, 0x85, 0xB1, 0xE1, 0x85, 0xB2, 0xE1, 0x85,
+               0xB3, 0xE1, 0x85, 0xB4, 0xE1, 0x85, 0xB5, 0xC2,
+               0xA2, 0xC2, 0xA3, 0xC2, 0xAC, 0x20, 0xCC, 0x84,
+               0xC2, 0xA6, 0xC2, 0xA5, 0xE2, 0x82, 0xA9, 0xE2,
+               0x94, 0x82, 0xE2, 0x86, 0x90, 0xE2, 0x86, 0x91,
+               0xE2, 0x86, 0x92, 0xE2, 0x86, 0x93, 0xE2, 0x96,
+               0xA0, 0xE2, 0x97, 0x8B, 0xF6, 0xF0, 0x9D, 0x85,
+               0x97, 0xF0, 0x9D, 0x85, 0xA5, 0xF6, 0xF0, 0x9D,
+               0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF6, 0xF0,
+               0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
+               0x9D, 0x85, 0xAE, 0xF6, 0xF0, 0x9D, 0x85, 0x98,
+               0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF,
+               0xF6, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
+               0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0xF6, 0xF0, 0x9D,
+               0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
+               0x85, 0xB1, 0xF6, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
+               0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xF6,
+               0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5,
+               0xF6, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
+               0xA5, 0xF6, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D,
+               0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xF6, 0xF0,
+               0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
+               0x9D, 0x85, 0xAE, 0xF6, 0xF0, 0x9D, 0x86, 0xB9,
+               0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF,
+               0xF6, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
+               0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
+               0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+               0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43, 0x44,
+               0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
+               0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
+               0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
+               0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
+               0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
+               0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
+               0x41, 0x43, 0x44, 0x47, 0x4A, 0x4B, 0x4E, 0x4F,
+               0x50, 0x51, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+               0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x66, 0x68,
+               0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x44,
+               0x45, 0x46, 0x47, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
+               0x4F, 0x50, 0x51, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+               0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
+               0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+               0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x44, 0x45,
+               0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4F,
+               0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+               0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65,
+               0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+               0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+               0x76, 0x77, 0x78, 0x79, 0x7A, 0x41, 0x42, 0x43,
+               0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+               0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+               0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61,
+               0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+               0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+               0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+               0x7A, 0xC4, 0xB1, 0xC8, 0xB7, 0xCE, 0x91, 0xCE,
+               0x92, 0xCE, 0x93, 0xCE, 0x94, 0xCE, 0x95, 0xCE,
+               0x96, 0xCE, 0x97, 0xCE, 0x98, 0xCE, 0x99, 0xCE,
+               0x9A, 0xCE, 0x9B, 0xCE, 0x9C, 0xCE, 0x9D, 0xCE,
+               0x9E, 0xCE, 0x9F, 0xCE, 0xA0, 0xCE, 0xA1, 0xCE,
+               0x98, 0xCE, 0xA3, 0xCE, 0xA4, 0xCE, 0xA5, 0xCE,
+               0xA6, 0xCE, 0xA7, 0xCE, 0xA8, 0xCE, 0xA9, 0xE2,
+               0x88, 0x87, 0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3,
+               0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6, 0xCE, 0xB7,
+               0xCE, 0xB8, 0xCE, 0xB9, 0xCE, 0xBA, 0xCE, 0xBB,
+               0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE, 0xCE, 0xBF,
+               0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x82, 0xCF, 0x83,
+               0xCF, 0x84, 0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87,
+               0xCF, 0x88, 0xCF, 0x89, 0xE2, 0x88, 0x82, 0xCE,
+               0xB5, 0xCE, 0xB8, 0xCE, 0xBA, 0xCF, 0x86, 0xCF,
+               0x81, 0xCF, 0x80, 0xCE, 0x91, 0xCE, 0x92, 0xCE,
+               0x93, 0xCE, 0x94, 0xCE, 0x95, 0xCE, 0x96, 0xCE,
+               0x97, 0xCE, 0x98, 0xCE, 0x99, 0xCE, 0x9A, 0xCE,
+               0x9B, 0xCE, 0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE,
+               0x9F, 0xCE, 0xA0, 0xCE, 0xA1, 0xCE, 0x98, 0xCE,
+               0xA3, 0xCE, 0xA4, 0xCE, 0xA5, 0xCE, 0xA6, 0xCE,
+               0xA7, 0xCE, 0xA8, 0xCE, 0xA9, 0xE2, 0x88, 0x87,
+               0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4,
+               0xCE, 0xB5, 0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8,
+               0xCE, 0xB9, 0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC,
+               0xCE, 0xBD, 0xCE, 0xBE, 0xCE, 0xBF, 0xCF, 0x80,
+               0xCF, 0x81, 0xCF, 0x82, 0xCF, 0x83, 0xCF, 0x84,
+               0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87, 0xCF, 0x88,
+               0xCF, 0x89, 0xE2, 0x88, 0x82, 0xCE, 0xB5, 0xCE,
+               0xB8, 0xCE, 0xBA, 0xCF, 0x86, 0xCF, 0x81, 0xCF,
+               0x80, 0xCE, 0x91, 0xCE, 0x92, 0xCE, 0x93, 0xCE,
+               0x94, 0xCE, 0x95, 0xCE, 0x96, 0xCE, 0x97, 0xCE,
+               0x98, 0xCE, 0x99, 0xCE, 0x9A, 0xCE, 0x9B, 0xCE,
+               0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE, 0x9F, 0xCE,
+               0xA0, 0xCE, 0xA1, 0xCE, 0x98, 0xCE, 0xA3, 0xCE,
+               0xA4, 0xCE, 0xA5, 0xCE, 0xA6, 0xCE, 0xA7, 0xCE,
+               0xA8, 0xCE, 0xA9, 0xE2, 0x88, 0x87, 0xCE, 0xB1,
+               0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4, 0xCE, 0xB5,
+               0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8, 0xCE, 0xB9,
+               0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC, 0xCE, 0xBD,
+               0xCE, 0xBE, 0xCE, 0xBF, 0xCF, 0x80, 0xCF, 0x81,
+               0xCF, 0x82, 0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85,
+               0xCF, 0x86, 0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89,
+               0xE2, 0x88, 0x82, 0xCE, 0xB5, 0xCE, 0xB8, 0xCE,
+               0xBA, 0xCF, 0x86, 0xCF, 0x81, 0xCF, 0x80, 0xCE,
+               0x91, 0xCE, 0x92, 0xCE, 0x93, 0xCE, 0x94, 0xCE,
+               0x95, 0xCE, 0x96, 0xCE, 0x97, 0xCE, 0x98, 0xCE,
+               0x99, 0xCE, 0x9A, 0xCE, 0x9B, 0xCE, 0x9C, 0xCE,
+               0x9D, 0xCE, 0x9E, 0xCE, 0x9F, 0xCE, 0xA0, 0xCE,
+               0xA1, 0xCE, 0x98, 0xCE, 0xA3, 0xCE, 0xA4, 0xCE,
+               0xA5, 0xCE, 0xA6, 0xCE, 0xA7, 0xCE, 0xA8, 0xCE,
+               0xA9, 0xE2, 0x88, 0x87, 0xCE, 0xB1, 0xCE, 0xB2,
+               0xCE, 0xB3, 0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6,
+               0xCE, 0xB7, 0xCE, 0xB8, 0xCE, 0xB9, 0xCE, 0xBA,
+               0xCE, 0xBB, 0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE,
+               0xCE, 0xBF, 0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x82,
+               0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85, 0xCF, 0x86,
+               0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89, 0xE2, 0x88,
+               0x82, 0xCE, 0xB5, 0xCE, 0xB8, 0xCE, 0xBA, 0xCF,
+               0x86, 0xCF, 0x81, 0xCF, 0x80, 0xCE, 0x91, 0xCE,
+               0x92, 0xCE, 0x93, 0xCE, 0x94, 0xCE, 0x95, 0xCE,
+               0x96, 0xCE, 0x97, 0xCE, 0x98, 0xCE, 0x99, 0xCE,
+               0x9A, 0xCE, 0x9B, 0xCE, 0x9C, 0xCE, 0x9D, 0xCE,
+               0x9E, 0xCE, 0x9F, 0xCE, 0xA0, 0xCE, 0xA1, 0xCE,
+               0x98, 0xCE, 0xA3, 0xCE, 0xA4, 0xCE, 0xA5, 0xCE,
+               0xA6, 0xCE, 0xA7, 0xCE, 0xA8, 0xCE, 0xA9, 0xE2,
+               0x88, 0x87, 0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3,
+               0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6, 0xCE, 0xB7,
+               0xCE, 0xB8, 0xCE, 0xB9, 0xCE, 0xBA, 0xCE, 0xBB,
+               0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE, 0xCE, 0xBF,
+               0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x82, 0xCF, 0x83,
+               0xCF, 0x84, 0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87,
+               0xCF, 0x88, 0xCF, 0x89, 0xE2, 0x88, 0x82, 0xCE,
+               0xB5, 0xCE, 0xB8, 0xCE, 0xBA, 0xCF, 0x86, 0xCF,
+               0x81, 0xCF, 0x80, 0xCF, 0x9C, 0xCF, 0x9D, 0x30,
+               0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+               0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
+               0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
+               0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
+               0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+               0x39, 0xF6, 0xE4, 0xB8, 0xBD, 0xF6, 0xE4, 0xB8,
+               0xB8, 0xF6, 0xE4, 0xB9, 0x81, 0xF6, 0xF0, 0xA0,
+               0x84, 0xA2, 0xF6, 0xE4, 0xBD, 0xA0, 0xF6, 0xE4,
+               0xBE, 0xAE, 0xF6, 0xE4, 0xBE, 0xBB, 0xF6, 0xE5,
+               0x80, 0x82, 0xF6, 0xE5, 0x81, 0xBA, 0xF6, 0xE5,
+               0x82, 0x99, 0xF6, 0xE5, 0x83, 0xA7, 0xF6, 0xE5,
+               0x83, 0x8F, 0xF6, 0xE3, 0x92, 0x9E, 0xF6, 0xF0,
+               0xA0, 0x98, 0xBA, 0xF6, 0xE5, 0x85, 0x8D, 0xF6,
+               0xE5, 0x85, 0x94, 0xF6, 0xE5, 0x85, 0xA4, 0xF6,
+               0xE5, 0x85, 0xB7, 0xF6, 0xF0, 0xA0, 0x94, 0x9C,
+               0xF6, 0xE3, 0x92, 0xB9, 0xF6, 0xE5, 0x85, 0xA7,
+               0xF6, 0xE5, 0x86, 0x8D, 0xF6, 0xF0, 0xA0, 0x95,
+               0x8B, 0xF6, 0xE5, 0x86, 0x97, 0xF6, 0xE5, 0x86,
+               0xA4, 0xF6, 0xE4, 0xBB, 0x8C, 0xF6, 0xE5, 0x86,
+               0xAC, 0xF6, 0xE5, 0x86, 0xB5, 0xF6, 0xF0, 0xA9,
+               0x87, 0x9F, 0xF6, 0xE5, 0x87, 0xB5, 0xF6, 0xE5,
+               0x88, 0x83, 0xF6, 0xE3, 0x93, 0x9F, 0xF6, 0xE5,
+               0x88, 0xBB, 0xF6, 0xE5, 0x89, 0x86, 0xF6, 0xE5,
+               0x89, 0xB2, 0xF6, 0xE5, 0x89, 0xB7, 0xF6, 0xE3,
+               0x94, 0x95, 0xF6, 0xE5, 0x8B, 0x87, 0xF6, 0xE5,
+               0x8B, 0x89, 0xF6, 0xE5, 0x8B, 0xA4, 0xF6, 0xE5,
+               0x8B, 0xBA, 0xF6, 0xE5, 0x8C, 0x85, 0xF6, 0xE5,
+               0x8C, 0x86, 0xF6, 0xE5, 0x8C, 0x97, 0xF6, 0xE5,
+               0x8D, 0x89, 0xF6, 0xE5, 0x8D, 0x91, 0xF6, 0xE5,
+               0x8D, 0x9A, 0xF6, 0xE5, 0x8D, 0xB3, 0xF6, 0xE5,
+               0x8D, 0xBD, 0xF6, 0xE5, 0x8D, 0xBF, 0xF6, 0xE5,
+               0x8D, 0xBF, 0xF6, 0xE5, 0x8D, 0xBF, 0xF6, 0xF0,
+               0xA0, 0xA8, 0xAC, 0xF6, 0xE7, 0x81, 0xB0, 0xF6,
+               0xE5, 0x8F, 0x8A, 0xF6, 0xE5, 0x8F, 0x9F, 0xF6,
+               0xF0, 0xA0, 0xAD, 0xA3, 0xF6, 0xE5, 0x8F, 0xAB,
+               0xF6, 0xE5, 0x8F, 0xB1, 0xF6, 0xE5, 0x90, 0x86,
+               0xF6, 0xE5, 0x92, 0x9E, 0xF6, 0xE5, 0x90, 0xB8,
+               0xF6, 0xE5, 0x91, 0x88, 0xF6, 0xE5, 0x91, 0xA8,
+               0xF6, 0xE5, 0x92, 0xA2, 0xF6, 0xE5, 0x93, 0xB6,
+               0xF6, 0xE5, 0x94, 0x90, 0xF6, 0xE5, 0x95, 0x93,
+               0xF6, 0xE5, 0x95, 0xA3, 0xF6, 0xE5, 0x96, 0x84,
+               0xF6, 0xE5, 0x96, 0x84, 0xF6, 0xE5, 0x96, 0x99,
+               0xF6, 0xE5, 0x96, 0xAB, 0xF6, 0xE5, 0x96, 0xB3,
+               0xF6, 0xE5, 0x97, 0x82, 0xF6, 0xE5, 0x9C, 0x96,
+               0xF6, 0xE5, 0x98, 0x86, 0xF6, 0xE5, 0x9C, 0x97,
+               0xF6, 0xE5, 0x99, 0x91, 0xF6, 0xE5, 0x99, 0xB4,
+               0xF6, 0xE5, 0x88, 0x87, 0xF6, 0xE5, 0xA3, 0xAE,
+               0xF6, 0xE5, 0x9F, 0x8E, 0xF6, 0xE5, 0x9F, 0xB4,
+               0xF6, 0xE5, 0xA0, 0x8D, 0xF6, 0xE5, 0x9E, 0x8B,
+               0xF6, 0xE5, 0xA0, 0xB2, 0xF6, 0xE5, 0xA0, 0xB1,
+               0xF6, 0xE5, 0xA2, 0xAC, 0xF6, 0xF0, 0xA1, 0x93,
+               0xA4, 0xF6, 0xE5, 0xA3, 0xB2, 0xF6, 0xE5, 0xA3,
+               0xB7, 0xF6, 0xE5, 0xA4, 0x86, 0xF6, 0xE5, 0xA4,
+               0x9A, 0xF6, 0xE5, 0xA4, 0xA2, 0xF6, 0xE5, 0xA5,
+               0xA2, 0xF6, 0xF0, 0xA1, 0x9A, 0xA8, 0xF6, 0xF0,
+               0xA1, 0x9B, 0xAA, 0xF6, 0xE5, 0xA7, 0xAC, 0xF6,
+               0xE5, 0xA8, 0x9B, 0xF6, 0xE5, 0xA8, 0xA7, 0xF6,
+               0xE5, 0xA7, 0x98, 0xF6, 0xE5, 0xA9, 0xA6, 0xF6,
+               0xE3, 0x9B, 0xAE, 0xF6, 0xE3, 0x9B, 0xBC, 0xF6,
+               0xE5, 0xAC, 0x88, 0xF6, 0xE5, 0xAC, 0xBE, 0xF6,
+               0xE5, 0xAC, 0xBE, 0xF6, 0xF0, 0xA1, 0xA7, 0x88,
+               0xF6, 0xE5, 0xAF, 0x83, 0xF6, 0xE5, 0xAF, 0x98,
+               0xF6, 0xE5, 0xAF, 0xA7, 0xF6, 0xE5, 0xAF, 0xB3,
+               0xF6, 0xF0, 0xA1, 0xAC, 0x98, 0xF6, 0xE5, 0xAF,
+               0xBF, 0xF6, 0xE5, 0xB0, 0x86, 0xF6, 0xE5, 0xBD,
+               0x93, 0xF6, 0xE5, 0xB0, 0xA2, 0xF6, 0xE3, 0x9E,
+               0x81, 0xF6, 0xE5, 0xB1, 0xA0, 0xF6, 0xE5, 0xB1,
+               0xAE, 0xF6, 0xE5, 0xB3, 0x80, 0xF6, 0xE5, 0xB2,
+               0x8D, 0xF6, 0xF0, 0xA1, 0xB7, 0xA4, 0xF6, 0xE5,
+               0xB5, 0x83, 0xF6, 0xF0, 0xA1, 0xB7, 0xA6, 0xF6,
+               0xE5, 0xB5, 0xAE, 0xF6, 0xE5, 0xB5, 0xAB, 0xF6,
+               0xE5, 0xB5, 0xBC, 0xF6, 0xE5, 0xB7, 0xA1, 0xF6,
+               0xE5, 0xB7, 0xA2, 0xF6, 0xE3, 0xA0, 0xAF, 0xF6,
+               0xE5, 0xB7, 0xBD, 0xF6, 0xE5, 0xB8, 0xA8, 0xF6,
+               0xE5, 0xB8, 0xBD, 0xF6, 0xE5, 0xB9, 0xA9, 0xF6,
+               0xE3, 0xA1, 0xA2, 0xF6, 0xF0, 0xA2, 0x86, 0x83,
+               0xF6, 0xE3, 0xA1, 0xBC, 0xF6, 0xE5, 0xBA, 0xB0,
+               0xF6, 0xE5, 0xBA, 0xB3, 0xF6, 0xE5, 0xBA, 0xB6,
+               0xF6, 0xE5, 0xBB, 0x8A, 0xF6, 0xF0, 0xAA, 0x8E,
+               0x92, 0xF6, 0xE5, 0xBB, 0xBE, 0xF6, 0xF0, 0xA2,
+               0x8C, 0xB1, 0xF6, 0xF0, 0xA2, 0x8C, 0xB1, 0xF6,
+               0xE8, 0x88, 0x81, 0xF6, 0xE5, 0xBC, 0xA2, 0xF6,
+               0xE5, 0xBC, 0xA2, 0xF6, 0xE3, 0xA3, 0x87, 0xF6,
+               0xF0, 0xA3, 0x8A, 0xB8, 0xF6, 0xF0, 0xA6, 0x87,
+               0x9A, 0xF6, 0xE5, 0xBD, 0xA2, 0xF6, 0xE5, 0xBD,
+               0xAB, 0xF6, 0xE3, 0xA3, 0xA3, 0xF6, 0xE5, 0xBE,
+               0x9A, 0xF6, 0xE5, 0xBF, 0x8D, 0xF6, 0xE5, 0xBF,
+               0x97, 0xF6, 0xE5, 0xBF, 0xB9, 0xF6, 0xE6, 0x82,
+               0x81, 0xF6, 0xE3, 0xA4, 0xBA, 0xF6, 0xE3, 0xA4,
+               0x9C, 0xF6, 0xE6, 0x82, 0x94, 0xF6, 0xF0, 0xA2,
+               0x9B, 0x94, 0xF6, 0xE6, 0x83, 0x87, 0xF6, 0xE6,
+               0x85, 0x88, 0xF6, 0xE6, 0x85, 0x8C, 0xF6, 0xE6,
+               0x85, 0x8E, 0xF6, 0xE6, 0x85, 0x8C, 0xF6, 0xE6,
+               0x85, 0xBA, 0xF6, 0xE6, 0x86, 0x8E, 0xF6, 0xE6,
+               0x86, 0xB2, 0xF6, 0xE6, 0x86, 0xA4, 0xF6, 0xE6,
+               0x86, 0xAF, 0xF6, 0xE6, 0x87, 0x9E, 0xF6, 0xE6,
+               0x87, 0xB2, 0xF6, 0xE6, 0x87, 0xB6, 0xF6, 0xE6,
+               0x88, 0x90, 0xF6, 0xE6, 0x88, 0x9B, 0xF6, 0xE6,
+               0x89, 0x9D, 0xF6, 0xE6, 0x8A, 0xB1, 0xF6, 0xE6,
+               0x8B, 0x94, 0xF6, 0xE6, 0x8D, 0x90, 0xF6, 0xF0,
+               0xA2, 0xAC, 0x8C, 0xF6, 0xE6, 0x8C, 0xBD, 0xF6,
+               0xE6, 0x8B, 0xBC, 0xF6, 0xE6, 0x8D, 0xA8, 0xF6,
+               0xE6, 0x8E, 0x83, 0xF6, 0xE6, 0x8F, 0xA4, 0xF6,
+               0xF0, 0xA2, 0xAF, 0xB1, 0xF6, 0xE6, 0x90, 0xA2,
+               0xF6, 0xE6, 0x8F, 0x85, 0xF6, 0xE6, 0x8E, 0xA9,
+               0xF6, 0xE3, 0xA8, 0xAE, 0xF6, 0xE6, 0x91, 0xA9,
+               0xF6, 0xE6, 0x91, 0xBE, 0xF6, 0xE6, 0x92, 0x9D,
+               0xF6, 0xE6, 0x91, 0xB7, 0xF6, 0xE3, 0xA9, 0xAC,
+               0xF6, 0xE6, 0x95, 0x8F, 0xF6, 0xE6, 0x95, 0xAC,
+               0xF6, 0xF0, 0xA3, 0x80, 0x8A, 0xF6, 0xE6, 0x97,
+               0xA3, 0xF6, 0xE6, 0x9B, 0xB8, 0xF6, 0xE6, 0x99,
+               0x89, 0xF6, 0xE3, 0xAC, 0x99, 0xF6, 0xE6, 0x9A,
+               0x91, 0xF6, 0xE3, 0xAC, 0x88, 0xF6, 0xE3, 0xAB,
+               0xA4, 0xF6, 0xE5, 0x86, 0x92, 0xF6, 0xE5, 0x86,
+               0x95, 0xF6, 0xE6, 0x9C, 0x80, 0xF6, 0xE6, 0x9A,
+               0x9C, 0xF6, 0xE8, 0x82, 0xAD, 0xF6, 0xE4, 0x8F,
+               0x99, 0xF6, 0xE6, 0x9C, 0x97, 0xF6, 0xE6, 0x9C,
+               0x9B, 0xF6, 0xE6, 0x9C, 0xA1, 0xF6, 0xE6, 0x9D,
+               0x9E, 0xF6, 0xE6, 0x9D, 0x93, 0xF6, 0xF0, 0xA3,
+               0x8F, 0x83, 0xF6, 0xE3, 0xAD, 0x89, 0xF6, 0xE6,
+               0x9F, 0xBA, 0xF6, 0xE6, 0x9E, 0x85, 0xF6, 0xE6,
+               0xA1, 0x92, 0xF6, 0xE6, 0xA2, 0x85, 0xF6, 0xF0,
+               0xA3, 0x91, 0xAD, 0xF6, 0xE6, 0xA2, 0x8E, 0xF6,
+               0xE6, 0xA0, 0x9F, 0xF6, 0xE6, 0xA4, 0x94, 0xF6,
+               0xE3, 0xAE, 0x9D, 0xF6, 0xE6, 0xA5, 0x82, 0xF6,
+               0xE6, 0xA6, 0xA3, 0xF6, 0xE6, 0xA7, 0xAA, 0xF6,
+               0xE6, 0xAA, 0xA8, 0xF6, 0xF0, 0xA3, 0x9A, 0xA3,
+               0xF6, 0xE6, 0xAB, 0x9B, 0xF6, 0xE3, 0xB0, 0x98,
+               0xF6, 0xE6, 0xAC, 0xA1, 0xF6, 0xF0, 0xA3, 0xA2,
+               0xA7, 0xF6, 0xE6, 0xAD, 0x94, 0xF6, 0xE3, 0xB1,
+               0x8E, 0xF6, 0xE6, 0xAD, 0xB2, 0xF6, 0xE6, 0xAE,
+               0x9F, 0xF6, 0xE6, 0xAE, 0xBA, 0xF6, 0xE6, 0xAE,
+               0xBB, 0xF6, 0xF0, 0xA3, 0xAA, 0x8D, 0xF6, 0xF0,
+               0xA1, 0xB4, 0x8B, 0xF6, 0xF0, 0xA3, 0xAB, 0xBA,
+               0xF6, 0xE6, 0xB1, 0x8E, 0xF6, 0xF0, 0xA3, 0xB2,
+               0xBC, 0xF6, 0xE6, 0xB2, 0xBF, 0xF6, 0xE6, 0xB3,
+               0x8D, 0xF6, 0xE6, 0xB1, 0xA7, 0xF6, 0xE6, 0xB4,
+               0x96, 0xF6, 0xE6, 0xB4, 0xBE, 0xF6, 0xE6, 0xB5,
+               0xB7, 0xF6, 0xE6, 0xB5, 0x81, 0xF6, 0xE6, 0xB5,
+               0xA9, 0xF6, 0xE6, 0xB5, 0xB8, 0xF6, 0xE6, 0xB6,
+               0x85, 0xF6, 0xF0, 0xA3, 0xB4, 0x9E, 0xF6, 0xE6,
+               0xB4, 0xB4, 0xF6, 0xE6, 0xB8, 0xAF, 0xF6, 0xE6,
+               0xB9, 0xAE, 0xF6, 0xE3, 0xB4, 0xB3, 0xF6, 0xE6,
+               0xBB, 0x8B, 0xF6, 0xE6, 0xBB, 0x87, 0xF6, 0xF0,
+               0xA3, 0xBB, 0x91, 0xF6, 0xE6, 0xB7, 0xB9, 0xF6,
+               0xE6, 0xBD, 0xAE, 0xF6, 0xF0, 0xA3, 0xBD, 0x9E,
+               0xF6, 0xF0, 0xA3, 0xBE, 0x8E, 0xF6, 0xE6, 0xBF,
+               0x86, 0xF6, 0xE7, 0x80, 0xB9, 0xF6, 0xE7, 0x80,
+               0x9E, 0xF6, 0xE7, 0x80, 0x9B, 0xF6, 0xE3, 0xB6,
+               0x96, 0xF6, 0xE7, 0x81, 0x8A, 0xF6, 0xE7, 0x81,
+               0xBD, 0xF6, 0xE7, 0x81, 0xB7, 0xF6, 0xE7, 0x82,
+               0xAD, 0xF6, 0xF0, 0xA0, 0x94, 0xA5, 0xF6, 0xE7,
+               0x85, 0x85, 0xF6, 0xF0, 0xA4, 0x89, 0xA3, 0xF6,
+               0xE7, 0x86, 0x9C, 0xF6, 0xF0, 0xA4, 0x8E, 0xAB,
+               0xF6, 0xE7, 0x88, 0xA8, 0xF6, 0xE7, 0x88, 0xB5,
+               0xF6, 0xE7, 0x89, 0x90, 0xF6, 0xF0, 0xA4, 0x98,
+               0x88, 0xF6, 0xE7, 0x8A, 0x80, 0xF6, 0xE7, 0x8A,
+               0x95, 0xF6, 0xF0, 0xA4, 0x9C, 0xB5, 0xF6, 0xF0,
+               0xA4, 0xA0, 0x94, 0xF6, 0xE7, 0x8D, 0xBA, 0xF6,
+               0xE7, 0x8E, 0x8B, 0xF6, 0xE3, 0xBA, 0xAC, 0xF6,
+               0xE7, 0x8E, 0xA5, 0xF6, 0xE3, 0xBA, 0xB8, 0xF6,
+               0xE3, 0xBA, 0xB8, 0xF6, 0xE7, 0x91, 0x87, 0xF6,
+               0xE7, 0x91, 0x9C, 0xF6, 0xE7, 0x91, 0xB1, 0xF6,
+               0xE7, 0x92, 0x85, 0xF6, 0xE7, 0x93, 0x8A, 0xF6,
+               0xE3, 0xBC, 0x9B, 0xF6, 0xE7, 0x94, 0xA4, 0xF6,
+               0xF0, 0xA4, 0xB0, 0xB6, 0xF6, 0xE7, 0x94, 0xBE,
+               0xF6, 0xF0, 0xA4, 0xB2, 0x92, 0xF6, 0xE7, 0x95,
+               0xB0, 0xF6, 0xF0, 0xA2, 0x86, 0x9F, 0xF6, 0xE7,
+               0x98, 0x90, 0xF6, 0xF0, 0xA4, 0xBE, 0xA1, 0xF6,
+               0xF0, 0xA4, 0xBE, 0xB8, 0xF6, 0xF0, 0xA5, 0x81,
+               0x84, 0xF6, 0xE3, 0xBF, 0xBC, 0xF6, 0xE4, 0x80,
+               0x88, 0xF6, 0xE7, 0x9B, 0xB4, 0xF6, 0xF0, 0xA5,
+               0x83, 0xB3, 0xF6, 0xF0, 0xA5, 0x83, 0xB2, 0xF6,
+               0xF0, 0xA5, 0x84, 0x99, 0xF6, 0xF0, 0xA5, 0x84,
+               0xB3, 0xF6, 0xE7, 0x9C, 0x9E, 0xF6, 0xE7, 0x9C,
+               0x9F, 0xF6, 0xE7, 0x9C, 0x9F, 0xF6, 0xE7, 0x9D,
+               0x8A, 0xF6, 0xE4, 0x80, 0xB9, 0xF6, 0xE7, 0x9E,
+               0x8B, 0xF6, 0xE4, 0x81, 0x86, 0xF6, 0xE4, 0x82,
+               0x96, 0xF6, 0xF0, 0xA5, 0x90, 0x9D, 0xF6, 0xE7,
+               0xA1, 0x8E, 0xF6, 0xE7, 0xA2, 0x8C, 0xF6, 0xE7,
+               0xA3, 0x8C, 0xF6, 0xE4, 0x83, 0xA3, 0xF6, 0xF0,
+               0xA5, 0x98, 0xA6, 0xF6, 0xE7, 0xA5, 0x96, 0xF6,
+               0xF0, 0xA5, 0x9A, 0x9A, 0xF6, 0xF0, 0xA5, 0x9B,
+               0x85, 0xF6, 0xE7, 0xA6, 0x8F, 0xF6, 0xE7, 0xA7,
+               0xAB, 0xF6, 0xE4, 0x84, 0xAF, 0xF6, 0xE7, 0xA9,
+               0x80, 0xF6, 0xE7, 0xA9, 0x8A, 0xF6, 0xE7, 0xA9,
+               0x8F, 0xF6, 0xF0, 0xA5, 0xA5, 0xBC, 0xF6, 0xF0,
+               0xA5, 0xAA, 0xA7, 0xF6, 0xF0, 0xA5, 0xAA, 0xA7,
+               0xF6, 0xE7, 0xAB, 0xAE, 0xF6, 0xE4, 0x88, 0x82,
+               0xF6, 0xF0, 0xA5, 0xAE, 0xAB, 0xF6, 0xE7, 0xAF,
+               0x86, 0xF6, 0xE7, 0xAF, 0x89, 0xF6, 0xE4, 0x88,
+               0xA7, 0xF6, 0xF0, 0xA5, 0xB2, 0x80, 0xF6, 0xE7,
+               0xB3, 0x92, 0xF6, 0xE4, 0x8A, 0xA0, 0xF6, 0xE7,
+               0xB3, 0xA8, 0xF6, 0xE7, 0xB3, 0xA3, 0xF6, 0xE7,
+               0xB4, 0x80, 0xF6, 0xF0, 0xA5, 0xBE, 0x86, 0xF6,
+               0xE7, 0xB5, 0xA3, 0xF6, 0xE4, 0x8C, 0x81, 0xF6,
+               0xE7, 0xB7, 0x87, 0xF6, 0xE7, 0xB8, 0x82, 0xF6,
+               0xE7, 0xB9, 0x85, 0xF6, 0xE4, 0x8C, 0xB4, 0xF6,
+               0xF0, 0xA6, 0x88, 0xA8, 0xF6, 0xF0, 0xA6, 0x89,
+               0x87, 0xF6, 0xE4, 0x8D, 0x99, 0xF6, 0xF0, 0xA6,
+               0x8B, 0x99, 0xF6, 0xE7, 0xBD, 0xBA, 0xF6, 0xF0,
+               0xA6, 0x8C, 0xBE, 0xF6, 0xE7, 0xBE, 0x95, 0xF6,
+               0xE7, 0xBF, 0xBA, 0xF6, 0xE8, 0x80, 0x85, 0xF6,
+               0xF0, 0xA6, 0x93, 0x9A, 0xF6, 0xF0, 0xA6, 0x94,
+               0xA3, 0xF6, 0xE8, 0x81, 0xA0, 0xF6, 0xF0, 0xA6,
+               0x96, 0xA8, 0xF6, 0xE8, 0x81, 0xB0, 0xF6, 0xF0,
+               0xA3, 0x8D, 0x9F, 0xF6, 0xE4, 0x8F, 0x95, 0xF6,
+               0xE8, 0x82, 0xB2, 0xF6, 0xE8, 0x84, 0x83, 0xF6,
+               0xE4, 0x90, 0x8B, 0xF6, 0xE8, 0x84, 0xBE, 0xF6,
+               0xE5, 0xAA, 0xB5, 0xF6, 0xF0, 0xA6, 0x9E, 0xA7,
+               0xF6, 0xF0, 0xA6, 0x9E, 0xB5, 0xF6, 0xF0, 0xA3,
+               0x8E, 0x93, 0xF6, 0xF0, 0xA3, 0x8E, 0x9C, 0xF6,
+               0xE8, 0x88, 0x81, 0xF6, 0xE8, 0x88, 0x84, 0xF6,
+               0xE8, 0xBE, 0x9E, 0xF6, 0xE4, 0x91, 0xAB, 0xF6,
+               0xE8, 0x8A, 0x91, 0xF6, 0xE8, 0x8A, 0x8B, 0xF6,
+               0xE8, 0x8A, 0x9D, 0xF6, 0xE5, 0x8A, 0xB3, 0xF6,
+               0xE8, 0x8A, 0xB1, 0xF6, 0xE8, 0x8A, 0xB3, 0xF6,
+               0xE8, 0x8A, 0xBD, 0xF6, 0xE8, 0x8B, 0xA6, 0xF6,
+               0xF0, 0xA6, 0xAC, 0xBC, 0xF6, 0xE8, 0x8B, 0xA5,
+               0xF6, 0xE8, 0x8C, 0x9D, 0xF6, 0xE8, 0x8D, 0xA3,
+               0xF6, 0xE8, 0x8E, 0xAD, 0xF6, 0xE8, 0x8C, 0xA3,
+               0xF6, 0xE8, 0x8E, 0xBD, 0xF6, 0xE8, 0x8F, 0xA7,
+               0xF6, 0xE8, 0x91, 0x97, 0xF6, 0xE8, 0x8D, 0x93,
+               0xF6, 0xE8, 0x8F, 0x8A, 0xF6, 0xE8, 0x8F, 0x8C,
+               0xF6, 0xE8, 0x8F, 0x9C, 0xF6, 0xF0, 0xA6, 0xB0,
+               0xB6, 0xF6, 0xF0, 0xA6, 0xB5, 0xAB, 0xF6, 0xF0,
+               0xA6, 0xB3, 0x95, 0xF6, 0xE4, 0x94, 0xAB, 0xF6,
+               0xE8, 0x93, 0xB1, 0xF6, 0xE8, 0x93, 0xB3, 0xF6,
+               0xE8, 0x94, 0x96, 0xF6, 0xF0, 0xA7, 0x8F, 0x8A,
+               0xF6, 0xE8, 0x95, 0xA4, 0xF6, 0xF0, 0xA6, 0xBC,
+               0xAC, 0xF6, 0xE4, 0x95, 0x9D, 0xF6, 0xE4, 0x95,
+               0xA1, 0xF6, 0xF0, 0xA6, 0xBE, 0xB1, 0xF6, 0xF0,
+               0xA7, 0x83, 0x92, 0xF6, 0xE4, 0x95, 0xAB, 0xF6,
+               0xE8, 0x99, 0x90, 0xF6, 0xE8, 0x99, 0x9C, 0xF6,
+               0xE8, 0x99, 0xA7, 0xF6, 0xE8, 0x99, 0xA9, 0xF6,
+               0xE8, 0x9A, 0xA9, 0xF6, 0xE8, 0x9A, 0x88, 0xF6,
+               0xE8, 0x9C, 0x8E, 0xF6, 0xE8, 0x9B, 0xA2, 0xF6,
+               0xE8, 0x9D, 0xB9, 0xF6, 0xE8, 0x9C, 0xA8, 0xF6,
+               0xE8, 0x9D, 0xAB, 0xF6, 0xE8, 0x9E, 0x86, 0xF6,
+               0xE4, 0x97, 0x97, 0xF6, 0xE8, 0x9F, 0xA1, 0xF6,
+               0xE8, 0xA0, 0x81, 0xF6, 0xE4, 0x97, 0xB9, 0xF6,
+               0xE8, 0xA1, 0xA0, 0xF6, 0xE8, 0xA1, 0xA3, 0xF6,
+               0xF0, 0xA7, 0x99, 0xA7, 0xF6, 0xE8, 0xA3, 0x97,
+               0xF6, 0xE8, 0xA3, 0x9E, 0xF6, 0xE4, 0x98, 0xB5,
+               0xF6, 0xE8, 0xA3, 0xBA, 0xF6, 0xE3, 0x92, 0xBB,
+               0xF6, 0xF0, 0xA7, 0xA2, 0xAE, 0xF6, 0xF0, 0xA7,
+               0xA5, 0xA6, 0xF6, 0xE4, 0x9A, 0xBE, 0xF6, 0xE4,
+               0x9B, 0x87, 0xF6, 0xE8, 0xAA, 0xA0, 0xF6, 0xE8,
+               0xAB, 0xAD, 0xF6, 0xE8, 0xAE, 0x8A, 0xF6, 0xE8,
+               0xB1, 0x95, 0xF6, 0xF0, 0xA7, 0xB2, 0xA8, 0xF6,
+               0xE8, 0xB2, 0xAB, 0xF6, 0xE8, 0xB3, 0x81, 0xF6,
+               0xE8, 0xB4, 0x9B, 0xF6, 0xE8, 0xB5, 0xB7, 0xF6,
+               0xF0, 0xA7, 0xBC, 0xAF, 0xF6, 0xF0, 0xA0, 0xA0,
+               0x84, 0xF6, 0xE8, 0xB7, 0x8B, 0xF6, 0xE8, 0xB6,
+               0xBC, 0xF6, 0xE8, 0xB7, 0xB0, 0xF6, 0xF0, 0xA0,
+               0xA3, 0x9E, 0xF6, 0xE8, 0xBB, 0x94, 0xF6, 0xE8,
+               0xBC, 0xB8, 0xF6, 0xF0, 0xA8, 0x97, 0x92, 0xF6,
+               0xF0, 0xA8, 0x97, 0xAD, 0xF6, 0xE9, 0x82, 0x94,
+               0xF6, 0xE9, 0x83, 0xB1, 0xF6, 0xE9, 0x84, 0x91,
+               0xF6, 0xF0, 0xA8, 0x9C, 0xAE, 0xF6, 0xE9, 0x84,
+               0x9B, 0xF6, 0xE9, 0x88, 0xB8, 0xF6, 0xE9, 0x8B,
+               0x97, 0xF6, 0xE9, 0x8B, 0x98, 0xF6, 0xE9, 0x89,
+               0xBC, 0xF6, 0xE9, 0x8F, 0xB9, 0xF6, 0xE9, 0x90,
+               0x95, 0xF6, 0xF0, 0xA8, 0xAF, 0xBA, 0xF6, 0xE9,
+               0x96, 0x8B, 0xF6, 0xE4, 0xA6, 0x95, 0xF6, 0xE9,
+               0x96, 0xB7, 0xF6, 0xF0, 0xA8, 0xB5, 0xB7, 0xF6,
+               0xE4, 0xA7, 0xA6, 0xF6, 0xE9, 0x9B, 0x83, 0xF6,
+               0xE5, 0xB6, 0xB2, 0xF6, 0xE9, 0x9C, 0xA3, 0xF6,
+               0xF0, 0xA9, 0x85, 0x85, 0xF6, 0xF0, 0xA9, 0x88,
+               0x9A, 0xF6, 0xE4, 0xA9, 0xAE, 0xF6, 0xE4, 0xA9,
+               0xB6, 0xF6, 0xE9, 0x9F, 0xA0, 0xF6, 0xF0, 0xA9,
+               0x90, 0x8A, 0xF6, 0xE4, 0xAA, 0xB2, 0xF6, 0xF0,
+               0xA9, 0x92, 0x96, 0xF6, 0xE9, 0xA0, 0x8B, 0xF6,
+               0xE9, 0xA0, 0x8B, 0xF6, 0xE9, 0xA0, 0xA9, 0xF6,
+               0xF0, 0xA9, 0x96, 0xB6, 0xF6, 0xE9, 0xA3, 0xA2,
+               0xF6, 0xE4, 0xAC, 0xB3, 0xF6, 0xE9, 0xA4, 0xA9,
+               0xF6, 0xE9, 0xA6, 0xA7, 0xF6, 0xE9, 0xA7, 0x82,
+               0xF6, 0xE9, 0xA7, 0xBE, 0xF6, 0xE4, 0xAF, 0x8E,
+               0xF6, 0xF0, 0xA9, 0xAC, 0xB0, 0xF6, 0xE9, 0xAC,
+               0x92, 0xF6, 0xE9, 0xB1, 0x80, 0xF6, 0xE9, 0xB3,
+               0xBD, 0xF6, 0xE4, 0xB3, 0x8E, 0xF6, 0xE4, 0xB3,
+               0xAD, 0xF6, 0xE9, 0xB5, 0xA7, 0xF6, 0xF0, 0xAA,
+               0x83, 0x8E, 0xF6, 0xE4, 0xB3, 0xB8, 0xF6, 0xF0,
+               0xAA, 0x84, 0x85, 0xF6, 0xF0, 0xAA, 0x88, 0x8E,
+               0xF6, 0xF0, 0xAA, 0x8A, 0x91, 0xF6, 0xE9, 0xBA,
+               0xBB, 0xF6, 0xE4, 0xB5, 0x96, 0xF6, 0xE9, 0xBB,
+               0xB9, 0xF6, 0xE9, 0xBB, 0xBE, 0xF6, 0xE9, 0xBC,
+               0x85, 0xF6, 0xE9, 0xBC, 0x8F, 0xF6, 0xE9, 0xBC,
+               0x96, 0xF6, 0xE9, 0xBC, 0xBB, 0xF6, 0xF0, 0xAA,
+               0x98, 0x80,
+       },
+};
+
+static const uchar_t u8_case_common_b2_tbl[2][2][256] = {
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, 1,  2,  N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 3,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       4,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+       {
+               {
+                       0,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, 1,  2,  N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, 3,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+               {
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       4,  N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+                       N_, N_, N_, N_, N_, N_, N_, N_,
+               },
+
+       },
+
+};
+
+static const u8_displacement_t u8_tolower_b3_tbl[2][5][256] = {
+       {
+               {       /* Third byte table 0. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { 0, 0 },
+                       { 1, 60 }, { 2, 123 }, { 3, 185 }, { 4, 257 },
+                       { 5, 321 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 6, 373 }, { 7, 439 },
+                       { 8, 465 }, { 9, 561 }, { 10, 593 }, { 11, 649 },
+                       { 12, 703 }, { 13, 749 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 14, 795 }, { 15, 891 }, { 16, 987 }, { 17, 1068 },
+                       { 18, 1155 }, { 19, 1245 }, { 20, 1299 }, { 21, 1386 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 22, 1443 }, { 23, 1448 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 24, 1496 }, { 25, 1526 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 26, 1574 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 27, 1652 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+       },
+       {
+               {       /* Third byte table 0. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { 0, 0 },
+                       { 1, 60 }, { 2, 123 }, { 3, 185 }, { 4, 257 },
+                       { 5, 321 }, { 6, 383 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 7, 401 }, { 8, 467 },
+                       { 9, 505 }, { 10, 601 }, { 11, 633 }, { 12, 689 },
+                       { 13, 753 }, { 14, 803 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 15, 849 }, { 16, 945 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 17, 963 }, { 18, 1059 }, { 19, 1155 }, { 20, 1236 },
+                       { 21, 1323 }, { 22, 1413 }, { 23, 1467 }, { 24, 1554 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 25, 1611 }, { 26, 1619 }, { 27, 1667 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 28, 1670 }, { 29, 1700 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 30, 1748 }, { 31, 1889 }, { 32, 1911 }, { 33, 2007 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 34, 2061 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 35, 2139 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+       },
+};
+
+static const uchar_t u8_tolower_b4_tbl[2][36][257] = {
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  49,  49,  51,  51,  53,  53,  55,
+                       55,  55,  57,  57,  59,  59,  61,  61,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   8,   10,  10,  12,  12,  14,
+                       14,  16,  16,  18,  18,  20,  20,  22,
+                       22,  24,  24,  26,  26,  28,  28,  30,
+                       30,  32,  32,  34,  34,  36,  36,  38,
+                       38,  40,  40,  42,  42,  44,  44,  46,
+                       46,  48,  48,  50,  50,  52,  52,  54,
+                       54,  56,  58,  58,  60,  60,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   4,   4,   6,   6,   8,
+                       10,  10,  12,  14,  16,  16,  16,  18,
+                       20,  22,  24,  24,  26,  28,  28,  30,
+                       32,  34,  34,  34,  34,  36,  38,  38,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       50,  50,  52,  52,  52,  54,  54,  56,
+                       58,  58,  60,  62,  64,  64,  66,  66,
+                       68,  70,  70,  70,  70,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   2,   4,   4,
+                       6,   8,   8,   10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  28,  30,
+                       30,  32,  32,  34,  34,  36,  36,  38,
+                       38,  40,  40,  42,  42,  44,  44,  46,
+                       46,  46,  48,  50,  50,  52,  52,  54,
+                       56,  58,  58,  60,  60,  62,  62,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  50,  50,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   2,
+                       2,   4,   6,   8,   8,   10,  10,  12,
+                       14,  14,  16,  18,  20,  22,  24,  26,
+                       28,  30,  32,  34,  36,  38,  40,  42,
+                       44,  46,  48,  48,  50,  52,  54,  56,
+                       58,  60,  62,  64,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  24,  24,  24,  24,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  66,  68,  70,  72,  74,  76,  78,
+                       80,  82,  84,  86,  88,  90,  92,  94,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  50,  50,  52,  52,  54,  54,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       14,  16,  16,  18,  18,  20,  20,  22,
+                       22,  24,  24,  26,  26,  28,  28,  30,
+                       30,  32,  32,  34,  34,  36,  36,  38,
+                       38,  40,  40,  42,  42,  44,  44,  46,
+                       46,  48,  48,  50,  50,  52,  52,  52,
+                       52,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  18,  20,  22,  24,  26,  28,
+                       30,  32,  34,  36,  38,  40,  42,  44,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  90,  90,  93,  93,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  90,  90,  93,  93,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  33,
+                       33,  33,  33,  33,  33,  33,  33,  33,
+                       33,  36,  36,  39,  39,  42,  42,  45,
+                       45,  48,  48,  51,  51,  54,  54,  57,
+                       57,  60,  60,  63,  63,  66,  66,  69,
+                       69,  72,  72,  75,  75,  78,  78,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  45,  48,  51,  54,  57,  60,  63,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  69,  72,  75,  78,  81,  84,  87,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  21,  21,  24,  24,  27,  27,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  33,  36,  39,  42,  45,  48,  51,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  75,  78,  81,  84,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  18,  21,  24,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  30,  33,  36,  39,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  45,  48,  51,  54,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   2,
+                       2,   2,   2,   3,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,   5,   5,   5,   5,   5,   5,   5,
+                       5,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   3,
+                       6,   9,   12,  15,  18,  21,  24,  27,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   6,   9,   12,  15,  18,
+                       21,  24,  27,  30,  33,  36,  39,  42,
+                       45,  48,  51,  54,  57,  60,  63,  66,
+                       69,  72,  75,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 116, 120, 124,
+                       128, 132, 136, 140, 144, 148, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152, 152, 152, 152, 152, 152, 152, 152,
+                       152,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+       },
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,  60,  60,  60,  60,  60,  60,  60,
+                       60,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  49,  49,  51,  51,  53,  53,  55,
+                       55,  55,  57,  57,  59,  59,  61,  61,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   8,   10,  10,  12,  12,  14,
+                       14,  16,  16,  18,  18,  20,  20,  22,
+                       22,  24,  24,  26,  26,  28,  28,  30,
+                       30,  32,  32,  34,  34,  36,  36,  38,
+                       38,  40,  40,  42,  42,  44,  44,  46,
+                       46,  48,  48,  50,  50,  52,  52,  54,
+                       54,  56,  58,  58,  60,  60,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   4,   4,   6,   6,   8,
+                       10,  10,  12,  14,  16,  16,  16,  18,
+                       20,  22,  24,  24,  26,  28,  28,  30,
+                       32,  34,  34,  34,  34,  36,  38,  38,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       50,  50,  52,  52,  52,  54,  54,  56,
+                       58,  58,  60,  62,  64,  64,  66,  66,
+                       68,  70,  70,  70,  70,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   2,   4,   4,
+                       6,   8,   8,   10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  28,  30,
+                       30,  32,  32,  34,  34,  36,  36,  38,
+                       38,  40,  40,  42,  42,  44,  44,  46,
+                       46,  46,  48,  50,  50,  52,  52,  54,
+                       56,  58,  58,  60,  60,  62,  62,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  50,  50,  52,  52,  52,  52,  52,
+                       52,  52,  52,  55,  57,  57,  59,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   6,   8,   10,
+                       10,  12,  12,  14,  14,  16,  16,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   2,
+                       2,   4,   6,   8,   8,   10,  10,  12,
+                       14,  14,  16,  18,  20,  22,  24,  26,
+                       28,  30,  32,  34,  36,  38,  40,  42,
+                       44,  46,  48,  48,  50,  52,  54,  56,
+                       58,  60,  62,  64,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  24,  24,  24,  24,  26,  26,  26,
+                       28,  28,  30,  32,  32,  32,  34,  36,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  66,  68,  70,  72,  74,  76,  78,
+                       80,  82,  84,  86,  88,  90,  92,  94,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  50,  50,  52,  52,  54,  54,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   4,   6,   6,   8,   8,
+                       10,  10,  12,  12,  14,  14,  16,  16,
+                       16,  18,  18,  20,  20,  22,  22,  24,
+                       24,  26,  26,  28,  28,  30,  30,  32,
+                       32,  34,  34,  36,  36,  38,  38,  40,
+                       40,  42,  42,  44,  44,  46,  46,  48,
+                       48,  50,  50,  52,  52,  54,  54,  56,
+                       56,  58,  58,  60,  60,  62,  62,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  12,  12,  14,  14,  16,
+                       16,  18,  18,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  22,  24,  26,  28,  30,  32,
+                       34,  36,  38,  40,  42,  44,  46,  48,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,  46,  46,  46,  46,  46,  46,  46,
+                       46,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  90,  90,  93,  93,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  90,  90,  93,  93,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  33,
+                       33,  33,  33,  33,  33,  33,  33,  33,
+                       33,  36,  36,  39,  39,  42,  42,  45,
+                       45,  48,  48,  51,  51,  54,  54,  57,
+                       57,  60,  60,  63,  63,  66,  66,  69,
+                       69,  72,  72,  75,  75,  78,  78,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  81,
+                       81,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  45,  48,  51,  54,  57,  60,  63,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  69,  72,  75,  78,  81,  84,  87,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  21,  21,  24,  24,  27,  27,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  33,  36,  39,  42,  45,  48,  51,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  75,  78,  81,  84,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  15,  15,
+                       15,  15,  15,  15,  15,  15,  15,  15,
+                       15,  18,  21,  24,  27,  27,  27,  27,
+                       27,  27,  27,  27,  27,  27,  27,  27,
+                       27,  30,  33,  36,  39,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  45,  48,  51,  54,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,  57,  57,  57,  57,  57,  57,  57,
+                       57,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   2,
+                       2,   2,   2,   3,   5,   5,   5,   5,
+                       5,   5,   5,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   3,
+                       6,   9,   12,  15,  18,  21,  24,  27,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 117,
+                       120, 123, 126, 129, 132, 135, 138, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141, 141, 141, 141, 141, 141, 141, 141,
+                       141,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   5,   8,   10,  10,  10,
+                       13,  13,  16,  16,  19,  19,  19,  19,
+                       19,  19,  19,  19,  19,  19,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,  22,  22,  22,  22,  22,  22,  22,
+                       22,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  57,  57,  60,
+                       60,  63,  63,  66,  66,  69,  69,  72,
+                       72,  75,  75,  78,  78,  81,  81,  84,
+                       84,  87,  87,  90,  90,  93,  93,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   3,   6,   6,   9,   9,   12,
+                       12,  15,  15,  18,  18,  21,  21,  24,
+                       24,  27,  27,  30,  30,  33,  33,  36,
+                       36,  39,  39,  42,  42,  45,  45,  48,
+                       48,  51,  51,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   6,   9,   12,  15,  18,
+                       21,  24,  27,  30,  33,  36,  39,  42,
+                       45,  48,  51,  54,  57,  60,  63,  66,
+                       69,  72,  75,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  100, 104, 108, 112, 116, 120, 124,
+                       128, 132, 136, 140, 144, 148, 152, 156,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160, 160, 160, 160, 160, 160, 160, 160,
+                       160,
+               },
+       },
+};
+
+static const uchar_t u8_tolower_final_tbl[2][2299] = {
+       {
+               0xC3, 0xA0, 0xC3, 0xA1, 0xC3, 0xA2, 0xC3, 0xA3,
+               0xC3, 0xA4, 0xC3, 0xA5, 0xC3, 0xA6, 0xC3, 0xA7,
+               0xC3, 0xA8, 0xC3, 0xA9, 0xC3, 0xAA, 0xC3, 0xAB,
+               0xC3, 0xAC, 0xC3, 0xAD, 0xC3, 0xAE, 0xC3, 0xAF,
+               0xC3, 0xB0, 0xC3, 0xB1, 0xC3, 0xB2, 0xC3, 0xB3,
+               0xC3, 0xB4, 0xC3, 0xB5, 0xC3, 0xB6, 0xC3, 0xB8,
+               0xC3, 0xB9, 0xC3, 0xBA, 0xC3, 0xBB, 0xC3, 0xBC,
+               0xC3, 0xBD, 0xC3, 0xBE, 0xC4, 0x81, 0xC4, 0x83,
+               0xC4, 0x85, 0xC4, 0x87, 0xC4, 0x89, 0xC4, 0x8B,
+               0xC4, 0x8D, 0xC4, 0x8F, 0xC4, 0x91, 0xC4, 0x93,
+               0xC4, 0x95, 0xC4, 0x97, 0xC4, 0x99, 0xC4, 0x9B,
+               0xC4, 0x9D, 0xC4, 0x9F, 0xC4, 0xA1, 0xC4, 0xA3,
+               0xC4, 0xA5, 0xC4, 0xA7, 0xC4, 0xA9, 0xC4, 0xAB,
+               0xC4, 0xAD, 0xC4, 0xAF, 0x69, 0xC4, 0xB3, 0xC4,
+               0xB5, 0xC4, 0xB7, 0xC4, 0xBA, 0xC4, 0xBC, 0xC4,
+               0xBE, 0xC5, 0x80, 0xC5, 0x82, 0xC5, 0x84, 0xC5,
+               0x86, 0xC5, 0x88, 0xC5, 0x8B, 0xC5, 0x8D, 0xC5,
+               0x8F, 0xC5, 0x91, 0xC5, 0x93, 0xC5, 0x95, 0xC5,
+               0x97, 0xC5, 0x99, 0xC5, 0x9B, 0xC5, 0x9D, 0xC5,
+               0x9F, 0xC5, 0xA1, 0xC5, 0xA3, 0xC5, 0xA5, 0xC5,
+               0xA7, 0xC5, 0xA9, 0xC5, 0xAB, 0xC5, 0xAD, 0xC5,
+               0xAF, 0xC5, 0xB1, 0xC5, 0xB3, 0xC5, 0xB5, 0xC5,
+               0xB7, 0xC3, 0xBF, 0xC5, 0xBA, 0xC5, 0xBC, 0xC5,
+               0xBE, 0xC9, 0x93, 0xC6, 0x83, 0xC6, 0x85, 0xC9,
+               0x94, 0xC6, 0x88, 0xC9, 0x96, 0xC9, 0x97, 0xC6,
+               0x8C, 0xC7, 0x9D, 0xC9, 0x99, 0xC9, 0x9B, 0xC6,
+               0x92, 0xC9, 0xA0, 0xC9, 0xA3, 0xC9, 0xA9, 0xC9,
+               0xA8, 0xC6, 0x99, 0xC9, 0xAF, 0xC9, 0xB2, 0xC9,
+               0xB5, 0xC6, 0xA1, 0xC6, 0xA3, 0xC6, 0xA5, 0xCA,
+               0x80, 0xC6, 0xA8, 0xCA, 0x83, 0xC6, 0xAD, 0xCA,
+               0x88, 0xC6, 0xB0, 0xCA, 0x8A, 0xCA, 0x8B, 0xC6,
+               0xB4, 0xC6, 0xB6, 0xCA, 0x92, 0xC6, 0xB9, 0xC6,
+               0xBD, 0xC7, 0x86, 0xC7, 0x86, 0xC7, 0x89, 0xC7,
+               0x89, 0xC7, 0x8C, 0xC7, 0x8C, 0xC7, 0x8E, 0xC7,
+               0x90, 0xC7, 0x92, 0xC7, 0x94, 0xC7, 0x96, 0xC7,
+               0x98, 0xC7, 0x9A, 0xC7, 0x9C, 0xC7, 0x9F, 0xC7,
+               0xA1, 0xC7, 0xA3, 0xC7, 0xA5, 0xC7, 0xA7, 0xC7,
+               0xA9, 0xC7, 0xAB, 0xC7, 0xAD, 0xC7, 0xAF, 0xC7,
+               0xB3, 0xC7, 0xB3, 0xC7, 0xB5, 0xC6, 0x95, 0xC6,
+               0xBF, 0xC7, 0xB9, 0xC7, 0xBB, 0xC7, 0xBD, 0xC7,
+               0xBF, 0xC8, 0x81, 0xC8, 0x83, 0xC8, 0x85, 0xC8,
+               0x87, 0xC8, 0x89, 0xC8, 0x8B, 0xC8, 0x8D, 0xC8,
+               0x8F, 0xC8, 0x91, 0xC8, 0x93, 0xC8, 0x95, 0xC8,
+               0x97, 0xC8, 0x99, 0xC8, 0x9B, 0xC8, 0x9D, 0xC8,
+               0x9F, 0xC6, 0x9E, 0xC8, 0xA3, 0xC8, 0xA5, 0xC8,
+               0xA7, 0xC8, 0xA9, 0xC8, 0xAB, 0xC8, 0xAD, 0xC8,
+               0xAF, 0xC8, 0xB1, 0xC8, 0xB3, 0xCE, 0xAC, 0xCE,
+               0xAD, 0xCE, 0xAE, 0xCE, 0xAF, 0xCF, 0x8C, 0xCF,
+               0x8D, 0xCF, 0x8E, 0xCE, 0xB1, 0xCE, 0xB2, 0xCE,
+               0xB3, 0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6, 0xCE,
+               0xB7, 0xCE, 0xB8, 0xCE, 0xB9, 0xCE, 0xBA, 0xCE,
+               0xBB, 0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE, 0xCE,
+               0xBF, 0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x83, 0xCF,
+               0x84, 0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87, 0xCF,
+               0x88, 0xCF, 0x89, 0xCF, 0x8A, 0xCF, 0x8B, 0xCF,
+               0x99, 0xCF, 0x9B, 0xCF, 0x9D, 0xCF, 0x9F, 0xCF,
+               0xA1, 0xCF, 0xA3, 0xCF, 0xA5, 0xCF, 0xA7, 0xCF,
+               0xA9, 0xCF, 0xAB, 0xCF, 0xAD, 0xCF, 0xAF, 0xCE,
+               0xB8, 0xD1, 0x90, 0xD1, 0x91, 0xD1, 0x92, 0xD1,
+               0x93, 0xD1, 0x94, 0xD1, 0x95, 0xD1, 0x96, 0xD1,
+               0x97, 0xD1, 0x98, 0xD1, 0x99, 0xD1, 0x9A, 0xD1,
+               0x9B, 0xD1, 0x9C, 0xD1, 0x9D, 0xD1, 0x9E, 0xD1,
+               0x9F, 0xD0, 0xB0, 0xD0, 0xB1, 0xD0, 0xB2, 0xD0,
+               0xB3, 0xD0, 0xB4, 0xD0, 0xB5, 0xD0, 0xB6, 0xD0,
+               0xB7, 0xD0, 0xB8, 0xD0, 0xB9, 0xD0, 0xBA, 0xD0,
+               0xBB, 0xD0, 0xBC, 0xD0, 0xBD, 0xD0, 0xBE, 0xD0,
+               0xBF, 0xD1, 0x80, 0xD1, 0x81, 0xD1, 0x82, 0xD1,
+               0x83, 0xD1, 0x84, 0xD1, 0x85, 0xD1, 0x86, 0xD1,
+               0x87, 0xD1, 0x88, 0xD1, 0x89, 0xD1, 0x8A, 0xD1,
+               0x8B, 0xD1, 0x8C, 0xD1, 0x8D, 0xD1, 0x8E, 0xD1,
+               0x8F, 0xD1, 0xA1, 0xD1, 0xA3, 0xD1, 0xA5, 0xD1,
+               0xA7, 0xD1, 0xA9, 0xD1, 0xAB, 0xD1, 0xAD, 0xD1,
+               0xAF, 0xD1, 0xB1, 0xD1, 0xB3, 0xD1, 0xB5, 0xD1,
+               0xB7, 0xD1, 0xB9, 0xD1, 0xBB, 0xD1, 0xBD, 0xD1,
+               0xBF, 0xD2, 0x81, 0xD2, 0x8B, 0xD2, 0x8D, 0xD2,
+               0x8F, 0xD2, 0x91, 0xD2, 0x93, 0xD2, 0x95, 0xD2,
+               0x97, 0xD2, 0x99, 0xD2, 0x9B, 0xD2, 0x9D, 0xD2,
+               0x9F, 0xD2, 0xA1, 0xD2, 0xA3, 0xD2, 0xA5, 0xD2,
+               0xA7, 0xD2, 0xA9, 0xD2, 0xAB, 0xD2, 0xAD, 0xD2,
+               0xAF, 0xD2, 0xB1, 0xD2, 0xB3, 0xD2, 0xB5, 0xD2,
+               0xB7, 0xD2, 0xB9, 0xD2, 0xBB, 0xD2, 0xBD, 0xD2,
+               0xBF, 0xD3, 0x82, 0xD3, 0x84, 0xD3, 0x86, 0xD3,
+               0x88, 0xD3, 0x8A, 0xD3, 0x8C, 0xD3, 0x8E, 0xD3,
+               0x91, 0xD3, 0x93, 0xD3, 0x95, 0xD3, 0x97, 0xD3,
+               0x99, 0xD3, 0x9B, 0xD3, 0x9D, 0xD3, 0x9F, 0xD3,
+               0xA1, 0xD3, 0xA3, 0xD3, 0xA5, 0xD3, 0xA7, 0xD3,
+               0xA9, 0xD3, 0xAB, 0xD3, 0xAD, 0xD3, 0xAF, 0xD3,
+               0xB1, 0xD3, 0xB3, 0xD3, 0xB5, 0xD3, 0xB9, 0xD4,
+               0x81, 0xD4, 0x83, 0xD4, 0x85, 0xD4, 0x87, 0xD4,
+               0x89, 0xD4, 0x8B, 0xD4, 0x8D, 0xD4, 0x8F, 0xD5,
+               0xA1, 0xD5, 0xA2, 0xD5, 0xA3, 0xD5, 0xA4, 0xD5,
+               0xA5, 0xD5, 0xA6, 0xD5, 0xA7, 0xD5, 0xA8, 0xD5,
+               0xA9, 0xD5, 0xAA, 0xD5, 0xAB, 0xD5, 0xAC, 0xD5,
+               0xAD, 0xD5, 0xAE, 0xD5, 0xAF, 0xD5, 0xB0, 0xD5,
+               0xB1, 0xD5, 0xB2, 0xD5, 0xB3, 0xD5, 0xB4, 0xD5,
+               0xB5, 0xD5, 0xB6, 0xD5, 0xB7, 0xD5, 0xB8, 0xD5,
+               0xB9, 0xD5, 0xBA, 0xD5, 0xBB, 0xD5, 0xBC, 0xD5,
+               0xBD, 0xD5, 0xBE, 0xD5, 0xBF, 0xD6, 0x80, 0xD6,
+               0x81, 0xD6, 0x82, 0xD6, 0x83, 0xD6, 0x84, 0xD6,
+               0x85, 0xD6, 0x86, 0xE1, 0xB8, 0x81, 0xE1, 0xB8,
+               0x83, 0xE1, 0xB8, 0x85, 0xE1, 0xB8, 0x87, 0xE1,
+               0xB8, 0x89, 0xE1, 0xB8, 0x8B, 0xE1, 0xB8, 0x8D,
+               0xE1, 0xB8, 0x8F, 0xE1, 0xB8, 0x91, 0xE1, 0xB8,
+               0x93, 0xE1, 0xB8, 0x95, 0xE1, 0xB8, 0x97, 0xE1,
+               0xB8, 0x99, 0xE1, 0xB8, 0x9B, 0xE1, 0xB8, 0x9D,
+               0xE1, 0xB8, 0x9F, 0xE1, 0xB8, 0xA1, 0xE1, 0xB8,
+               0xA3, 0xE1, 0xB8, 0xA5, 0xE1, 0xB8, 0xA7, 0xE1,
+               0xB8, 0xA9, 0xE1, 0xB8, 0xAB, 0xE1, 0xB8, 0xAD,
+               0xE1, 0xB8, 0xAF, 0xE1, 0xB8, 0xB1, 0xE1, 0xB8,
+               0xB3, 0xE1, 0xB8, 0xB5, 0xE1, 0xB8, 0xB7, 0xE1,
+               0xB8, 0xB9, 0xE1, 0xB8, 0xBB, 0xE1, 0xB8, 0xBD,
+               0xE1, 0xB8, 0xBF, 0xE1, 0xB9, 0x81, 0xE1, 0xB9,
+               0x83, 0xE1, 0xB9, 0x85, 0xE1, 0xB9, 0x87, 0xE1,
+               0xB9, 0x89, 0xE1, 0xB9, 0x8B, 0xE1, 0xB9, 0x8D,
+               0xE1, 0xB9, 0x8F, 0xE1, 0xB9, 0x91, 0xE1, 0xB9,
+               0x93, 0xE1, 0xB9, 0x95, 0xE1, 0xB9, 0x97, 0xE1,
+               0xB9, 0x99, 0xE1, 0xB9, 0x9B, 0xE1, 0xB9, 0x9D,
+               0xE1, 0xB9, 0x9F, 0xE1, 0xB9, 0xA1, 0xE1, 0xB9,
+               0xA3, 0xE1, 0xB9, 0xA5, 0xE1, 0xB9, 0xA7, 0xE1,
+               0xB9, 0xA9, 0xE1, 0xB9, 0xAB, 0xE1, 0xB9, 0xAD,
+               0xE1, 0xB9, 0xAF, 0xE1, 0xB9, 0xB1, 0xE1, 0xB9,
+               0xB3, 0xE1, 0xB9, 0xB5, 0xE1, 0xB9, 0xB7, 0xE1,
+               0xB9, 0xB9, 0xE1, 0xB9, 0xBB, 0xE1, 0xB9, 0xBD,
+               0xE1, 0xB9, 0xBF, 0xE1, 0xBA, 0x81, 0xE1, 0xBA,
+               0x83, 0xE1, 0xBA, 0x85, 0xE1, 0xBA, 0x87, 0xE1,
+               0xBA, 0x89, 0xE1, 0xBA, 0x8B, 0xE1, 0xBA, 0x8D,
+               0xE1, 0xBA, 0x8F, 0xE1, 0xBA, 0x91, 0xE1, 0xBA,
+               0x93, 0xE1, 0xBA, 0x95, 0xE1, 0xBA, 0xA1, 0xE1,
+               0xBA, 0xA3, 0xE1, 0xBA, 0xA5, 0xE1, 0xBA, 0xA7,
+               0xE1, 0xBA, 0xA9, 0xE1, 0xBA, 0xAB, 0xE1, 0xBA,
+               0xAD, 0xE1, 0xBA, 0xAF, 0xE1, 0xBA, 0xB1, 0xE1,
+               0xBA, 0xB3, 0xE1, 0xBA, 0xB5, 0xE1, 0xBA, 0xB7,
+               0xE1, 0xBA, 0xB9, 0xE1, 0xBA, 0xBB, 0xE1, 0xBA,
+               0xBD, 0xE1, 0xBA, 0xBF, 0xE1, 0xBB, 0x81, 0xE1,
+               0xBB, 0x83, 0xE1, 0xBB, 0x85, 0xE1, 0xBB, 0x87,
+               0xE1, 0xBB, 0x89, 0xE1, 0xBB, 0x8B, 0xE1, 0xBB,
+               0x8D, 0xE1, 0xBB, 0x8F, 0xE1, 0xBB, 0x91, 0xE1,
+               0xBB, 0x93, 0xE1, 0xBB, 0x95, 0xE1, 0xBB, 0x97,
+               0xE1, 0xBB, 0x99, 0xE1, 0xBB, 0x9B, 0xE1, 0xBB,
+               0x9D, 0xE1, 0xBB, 0x9F, 0xE1, 0xBB, 0xA1, 0xE1,
+               0xBB, 0xA3, 0xE1, 0xBB, 0xA5, 0xE1, 0xBB, 0xA7,
+               0xE1, 0xBB, 0xA9, 0xE1, 0xBB, 0xAB, 0xE1, 0xBB,
+               0xAD, 0xE1, 0xBB, 0xAF, 0xE1, 0xBB, 0xB1, 0xE1,
+               0xBB, 0xB3, 0xE1, 0xBB, 0xB5, 0xE1, 0xBB, 0xB7,
+               0xE1, 0xBB, 0xB9, 0xE1, 0xBC, 0x80, 0xE1, 0xBC,
+               0x81, 0xE1, 0xBC, 0x82, 0xE1, 0xBC, 0x83, 0xE1,
+               0xBC, 0x84, 0xE1, 0xBC, 0x85, 0xE1, 0xBC, 0x86,
+               0xE1, 0xBC, 0x87, 0xE1, 0xBC, 0x90, 0xE1, 0xBC,
+               0x91, 0xE1, 0xBC, 0x92, 0xE1, 0xBC, 0x93, 0xE1,
+               0xBC, 0x94, 0xE1, 0xBC, 0x95, 0xE1, 0xBC, 0xA0,
+               0xE1, 0xBC, 0xA1, 0xE1, 0xBC, 0xA2, 0xE1, 0xBC,
+               0xA3, 0xE1, 0xBC, 0xA4, 0xE1, 0xBC, 0xA5, 0xE1,
+               0xBC, 0xA6, 0xE1, 0xBC, 0xA7, 0xE1, 0xBC, 0xB0,
+               0xE1, 0xBC, 0xB1, 0xE1, 0xBC, 0xB2, 0xE1, 0xBC,
+               0xB3, 0xE1, 0xBC, 0xB4, 0xE1, 0xBC, 0xB5, 0xE1,
+               0xBC, 0xB6, 0xE1, 0xBC, 0xB7, 0xE1, 0xBD, 0x80,
+               0xE1, 0xBD, 0x81, 0xE1, 0xBD, 0x82, 0xE1, 0xBD,
+               0x83, 0xE1, 0xBD, 0x84, 0xE1, 0xBD, 0x85, 0xE1,
+               0xBD, 0x91, 0xE1, 0xBD, 0x93, 0xE1, 0xBD, 0x95,
+               0xE1, 0xBD, 0x97, 0xE1, 0xBD, 0xA0, 0xE1, 0xBD,
+               0xA1, 0xE1, 0xBD, 0xA2, 0xE1, 0xBD, 0xA3, 0xE1,
+               0xBD, 0xA4, 0xE1, 0xBD, 0xA5, 0xE1, 0xBD, 0xA6,
+               0xE1, 0xBD, 0xA7, 0xE1, 0xBE, 0x80, 0xE1, 0xBE,
+               0x81, 0xE1, 0xBE, 0x82, 0xE1, 0xBE, 0x83, 0xE1,
+               0xBE, 0x84, 0xE1, 0xBE, 0x85, 0xE1, 0xBE, 0x86,
+               0xE1, 0xBE, 0x87, 0xE1, 0xBE, 0x90, 0xE1, 0xBE,
+               0x91, 0xE1, 0xBE, 0x92, 0xE1, 0xBE, 0x93, 0xE1,
+               0xBE, 0x94, 0xE1, 0xBE, 0x95, 0xE1, 0xBE, 0x96,
+               0xE1, 0xBE, 0x97, 0xE1, 0xBE, 0xA0, 0xE1, 0xBE,
+               0xA1, 0xE1, 0xBE, 0xA2, 0xE1, 0xBE, 0xA3, 0xE1,
+               0xBE, 0xA4, 0xE1, 0xBE, 0xA5, 0xE1, 0xBE, 0xA6,
+               0xE1, 0xBE, 0xA7, 0xE1, 0xBE, 0xB0, 0xE1, 0xBE,
+               0xB1, 0xE1, 0xBD, 0xB0, 0xE1, 0xBD, 0xB1, 0xE1,
+               0xBE, 0xB3, 0xE1, 0xBD, 0xB2, 0xE1, 0xBD, 0xB3,
+               0xE1, 0xBD, 0xB4, 0xE1, 0xBD, 0xB5, 0xE1, 0xBF,
+               0x83, 0xE1, 0xBF, 0x90, 0xE1, 0xBF, 0x91, 0xE1,
+               0xBD, 0xB6, 0xE1, 0xBD, 0xB7, 0xE1, 0xBF, 0xA0,
+               0xE1, 0xBF, 0xA1, 0xE1, 0xBD, 0xBA, 0xE1, 0xBD,
+               0xBB, 0xE1, 0xBF, 0xA5, 0xE1, 0xBD, 0xB8, 0xE1,
+               0xBD, 0xB9, 0xE1, 0xBD, 0xBC, 0xE1, 0xBD, 0xBD,
+               0xE1, 0xBF, 0xB3, 0xCF, 0x89, 0x6B, 0xC3, 0xA5,
+               0xE2, 0x85, 0xB0, 0xE2, 0x85, 0xB1, 0xE2, 0x85,
+               0xB2, 0xE2, 0x85, 0xB3, 0xE2, 0x85, 0xB4, 0xE2,
+               0x85, 0xB5, 0xE2, 0x85, 0xB6, 0xE2, 0x85, 0xB7,
+               0xE2, 0x85, 0xB8, 0xE2, 0x85, 0xB9, 0xE2, 0x85,
+               0xBA, 0xE2, 0x85, 0xBB, 0xE2, 0x85, 0xBC, 0xE2,
+               0x85, 0xBD, 0xE2, 0x85, 0xBE, 0xE2, 0x85, 0xBF,
+               0xE2, 0x93, 0x90, 0xE2, 0x93, 0x91, 0xE2, 0x93,
+               0x92, 0xE2, 0x93, 0x93, 0xE2, 0x93, 0x94, 0xE2,
+               0x93, 0x95, 0xE2, 0x93, 0x96, 0xE2, 0x93, 0x97,
+               0xE2, 0x93, 0x98, 0xE2, 0x93, 0x99, 0xE2, 0x93,
+               0x9A, 0xE2, 0x93, 0x9B, 0xE2, 0x93, 0x9C, 0xE2,
+               0x93, 0x9D, 0xE2, 0x93, 0x9E, 0xE2, 0x93, 0x9F,
+               0xE2, 0x93, 0xA0, 0xE2, 0x93, 0xA1, 0xE2, 0x93,
+               0xA2, 0xE2, 0x93, 0xA3, 0xE2, 0x93, 0xA4, 0xE2,
+               0x93, 0xA5, 0xE2, 0x93, 0xA6, 0xE2, 0x93, 0xA7,
+               0xE2, 0x93, 0xA8, 0xE2, 0x93, 0xA9, 0xEF, 0xBD,
+               0x81, 0xEF, 0xBD, 0x82, 0xEF, 0xBD, 0x83, 0xEF,
+               0xBD, 0x84, 0xEF, 0xBD, 0x85, 0xEF, 0xBD, 0x86,
+               0xEF, 0xBD, 0x87, 0xEF, 0xBD, 0x88, 0xEF, 0xBD,
+               0x89, 0xEF, 0xBD, 0x8A, 0xEF, 0xBD, 0x8B, 0xEF,
+               0xBD, 0x8C, 0xEF, 0xBD, 0x8D, 0xEF, 0xBD, 0x8E,
+               0xEF, 0xBD, 0x8F, 0xEF, 0xBD, 0x90, 0xEF, 0xBD,
+               0x91, 0xEF, 0xBD, 0x92, 0xEF, 0xBD, 0x93, 0xEF,
+               0xBD, 0x94, 0xEF, 0xBD, 0x95, 0xEF, 0xBD, 0x96,
+               0xEF, 0xBD, 0x97, 0xEF, 0xBD, 0x98, 0xEF, 0xBD,
+               0x99, 0xEF, 0xBD, 0x9A, 0xF0, 0x90, 0x90, 0xA8,
+               0xF0, 0x90, 0x90, 0xA9, 0xF0, 0x90, 0x90, 0xAA,
+               0xF0, 0x90, 0x90, 0xAB, 0xF0, 0x90, 0x90, 0xAC,
+               0xF0, 0x90, 0x90, 0xAD, 0xF0, 0x90, 0x90, 0xAE,
+               0xF0, 0x90, 0x90, 0xAF, 0xF0, 0x90, 0x90, 0xB0,
+               0xF0, 0x90, 0x90, 0xB1, 0xF0, 0x90, 0x90, 0xB2,
+               0xF0, 0x90, 0x90, 0xB3, 0xF0, 0x90, 0x90, 0xB4,
+               0xF0, 0x90, 0x90, 0xB5, 0xF0, 0x90, 0x90, 0xB6,
+               0xF0, 0x90, 0x90, 0xB7, 0xF0, 0x90, 0x90, 0xB8,
+               0xF0, 0x90, 0x90, 0xB9, 0xF0, 0x90, 0x90, 0xBA,
+               0xF0, 0x90, 0x90, 0xBB, 0xF0, 0x90, 0x90, 0xBC,
+               0xF0, 0x90, 0x90, 0xBD, 0xF0, 0x90, 0x90, 0xBE,
+               0xF0, 0x90, 0x90, 0xBF, 0xF0, 0x90, 0x91, 0x80,
+               0xF0, 0x90, 0x91, 0x81, 0xF0, 0x90, 0x91, 0x82,
+               0xF0, 0x90, 0x91, 0x83, 0xF0, 0x90, 0x91, 0x84,
+               0xF0, 0x90, 0x91, 0x85, 0xF0, 0x90, 0x91, 0x86,
+               0xF0, 0x90, 0x91, 0x87, 0xF0, 0x90, 0x91, 0x88,
+               0xF0, 0x90, 0x91, 0x89, 0xF0, 0x90, 0x91, 0x8A,
+               0xF0, 0x90, 0x91, 0x8B, 0xF0, 0x90, 0x91, 0x8C,
+               0xF0, 0x90, 0x91, 0x8D, 0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,
+       },
+       {
+               0xC3, 0xA0, 0xC3, 0xA1, 0xC3, 0xA2, 0xC3, 0xA3,
+               0xC3, 0xA4, 0xC3, 0xA5, 0xC3, 0xA6, 0xC3, 0xA7,
+               0xC3, 0xA8, 0xC3, 0xA9, 0xC3, 0xAA, 0xC3, 0xAB,
+               0xC3, 0xAC, 0xC3, 0xAD, 0xC3, 0xAE, 0xC3, 0xAF,
+               0xC3, 0xB0, 0xC3, 0xB1, 0xC3, 0xB2, 0xC3, 0xB3,
+               0xC3, 0xB4, 0xC3, 0xB5, 0xC3, 0xB6, 0xC3, 0xB8,
+               0xC3, 0xB9, 0xC3, 0xBA, 0xC3, 0xBB, 0xC3, 0xBC,
+               0xC3, 0xBD, 0xC3, 0xBE, 0xC4, 0x81, 0xC4, 0x83,
+               0xC4, 0x85, 0xC4, 0x87, 0xC4, 0x89, 0xC4, 0x8B,
+               0xC4, 0x8D, 0xC4, 0x8F, 0xC4, 0x91, 0xC4, 0x93,
+               0xC4, 0x95, 0xC4, 0x97, 0xC4, 0x99, 0xC4, 0x9B,
+               0xC4, 0x9D, 0xC4, 0x9F, 0xC4, 0xA1, 0xC4, 0xA3,
+               0xC4, 0xA5, 0xC4, 0xA7, 0xC4, 0xA9, 0xC4, 0xAB,
+               0xC4, 0xAD, 0xC4, 0xAF, 0x69, 0xC4, 0xB3, 0xC4,
+               0xB5, 0xC4, 0xB7, 0xC4, 0xBA, 0xC4, 0xBC, 0xC4,
+               0xBE, 0xC5, 0x80, 0xC5, 0x82, 0xC5, 0x84, 0xC5,
+               0x86, 0xC5, 0x88, 0xC5, 0x8B, 0xC5, 0x8D, 0xC5,
+               0x8F, 0xC5, 0x91, 0xC5, 0x93, 0xC5, 0x95, 0xC5,
+               0x97, 0xC5, 0x99, 0xC5, 0x9B, 0xC5, 0x9D, 0xC5,
+               0x9F, 0xC5, 0xA1, 0xC5, 0xA3, 0xC5, 0xA5, 0xC5,
+               0xA7, 0xC5, 0xA9, 0xC5, 0xAB, 0xC5, 0xAD, 0xC5,
+               0xAF, 0xC5, 0xB1, 0xC5, 0xB3, 0xC5, 0xB5, 0xC5,
+               0xB7, 0xC3, 0xBF, 0xC5, 0xBA, 0xC5, 0xBC, 0xC5,
+               0xBE, 0xC9, 0x93, 0xC6, 0x83, 0xC6, 0x85, 0xC9,
+               0x94, 0xC6, 0x88, 0xC9, 0x96, 0xC9, 0x97, 0xC6,
+               0x8C, 0xC7, 0x9D, 0xC9, 0x99, 0xC9, 0x9B, 0xC6,
+               0x92, 0xC9, 0xA0, 0xC9, 0xA3, 0xC9, 0xA9, 0xC9,
+               0xA8, 0xC6, 0x99, 0xC9, 0xAF, 0xC9, 0xB2, 0xC9,
+               0xB5, 0xC6, 0xA1, 0xC6, 0xA3, 0xC6, 0xA5, 0xCA,
+               0x80, 0xC6, 0xA8, 0xCA, 0x83, 0xC6, 0xAD, 0xCA,
+               0x88, 0xC6, 0xB0, 0xCA, 0x8A, 0xCA, 0x8B, 0xC6,
+               0xB4, 0xC6, 0xB6, 0xCA, 0x92, 0xC6, 0xB9, 0xC6,
+               0xBD, 0xC7, 0x86, 0xC7, 0x86, 0xC7, 0x89, 0xC7,
+               0x89, 0xC7, 0x8C, 0xC7, 0x8C, 0xC7, 0x8E, 0xC7,
+               0x90, 0xC7, 0x92, 0xC7, 0x94, 0xC7, 0x96, 0xC7,
+               0x98, 0xC7, 0x9A, 0xC7, 0x9C, 0xC7, 0x9F, 0xC7,
+               0xA1, 0xC7, 0xA3, 0xC7, 0xA5, 0xC7, 0xA7, 0xC7,
+               0xA9, 0xC7, 0xAB, 0xC7, 0xAD, 0xC7, 0xAF, 0xC7,
+               0xB3, 0xC7, 0xB3, 0xC7, 0xB5, 0xC6, 0x95, 0xC6,
+               0xBF, 0xC7, 0xB9, 0xC7, 0xBB, 0xC7, 0xBD, 0xC7,
+               0xBF, 0xC8, 0x81, 0xC8, 0x83, 0xC8, 0x85, 0xC8,
+               0x87, 0xC8, 0x89, 0xC8, 0x8B, 0xC8, 0x8D, 0xC8,
+               0x8F, 0xC8, 0x91, 0xC8, 0x93, 0xC8, 0x95, 0xC8,
+               0x97, 0xC8, 0x99, 0xC8, 0x9B, 0xC8, 0x9D, 0xC8,
+               0x9F, 0xC6, 0x9E, 0xC8, 0xA3, 0xC8, 0xA5, 0xC8,
+               0xA7, 0xC8, 0xA9, 0xC8, 0xAB, 0xC8, 0xAD, 0xC8,
+               0xAF, 0xC8, 0xB1, 0xC8, 0xB3, 0xE2, 0xB1, 0xA5,
+               0xC8, 0xBC, 0xC6, 0x9A, 0xE2, 0xB1, 0xA6, 0xC9,
+               0x82, 0xC6, 0x80, 0xCA, 0x89, 0xCA, 0x8C, 0xC9,
+               0x87, 0xC9, 0x89, 0xC9, 0x8B, 0xC9, 0x8D, 0xC9,
+               0x8F, 0xCE, 0xAC, 0xCE, 0xAD, 0xCE, 0xAE, 0xCE,
+               0xAF, 0xCF, 0x8C, 0xCF, 0x8D, 0xCF, 0x8E, 0xCE,
+               0xB1, 0xCE, 0xB2, 0xCE, 0xB3, 0xCE, 0xB4, 0xCE,
+               0xB5, 0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8, 0xCE,
+               0xB9, 0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC, 0xCE,
+               0xBD, 0xCE, 0xBE, 0xCE, 0xBF, 0xCF, 0x80, 0xCF,
+               0x81, 0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85, 0xCF,
+               0x86, 0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89, 0xCF,
+               0x8A, 0xCF, 0x8B, 0xCF, 0x99, 0xCF, 0x9B, 0xCF,
+               0x9D, 0xCF, 0x9F, 0xCF, 0xA1, 0xCF, 0xA3, 0xCF,
+               0xA5, 0xCF, 0xA7, 0xCF, 0xA9, 0xCF, 0xAB, 0xCF,
+               0xAD, 0xCF, 0xAF, 0xCE, 0xB8, 0xCF, 0xB8, 0xCF,
+               0xB2, 0xCF, 0xBB, 0xCD, 0xBB, 0xCD, 0xBC, 0xCD,
+               0xBD, 0xD1, 0x90, 0xD1, 0x91, 0xD1, 0x92, 0xD1,
+               0x93, 0xD1, 0x94, 0xD1, 0x95, 0xD1, 0x96, 0xD1,
+               0x97, 0xD1, 0x98, 0xD1, 0x99, 0xD1, 0x9A, 0xD1,
+               0x9B, 0xD1, 0x9C, 0xD1, 0x9D, 0xD1, 0x9E, 0xD1,
+               0x9F, 0xD0, 0xB0, 0xD0, 0xB1, 0xD0, 0xB2, 0xD0,
+               0xB3, 0xD0, 0xB4, 0xD0, 0xB5, 0xD0, 0xB6, 0xD0,
+               0xB7, 0xD0, 0xB8, 0xD0, 0xB9, 0xD0, 0xBA, 0xD0,
+               0xBB, 0xD0, 0xBC, 0xD0, 0xBD, 0xD0, 0xBE, 0xD0,
+               0xBF, 0xD1, 0x80, 0xD1, 0x81, 0xD1, 0x82, 0xD1,
+               0x83, 0xD1, 0x84, 0xD1, 0x85, 0xD1, 0x86, 0xD1,
+               0x87, 0xD1, 0x88, 0xD1, 0x89, 0xD1, 0x8A, 0xD1,
+               0x8B, 0xD1, 0x8C, 0xD1, 0x8D, 0xD1, 0x8E, 0xD1,
+               0x8F, 0xD1, 0xA1, 0xD1, 0xA3, 0xD1, 0xA5, 0xD1,
+               0xA7, 0xD1, 0xA9, 0xD1, 0xAB, 0xD1, 0xAD, 0xD1,
+               0xAF, 0xD1, 0xB1, 0xD1, 0xB3, 0xD1, 0xB5, 0xD1,
+               0xB7, 0xD1, 0xB9, 0xD1, 0xBB, 0xD1, 0xBD, 0xD1,
+               0xBF, 0xD2, 0x81, 0xD2, 0x8B, 0xD2, 0x8D, 0xD2,
+               0x8F, 0xD2, 0x91, 0xD2, 0x93, 0xD2, 0x95, 0xD2,
+               0x97, 0xD2, 0x99, 0xD2, 0x9B, 0xD2, 0x9D, 0xD2,
+               0x9F, 0xD2, 0xA1, 0xD2, 0xA3, 0xD2, 0xA5, 0xD2,
+               0xA7, 0xD2, 0xA9, 0xD2, 0xAB, 0xD2, 0xAD, 0xD2,
+               0xAF, 0xD2, 0xB1, 0xD2, 0xB3, 0xD2, 0xB5, 0xD2,
+               0xB7, 0xD2, 0xB9, 0xD2, 0xBB, 0xD2, 0xBD, 0xD2,
+               0xBF, 0xD3, 0x8F, 0xD3, 0x82, 0xD3, 0x84, 0xD3,
+               0x86, 0xD3, 0x88, 0xD3, 0x8A, 0xD3, 0x8C, 0xD3,
+               0x8E, 0xD3, 0x91, 0xD3, 0x93, 0xD3, 0x95, 0xD3,
+               0x97, 0xD3, 0x99, 0xD3, 0x9B, 0xD3, 0x9D, 0xD3,
+               0x9F, 0xD3, 0xA1, 0xD3, 0xA3, 0xD3, 0xA5, 0xD3,
+               0xA7, 0xD3, 0xA9, 0xD3, 0xAB, 0xD3, 0xAD, 0xD3,
+               0xAF, 0xD3, 0xB1, 0xD3, 0xB3, 0xD3, 0xB5, 0xD3,
+               0xB7, 0xD3, 0xB9, 0xD3, 0xBB, 0xD3, 0xBD, 0xD3,
+               0xBF, 0xD4, 0x81, 0xD4, 0x83, 0xD4, 0x85, 0xD4,
+               0x87, 0xD4, 0x89, 0xD4, 0x8B, 0xD4, 0x8D, 0xD4,
+               0x8F, 0xD4, 0x91, 0xD4, 0x93, 0xD5, 0xA1, 0xD5,
+               0xA2, 0xD5, 0xA3, 0xD5, 0xA4, 0xD5, 0xA5, 0xD5,
+               0xA6, 0xD5, 0xA7, 0xD5, 0xA8, 0xD5, 0xA9, 0xD5,
+               0xAA, 0xD5, 0xAB, 0xD5, 0xAC, 0xD5, 0xAD, 0xD5,
+               0xAE, 0xD5, 0xAF, 0xD5, 0xB0, 0xD5, 0xB1, 0xD5,
+               0xB2, 0xD5, 0xB3, 0xD5, 0xB4, 0xD5, 0xB5, 0xD5,
+               0xB6, 0xD5, 0xB7, 0xD5, 0xB8, 0xD5, 0xB9, 0xD5,
+               0xBA, 0xD5, 0xBB, 0xD5, 0xBC, 0xD5, 0xBD, 0xD5,
+               0xBE, 0xD5, 0xBF, 0xD6, 0x80, 0xD6, 0x81, 0xD6,
+               0x82, 0xD6, 0x83, 0xD6, 0x84, 0xD6, 0x85, 0xD6,
+               0x86, 0xE2, 0xB4, 0x80, 0xE2, 0xB4, 0x81, 0xE2,
+               0xB4, 0x82, 0xE2, 0xB4, 0x83, 0xE2, 0xB4, 0x84,
+               0xE2, 0xB4, 0x85, 0xE2, 0xB4, 0x86, 0xE2, 0xB4,
+               0x87, 0xE2, 0xB4, 0x88, 0xE2, 0xB4, 0x89, 0xE2,
+               0xB4, 0x8A, 0xE2, 0xB4, 0x8B, 0xE2, 0xB4, 0x8C,
+               0xE2, 0xB4, 0x8D, 0xE2, 0xB4, 0x8E, 0xE2, 0xB4,
+               0x8F, 0xE2, 0xB4, 0x90, 0xE2, 0xB4, 0x91, 0xE2,
+               0xB4, 0x92, 0xE2, 0xB4, 0x93, 0xE2, 0xB4, 0x94,
+               0xE2, 0xB4, 0x95, 0xE2, 0xB4, 0x96, 0xE2, 0xB4,
+               0x97, 0xE2, 0xB4, 0x98, 0xE2, 0xB4, 0x99, 0xE2,
+               0xB4, 0x9A, 0xE2, 0xB4, 0x9B, 0xE2, 0xB4, 0x9C,
+               0xE2, 0xB4, 0x9D, 0xE2, 0xB4, 0x9E, 0xE2, 0xB4,
+               0x9F, 0xE2, 0xB4, 0xA0, 0xE2, 0xB4, 0xA1, 0xE2,
+               0xB4, 0xA2, 0xE2, 0xB4, 0xA3, 0xE2, 0xB4, 0xA4,
+               0xE2, 0xB4, 0xA5, 0xE1, 0xB8, 0x81, 0xE1, 0xB8,
+               0x83, 0xE1, 0xB8, 0x85, 0xE1, 0xB8, 0x87, 0xE1,
+               0xB8, 0x89, 0xE1, 0xB8, 0x8B, 0xE1, 0xB8, 0x8D,
+               0xE1, 0xB8, 0x8F, 0xE1, 0xB8, 0x91, 0xE1, 0xB8,
+               0x93, 0xE1, 0xB8, 0x95, 0xE1, 0xB8, 0x97, 0xE1,
+               0xB8, 0x99, 0xE1, 0xB8, 0x9B, 0xE1, 0xB8, 0x9D,
+               0xE1, 0xB8, 0x9F, 0xE1, 0xB8, 0xA1, 0xE1, 0xB8,
+               0xA3, 0xE1, 0xB8, 0xA5, 0xE1, 0xB8, 0xA7, 0xE1,
+               0xB8, 0xA9, 0xE1, 0xB8, 0xAB, 0xE1, 0xB8, 0xAD,
+               0xE1, 0xB8, 0xAF, 0xE1, 0xB8, 0xB1, 0xE1, 0xB8,
+               0xB3, 0xE1, 0xB8, 0xB5, 0xE1, 0xB8, 0xB7, 0xE1,
+               0xB8, 0xB9, 0xE1, 0xB8, 0xBB, 0xE1, 0xB8, 0xBD,
+               0xE1, 0xB8, 0xBF, 0xE1, 0xB9, 0x81, 0xE1, 0xB9,
+               0x83, 0xE1, 0xB9, 0x85, 0xE1, 0xB9, 0x87, 0xE1,
+               0xB9, 0x89, 0xE1, 0xB9, 0x8B, 0xE1, 0xB9, 0x8D,
+               0xE1, 0xB9, 0x8F, 0xE1, 0xB9, 0x91, 0xE1, 0xB9,
+               0x93, 0xE1, 0xB9, 0x95, 0xE1, 0xB9, 0x97, 0xE1,
+               0xB9, 0x99, 0xE1, 0xB9, 0x9B, 0xE1, 0xB9, 0x9D,
+               0xE1, 0xB9, 0x9F, 0xE1, 0xB9, 0xA1, 0xE1, 0xB9,
+               0xA3, 0xE1, 0xB9, 0xA5, 0xE1, 0xB9, 0xA7, 0xE1,
+               0xB9, 0xA9, 0xE1, 0xB9, 0xAB, 0xE1, 0xB9, 0xAD,
+               0xE1, 0xB9, 0xAF, 0xE1, 0xB9, 0xB1, 0xE1, 0xB9,
+               0xB3, 0xE1, 0xB9, 0xB5, 0xE1, 0xB9, 0xB7, 0xE1,
+               0xB9, 0xB9, 0xE1, 0xB9, 0xBB, 0xE1, 0xB9, 0xBD,
+               0xE1, 0xB9, 0xBF, 0xE1, 0xBA, 0x81, 0xE1, 0xBA,
+               0x83, 0xE1, 0xBA, 0x85, 0xE1, 0xBA, 0x87, 0xE1,
+               0xBA, 0x89, 0xE1, 0xBA, 0x8B, 0xE1, 0xBA, 0x8D,
+               0xE1, 0xBA, 0x8F, 0xE1, 0xBA, 0x91, 0xE1, 0xBA,
+               0x93, 0xE1, 0xBA, 0x95, 0xE1, 0xBA, 0xA1, 0xE1,
+               0xBA, 0xA3, 0xE1, 0xBA, 0xA5, 0xE1, 0xBA, 0xA7,
+               0xE1, 0xBA, 0xA9, 0xE1, 0xBA, 0xAB, 0xE1, 0xBA,
+               0xAD, 0xE1, 0xBA, 0xAF, 0xE1, 0xBA, 0xB1, 0xE1,
+               0xBA, 0xB3, 0xE1, 0xBA, 0xB5, 0xE1, 0xBA, 0xB7,
+               0xE1, 0xBA, 0xB9, 0xE1, 0xBA, 0xBB, 0xE1, 0xBA,
+               0xBD, 0xE1, 0xBA, 0xBF, 0xE1, 0xBB, 0x81, 0xE1,
+               0xBB, 0x83, 0xE1, 0xBB, 0x85, 0xE1, 0xBB, 0x87,
+               0xE1, 0xBB, 0x89, 0xE1, 0xBB, 0x8B, 0xE1, 0xBB,
+               0x8D, 0xE1, 0xBB, 0x8F, 0xE1, 0xBB, 0x91, 0xE1,
+               0xBB, 0x93, 0xE1, 0xBB, 0x95, 0xE1, 0xBB, 0x97,
+               0xE1, 0xBB, 0x99, 0xE1, 0xBB, 0x9B, 0xE1, 0xBB,
+               0x9D, 0xE1, 0xBB, 0x9F, 0xE1, 0xBB, 0xA1, 0xE1,
+               0xBB, 0xA3, 0xE1, 0xBB, 0xA5, 0xE1, 0xBB, 0xA7,
+               0xE1, 0xBB, 0xA9, 0xE1, 0xBB, 0xAB, 0xE1, 0xBB,
+               0xAD, 0xE1, 0xBB, 0xAF, 0xE1, 0xBB, 0xB1, 0xE1,
+               0xBB, 0xB3, 0xE1, 0xBB, 0xB5, 0xE1, 0xBB, 0xB7,
+               0xE1, 0xBB, 0xB9, 0xE1, 0xBC, 0x80, 0xE1, 0xBC,
+               0x81, 0xE1, 0xBC, 0x82, 0xE1, 0xBC, 0x83, 0xE1,
+               0xBC, 0x84, 0xE1, 0xBC, 0x85, 0xE1, 0xBC, 0x86,
+               0xE1, 0xBC, 0x87, 0xE1, 0xBC, 0x90, 0xE1, 0xBC,
+               0x91, 0xE1, 0xBC, 0x92, 0xE1, 0xBC, 0x93, 0xE1,
+               0xBC, 0x94, 0xE1, 0xBC, 0x95, 0xE1, 0xBC, 0xA0,
+               0xE1, 0xBC, 0xA1, 0xE1, 0xBC, 0xA2, 0xE1, 0xBC,
+               0xA3, 0xE1, 0xBC, 0xA4, 0xE1, 0xBC, 0xA5, 0xE1,
+               0xBC, 0xA6, 0xE1, 0xBC, 0xA7, 0xE1, 0xBC, 0xB0,
+               0xE1, 0xBC, 0xB1, 0xE1, 0xBC, 0xB2, 0xE1, 0xBC,
+               0xB3, 0xE1, 0xBC, 0xB4, 0xE1, 0xBC, 0xB5, 0xE1,
+               0xBC, 0xB6, 0xE1, 0xBC, 0xB7, 0xE1, 0xBD, 0x80,
+               0xE1, 0xBD, 0x81, 0xE1, 0xBD, 0x82, 0xE1, 0xBD,
+               0x83, 0xE1, 0xBD, 0x84, 0xE1, 0xBD, 0x85, 0xE1,
+               0xBD, 0x91, 0xE1, 0xBD, 0x93, 0xE1, 0xBD, 0x95,
+               0xE1, 0xBD, 0x97, 0xE1, 0xBD, 0xA0, 0xE1, 0xBD,
+               0xA1, 0xE1, 0xBD, 0xA2, 0xE1, 0xBD, 0xA3, 0xE1,
+               0xBD, 0xA4, 0xE1, 0xBD, 0xA5, 0xE1, 0xBD, 0xA6,
+               0xE1, 0xBD, 0xA7, 0xE1, 0xBE, 0x80, 0xE1, 0xBE,
+               0x81, 0xE1, 0xBE, 0x82, 0xE1, 0xBE, 0x83, 0xE1,
+               0xBE, 0x84, 0xE1, 0xBE, 0x85, 0xE1, 0xBE, 0x86,
+               0xE1, 0xBE, 0x87, 0xE1, 0xBE, 0x90, 0xE1, 0xBE,
+               0x91, 0xE1, 0xBE, 0x92, 0xE1, 0xBE, 0x93, 0xE1,
+               0xBE, 0x94, 0xE1, 0xBE, 0x95, 0xE1, 0xBE, 0x96,
+               0xE1, 0xBE, 0x97, 0xE1, 0xBE, 0xA0, 0xE1, 0xBE,
+               0xA1, 0xE1, 0xBE, 0xA2, 0xE1, 0xBE, 0xA3, 0xE1,
+               0xBE, 0xA4, 0xE1, 0xBE, 0xA5, 0xE1, 0xBE, 0xA6,
+               0xE1, 0xBE, 0xA7, 0xE1, 0xBE, 0xB0, 0xE1, 0xBE,
+               0xB1, 0xE1, 0xBD, 0xB0, 0xE1, 0xBD, 0xB1, 0xE1,
+               0xBE, 0xB3, 0xE1, 0xBD, 0xB2, 0xE1, 0xBD, 0xB3,
+               0xE1, 0xBD, 0xB4, 0xE1, 0xBD, 0xB5, 0xE1, 0xBF,
+               0x83, 0xE1, 0xBF, 0x90, 0xE1, 0xBF, 0x91, 0xE1,
+               0xBD, 0xB6, 0xE1, 0xBD, 0xB7, 0xE1, 0xBF, 0xA0,
+               0xE1, 0xBF, 0xA1, 0xE1, 0xBD, 0xBA, 0xE1, 0xBD,
+               0xBB, 0xE1, 0xBF, 0xA5, 0xE1, 0xBD, 0xB8, 0xE1,
+               0xBD, 0xB9, 0xE1, 0xBD, 0xBC, 0xE1, 0xBD, 0xBD,
+               0xE1, 0xBF, 0xB3, 0xCF, 0x89, 0x6B, 0xC3, 0xA5,
+               0xE2, 0x85, 0x8E, 0xE2, 0x85, 0xB0, 0xE2, 0x85,
+               0xB1, 0xE2, 0x85, 0xB2, 0xE2, 0x85, 0xB3, 0xE2,
+               0x85, 0xB4, 0xE2, 0x85, 0xB5, 0xE2, 0x85, 0xB6,
+               0xE2, 0x85, 0xB7, 0xE2, 0x85, 0xB8, 0xE2, 0x85,
+               0xB9, 0xE2, 0x85, 0xBA, 0xE2, 0x85, 0xBB, 0xE2,
+               0x85, 0xBC, 0xE2, 0x85, 0xBD, 0xE2, 0x85, 0xBE,
+               0xE2, 0x85, 0xBF, 0xE2, 0x86, 0x84, 0xE2, 0x93,
+               0x90, 0xE2, 0x93, 0x91, 0xE2, 0x93, 0x92, 0xE2,
+               0x93, 0x93, 0xE2, 0x93, 0x94, 0xE2, 0x93, 0x95,
+               0xE2, 0x93, 0x96, 0xE2, 0x93, 0x97, 0xE2, 0x93,
+               0x98, 0xE2, 0x93, 0x99, 0xE2, 0x93, 0x9A, 0xE2,
+               0x93, 0x9B, 0xE2, 0x93, 0x9C, 0xE2, 0x93, 0x9D,
+               0xE2, 0x93, 0x9E, 0xE2, 0x93, 0x9F, 0xE2, 0x93,
+               0xA0, 0xE2, 0x93, 0xA1, 0xE2, 0x93, 0xA2, 0xE2,
+               0x93, 0xA3, 0xE2, 0x93, 0xA4, 0xE2, 0x93, 0xA5,
+               0xE2, 0x93, 0xA6, 0xE2, 0x93, 0xA7, 0xE2, 0x93,
+               0xA8, 0xE2, 0x93, 0xA9, 0xE2, 0xB0, 0xB0, 0xE2,
+               0xB0, 0xB1, 0xE2, 0xB0, 0xB2, 0xE2, 0xB0, 0xB3,
+               0xE2, 0xB0, 0xB4, 0xE2, 0xB0, 0xB5, 0xE2, 0xB0,
+               0xB6, 0xE2, 0xB0, 0xB7, 0xE2, 0xB0, 0xB8, 0xE2,
+               0xB0, 0xB9, 0xE2, 0xB0, 0xBA, 0xE2, 0xB0, 0xBB,
+               0xE2, 0xB0, 0xBC, 0xE2, 0xB0, 0xBD, 0xE2, 0xB0,
+               0xBE, 0xE2, 0xB0, 0xBF, 0xE2, 0xB1, 0x80, 0xE2,
+               0xB1, 0x81, 0xE2, 0xB1, 0x82, 0xE2, 0xB1, 0x83,
+               0xE2, 0xB1, 0x84, 0xE2, 0xB1, 0x85, 0xE2, 0xB1,
+               0x86, 0xE2, 0xB1, 0x87, 0xE2, 0xB1, 0x88, 0xE2,
+               0xB1, 0x89, 0xE2, 0xB1, 0x8A, 0xE2, 0xB1, 0x8B,
+               0xE2, 0xB1, 0x8C, 0xE2, 0xB1, 0x8D, 0xE2, 0xB1,
+               0x8E, 0xE2, 0xB1, 0x8F, 0xE2, 0xB1, 0x90, 0xE2,
+               0xB1, 0x91, 0xE2, 0xB1, 0x92, 0xE2, 0xB1, 0x93,
+               0xE2, 0xB1, 0x94, 0xE2, 0xB1, 0x95, 0xE2, 0xB1,
+               0x96, 0xE2, 0xB1, 0x97, 0xE2, 0xB1, 0x98, 0xE2,
+               0xB1, 0x99, 0xE2, 0xB1, 0x9A, 0xE2, 0xB1, 0x9B,
+               0xE2, 0xB1, 0x9C, 0xE2, 0xB1, 0x9D, 0xE2, 0xB1,
+               0x9E, 0xE2, 0xB1, 0xA1, 0xC9, 0xAB, 0xE1, 0xB5,
+               0xBD, 0xC9, 0xBD, 0xE2, 0xB1, 0xA8, 0xE2, 0xB1,
+               0xAA, 0xE2, 0xB1, 0xAC, 0xE2, 0xB1, 0xB6, 0xE2,
+               0xB2, 0x81, 0xE2, 0xB2, 0x83, 0xE2, 0xB2, 0x85,
+               0xE2, 0xB2, 0x87, 0xE2, 0xB2, 0x89, 0xE2, 0xB2,
+               0x8B, 0xE2, 0xB2, 0x8D, 0xE2, 0xB2, 0x8F, 0xE2,
+               0xB2, 0x91, 0xE2, 0xB2, 0x93, 0xE2, 0xB2, 0x95,
+               0xE2, 0xB2, 0x97, 0xE2, 0xB2, 0x99, 0xE2, 0xB2,
+               0x9B, 0xE2, 0xB2, 0x9D, 0xE2, 0xB2, 0x9F, 0xE2,
+               0xB2, 0xA1, 0xE2, 0xB2, 0xA3, 0xE2, 0xB2, 0xA5,
+               0xE2, 0xB2, 0xA7, 0xE2, 0xB2, 0xA9, 0xE2, 0xB2,
+               0xAB, 0xE2, 0xB2, 0xAD, 0xE2, 0xB2, 0xAF, 0xE2,
+               0xB2, 0xB1, 0xE2, 0xB2, 0xB3, 0xE2, 0xB2, 0xB5,
+               0xE2, 0xB2, 0xB7, 0xE2, 0xB2, 0xB9, 0xE2, 0xB2,
+               0xBB, 0xE2, 0xB2, 0xBD, 0xE2, 0xB2, 0xBF, 0xE2,
+               0xB3, 0x81, 0xE2, 0xB3, 0x83, 0xE2, 0xB3, 0x85,
+               0xE2, 0xB3, 0x87, 0xE2, 0xB3, 0x89, 0xE2, 0xB3,
+               0x8B, 0xE2, 0xB3, 0x8D, 0xE2, 0xB3, 0x8F, 0xE2,
+               0xB3, 0x91, 0xE2, 0xB3, 0x93, 0xE2, 0xB3, 0x95,
+               0xE2, 0xB3, 0x97, 0xE2, 0xB3, 0x99, 0xE2, 0xB3,
+               0x9B, 0xE2, 0xB3, 0x9D, 0xE2, 0xB3, 0x9F, 0xE2,
+               0xB3, 0xA1, 0xE2, 0xB3, 0xA3, 0xEF, 0xBD, 0x81,
+               0xEF, 0xBD, 0x82, 0xEF, 0xBD, 0x83, 0xEF, 0xBD,
+               0x84, 0xEF, 0xBD, 0x85, 0xEF, 0xBD, 0x86, 0xEF,
+               0xBD, 0x87, 0xEF, 0xBD, 0x88, 0xEF, 0xBD, 0x89,
+               0xEF, 0xBD, 0x8A, 0xEF, 0xBD, 0x8B, 0xEF, 0xBD,
+               0x8C, 0xEF, 0xBD, 0x8D, 0xEF, 0xBD, 0x8E, 0xEF,
+               0xBD, 0x8F, 0xEF, 0xBD, 0x90, 0xEF, 0xBD, 0x91,
+               0xEF, 0xBD, 0x92, 0xEF, 0xBD, 0x93, 0xEF, 0xBD,
+               0x94, 0xEF, 0xBD, 0x95, 0xEF, 0xBD, 0x96, 0xEF,
+               0xBD, 0x97, 0xEF, 0xBD, 0x98, 0xEF, 0xBD, 0x99,
+               0xEF, 0xBD, 0x9A, 0xF0, 0x90, 0x90, 0xA8, 0xF0,
+               0x90, 0x90, 0xA9, 0xF0, 0x90, 0x90, 0xAA, 0xF0,
+               0x90, 0x90, 0xAB, 0xF0, 0x90, 0x90, 0xAC, 0xF0,
+               0x90, 0x90, 0xAD, 0xF0, 0x90, 0x90, 0xAE, 0xF0,
+               0x90, 0x90, 0xAF, 0xF0, 0x90, 0x90, 0xB0, 0xF0,
+               0x90, 0x90, 0xB1, 0xF0, 0x90, 0x90, 0xB2, 0xF0,
+               0x90, 0x90, 0xB3, 0xF0, 0x90, 0x90, 0xB4, 0xF0,
+               0x90, 0x90, 0xB5, 0xF0, 0x90, 0x90, 0xB6, 0xF0,
+               0x90, 0x90, 0xB7, 0xF0, 0x90, 0x90, 0xB8, 0xF0,
+               0x90, 0x90, 0xB9, 0xF0, 0x90, 0x90, 0xBA, 0xF0,
+               0x90, 0x90, 0xBB, 0xF0, 0x90, 0x90, 0xBC, 0xF0,
+               0x90, 0x90, 0xBD, 0xF0, 0x90, 0x90, 0xBE, 0xF0,
+               0x90, 0x90, 0xBF, 0xF0, 0x90, 0x91, 0x80, 0xF0,
+               0x90, 0x91, 0x81, 0xF0, 0x90, 0x91, 0x82, 0xF0,
+               0x90, 0x91, 0x83, 0xF0, 0x90, 0x91, 0x84, 0xF0,
+               0x90, 0x91, 0x85, 0xF0, 0x90, 0x91, 0x86, 0xF0,
+               0x90, 0x91, 0x87, 0xF0, 0x90, 0x91, 0x88, 0xF0,
+               0x90, 0x91, 0x89, 0xF0, 0x90, 0x91, 0x8A, 0xF0,
+               0x90, 0x91, 0x8B, 0xF0, 0x90, 0x91, 0x8C, 0xF0,
+               0x90, 0x91, 0x8D, 0xF0, 0x90, 0x91, 0x8E, 0xF0,
+               0x90, 0x91, 0x8F,
+       },
+};
+
+static const u8_displacement_t u8_toupper_b3_tbl[2][5][256] = {
+       {
+               {       /* Third byte table 0. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0, 0 }, { 1, 2 },
+                       { 2, 64 }, { 3, 125 }, { 4, 188 }, { 5, 226 },
+                       { 6, 288 }, { 7, 338 }, { 8, 364 }, { N_, 0 },
+                       { N_, 0 }, { 9, 376 }, { 10, 378 }, { 11, 416 },
+                       { 12, 486 }, { 13, 518 }, { 14, 614 }, { 15, 670 },
+                       { 16, 724 }, { 17, 740 }, { 18, 802 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 19, 816 }, { 20, 912 }, { 21, 1008 }, { 22, 1092 },
+                       { 23, 1179 }, { 24, 1269 }, { 25, 1365 }, { 26, 1448 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 27, 1469 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { 28, 1517 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 29, 1595 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 30, 1673 }, { 31, 1769 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+       },
+       {
+               {       /* Third byte table 0. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { 0, 0 }, { 1, 2 },
+                       { 2, 64 }, { 3, 125 }, { 4, 188 }, { 5, 230 },
+                       { 6, 292 }, { 7, 344 }, { 8, 388 }, { N_, 0 },
+                       { N_, 0 }, { 9, 404 }, { 10, 412 }, { 11, 450 },
+                       { 12, 524 }, { 13, 556 }, { 14, 652 }, { 15, 708 },
+                       { 16, 772 }, { 17, 792 }, { 18, 854 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 1. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 19, 868 }, { N_, 0 }, { N_, 0 },
+                       { 20, 871 }, { 21, 967 }, { 22, 1063 }, { 23, 1147 },
+                       { 24, 1234 }, { 25, 1324 }, { 26, 1420 }, { 27, 1503 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 2. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 28, 1524 }, { 29, 1575 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { 30, 1578 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 31, 1656 }, { 32, 1704 }, { 33, 1816 }, { 34, 1912 },
+                       { 35, 1966 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 3. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { 36, 2080 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+               {       /* Third byte table 4. */
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { 37, 2158 }, { 38, 2254 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+                       { N_, 0 }, { N_, 0 }, { N_, 0 }, { N_, 0 },
+               },
+       },
+};
+
+static const uchar_t u8_toupper_b4_tbl[2][39][257] = {
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  49,  49,  51,  51,  53,  53,
+                       55,  55,  55,  57,  57,  59,  59,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  50,  50,  52,  52,  54,  54,
+                       56,  56,  56,  58,  58,  60,  60,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   2,   2,   4,   4,
+                       4,   6,   6,   6,   6,   8,   8,   8,
+                       8,   8,   8,   10,  10,  10,  12,  12,
+                       12,  12,  14,  14,  14,  14,  14,  16,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       22,  24,  24,  24,  24,  24,  26,  26,
+                       26,  28,  28,  28,  28,  30,  30,  32,
+                       32,  32,  34,  34,  34,  34,  36,  36,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   2,   4,
+                       4,   6,   8,   8,   10,  12,  12,  14,
+                       14,  16,  16,  18,  18,  20,  20,  22,
+                       22,  24,  24,  26,  26,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  48,  50,  52,  52,  54,  54,
+                       54,  54,  56,  56,  58,  58,  60,  60,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  32,  32,  34,  34,  36,  36,
+                       38,  38,  40,  40,  42,  42,  44,  44,
+                       46,  46,  48,  48,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  50,  50,  50,
+                       50,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   2,   4,   4,   6,
+                       8,   8,   10,  10,  12,  12,  12,  12,
+                       12,  14,  14,  14,  16,  16,  16,  16,
+                       16,  18,  20,  20,  20,  20,  20,  20,
+                       22,  22,  22,  24,  24,  24,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,  26,  26,  26,  26,  26,  26,  26,
+                       26,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   2,   4,   4,   4,   4,
+                       4,   6,   6,   8,   10,  10,  10,  10,
+                       10,  10,  10,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,  12,  12,  12,  12,  12,  12,  12,
+                       12,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   2,   4,   6,
+                       8,   8,   10,  12,  14,  16,  18,  20,
+                       22,  24,  26,  28,  30,  32,  34,  36,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       30,  32,  34,  34,  34,  34,  36,  38,
+                       38,  38,  40,  40,  42,  42,  44,  44,
+                       46,  46,  48,  48,  50,  50,  52,  52,
+                       54,  54,  56,  56,  58,  58,  60,  60,
+                       62,  64,  66,  68,  68,  68,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,  70,  70,  70,  70,  70,  70,  70,
+                       70,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  64,  66,  66,  68,  68,  70,  70,
+                       72,  72,  74,  74,  76,  76,  78,  78,
+                       80,  80,  82,  82,  84,  84,  86,  86,
+                       88,  88,  90,  90,  92,  92,  94,  94,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  50,  50,  52,  52,  54,  54,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   2,   2,   4,   4,   6,
+                       6,   8,   8,   10,  10,  12,  12,  14,
+                       14,  14,  16,  16,  18,  18,  20,  20,
+                       22,  22,  24,  24,  26,  26,  28,  28,
+                       30,  30,  32,  32,  34,  34,  36,  36,
+                       38,  38,  40,  40,  42,  42,  44,  44,
+                       46,  46,  48,  48,  50,  50,  52,  52,
+                       52,  52,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   4,   6,   8,   10,  12,
+                       14,  16,  18,  20,  22,  24,  26,  28,
+                       30,  32,  34,  36,  38,  40,  42,  44,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  90,  90,  93,  93,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  90,  90,  93,  93,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       33,  33,  33,  33,  36,  36,  36,  36,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  45,  48,  51,  54,  57,  60,  63,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  69,  72,  75,  78,  81,  84,  87,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  21,  21,  24,  24,  27,  27,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  33,  36,  39,  42,  45,  48,  51,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  57,  60,  63,  66,  69,  72,  75,
+                       78,  81,  84,  87,  90,  93,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  75,  78,  78,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   6,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   12,  15,  15,  15,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   6,   9,   12,  15,  18,
+                       21,  24,  27,  30,  33,  36,  39,  42,
+                       45,  48,  51,  54,  57,  60,  63,  66,
+                       69,  72,  75,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,
+               },
+       },
+       {
+               {       /* Fourth byte table 0. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,
+               },
+               {       /* Fourth byte table 1. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 2. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  49,  49,  51,  51,  53,  53,
+                       55,  55,  55,  57,  57,  59,  59,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,  61,  61,  61,  61,  61,  61,  61,
+                       61,
+               },
+               {       /* Fourth byte table 3. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   4,   4,   6,   6,   8,
+                       8,   10,  10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  50,  50,  52,  52,  54,  54,
+                       56,  56,  56,  58,  58,  60,  60,  62,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,  63,  63,  63,  63,  63,  63,  63,
+                       63,
+               },
+               {       /* Fourth byte table 4. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   2,   4,   4,   6,   6,
+                       6,   8,   8,   8,   8,   10,  10,  10,
+                       10,  10,  10,  12,  12,  12,  14,  14,
+                       14,  14,  16,  18,  18,  18,  18,  20,
+                       20,  20,  22,  22,  24,  24,  26,  26,
+                       26,  28,  28,  28,  28,  28,  30,  30,
+                       30,  32,  32,  32,  32,  34,  34,  36,
+                       36,  36,  38,  38,  38,  38,  40,  40,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,
+               },
+               {       /* Fourth byte table 5. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   2,   4,
+                       4,   6,   8,   8,   10,  12,  12,  14,
+                       14,  16,  16,  18,  18,  20,  20,  22,
+                       22,  24,  24,  26,  26,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  48,  50,  52,  52,  54,  54,
+                       54,  54,  56,  56,  58,  58,  60,  60,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 6. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  32,  32,  34,  34,  36,  36,
+                       38,  38,  40,  40,  42,  42,  44,  44,
+                       46,  46,  48,  48,  50,  50,  50,  50,
+                       50,  50,  50,  50,  50,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,  52,  52,  52,  52,  52,  52,  52,
+                       52,
+               },
+               {       /* Fourth byte table 7. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   2,   2,   2,   2,   2,
+                       4,   4,   6,   6,   8,   8,   10,  10,
+                       12,  12,  12,  12,  14,  16,  16,  18,
+                       20,  20,  22,  22,  24,  24,  24,  24,
+                       24,  26,  26,  26,  28,  28,  28,  28,
+                       28,  30,  32,  32,  35,  35,  35,  35,
+                       37,  37,  37,  39,  39,  39,  41,  41,
+                       41,  41,  41,  41,  41,  41,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,  44,  44,  44,  44,  44,  44,  44,
+                       44,
+               },
+               {       /* Fourth byte table 8. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   2,   2,   4,   4,   4,   4,
+                       4,   6,   8,   10,  12,  14,  14,  14,
+                       14,  14,  14,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,  16,  16,  16,  16,  16,  16,  16,
+                       16,
+               },
+               {       /* Fourth byte table 9. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   4,   6,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,   8,   8,   8,   8,   8,   8,   8,
+                       8,
+               },
+               {       /* Fourth byte table 10. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   2,   4,   6,
+                       8,   8,   10,  12,  14,  16,  18,  20,
+                       22,  24,  26,  28,  30,  32,  34,  36,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,  38,  38,  38,  38,  38,  38,  38,
+                       38,
+               },
+               {       /* Fourth byte table 11. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       30,  32,  34,  34,  34,  34,  36,  38,
+                       38,  38,  40,  40,  42,  42,  44,  44,
+                       46,  46,  48,  48,  50,  50,  52,  52,
+                       54,  54,  56,  56,  58,  58,  60,  60,
+                       62,  64,  66,  68,  68,  68,  70,  70,
+                       70,  72,  72,  72,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,  74,  74,  74,  74,  74,  74,  74,
+                       74,
+               },
+               {       /* Fourth byte table 12. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,  32,  32,  32,  32,  32,  32,  32,
+                       32,
+               },
+               {       /* Fourth byte table 13. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       16,  18,  20,  22,  24,  26,  28,  30,
+                       32,  34,  36,  38,  40,  42,  44,  46,
+                       48,  50,  52,  54,  56,  58,  60,  62,
+                       64,  64,  66,  66,  68,  68,  70,  70,
+                       72,  72,  74,  74,  76,  76,  78,  78,
+                       80,  80,  82,  82,  84,  84,  86,  86,
+                       88,  88,  90,  90,  92,  92,  94,  94,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 14. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   2,   2,   2,   2,
+                       2,   2,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  50,  50,  52,  52,  54,  54,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,  56,  56,  56,  56,  56,  56,  56,
+                       56,
+               },
+               {       /* Fourth byte table 15. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   2,   2,   4,   4,   6,
+                       6,   8,   8,   10,  10,  12,  12,  14,
+                       16,  16,  18,  18,  20,  20,  22,  22,
+                       24,  24,  26,  26,  28,  28,  30,  30,
+                       32,  32,  34,  34,  36,  36,  38,  38,
+                       40,  40,  42,  42,  44,  44,  46,  46,
+                       48,  48,  50,  50,  52,  52,  54,  54,
+                       56,  56,  58,  58,  60,  60,  62,  62,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+               {       /* Fourth byte table 16. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   2,   4,   4,   6,   6,
+                       8,   8,   10,  10,  12,  12,  14,  14,
+                       16,  16,  18,  18,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,  20,  20,  20,  20,  20,  20,  20,
+                       20,
+               },
+               {       /* Fourth byte table 17. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   2,   4,   6,   8,   10,  12,
+                       14,  16,  18,  20,  22,  24,  26,  28,
+                       30,  32,  34,  36,  38,  40,  42,  44,
+                       46,  48,  50,  52,  54,  56,  58,  60,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,  62,  62,  62,  62,  62,  62,  62,
+                       62,
+               },
+               {       /* Fourth byte table 18. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   2,   4,   6,   8,   10,  12,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,  14,  14,  14,  14,  14,  14,  14,
+                       14,
+               },
+               {       /* Fourth byte table 19. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 20. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  90,  90,  93,  93,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 21. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  90,  90,  93,  93,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 22. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       33,  33,  33,  33,  36,  36,  36,  36,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,  84,  84,  84,  84,  84,  84,  84,
+                       84,
+               },
+               {       /* Fourth byte table 23. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,  87,  87,  87,  87,  87,  87,  87,
+                       87,
+               },
+               {       /* Fourth byte table 24. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  42,
+                       42,  42,  42,  42,  42,  42,  42,  42,
+                       42,  45,  48,  51,  54,  57,  60,  63,
+                       66,  66,  66,  66,  66,  66,  66,  66,
+                       66,  69,  72,  75,  78,  81,  84,  87,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,  90,  90,  90,  90,  90,  90,  90,
+                       90,
+               },
+               {       /* Fourth byte table 25. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  21,  21,  24,  24,  27,  27,
+                       30,  30,  30,  30,  30,  30,  30,  30,
+                       30,  33,  36,  39,  42,  45,  48,  51,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  57,  60,  63,  66,  69,  72,  75,
+                       78,  81,  84,  87,  90,  93,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 26. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  24,  24,  24,  24,  24,  24,  24,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  72,  72,  72,  72,  72,  72,  72,
+                       72,  75,  78,  78,  81,  81,  81,  81,
+                       81,  81,  81,  81,  81,  81,  81,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,  83,  83,  83,  83,  83,  83,  83,
+                       83,
+               },
+               {       /* Fourth byte table 27. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   6,   9,   9,   9,   9,   9,   9,
+                       9,   9,   9,   9,   9,   9,   9,   9,
+                       9,   12,  15,  15,  15,  15,  18,  18,
+                       18,  18,  18,  18,  18,  18,  18,  18,
+                       18,  18,  18,  18,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,  21,  21,  21,  21,  21,  21,  21,
+                       21,
+               },
+               {       /* Fourth byte table 28. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   6,   9,   12,  15,  18,  21,  24,
+                       27,  30,  33,  36,  39,  42,  45,  48,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,  51,  51,  51,  51,  51,  51,  51,
+                       51,
+               },
+               {       /* Fourth byte table 29. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,   3,   3,   3,   3,   3,   3,   3,
+                       3,
+               },
+               {       /* Fourth byte table 30. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,
+               },
+               {       /* Fourth byte table 31. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,  48,  48,  48,  48,  48,  48,  48,
+                       48,
+               },
+               {       /* Fourth byte table 32. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       93,  93,  96,  96,  96,  96,  98,  100,
+                       100, 103, 103, 106, 106, 109, 109, 109,
+                       109, 109, 109, 109, 109, 109, 109, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112, 112, 112, 112, 112, 112, 112, 112,
+                       112,
+               },
+               {       /* Fourth byte table 33. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  57,  57,
+                       60,  60,  63,  63,  66,  66,  69,  69,
+                       72,  72,  75,  75,  78,  78,  81,  81,
+                       84,  84,  87,  87,  90,  90,  93,  93,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 34. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   3,   6,   6,   9,   9,
+                       12,  12,  15,  15,  18,  18,  21,  21,
+                       24,  24,  27,  27,  30,  30,  33,  33,
+                       36,  36,  39,  39,  42,  42,  45,  45,
+                       48,  48,  51,  51,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,  54,  54,  54,  54,  54,  54,  54,
+                       54,
+               },
+               {       /* Fourth byte table 35. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   3,   6,   9,   12,  15,  18,  21,
+                       24,  27,  30,  33,  36,  39,  42,  45,
+                       48,  51,  54,  57,  60,  63,  66,  69,
+                       72,  75,  78,  81,  84,  87,  90,  93,
+                       96,  99,  102, 105, 108, 111, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114, 114, 114, 114, 114, 114, 114, 114,
+                       114,
+               },
+               {       /* Fourth byte table 36. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   3,   6,   9,   12,  15,  18,
+                       21,  24,  27,  30,  33,  36,  39,  42,
+                       45,  48,  51,  54,  57,  60,  63,  66,
+                       69,  72,  75,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,  78,  78,  78,  78,  78,  78,  78,
+                       78,
+               },
+               {       /* Fourth byte table 37. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  68,  72,  76,  80,  84,  88,  92,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,  96,  96,  96,  96,  96,  96,  96,
+                       96,
+               },
+               {       /* Fourth byte table 38. */
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   0,   0,   0,   0,   0,   0,   0,
+                       0,   4,   8,   12,  16,  20,  24,  28,
+                       32,  36,  40,  44,  48,  52,  56,  60,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,  64,  64,  64,  64,  64,  64,  64,
+                       64,
+               },
+       },
+};
+
+static const uchar_t u8_toupper_final_tbl[2][2318] = {
+       {
+               0xCE, 0x9C, 0xC3, 0x80, 0xC3, 0x81, 0xC3, 0x82,
+               0xC3, 0x83, 0xC3, 0x84, 0xC3, 0x85, 0xC3, 0x86,
+               0xC3, 0x87, 0xC3, 0x88, 0xC3, 0x89, 0xC3, 0x8A,
+               0xC3, 0x8B, 0xC3, 0x8C, 0xC3, 0x8D, 0xC3, 0x8E,
+               0xC3, 0x8F, 0xC3, 0x90, 0xC3, 0x91, 0xC3, 0x92,
+               0xC3, 0x93, 0xC3, 0x94, 0xC3, 0x95, 0xC3, 0x96,
+               0xC3, 0x98, 0xC3, 0x99, 0xC3, 0x9A, 0xC3, 0x9B,
+               0xC3, 0x9C, 0xC3, 0x9D, 0xC3, 0x9E, 0xC5, 0xB8,
+               0xC4, 0x80, 0xC4, 0x82, 0xC4, 0x84, 0xC4, 0x86,
+               0xC4, 0x88, 0xC4, 0x8A, 0xC4, 0x8C, 0xC4, 0x8E,
+               0xC4, 0x90, 0xC4, 0x92, 0xC4, 0x94, 0xC4, 0x96,
+               0xC4, 0x98, 0xC4, 0x9A, 0xC4, 0x9C, 0xC4, 0x9E,
+               0xC4, 0xA0, 0xC4, 0xA2, 0xC4, 0xA4, 0xC4, 0xA6,
+               0xC4, 0xA8, 0xC4, 0xAA, 0xC4, 0xAC, 0xC4, 0xAE,
+               0x49, 0xC4, 0xB2, 0xC4, 0xB4, 0xC4, 0xB6, 0xC4,
+               0xB9, 0xC4, 0xBB, 0xC4, 0xBD, 0xC4, 0xBF, 0xC5,
+               0x81, 0xC5, 0x83, 0xC5, 0x85, 0xC5, 0x87, 0xC5,
+               0x8A, 0xC5, 0x8C, 0xC5, 0x8E, 0xC5, 0x90, 0xC5,
+               0x92, 0xC5, 0x94, 0xC5, 0x96, 0xC5, 0x98, 0xC5,
+               0x9A, 0xC5, 0x9C, 0xC5, 0x9E, 0xC5, 0xA0, 0xC5,
+               0xA2, 0xC5, 0xA4, 0xC5, 0xA6, 0xC5, 0xA8, 0xC5,
+               0xAA, 0xC5, 0xAC, 0xC5, 0xAE, 0xC5, 0xB0, 0xC5,
+               0xB2, 0xC5, 0xB4, 0xC5, 0xB6, 0xC5, 0xB9, 0xC5,
+               0xBB, 0xC5, 0xBD, 0x53, 0xC6, 0x82, 0xC6, 0x84,
+               0xC6, 0x87, 0xC6, 0x8B, 0xC6, 0x91, 0xC7, 0xB6,
+               0xC6, 0x98, 0xC8, 0xA0, 0xC6, 0xA0, 0xC6, 0xA2,
+               0xC6, 0xA4, 0xC6, 0xA7, 0xC6, 0xAC, 0xC6, 0xAF,
+               0xC6, 0xB3, 0xC6, 0xB5, 0xC6, 0xB8, 0xC6, 0xBC,
+               0xC7, 0xB7, 0xC7, 0x84, 0xC7, 0x84, 0xC7, 0x87,
+               0xC7, 0x87, 0xC7, 0x8A, 0xC7, 0x8A, 0xC7, 0x8D,
+               0xC7, 0x8F, 0xC7, 0x91, 0xC7, 0x93, 0xC7, 0x95,
+               0xC7, 0x97, 0xC7, 0x99, 0xC7, 0x9B, 0xC6, 0x8E,
+               0xC7, 0x9E, 0xC7, 0xA0, 0xC7, 0xA2, 0xC7, 0xA4,
+               0xC7, 0xA6, 0xC7, 0xA8, 0xC7, 0xAA, 0xC7, 0xAC,
+               0xC7, 0xAE, 0xC7, 0xB1, 0xC7, 0xB1, 0xC7, 0xB4,
+               0xC7, 0xB8, 0xC7, 0xBA, 0xC7, 0xBC, 0xC7, 0xBE,
+               0xC8, 0x80, 0xC8, 0x82, 0xC8, 0x84, 0xC8, 0x86,
+               0xC8, 0x88, 0xC8, 0x8A, 0xC8, 0x8C, 0xC8, 0x8E,
+               0xC8, 0x90, 0xC8, 0x92, 0xC8, 0x94, 0xC8, 0x96,
+               0xC8, 0x98, 0xC8, 0x9A, 0xC8, 0x9C, 0xC8, 0x9E,
+               0xC8, 0xA2, 0xC8, 0xA4, 0xC8, 0xA6, 0xC8, 0xA8,
+               0xC8, 0xAA, 0xC8, 0xAC, 0xC8, 0xAE, 0xC8, 0xB0,
+               0xC8, 0xB2, 0xC6, 0x81, 0xC6, 0x86, 0xC6, 0x89,
+               0xC6, 0x8A, 0xC6, 0x8F, 0xC6, 0x90, 0xC6, 0x93,
+               0xC6, 0x94, 0xC6, 0x97, 0xC6, 0x96, 0xC6, 0x9C,
+               0xC6, 0x9D, 0xC6, 0x9F, 0xC6, 0xA6, 0xC6, 0xA9,
+               0xC6, 0xAE, 0xC6, 0xB1, 0xC6, 0xB2, 0xC6, 0xB7,
+               0xCE, 0x99, 0xCE, 0x86, 0xCE, 0x88, 0xCE, 0x89,
+               0xCE, 0x8A, 0xCE, 0x91, 0xCE, 0x92, 0xCE, 0x93,
+               0xCE, 0x94, 0xCE, 0x95, 0xCE, 0x96, 0xCE, 0x97,
+               0xCE, 0x98, 0xCE, 0x99, 0xCE, 0x9A, 0xCE, 0x9B,
+               0xCE, 0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE, 0x9F,
+               0xCE, 0xA0, 0xCE, 0xA1, 0xCE, 0xA3, 0xCE, 0xA3,
+               0xCE, 0xA4, 0xCE, 0xA5, 0xCE, 0xA6, 0xCE, 0xA7,
+               0xCE, 0xA8, 0xCE, 0xA9, 0xCE, 0xAA, 0xCE, 0xAB,
+               0xCE, 0x8C, 0xCE, 0x8E, 0xCE, 0x8F, 0xCE, 0x92,
+               0xCE, 0x98, 0xCE, 0xA6, 0xCE, 0xA0, 0xCF, 0x98,
+               0xCF, 0x9A, 0xCF, 0x9C, 0xCF, 0x9E, 0xCF, 0xA0,
+               0xCF, 0xA2, 0xCF, 0xA4, 0xCF, 0xA6, 0xCF, 0xA8,
+               0xCF, 0xAA, 0xCF, 0xAC, 0xCF, 0xAE, 0xCE, 0x9A,
+               0xCE, 0xA1, 0xCE, 0xA3, 0xCE, 0x95, 0xD0, 0x90,
+               0xD0, 0x91, 0xD0, 0x92, 0xD0, 0x93, 0xD0, 0x94,
+               0xD0, 0x95, 0xD0, 0x96, 0xD0, 0x97, 0xD0, 0x98,
+               0xD0, 0x99, 0xD0, 0x9A, 0xD0, 0x9B, 0xD0, 0x9C,
+               0xD0, 0x9D, 0xD0, 0x9E, 0xD0, 0x9F, 0xD0, 0xA0,
+               0xD0, 0xA1, 0xD0, 0xA2, 0xD0, 0xA3, 0xD0, 0xA4,
+               0xD0, 0xA5, 0xD0, 0xA6, 0xD0, 0xA7, 0xD0, 0xA8,
+               0xD0, 0xA9, 0xD0, 0xAA, 0xD0, 0xAB, 0xD0, 0xAC,
+               0xD0, 0xAD, 0xD0, 0xAE, 0xD0, 0xAF, 0xD0, 0x80,
+               0xD0, 0x81, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0x84,
+               0xD0, 0x85, 0xD0, 0x86, 0xD0, 0x87, 0xD0, 0x88,
+               0xD0, 0x89, 0xD0, 0x8A, 0xD0, 0x8B, 0xD0, 0x8C,
+               0xD0, 0x8D, 0xD0, 0x8E, 0xD0, 0x8F, 0xD1, 0xA0,
+               0xD1, 0xA2, 0xD1, 0xA4, 0xD1, 0xA6, 0xD1, 0xA8,
+               0xD1, 0xAA, 0xD1, 0xAC, 0xD1, 0xAE, 0xD1, 0xB0,
+               0xD1, 0xB2, 0xD1, 0xB4, 0xD1, 0xB6, 0xD1, 0xB8,
+               0xD1, 0xBA, 0xD1, 0xBC, 0xD1, 0xBE, 0xD2, 0x80,
+               0xD2, 0x8A, 0xD2, 0x8C, 0xD2, 0x8E, 0xD2, 0x90,
+               0xD2, 0x92, 0xD2, 0x94, 0xD2, 0x96, 0xD2, 0x98,
+               0xD2, 0x9A, 0xD2, 0x9C, 0xD2, 0x9E, 0xD2, 0xA0,
+               0xD2, 0xA2, 0xD2, 0xA4, 0xD2, 0xA6, 0xD2, 0xA8,
+               0xD2, 0xAA, 0xD2, 0xAC, 0xD2, 0xAE, 0xD2, 0xB0,
+               0xD2, 0xB2, 0xD2, 0xB4, 0xD2, 0xB6, 0xD2, 0xB8,
+               0xD2, 0xBA, 0xD2, 0xBC, 0xD2, 0xBE, 0xD3, 0x81,
+               0xD3, 0x83, 0xD3, 0x85, 0xD3, 0x87, 0xD3, 0x89,
+               0xD3, 0x8B, 0xD3, 0x8D, 0xD3, 0x90, 0xD3, 0x92,
+               0xD3, 0x94, 0xD3, 0x96, 0xD3, 0x98, 0xD3, 0x9A,
+               0xD3, 0x9C, 0xD3, 0x9E, 0xD3, 0xA0, 0xD3, 0xA2,
+               0xD3, 0xA4, 0xD3, 0xA6, 0xD3, 0xA8, 0xD3, 0xAA,
+               0xD3, 0xAC, 0xD3, 0xAE, 0xD3, 0xB0, 0xD3, 0xB2,
+               0xD3, 0xB4, 0xD3, 0xB8, 0xD4, 0x80, 0xD4, 0x82,
+               0xD4, 0x84, 0xD4, 0x86, 0xD4, 0x88, 0xD4, 0x8A,
+               0xD4, 0x8C, 0xD4, 0x8E, 0xD4, 0xB1, 0xD4, 0xB2,
+               0xD4, 0xB3, 0xD4, 0xB4, 0xD4, 0xB5, 0xD4, 0xB6,
+               0xD4, 0xB7, 0xD4, 0xB8, 0xD4, 0xB9, 0xD4, 0xBA,
+               0xD4, 0xBB, 0xD4, 0xBC, 0xD4, 0xBD, 0xD4, 0xBE,
+               0xD4, 0xBF, 0xD5, 0x80, 0xD5, 0x81, 0xD5, 0x82,
+               0xD5, 0x83, 0xD5, 0x84, 0xD5, 0x85, 0xD5, 0x86,
+               0xD5, 0x87, 0xD5, 0x88, 0xD5, 0x89, 0xD5, 0x8A,
+               0xD5, 0x8B, 0xD5, 0x8C, 0xD5, 0x8D, 0xD5, 0x8E,
+               0xD5, 0x8F, 0xD5, 0x90, 0xD5, 0x91, 0xD5, 0x92,
+               0xD5, 0x93, 0xD5, 0x94, 0xD5, 0x95, 0xD5, 0x96,
+               0xE1, 0xB8, 0x80, 0xE1, 0xB8, 0x82, 0xE1, 0xB8,
+               0x84, 0xE1, 0xB8, 0x86, 0xE1, 0xB8, 0x88, 0xE1,
+               0xB8, 0x8A, 0xE1, 0xB8, 0x8C, 0xE1, 0xB8, 0x8E,
+               0xE1, 0xB8, 0x90, 0xE1, 0xB8, 0x92, 0xE1, 0xB8,
+               0x94, 0xE1, 0xB8, 0x96, 0xE1, 0xB8, 0x98, 0xE1,
+               0xB8, 0x9A, 0xE1, 0xB8, 0x9C, 0xE1, 0xB8, 0x9E,
+               0xE1, 0xB8, 0xA0, 0xE1, 0xB8, 0xA2, 0xE1, 0xB8,
+               0xA4, 0xE1, 0xB8, 0xA6, 0xE1, 0xB8, 0xA8, 0xE1,
+               0xB8, 0xAA, 0xE1, 0xB8, 0xAC, 0xE1, 0xB8, 0xAE,
+               0xE1, 0xB8, 0xB0, 0xE1, 0xB8, 0xB2, 0xE1, 0xB8,
+               0xB4, 0xE1, 0xB8, 0xB6, 0xE1, 0xB8, 0xB8, 0xE1,
+               0xB8, 0xBA, 0xE1, 0xB8, 0xBC, 0xE1, 0xB8, 0xBE,
+               0xE1, 0xB9, 0x80, 0xE1, 0xB9, 0x82, 0xE1, 0xB9,
+               0x84, 0xE1, 0xB9, 0x86, 0xE1, 0xB9, 0x88, 0xE1,
+               0xB9, 0x8A, 0xE1, 0xB9, 0x8C, 0xE1, 0xB9, 0x8E,
+               0xE1, 0xB9, 0x90, 0xE1, 0xB9, 0x92, 0xE1, 0xB9,
+               0x94, 0xE1, 0xB9, 0x96, 0xE1, 0xB9, 0x98, 0xE1,
+               0xB9, 0x9A, 0xE1, 0xB9, 0x9C, 0xE1, 0xB9, 0x9E,
+               0xE1, 0xB9, 0xA0, 0xE1, 0xB9, 0xA2, 0xE1, 0xB9,
+               0xA4, 0xE1, 0xB9, 0xA6, 0xE1, 0xB9, 0xA8, 0xE1,
+               0xB9, 0xAA, 0xE1, 0xB9, 0xAC, 0xE1, 0xB9, 0xAE,
+               0xE1, 0xB9, 0xB0, 0xE1, 0xB9, 0xB2, 0xE1, 0xB9,
+               0xB4, 0xE1, 0xB9, 0xB6, 0xE1, 0xB9, 0xB8, 0xE1,
+               0xB9, 0xBA, 0xE1, 0xB9, 0xBC, 0xE1, 0xB9, 0xBE,
+               0xE1, 0xBA, 0x80, 0xE1, 0xBA, 0x82, 0xE1, 0xBA,
+               0x84, 0xE1, 0xBA, 0x86, 0xE1, 0xBA, 0x88, 0xE1,
+               0xBA, 0x8A, 0xE1, 0xBA, 0x8C, 0xE1, 0xBA, 0x8E,
+               0xE1, 0xBA, 0x90, 0xE1, 0xBA, 0x92, 0xE1, 0xBA,
+               0x94, 0xE1, 0xB9, 0xA0, 0xE1, 0xBA, 0xA0, 0xE1,
+               0xBA, 0xA2, 0xE1, 0xBA, 0xA4, 0xE1, 0xBA, 0xA6,
+               0xE1, 0xBA, 0xA8, 0xE1, 0xBA, 0xAA, 0xE1, 0xBA,
+               0xAC, 0xE1, 0xBA, 0xAE, 0xE1, 0xBA, 0xB0, 0xE1,
+               0xBA, 0xB2, 0xE1, 0xBA, 0xB4, 0xE1, 0xBA, 0xB6,
+               0xE1, 0xBA, 0xB8, 0xE1, 0xBA, 0xBA, 0xE1, 0xBA,
+               0xBC, 0xE1, 0xBA, 0xBE, 0xE1, 0xBB, 0x80, 0xE1,
+               0xBB, 0x82, 0xE1, 0xBB, 0x84, 0xE1, 0xBB, 0x86,
+               0xE1, 0xBB, 0x88, 0xE1, 0xBB, 0x8A, 0xE1, 0xBB,
+               0x8C, 0xE1, 0xBB, 0x8E, 0xE1, 0xBB, 0x90, 0xE1,
+               0xBB, 0x92, 0xE1, 0xBB, 0x94, 0xE1, 0xBB, 0x96,
+               0xE1, 0xBB, 0x98, 0xE1, 0xBB, 0x9A, 0xE1, 0xBB,
+               0x9C, 0xE1, 0xBB, 0x9E, 0xE1, 0xBB, 0xA0, 0xE1,
+               0xBB, 0xA2, 0xE1, 0xBB, 0xA4, 0xE1, 0xBB, 0xA6,
+               0xE1, 0xBB, 0xA8, 0xE1, 0xBB, 0xAA, 0xE1, 0xBB,
+               0xAC, 0xE1, 0xBB, 0xAE, 0xE1, 0xBB, 0xB0, 0xE1,
+               0xBB, 0xB2, 0xE1, 0xBB, 0xB4, 0xE1, 0xBB, 0xB6,
+               0xE1, 0xBB, 0xB8, 0xE1, 0xBC, 0x88, 0xE1, 0xBC,
+               0x89, 0xE1, 0xBC, 0x8A, 0xE1, 0xBC, 0x8B, 0xE1,
+               0xBC, 0x8C, 0xE1, 0xBC, 0x8D, 0xE1, 0xBC, 0x8E,
+               0xE1, 0xBC, 0x8F, 0xE1, 0xBC, 0x98, 0xE1, 0xBC,
+               0x99, 0xE1, 0xBC, 0x9A, 0xE1, 0xBC, 0x9B, 0xE1,
+               0xBC, 0x9C, 0xE1, 0xBC, 0x9D, 0xE1, 0xBC, 0xA8,
+               0xE1, 0xBC, 0xA9, 0xE1, 0xBC, 0xAA, 0xE1, 0xBC,
+               0xAB, 0xE1, 0xBC, 0xAC, 0xE1, 0xBC, 0xAD, 0xE1,
+               0xBC, 0xAE, 0xE1, 0xBC, 0xAF, 0xE1, 0xBC, 0xB8,
+               0xE1, 0xBC, 0xB9, 0xE1, 0xBC, 0xBA, 0xE1, 0xBC,
+               0xBB, 0xE1, 0xBC, 0xBC, 0xE1, 0xBC, 0xBD, 0xE1,
+               0xBC, 0xBE, 0xE1, 0xBC, 0xBF, 0xE1, 0xBD, 0x88,
+               0xE1, 0xBD, 0x89, 0xE1, 0xBD, 0x8A, 0xE1, 0xBD,
+               0x8B, 0xE1, 0xBD, 0x8C, 0xE1, 0xBD, 0x8D, 0xE1,
+               0xBD, 0x99, 0xE1, 0xBD, 0x9B, 0xE1, 0xBD, 0x9D,
+               0xE1, 0xBD, 0x9F, 0xE1, 0xBD, 0xA8, 0xE1, 0xBD,
+               0xA9, 0xE1, 0xBD, 0xAA, 0xE1, 0xBD, 0xAB, 0xE1,
+               0xBD, 0xAC, 0xE1, 0xBD, 0xAD, 0xE1, 0xBD, 0xAE,
+               0xE1, 0xBD, 0xAF, 0xE1, 0xBE, 0xBA, 0xE1, 0xBE,
+               0xBB, 0xE1, 0xBF, 0x88, 0xE1, 0xBF, 0x89, 0xE1,
+               0xBF, 0x8A, 0xE1, 0xBF, 0x8B, 0xE1, 0xBF, 0x9A,
+               0xE1, 0xBF, 0x9B, 0xE1, 0xBF, 0xB8, 0xE1, 0xBF,
+               0xB9, 0xE1, 0xBF, 0xAA, 0xE1, 0xBF, 0xAB, 0xE1,
+               0xBF, 0xBA, 0xE1, 0xBF, 0xBB, 0xE1, 0xBE, 0x88,
+               0xE1, 0xBE, 0x89, 0xE1, 0xBE, 0x8A, 0xE1, 0xBE,
+               0x8B, 0xE1, 0xBE, 0x8C, 0xE1, 0xBE, 0x8D, 0xE1,
+               0xBE, 0x8E, 0xE1, 0xBE, 0x8F, 0xE1, 0xBE, 0x98,
+               0xE1, 0xBE, 0x99, 0xE1, 0xBE, 0x9A, 0xE1, 0xBE,
+               0x9B, 0xE1, 0xBE, 0x9C, 0xE1, 0xBE, 0x9D, 0xE1,
+               0xBE, 0x9E, 0xE1, 0xBE, 0x9F, 0xE1, 0xBE, 0xA8,
+               0xE1, 0xBE, 0xA9, 0xE1, 0xBE, 0xAA, 0xE1, 0xBE,
+               0xAB, 0xE1, 0xBE, 0xAC, 0xE1, 0xBE, 0xAD, 0xE1,
+               0xBE, 0xAE, 0xE1, 0xBE, 0xAF, 0xE1, 0xBE, 0xB8,
+               0xE1, 0xBE, 0xB9, 0xE1, 0xBE, 0xBC, 0xCE, 0x99,
+               0xE1, 0xBF, 0x8C, 0xE1, 0xBF, 0x98, 0xE1, 0xBF,
+               0x99, 0xE1, 0xBF, 0xA8, 0xE1, 0xBF, 0xA9, 0xE1,
+               0xBF, 0xAC, 0xE1, 0xBF, 0xBC, 0xE2, 0x85, 0xA0,
+               0xE2, 0x85, 0xA1, 0xE2, 0x85, 0xA2, 0xE2, 0x85,
+               0xA3, 0xE2, 0x85, 0xA4, 0xE2, 0x85, 0xA5, 0xE2,
+               0x85, 0xA6, 0xE2, 0x85, 0xA7, 0xE2, 0x85, 0xA8,
+               0xE2, 0x85, 0xA9, 0xE2, 0x85, 0xAA, 0xE2, 0x85,
+               0xAB, 0xE2, 0x85, 0xAC, 0xE2, 0x85, 0xAD, 0xE2,
+               0x85, 0xAE, 0xE2, 0x85, 0xAF, 0xE2, 0x92, 0xB6,
+               0xE2, 0x92, 0xB7, 0xE2, 0x92, 0xB8, 0xE2, 0x92,
+               0xB9, 0xE2, 0x92, 0xBA, 0xE2, 0x92, 0xBB, 0xE2,
+               0x92, 0xBC, 0xE2, 0x92, 0xBD, 0xE2, 0x92, 0xBE,
+               0xE2, 0x92, 0xBF, 0xE2, 0x93, 0x80, 0xE2, 0x93,
+               0x81, 0xE2, 0x93, 0x82, 0xE2, 0x93, 0x83, 0xE2,
+               0x93, 0x84, 0xE2, 0x93, 0x85, 0xE2, 0x93, 0x86,
+               0xE2, 0x93, 0x87, 0xE2, 0x93, 0x88, 0xE2, 0x93,
+               0x89, 0xE2, 0x93, 0x8A, 0xE2, 0x93, 0x8B, 0xE2,
+               0x93, 0x8C, 0xE2, 0x93, 0x8D, 0xE2, 0x93, 0x8E,
+               0xE2, 0x93, 0x8F, 0xEF, 0xBC, 0xA1, 0xEF, 0xBC,
+               0xA2, 0xEF, 0xBC, 0xA3, 0xEF, 0xBC, 0xA4, 0xEF,
+               0xBC, 0xA5, 0xEF, 0xBC, 0xA6, 0xEF, 0xBC, 0xA7,
+               0xEF, 0xBC, 0xA8, 0xEF, 0xBC, 0xA9, 0xEF, 0xBC,
+               0xAA, 0xEF, 0xBC, 0xAB, 0xEF, 0xBC, 0xAC, 0xEF,
+               0xBC, 0xAD, 0xEF, 0xBC, 0xAE, 0xEF, 0xBC, 0xAF,
+               0xEF, 0xBC, 0xB0, 0xEF, 0xBC, 0xB1, 0xEF, 0xBC,
+               0xB2, 0xEF, 0xBC, 0xB3, 0xEF, 0xBC, 0xB4, 0xEF,
+               0xBC, 0xB5, 0xEF, 0xBC, 0xB6, 0xEF, 0xBC, 0xB7,
+               0xEF, 0xBC, 0xB8, 0xEF, 0xBC, 0xB9, 0xEF, 0xBC,
+               0xBA, 0xF0, 0x90, 0x90, 0x80, 0xF0, 0x90, 0x90,
+               0x81, 0xF0, 0x90, 0x90, 0x82, 0xF0, 0x90, 0x90,
+               0x83, 0xF0, 0x90, 0x90, 0x84, 0xF0, 0x90, 0x90,
+               0x85, 0xF0, 0x90, 0x90, 0x86, 0xF0, 0x90, 0x90,
+               0x87, 0xF0, 0x90, 0x90, 0x88, 0xF0, 0x90, 0x90,
+               0x89, 0xF0, 0x90, 0x90, 0x8A, 0xF0, 0x90, 0x90,
+               0x8B, 0xF0, 0x90, 0x90, 0x8C, 0xF0, 0x90, 0x90,
+               0x8D, 0xF0, 0x90, 0x90, 0x8E, 0xF0, 0x90, 0x90,
+               0x8F, 0xF0, 0x90, 0x90, 0x90, 0xF0, 0x90, 0x90,
+               0x91, 0xF0, 0x90, 0x90, 0x92, 0xF0, 0x90, 0x90,
+               0x93, 0xF0, 0x90, 0x90, 0x94, 0xF0, 0x90, 0x90,
+               0x95, 0xF0, 0x90, 0x90, 0x96, 0xF0, 0x90, 0x90,
+               0x97, 0xF0, 0x90, 0x90, 0x98, 0xF0, 0x90, 0x90,
+               0x99, 0xF0, 0x90, 0x90, 0x9A, 0xF0, 0x90, 0x90,
+               0x9B, 0xF0, 0x90, 0x90, 0x9C, 0xF0, 0x90, 0x90,
+               0x9D, 0xF0, 0x90, 0x90, 0x9E, 0xF0, 0x90, 0x90,
+               0x9F, 0xF0, 0x90, 0x90, 0xA0, 0xF0, 0x90, 0x90,
+               0xA1, 0xF0, 0x90, 0x90, 0xA2, 0xF0, 0x90, 0x90,
+               0xA3, 0xF0, 0x90, 0x90, 0xA4, 0xF0, 0x90, 0x90,
+               0xA5, 0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,    0,    0,
+               0,    0,    0,    0,    0,    0,
+       },
+       {
+               0xCE, 0x9C, 0xC3, 0x80, 0xC3, 0x81, 0xC3, 0x82,
+               0xC3, 0x83, 0xC3, 0x84, 0xC3, 0x85, 0xC3, 0x86,
+               0xC3, 0x87, 0xC3, 0x88, 0xC3, 0x89, 0xC3, 0x8A,
+               0xC3, 0x8B, 0xC3, 0x8C, 0xC3, 0x8D, 0xC3, 0x8E,
+               0xC3, 0x8F, 0xC3, 0x90, 0xC3, 0x91, 0xC3, 0x92,
+               0xC3, 0x93, 0xC3, 0x94, 0xC3, 0x95, 0xC3, 0x96,
+               0xC3, 0x98, 0xC3, 0x99, 0xC3, 0x9A, 0xC3, 0x9B,
+               0xC3, 0x9C, 0xC3, 0x9D, 0xC3, 0x9E, 0xC5, 0xB8,
+               0xC4, 0x80, 0xC4, 0x82, 0xC4, 0x84, 0xC4, 0x86,
+               0xC4, 0x88, 0xC4, 0x8A, 0xC4, 0x8C, 0xC4, 0x8E,
+               0xC4, 0x90, 0xC4, 0x92, 0xC4, 0x94, 0xC4, 0x96,
+               0xC4, 0x98, 0xC4, 0x9A, 0xC4, 0x9C, 0xC4, 0x9E,
+               0xC4, 0xA0, 0xC4, 0xA2, 0xC4, 0xA4, 0xC4, 0xA6,
+               0xC4, 0xA8, 0xC4, 0xAA, 0xC4, 0xAC, 0xC4, 0xAE,
+               0x49, 0xC4, 0xB2, 0xC4, 0xB4, 0xC4, 0xB6, 0xC4,
+               0xB9, 0xC4, 0xBB, 0xC4, 0xBD, 0xC4, 0xBF, 0xC5,
+               0x81, 0xC5, 0x83, 0xC5, 0x85, 0xC5, 0x87, 0xC5,
+               0x8A, 0xC5, 0x8C, 0xC5, 0x8E, 0xC5, 0x90, 0xC5,
+               0x92, 0xC5, 0x94, 0xC5, 0x96, 0xC5, 0x98, 0xC5,
+               0x9A, 0xC5, 0x9C, 0xC5, 0x9E, 0xC5, 0xA0, 0xC5,
+               0xA2, 0xC5, 0xA4, 0xC5, 0xA6, 0xC5, 0xA8, 0xC5,
+               0xAA, 0xC5, 0xAC, 0xC5, 0xAE, 0xC5, 0xB0, 0xC5,
+               0xB2, 0xC5, 0xB4, 0xC5, 0xB6, 0xC5, 0xB9, 0xC5,
+               0xBB, 0xC5, 0xBD, 0x53, 0xC9, 0x83, 0xC6, 0x82,
+               0xC6, 0x84, 0xC6, 0x87, 0xC6, 0x8B, 0xC6, 0x91,
+               0xC7, 0xB6, 0xC6, 0x98, 0xC8, 0xBD, 0xC8, 0xA0,
+               0xC6, 0xA0, 0xC6, 0xA2, 0xC6, 0xA4, 0xC6, 0xA7,
+               0xC6, 0xAC, 0xC6, 0xAF, 0xC6, 0xB3, 0xC6, 0xB5,
+               0xC6, 0xB8, 0xC6, 0xBC, 0xC7, 0xB7, 0xC7, 0x84,
+               0xC7, 0x84, 0xC7, 0x87, 0xC7, 0x87, 0xC7, 0x8A,
+               0xC7, 0x8A, 0xC7, 0x8D, 0xC7, 0x8F, 0xC7, 0x91,
+               0xC7, 0x93, 0xC7, 0x95, 0xC7, 0x97, 0xC7, 0x99,
+               0xC7, 0x9B, 0xC6, 0x8E, 0xC7, 0x9E, 0xC7, 0xA0,
+               0xC7, 0xA2, 0xC7, 0xA4, 0xC7, 0xA6, 0xC7, 0xA8,
+               0xC7, 0xAA, 0xC7, 0xAC, 0xC7, 0xAE, 0xC7, 0xB1,
+               0xC7, 0xB1, 0xC7, 0xB4, 0xC7, 0xB8, 0xC7, 0xBA,
+               0xC7, 0xBC, 0xC7, 0xBE, 0xC8, 0x80, 0xC8, 0x82,
+               0xC8, 0x84, 0xC8, 0x86, 0xC8, 0x88, 0xC8, 0x8A,
+               0xC8, 0x8C, 0xC8, 0x8E, 0xC8, 0x90, 0xC8, 0x92,
+               0xC8, 0x94, 0xC8, 0x96, 0xC8, 0x98, 0xC8, 0x9A,
+               0xC8, 0x9C, 0xC8, 0x9E, 0xC8, 0xA2, 0xC8, 0xA4,
+               0xC8, 0xA6, 0xC8, 0xA8, 0xC8, 0xAA, 0xC8, 0xAC,
+               0xC8, 0xAE, 0xC8, 0xB0, 0xC8, 0xB2, 0xC8, 0xBB,
+               0xC9, 0x81, 0xC9, 0x86, 0xC9, 0x88, 0xC9, 0x8A,
+               0xC9, 0x8C, 0xC9, 0x8E, 0xC6, 0x81, 0xC6, 0x86,
+               0xC6, 0x89, 0xC6, 0x8A, 0xC6, 0x8F, 0xC6, 0x90,
+               0xC6, 0x93, 0xC6, 0x94, 0xC6, 0x97, 0xC6, 0x96,
+               0xE2, 0xB1, 0xA2, 0xC6, 0x9C, 0xC6, 0x9D, 0xC6,
+               0x9F, 0xE2, 0xB1, 0xA4, 0xC6, 0xA6, 0xC6, 0xA9,
+               0xC6, 0xAE, 0xC9, 0x84, 0xC6, 0xB1, 0xC6, 0xB2,
+               0xC9, 0x85, 0xC6, 0xB7, 0xCE, 0x99, 0xCF, 0xBD,
+               0xCF, 0xBE, 0xCF, 0xBF, 0xCE, 0x86, 0xCE, 0x88,
+               0xCE, 0x89, 0xCE, 0x8A, 0xCE, 0x91, 0xCE, 0x92,
+               0xCE, 0x93, 0xCE, 0x94, 0xCE, 0x95, 0xCE, 0x96,
+               0xCE, 0x97, 0xCE, 0x98, 0xCE, 0x99, 0xCE, 0x9A,
+               0xCE, 0x9B, 0xCE, 0x9C, 0xCE, 0x9D, 0xCE, 0x9E,
+               0xCE, 0x9F, 0xCE, 0xA0, 0xCE, 0xA1, 0xCE, 0xA3,
+               0xCE, 0xA3, 0xCE, 0xA4, 0xCE, 0xA5, 0xCE, 0xA6,
+               0xCE, 0xA7, 0xCE, 0xA8, 0xCE, 0xA9, 0xCE, 0xAA,
+               0xCE, 0xAB, 0xCE, 0x8C, 0xCE, 0x8E, 0xCE, 0x8F,
+               0xCE, 0x92, 0xCE, 0x98, 0xCE, 0xA6, 0xCE, 0xA0,
+               0xCF, 0x98, 0xCF, 0x9A, 0xCF, 0x9C, 0xCF, 0x9E,
+               0xCF, 0xA0, 0xCF, 0xA2, 0xCF, 0xA4, 0xCF, 0xA6,
+               0xCF, 0xA8, 0xCF, 0xAA, 0xCF, 0xAC, 0xCF, 0xAE,
+               0xCE, 0x9A, 0xCE, 0xA1, 0xCF, 0xB9, 0xCE, 0x95,
+               0xCF, 0xB7, 0xCF, 0xBA, 0xD0, 0x90, 0xD0, 0x91,
+               0xD0, 0x92, 0xD0, 0x93, 0xD0, 0x94, 0xD0, 0x95,
+               0xD0, 0x96, 0xD0, 0x97, 0xD0, 0x98, 0xD0, 0x99,
+               0xD0, 0x9A, 0xD0, 0x9B, 0xD0, 0x9C, 0xD0, 0x9D,
+               0xD0, 0x9E, 0xD0, 0x9F, 0xD0, 0xA0, 0xD0, 0xA1,
+               0xD0, 0xA2, 0xD0, 0xA3, 0xD0, 0xA4, 0xD0, 0xA5,
+               0xD0, 0xA6, 0xD0, 0xA7, 0xD0, 0xA8, 0xD0, 0xA9,
+               0xD0, 0xAA, 0xD0, 0xAB, 0xD0, 0xAC, 0xD0, 0xAD,
+               0xD0, 0xAE, 0xD0, 0xAF, 0xD0, 0x80, 0xD0, 0x81,
+               0xD0, 0x82, 0xD0, 0x83, 0xD0, 0x84, 0xD0, 0x85,
+               0xD0, 0x86, 0xD0, 0x87, 0xD0, 0x88, 0xD0, 0x89,
+               0xD0, 0x8A, 0xD0, 0x8B, 0xD0, 0x8C, 0xD0, 0x8D,
+               0xD0, 0x8E, 0xD0, 0x8F, 0xD1, 0xA0, 0xD1, 0xA2,
+               0xD1, 0xA4, 0xD1, 0xA6, 0xD1, 0xA8, 0xD1, 0xAA,
+               0xD1, 0xAC, 0xD1, 0xAE, 0xD1, 0xB0, 0xD1, 0xB2,
+               0xD1, 0xB4, 0xD1, 0xB6, 0xD1, 0xB8, 0xD1, 0xBA,
+               0xD1, 0xBC, 0xD1, 0xBE, 0xD2, 0x80, 0xD2, 0x8A,
+               0xD2, 0x8C, 0xD2, 0x8E, 0xD2, 0x90, 0xD2, 0x92,
+               0xD2, 0x94, 0xD2, 0x96, 0xD2, 0x98, 0xD2, 0x9A,
+               0xD2, 0x9C, 0xD2, 0x9E, 0xD2, 0xA0, 0xD2, 0xA2,
+               0xD2, 0xA4, 0xD2, 0xA6, 0xD2, 0xA8, 0xD2, 0xAA,
+               0xD2, 0xAC, 0xD2, 0xAE, 0xD2, 0xB0, 0xD2, 0xB2,
+               0xD2, 0xB4, 0xD2, 0xB6, 0xD2, 0xB8, 0xD2, 0xBA,
+               0xD2, 0xBC, 0xD2, 0xBE, 0xD3, 0x81, 0xD3, 0x83,
+               0xD3, 0x85, 0xD3, 0x87, 0xD3, 0x89, 0xD3, 0x8B,
+               0xD3, 0x8D, 0xD3, 0x80, 0xD3, 0x90, 0xD3, 0x92,
+               0xD3, 0x94, 0xD3, 0x96, 0xD3, 0x98, 0xD3, 0x9A,
+               0xD3, 0x9C, 0xD3, 0x9E, 0xD3, 0xA0, 0xD3, 0xA2,
+               0xD3, 0xA4, 0xD3, 0xA6, 0xD3, 0xA8, 0xD3, 0xAA,
+               0xD3, 0xAC, 0xD3, 0xAE, 0xD3, 0xB0, 0xD3, 0xB2,
+               0xD3, 0xB4, 0xD3, 0xB6, 0xD3, 0xB8, 0xD3, 0xBA,
+               0xD3, 0xBC, 0xD3, 0xBE, 0xD4, 0x80, 0xD4, 0x82,
+               0xD4, 0x84, 0xD4, 0x86, 0xD4, 0x88, 0xD4, 0x8A,
+               0xD4, 0x8C, 0xD4, 0x8E, 0xD4, 0x90, 0xD4, 0x92,
+               0xD4, 0xB1, 0xD4, 0xB2, 0xD4, 0xB3, 0xD4, 0xB4,
+               0xD4, 0xB5, 0xD4, 0xB6, 0xD4, 0xB7, 0xD4, 0xB8,
+               0xD4, 0xB9, 0xD4, 0xBA, 0xD4, 0xBB, 0xD4, 0xBC,
+               0xD4, 0xBD, 0xD4, 0xBE, 0xD4, 0xBF, 0xD5, 0x80,
+               0xD5, 0x81, 0xD5, 0x82, 0xD5, 0x83, 0xD5, 0x84,
+               0xD5, 0x85, 0xD5, 0x86, 0xD5, 0x87, 0xD5, 0x88,
+               0xD5, 0x89, 0xD5, 0x8A, 0xD5, 0x8B, 0xD5, 0x8C,
+               0xD5, 0x8D, 0xD5, 0x8E, 0xD5, 0x8F, 0xD5, 0x90,
+               0xD5, 0x91, 0xD5, 0x92, 0xD5, 0x93, 0xD5, 0x94,
+               0xD5, 0x95, 0xD5, 0x96, 0xE2, 0xB1, 0xA3, 0xE1,
+               0xB8, 0x80, 0xE1, 0xB8, 0x82, 0xE1, 0xB8, 0x84,
+               0xE1, 0xB8, 0x86, 0xE1, 0xB8, 0x88, 0xE1, 0xB8,
+               0x8A, 0xE1, 0xB8, 0x8C, 0xE1, 0xB8, 0x8E, 0xE1,
+               0xB8, 0x90, 0xE1, 0xB8, 0x92, 0xE1, 0xB8, 0x94,
+               0xE1, 0xB8, 0x96, 0xE1, 0xB8, 0x98, 0xE1, 0xB8,
+               0x9A, 0xE1, 0xB8, 0x9C, 0xE1, 0xB8, 0x9E, 0xE1,
+               0xB8, 0xA0, 0xE1, 0xB8, 0xA2, 0xE1, 0xB8, 0xA4,
+               0xE1, 0xB8, 0xA6, 0xE1, 0xB8, 0xA8, 0xE1, 0xB8,
+               0xAA, 0xE1, 0xB8, 0xAC, 0xE1, 0xB8, 0xAE, 0xE1,
+               0xB8, 0xB0, 0xE1, 0xB8, 0xB2, 0xE1, 0xB8, 0xB4,
+               0xE1, 0xB8, 0xB6, 0xE1, 0xB8, 0xB8, 0xE1, 0xB8,
+               0xBA, 0xE1, 0xB8, 0xBC, 0xE1, 0xB8, 0xBE, 0xE1,
+               0xB9, 0x80, 0xE1, 0xB9, 0x82, 0xE1, 0xB9, 0x84,
+               0xE1, 0xB9, 0x86, 0xE1, 0xB9, 0x88, 0xE1, 0xB9,
+               0x8A, 0xE1, 0xB9, 0x8C, 0xE1, 0xB9, 0x8E, 0xE1,
+               0xB9, 0x90, 0xE1, 0xB9, 0x92, 0xE1, 0xB9, 0x94,
+               0xE1, 0xB9, 0x96, 0xE1, 0xB9, 0x98, 0xE1, 0xB9,
+               0x9A, 0xE1, 0xB9, 0x9C, 0xE1, 0xB9, 0x9E, 0xE1,
+               0xB9, 0xA0, 0xE1, 0xB9, 0xA2, 0xE1, 0xB9, 0xA4,
+               0xE1, 0xB9, 0xA6, 0xE1, 0xB9, 0xA8, 0xE1, 0xB9,
+               0xAA, 0xE1, 0xB9, 0xAC, 0xE1, 0xB9, 0xAE, 0xE1,
+               0xB9, 0xB0, 0xE1, 0xB9, 0xB2, 0xE1, 0xB9, 0xB4,
+               0xE1, 0xB9, 0xB6, 0xE1, 0xB9, 0xB8, 0xE1, 0xB9,
+               0xBA, 0xE1, 0xB9, 0xBC, 0xE1, 0xB9, 0xBE, 0xE1,
+               0xBA, 0x80, 0xE1, 0xBA, 0x82, 0xE1, 0xBA, 0x84,
+               0xE1, 0xBA, 0x86, 0xE1, 0xBA, 0x88, 0xE1, 0xBA,
+               0x8A, 0xE1, 0xBA, 0x8C, 0xE1, 0xBA, 0x8E, 0xE1,
+               0xBA, 0x90, 0xE1, 0xBA, 0x92, 0xE1, 0xBA, 0x94,
+               0xE1, 0xB9, 0xA0, 0xE1, 0xBA, 0xA0, 0xE1, 0xBA,
+               0xA2, 0xE1, 0xBA, 0xA4, 0xE1, 0xBA, 0xA6, 0xE1,
+               0xBA, 0xA8, 0xE1, 0xBA, 0xAA, 0xE1, 0xBA, 0xAC,
+               0xE1, 0xBA, 0xAE, 0xE1, 0xBA, 0xB0, 0xE1, 0xBA,
+               0xB2, 0xE1, 0xBA, 0xB4, 0xE1, 0xBA, 0xB6, 0xE1,
+               0xBA, 0xB8, 0xE1, 0xBA, 0xBA, 0xE1, 0xBA, 0xBC,
+               0xE1, 0xBA, 0xBE, 0xE1, 0xBB, 0x80, 0xE1, 0xBB,
+               0x82, 0xE1, 0xBB, 0x84, 0xE1, 0xBB, 0x86, 0xE1,
+               0xBB, 0x88, 0xE1, 0xBB, 0x8A, 0xE1, 0xBB, 0x8C,
+               0xE1, 0xBB, 0x8E, 0xE1, 0xBB, 0x90, 0xE1, 0xBB,
+               0x92, 0xE1, 0xBB, 0x94, 0xE1, 0xBB, 0x96, 0xE1,
+               0xBB, 0x98, 0xE1, 0xBB, 0x9A, 0xE1, 0xBB, 0x9C,
+               0xE1, 0xBB, 0x9E, 0xE1, 0xBB, 0xA0, 0xE1, 0xBB,
+               0xA2, 0xE1, 0xBB, 0xA4, 0xE1, 0xBB, 0xA6, 0xE1,
+               0xBB, 0xA8, 0xE1, 0xBB, 0xAA, 0xE1, 0xBB, 0xAC,
+               0xE1, 0xBB, 0xAE, 0xE1, 0xBB, 0xB0, 0xE1, 0xBB,
+               0xB2, 0xE1, 0xBB, 0xB4, 0xE1, 0xBB, 0xB6, 0xE1,
+               0xBB, 0xB8, 0xE1, 0xBC, 0x88, 0xE1, 0xBC, 0x89,
+               0xE1, 0xBC, 0x8A, 0xE1, 0xBC, 0x8B, 0xE1, 0xBC,
+               0x8C, 0xE1, 0xBC, 0x8D, 0xE1, 0xBC, 0x8E, 0xE1,
+               0xBC, 0x8F, 0xE1, 0xBC, 0x98, 0xE1, 0xBC, 0x99,
+               0xE1, 0xBC, 0x9A, 0xE1, 0xBC, 0x9B, 0xE1, 0xBC,
+               0x9C, 0xE1, 0xBC, 0x9D, 0xE1, 0xBC, 0xA8, 0xE1,
+               0xBC, 0xA9, 0xE1, 0xBC, 0xAA, 0xE1, 0xBC, 0xAB,
+               0xE1, 0xBC, 0xAC, 0xE1, 0xBC, 0xAD, 0xE1, 0xBC,
+               0xAE, 0xE1, 0xBC, 0xAF, 0xE1, 0xBC, 0xB8, 0xE1,
+               0xBC, 0xB9, 0xE1, 0xBC, 0xBA, 0xE1, 0xBC, 0xBB,
+               0xE1, 0xBC, 0xBC, 0xE1, 0xBC, 0xBD, 0xE1, 0xBC,
+               0xBE, 0xE1, 0xBC, 0xBF, 0xE1, 0xBD, 0x88, 0xE1,
+               0xBD, 0x89, 0xE1, 0xBD, 0x8A, 0xE1, 0xBD, 0x8B,
+               0xE1, 0xBD, 0x8C, 0xE1, 0xBD, 0x8D, 0xE1, 0xBD,
+               0x99, 0xE1, 0xBD, 0x9B, 0xE1, 0xBD, 0x9D, 0xE1,
+               0xBD, 0x9F, 0xE1, 0xBD, 0xA8, 0xE1, 0xBD, 0xA9,
+               0xE1, 0xBD, 0xAA, 0xE1, 0xBD, 0xAB, 0xE1, 0xBD,
+               0xAC, 0xE1, 0xBD, 0xAD, 0xE1, 0xBD, 0xAE, 0xE1,
+               0xBD, 0xAF, 0xE1, 0xBE, 0xBA, 0xE1, 0xBE, 0xBB,
+               0xE1, 0xBF, 0x88, 0xE1, 0xBF, 0x89, 0xE1, 0xBF,
+               0x8A, 0xE1, 0xBF, 0x8B, 0xE1, 0xBF, 0x9A, 0xE1,
+               0xBF, 0x9B, 0xE1, 0xBF, 0xB8, 0xE1, 0xBF, 0xB9,
+               0xE1, 0xBF, 0xAA, 0xE1, 0xBF, 0xAB, 0xE1, 0xBF,
+               0xBA, 0xE1, 0xBF, 0xBB, 0xE1, 0xBE, 0x88, 0xE1,
+               0xBE, 0x89, 0xE1, 0xBE, 0x8A, 0xE1, 0xBE, 0x8B,
+               0xE1, 0xBE, 0x8C, 0xE1, 0xBE, 0x8D, 0xE1, 0xBE,
+               0x8E, 0xE1, 0xBE, 0x8F, 0xE1, 0xBE, 0x98, 0xE1,
+               0xBE, 0x99, 0xE1, 0xBE, 0x9A, 0xE1, 0xBE, 0x9B,
+               0xE1, 0xBE, 0x9C, 0xE1, 0xBE, 0x9D, 0xE1, 0xBE,
+               0x9E, 0xE1, 0xBE, 0x9F, 0xE1, 0xBE, 0xA8, 0xE1,
+               0xBE, 0xA9, 0xE1, 0xBE, 0xAA, 0xE1, 0xBE, 0xAB,
+               0xE1, 0xBE, 0xAC, 0xE1, 0xBE, 0xAD, 0xE1, 0xBE,
+               0xAE, 0xE1, 0xBE, 0xAF, 0xE1, 0xBE, 0xB8, 0xE1,
+               0xBE, 0xB9, 0xE1, 0xBE, 0xBC, 0xCE, 0x99, 0xE1,
+               0xBF, 0x8C, 0xE1, 0xBF, 0x98, 0xE1, 0xBF, 0x99,
+               0xE1, 0xBF, 0xA8, 0xE1, 0xBF, 0xA9, 0xE1, 0xBF,
+               0xAC, 0xE1, 0xBF, 0xBC, 0xE2, 0x84, 0xB2, 0xE2,
+               0x85, 0xA0, 0xE2, 0x85, 0xA1, 0xE2, 0x85, 0xA2,
+               0xE2, 0x85, 0xA3, 0xE2, 0x85, 0xA4, 0xE2, 0x85,
+               0xA5, 0xE2, 0x85, 0xA6, 0xE2, 0x85, 0xA7, 0xE2,
+               0x85, 0xA8, 0xE2, 0x85, 0xA9, 0xE2, 0x85, 0xAA,
+               0xE2, 0x85, 0xAB, 0xE2, 0x85, 0xAC, 0xE2, 0x85,
+               0xAD, 0xE2, 0x85, 0xAE, 0xE2, 0x85, 0xAF, 0xE2,
+               0x86, 0x83, 0xE2, 0x92, 0xB6, 0xE2, 0x92, 0xB7,
+               0xE2, 0x92, 0xB8, 0xE2, 0x92, 0xB9, 0xE2, 0x92,
+               0xBA, 0xE2, 0x92, 0xBB, 0xE2, 0x92, 0xBC, 0xE2,
+               0x92, 0xBD, 0xE2, 0x92, 0xBE, 0xE2, 0x92, 0xBF,
+               0xE2, 0x93, 0x80, 0xE2, 0x93, 0x81, 0xE2, 0x93,
+               0x82, 0xE2, 0x93, 0x83, 0xE2, 0x93, 0x84, 0xE2,
+               0x93, 0x85, 0xE2, 0x93, 0x86, 0xE2, 0x93, 0x87,
+               0xE2, 0x93, 0x88, 0xE2, 0x93, 0x89, 0xE2, 0x93,
+               0x8A, 0xE2, 0x93, 0x8B, 0xE2, 0x93, 0x8C, 0xE2,
+               0x93, 0x8D, 0xE2, 0x93, 0x8E, 0xE2, 0x93, 0x8F,
+               0xE2, 0xB0, 0x80, 0xE2, 0xB0, 0x81, 0xE2, 0xB0,
+               0x82, 0xE2, 0xB0, 0x83, 0xE2, 0xB0, 0x84, 0xE2,
+               0xB0, 0x85, 0xE2, 0xB0, 0x86, 0xE2, 0xB0, 0x87,
+               0xE2, 0xB0, 0x88, 0xE2, 0xB0, 0x89, 0xE2, 0xB0,
+               0x8A, 0xE2, 0xB0, 0x8B, 0xE2, 0xB0, 0x8C, 0xE2,
+               0xB0, 0x8D, 0xE2, 0xB0, 0x8E, 0xE2, 0xB0, 0x8F,
+               0xE2, 0xB0, 0x90, 0xE2, 0xB0, 0x91, 0xE2, 0xB0,
+               0x92, 0xE2, 0xB0, 0x93, 0xE2, 0xB0, 0x94, 0xE2,
+               0xB0, 0x95, 0xE2, 0xB0, 0x96, 0xE2, 0xB0, 0x97,
+               0xE2, 0xB0, 0x98, 0xE2, 0xB0, 0x99, 0xE2, 0xB0,
+               0x9A, 0xE2, 0xB0, 0x9B, 0xE2, 0xB0, 0x9C, 0xE2,
+               0xB0, 0x9D, 0xE2, 0xB0, 0x9E, 0xE2, 0xB0, 0x9F,
+               0xE2, 0xB0, 0xA0, 0xE2, 0xB0, 0xA1, 0xE2, 0xB0,
+               0xA2, 0xE2, 0xB0, 0xA3, 0xE2, 0xB0, 0xA4, 0xE2,
+               0xB0, 0xA5, 0xE2, 0xB0, 0xA6, 0xE2, 0xB0, 0xA7,
+               0xE2, 0xB0, 0xA8, 0xE2, 0xB0, 0xA9, 0xE2, 0xB0,
+               0xAA, 0xE2, 0xB0, 0xAB, 0xE2, 0xB0, 0xAC, 0xE2,
+               0xB0, 0xAD, 0xE2, 0xB0, 0xAE, 0xE2, 0xB1, 0xA0,
+               0xC8, 0xBA, 0xC8, 0xBE, 0xE2, 0xB1, 0xA7, 0xE2,
+               0xB1, 0xA9, 0xE2, 0xB1, 0xAB, 0xE2, 0xB1, 0xB5,
+               0xE2, 0xB2, 0x80, 0xE2, 0xB2, 0x82, 0xE2, 0xB2,
+               0x84, 0xE2, 0xB2, 0x86, 0xE2, 0xB2, 0x88, 0xE2,
+               0xB2, 0x8A, 0xE2, 0xB2, 0x8C, 0xE2, 0xB2, 0x8E,
+               0xE2, 0xB2, 0x90, 0xE2, 0xB2, 0x92, 0xE2, 0xB2,
+               0x94, 0xE2, 0xB2, 0x96, 0xE2, 0xB2, 0x98, 0xE2,
+               0xB2, 0x9A, 0xE2, 0xB2, 0x9C, 0xE2, 0xB2, 0x9E,
+               0xE2, 0xB2, 0xA0, 0xE2, 0xB2, 0xA2, 0xE2, 0xB2,
+               0xA4, 0xE2, 0xB2, 0xA6, 0xE2, 0xB2, 0xA8, 0xE2,
+               0xB2, 0xAA, 0xE2, 0xB2, 0xAC, 0xE2, 0xB2, 0xAE,
+               0xE2, 0xB2, 0xB0, 0xE2, 0xB2, 0xB2, 0xE2, 0xB2,
+               0xB4, 0xE2, 0xB2, 0xB6, 0xE2, 0xB2, 0xB8, 0xE2,
+               0xB2, 0xBA, 0xE2, 0xB2, 0xBC, 0xE2, 0xB2, 0xBE,
+               0xE2, 0xB3, 0x80, 0xE2, 0xB3, 0x82, 0xE2, 0xB3,
+               0x84, 0xE2, 0xB3, 0x86, 0xE2, 0xB3, 0x88, 0xE2,
+               0xB3, 0x8A, 0xE2, 0xB3, 0x8C, 0xE2, 0xB3, 0x8E,
+               0xE2, 0xB3, 0x90, 0xE2, 0xB3, 0x92, 0xE2, 0xB3,
+               0x94, 0xE2, 0xB3, 0x96, 0xE2, 0xB3, 0x98, 0xE2,
+               0xB3, 0x9A, 0xE2, 0xB3, 0x9C, 0xE2, 0xB3, 0x9E,
+               0xE2, 0xB3, 0xA0, 0xE2, 0xB3, 0xA2, 0xE1, 0x82,
+               0xA0, 0xE1, 0x82, 0xA1, 0xE1, 0x82, 0xA2, 0xE1,
+               0x82, 0xA3, 0xE1, 0x82, 0xA4, 0xE1, 0x82, 0xA5,
+               0xE1, 0x82, 0xA6, 0xE1, 0x82, 0xA7, 0xE1, 0x82,
+               0xA8, 0xE1, 0x82, 0xA9, 0xE1, 0x82, 0xAA, 0xE1,
+               0x82, 0xAB, 0xE1, 0x82, 0xAC, 0xE1, 0x82, 0xAD,
+               0xE1, 0x82, 0xAE, 0xE1, 0x82, 0xAF, 0xE1, 0x82,
+               0xB0, 0xE1, 0x82, 0xB1, 0xE1, 0x82, 0xB2, 0xE1,
+               0x82, 0xB3, 0xE1, 0x82, 0xB4, 0xE1, 0x82, 0xB5,
+               0xE1, 0x82, 0xB6, 0xE1, 0x82, 0xB7, 0xE1, 0x82,
+               0xB8, 0xE1, 0x82, 0xB9, 0xE1, 0x82, 0xBA, 0xE1,
+               0x82, 0xBB, 0xE1, 0x82, 0xBC, 0xE1, 0x82, 0xBD,
+               0xE1, 0x82, 0xBE, 0xE1, 0x82, 0xBF, 0xE1, 0x83,
+               0x80, 0xE1, 0x83, 0x81, 0xE1, 0x83, 0x82, 0xE1,
+               0x83, 0x83, 0xE1, 0x83, 0x84, 0xE1, 0x83, 0x85,
+               0xEF, 0xBC, 0xA1, 0xEF, 0xBC, 0xA2, 0xEF, 0xBC,
+               0xA3, 0xEF, 0xBC, 0xA4, 0xEF, 0xBC, 0xA5, 0xEF,
+               0xBC, 0xA6, 0xEF, 0xBC, 0xA7, 0xEF, 0xBC, 0xA8,
+               0xEF, 0xBC, 0xA9, 0xEF, 0xBC, 0xAA, 0xEF, 0xBC,
+               0xAB, 0xEF, 0xBC, 0xAC, 0xEF, 0xBC, 0xAD, 0xEF,
+               0xBC, 0xAE, 0xEF, 0xBC, 0xAF, 0xEF, 0xBC, 0xB0,
+               0xEF, 0xBC, 0xB1, 0xEF, 0xBC, 0xB2, 0xEF, 0xBC,
+               0xB3, 0xEF, 0xBC, 0xB4, 0xEF, 0xBC, 0xB5, 0xEF,
+               0xBC, 0xB6, 0xEF, 0xBC, 0xB7, 0xEF, 0xBC, 0xB8,
+               0xEF, 0xBC, 0xB9, 0xEF, 0xBC, 0xBA, 0xF0, 0x90,
+               0x90, 0x80, 0xF0, 0x90, 0x90, 0x81, 0xF0, 0x90,
+               0x90, 0x82, 0xF0, 0x90, 0x90, 0x83, 0xF0, 0x90,
+               0x90, 0x84, 0xF0, 0x90, 0x90, 0x85, 0xF0, 0x90,
+               0x90, 0x86, 0xF0, 0x90, 0x90, 0x87, 0xF0, 0x90,
+               0x90, 0x88, 0xF0, 0x90, 0x90, 0x89, 0xF0, 0x90,
+               0x90, 0x8A, 0xF0, 0x90, 0x90, 0x8B, 0xF0, 0x90,
+               0x90, 0x8C, 0xF0, 0x90, 0x90, 0x8D, 0xF0, 0x90,
+               0x90, 0x8E, 0xF0, 0x90, 0x90, 0x8F, 0xF0, 0x90,
+               0x90, 0x90, 0xF0, 0x90, 0x90, 0x91, 0xF0, 0x90,
+               0x90, 0x92, 0xF0, 0x90, 0x90, 0x93, 0xF0, 0x90,
+               0x90, 0x94, 0xF0, 0x90, 0x90, 0x95, 0xF0, 0x90,
+               0x90, 0x96, 0xF0, 0x90, 0x90, 0x97, 0xF0, 0x90,
+               0x90, 0x98, 0xF0, 0x90, 0x90, 0x99, 0xF0, 0x90,
+               0x90, 0x9A, 0xF0, 0x90, 0x90, 0x9B, 0xF0, 0x90,
+               0x90, 0x9C, 0xF0, 0x90, 0x90, 0x9D, 0xF0, 0x90,
+               0x90, 0x9E, 0xF0, 0x90, 0x90, 0x9F, 0xF0, 0x90,
+               0x90, 0xA0, 0xF0, 0x90, 0x90, 0xA1, 0xF0, 0x90,
+               0x90, 0xA2, 0xF0, 0x90, 0x90, 0xA3, 0xF0, 0x90,
+               0x90, 0xA4, 0xF0, 0x90, 0x90, 0xA5, 0xF0, 0x90,
+               0x90, 0xA6, 0xF0, 0x90, 0x90, 0xA7,
+       },
+};
+
+#undef N_
+#undef FIL_
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_U8_TEXTPREP_DATA_H */
diff --git a/zfs/include/sys/uberblock.h b/zfs/include/sys/uberblock.h
new file mode 100644 (file)
index 0000000..21e7ae0
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_UBERBLOCK_H
+#define        _SYS_UBERBLOCK_H
+
+#include <sys/spa.h>
+#include <sys/vdev.h>
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct uberblock uberblock_t;
+
+extern int uberblock_verify(uberblock_t *);
+extern boolean_t uberblock_update(uberblock_t *, vdev_t *, uint64_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_UBERBLOCK_H */
diff --git a/zfs/include/sys/uberblock_impl.h b/zfs/include/sys/uberblock_impl.h
new file mode 100644 (file)
index 0000000..6ab6aa3
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _SYS_UBERBLOCK_IMPL_H
+#define        _SYS_UBERBLOCK_IMPL_H
+
+#include <sys/uberblock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The uberblock version is incremented whenever an incompatible on-disk
+ * format change is made to the SPA, DMU, or ZAP.
+ *
+ * Note: the first two fields should never be moved.  When a storage pool
+ * is opened, the uberblock must be read off the disk before the version
+ * can be checked.  If the ub_version field is moved, we may not detect
+ * version mismatch.  If the ub_magic field is moved, applications that
+ * expect the magic number in the first word won't work.
+ */
+#define        UBERBLOCK_MAGIC         0x00bab10c              /* oo-ba-bloc!  */
+#define        UBERBLOCK_SHIFT         10                      /* up to 1K     */
+
+struct uberblock {
+       uint64_t        ub_magic;       /* UBERBLOCK_MAGIC              */
+       uint64_t        ub_version;     /* SPA_VERSION                  */
+       uint64_t        ub_txg;         /* txg of last sync             */
+       uint64_t        ub_guid_sum;    /* sum of all vdev guids        */
+       uint64_t        ub_timestamp;   /* UTC time of last sync        */
+       blkptr_t        ub_rootbp;      /* MOS objset_phys_t            */
+
+       /* highest SPA_VERSION supported by software that wrote this txg */
+       uint64_t        ub_software_version;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_UBERBLOCK_IMPL_H */
diff --git a/zfs/include/sys/uio_impl.h b/zfs/include/sys/uio_impl.h
new file mode 100644 (file)
index 0000000..37e283d
--- /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 2010 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 _SYS_UIO_IMPL_H
+#define        _SYS_UIO_IMPL_H
+
+#include <sys/uio.h>
+
+extern int uiomove(void *, size_t, enum uio_rw, uio_t *);
+extern void uio_prefaultpages(ssize_t, uio_t *);
+extern int uiocopy(void *, size_t, enum uio_rw, uio_t *, size_t *);
+extern void uioskip(uio_t *, size_t);
+
+#endif /* _SYS_UIO_IMPL_H */
diff --git a/zfs/include/sys/unique.h b/zfs/include/sys/unique.h
new file mode 100644 (file)
index 0000000..d4ba32e
--- /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.
+ */
+
+#ifndef        _SYS_UNIQUE_H
+#define        _SYS_UNIQUE_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The number of significant bits in each unique value. */
+#define        UNIQUE_BITS     56
+
+void unique_init(void);
+void unique_fini(void);
+
+/*
+ * Return a new unique value (which will not be uniquified against until
+ * it is unique_insert()-ed).
+ */
+uint64_t unique_create(void);
+
+/* Return a unique value, which equals the one passed in if possible. */
+uint64_t unique_insert(uint64_t value);
+
+/* Indicate that this value no longer needs to be uniquified against. */
+void unique_remove(uint64_t value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_UNIQUE_H */
diff --git a/zfs/include/sys/uuid.h b/zfs/include/sys/uuid.h
new file mode 100644 (file)
index 0000000..eab4622
--- /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, 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_UUID_H
+#define        _SYS_UUID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The copyright in this file is taken from the original Leach
+ * & Salz UUID specification, from which this implementation
+ * is derived.
+ */
+
+/*
+ * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+ * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+ * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
+ * Microsoft.  To anyone who acknowledges that this file is provided
+ * "AS IS" without any express or implied warranty: permission to use,
+ * copy, modify, and distribute this file for any purpose is hereby
+ * granted without fee, provided that the above copyright notices and
+ * this notice appears in all source code copies, and that none of the
+ * names of Open Software Foundation, Inc., Hewlett-Packard Company,
+ * or Digital Equipment Corporation be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Neither Open Software
+ * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
+ * Equipment Corporation makes any representations about the
+ * suitability of this software for any purpose.
+ */
+
+#include <sys/types.h>
+#include <sys/byteorder.h>
+
+typedef struct {
+       uint8_t         nodeID[6];
+} uuid_node_t;
+
+/*
+ * The uuid type used throughout when referencing uuids themselves
+ */
+struct uuid {
+       uint32_t        time_low;
+       uint16_t        time_mid;
+       uint16_t        time_hi_and_version;
+       uint8_t         clock_seq_hi_and_reserved;
+       uint8_t         clock_seq_low;
+       uint8_t         node_addr[6];
+};
+
+#define        UUID_PRINTABLE_STRING_LENGTH 37
+
+/*
+ * Convert a uuid to/from little-endian format
+ */
+#define        UUID_LE_CONVERT(dest, src)                                      \
+{                                                                      \
+       (dest) = (src);                                                 \
+       (dest).time_low = LE_32((dest).time_low);                       \
+       (dest).time_mid = LE_16((dest).time_mid);                       \
+       (dest).time_hi_and_version = LE_16((dest).time_hi_and_version); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_UUID_H */
diff --git a/zfs/include/sys/vdev.h b/zfs/include/sys/vdev.h
new file mode 100644 (file)
index 0000000..365789e
--- /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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_VDEV_H
+#define        _SYS_VDEV_H
+
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/dmu.h>
+#include <sys/space_map.h>
+#include <sys/fs/zfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum vdev_dtl_type {
+       DTL_MISSING,    /* 0% replication: no copies of the data */
+       DTL_PARTIAL,    /* less than 100% replication: some copies missing */
+       DTL_SCRUB,      /* unable to fully repair during scrub/resilver */
+       DTL_OUTAGE,     /* temporarily missing (used to attempt detach) */
+       DTL_TYPES
+} vdev_dtl_type_t;
+
+extern int zfs_nocacheflush;
+
+extern int vdev_open(vdev_t *);
+extern void vdev_open_children(vdev_t *);
+extern int vdev_validate(vdev_t *, boolean_t);
+extern void vdev_close(vdev_t *);
+extern int vdev_create(vdev_t *, uint64_t txg, boolean_t isreplace);
+extern void vdev_reopen(vdev_t *);
+extern int vdev_validate_aux(vdev_t *vd);
+extern zio_t *vdev_probe(vdev_t *vd, zio_t *pio);
+
+extern boolean_t vdev_is_bootable(vdev_t *vd);
+extern vdev_t *vdev_lookup_top(spa_t *spa, uint64_t vdev);
+extern vdev_t *vdev_lookup_by_guid(vdev_t *vd, uint64_t guid);
+extern int vdev_count_leaves(spa_t *spa);
+extern void vdev_dtl_dirty(vdev_t *vd, vdev_dtl_type_t d,
+    uint64_t txg, uint64_t size);
+extern boolean_t vdev_dtl_contains(vdev_t *vd, vdev_dtl_type_t d,
+    uint64_t txg, uint64_t size);
+extern boolean_t vdev_dtl_empty(vdev_t *vd, vdev_dtl_type_t d);
+extern void vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg,
+    int scrub_done);
+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_hold(vdev_t *);
+extern void vdev_rele(vdev_t *);
+
+extern int vdev_metaslab_init(vdev_t *vd, uint64_t txg);
+extern void vdev_metaslab_fini(vdev_t *vd);
+extern void vdev_metaslab_set_size(vdev_t *);
+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(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);
+extern void vdev_scan_stat_init(vdev_t *vd);
+extern void vdev_propagate_state(vdev_t *vd);
+extern void vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state,
+    vdev_aux_t aux);
+
+extern void vdev_space_update(vdev_t *vd,
+    int64_t alloc_delta, int64_t defer_delta, int64_t space_delta);
+
+extern uint64_t vdev_psize_to_asize(vdev_t *vd, uint64_t psize);
+
+extern int vdev_fault(spa_t *spa, uint64_t guid, vdev_aux_t aux);
+extern int vdev_degrade(spa_t *spa, uint64_t guid, vdev_aux_t aux);
+extern int vdev_online(spa_t *spa, uint64_t guid, uint64_t flags,
+    vdev_state_t *);
+extern int vdev_offline(spa_t *spa, uint64_t guid, uint64_t flags);
+extern void vdev_clear(spa_t *spa, vdev_t *vd);
+
+extern boolean_t vdev_is_dead(vdev_t *vd);
+extern boolean_t vdev_readable(vdev_t *vd);
+extern boolean_t vdev_writeable(vdev_t *vd);
+extern boolean_t vdev_allocatable(vdev_t *vd);
+extern boolean_t vdev_accessible(vdev_t *vd, zio_t *zio);
+
+extern void vdev_cache_init(vdev_t *vd);
+extern void vdev_cache_fini(vdev_t *vd);
+extern boolean_t vdev_cache_read(zio_t *zio);
+extern void vdev_cache_write(zio_t *zio);
+extern void vdev_cache_purge(vdev_t *vd);
+
+extern void vdev_queue_init(vdev_t *vd);
+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 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 void vdev_state_dirty(vdev_t *vd);
+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_flag_t;
+
+extern void vdev_top_config_generate(spa_t *spa, nvlist_t *config);
+extern nvlist_t *vdev_config_generate(spa_t *spa, vdev_t *vd,
+    boolean_t getstats, vdev_config_flag_t flags);
+
+/*
+ * Label routines
+ */
+struct uberblock;
+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 **);
+
+typedef enum {
+       VDEV_LABEL_CREATE,      /* create/add a new device */
+       VDEV_LABEL_REPLACE,     /* replace an existing device */
+       VDEV_LABEL_SPARE,       /* add a new hot spare */
+       VDEV_LABEL_REMOVE,      /* remove an existing device */
+       VDEV_LABEL_L2CACHE,     /* add an L2ARC cache device */
+       VDEV_LABEL_SPLIT        /* generating new label for split-off dev */
+} vdev_labeltype_t;
+
+extern int vdev_label_init(vdev_t *vd, uint64_t txg, vdev_labeltype_t reason);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VDEV_H */
diff --git a/zfs/include/sys/vdev_disk.h b/zfs/include/sys/vdev_disk.h
new file mode 100644 (file)
index 0000000..15570b1
--- /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 (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.
+ */
+
+#ifndef _SYS_VDEV_DISK_H
+#define        _SYS_VDEV_DISK_H
+
+#ifdef _KERNEL
+#include <sys/vdev.h>
+
+typedef struct vdev_disk {
+       ddi_devid_t             vd_devid;
+       char                    *vd_minor;
+       struct block_device     *vd_bdev;
+} vdev_disk_t;
+
+#endif /* _KERNEL */
+#endif /* _SYS_VDEV_DISK_H */
diff --git a/zfs/include/sys/vdev_file.h b/zfs/include/sys/vdev_file.h
new file mode 100644 (file)
index 0000000..aebcf55
--- /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, 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_VDEV_FILE_H
+#define        _SYS_VDEV_FILE_H
+
+#include <sys/vdev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct vdev_file {
+       vnode_t         *vf_vnode;
+} vdev_file_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VDEV_FILE_H */
diff --git a/zfs/include/sys/vdev_impl.h b/zfs/include/sys/vdev_impl.h
new file mode 100644 (file)
index 0000000..1371a3f
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef _SYS_VDEV_IMPL_H
+#define        _SYS_VDEV_IMPL_H
+
+#include <sys/avl.h>
+#include <sys/dmu.h>
+#include <sys/metaslab.h>
+#include <sys/nvpair.h>
+#include <sys/space_map.h>
+#include <sys/vdev.h>
+#include <sys/dkio.h>
+#include <sys/uberblock_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Virtual device descriptors.
+ *
+ * All storage pool operations go through the virtual device framework,
+ * which provides data replication and I/O scheduling.
+ */
+
+/*
+ * Forward declarations that lots of things need.
+ */
+typedef struct vdev_queue vdev_queue_t;
+typedef struct vdev_cache vdev_cache_t;
+typedef struct vdev_cache_entry vdev_cache_entry_t;
+
+/*
+ * Virtual device operations
+ */
+typedef int    vdev_open_func_t(vdev_t *vd, uint64_t *size, uint64_t *max_size,
+    uint64_t *ashift);
+typedef void   vdev_close_func_t(vdev_t *vd);
+typedef uint64_t vdev_asize_func_t(vdev_t *vd, uint64_t psize);
+typedef void   vdev_io_start_func_t(zio_t *zio);
+typedef void   vdev_io_done_func_t(zio_t *zio);
+typedef void   vdev_state_change_func_t(vdev_t *vd, int, int);
+typedef void   vdev_hold_func_t(vdev_t *vd);
+typedef void   vdev_rele_func_t(vdev_t *vd);
+
+typedef const struct vdev_ops {
+       vdev_open_func_t                *vdev_op_open;
+       vdev_close_func_t               *vdev_op_close;
+       vdev_asize_func_t               *vdev_op_asize;
+       vdev_io_start_func_t            *vdev_op_io_start;
+       vdev_io_done_func_t             *vdev_op_io_done;
+       vdev_state_change_func_t        *vdev_op_state_change;
+       vdev_hold_func_t                *vdev_op_hold;
+       vdev_rele_func_t                *vdev_op_rele;
+       char                            vdev_op_type[16];
+       boolean_t                       vdev_op_leaf;
+} vdev_ops_t;
+
+/*
+ * Virtual device properties
+ */
+struct vdev_cache_entry {
+       char            *ve_data;
+       uint64_t        ve_offset;
+       clock_t         ve_lastused;
+       avl_node_t      ve_offset_node;
+       avl_node_t      ve_lastused_node;
+       uint32_t        ve_hits;
+       uint16_t        ve_missed_update;
+       zio_t           *ve_fill_io;
+};
+
+struct vdev_cache {
+       avl_tree_t      vc_offset_tree;
+       avl_tree_t      vc_lastused_tree;
+       kmutex_t        vc_lock;
+};
+
+typedef struct vdev_queue_class {
+       uint32_t        vqc_active;
+
+       /*
+        * Sorted by offset or timestamp, depending on if the queue is
+        * LBA-ordered vs FIFO.
+        */
+       avl_tree_t      vqc_queued_tree;
+} vdev_queue_class_t;
+
+struct vdev_queue {
+       vdev_t          *vq_vdev;
+       vdev_queue_class_t vq_class[ZIO_PRIORITY_NUM_QUEUEABLE];
+       avl_tree_t      vq_active_tree;
+       avl_tree_t      vq_read_offset_tree;
+       avl_tree_t      vq_write_offset_tree;
+       uint64_t        vq_last_offset;
+       hrtime_t        vq_io_complete_ts; /* time last i/o completed */
+       hrtime_t        vq_io_delta_ts;
+       zio_t           vq_io_search; /* used as local for stack reduction */
+       kmutex_t        vq_lock;
+};
+
+/*
+ * Virtual device descriptor
+ */
+struct vdev {
+       /*
+        * Common to all vdev types.
+        */
+       uint64_t        vdev_id;        /* child number in vdev parent  */
+       uint64_t        vdev_guid;      /* unique ID for this vdev      */
+       uint64_t        vdev_guid_sum;  /* self guid + all child guids  */
+       uint64_t        vdev_orig_guid; /* orig. guid prior to remove   */
+       uint64_t        vdev_asize;     /* allocatable device capacity  */
+       uint64_t        vdev_min_asize; /* min acceptable asize         */
+       uint64_t        vdev_max_asize; /* max acceptable asize         */
+       uint64_t        vdev_ashift;    /* block alignment shift        */
+       uint64_t        vdev_state;     /* see VDEV_STATE_* #defines    */
+       uint64_t        vdev_prevstate; /* used when reopening a vdev   */
+       vdev_ops_t      *vdev_ops;      /* vdev operations              */
+       spa_t           *vdev_spa;      /* spa for this vdev            */
+       void            *vdev_tsd;      /* type-specific data           */
+       vnode_t         *vdev_name_vp;  /* vnode for pathname           */
+       vnode_t         *vdev_devid_vp; /* vnode for devid              */
+       vdev_t          *vdev_top;      /* top-level vdev               */
+       vdev_t          *vdev_parent;   /* parent vdev                  */
+       vdev_t          **vdev_child;   /* array of children            */
+       uint64_t        vdev_children;  /* number of children           */
+       vdev_stat_t     vdev_stat;      /* virtual device statistics    */
+       boolean_t       vdev_expanding; /* expand the vdev?             */
+       boolean_t       vdev_reopening; /* reopen in progress?          */
+       boolean_t       vdev_nonrot;    /* true if solid state          */
+       int             vdev_open_error; /* error on last open          */
+       kthread_t       *vdev_open_thread; /* thread opening children   */
+       uint64_t        vdev_crtxg;     /* txg when top-level was added */
+
+       /*
+        * Top-level vdev state.
+        */
+       uint64_t        vdev_ms_array;  /* metaslab array object        */
+       uint64_t        vdev_ms_shift;  /* metaslab size shift          */
+       uint64_t        vdev_ms_count;  /* number of metaslabs          */
+       metaslab_group_t *vdev_mg;      /* metaslab group               */
+       metaslab_t      **vdev_ms;      /* metaslab array               */
+       uint64_t        vdev_pending_fastwrite; /* allocated fastwrites */
+       txg_list_t      vdev_ms_list;   /* per-txg dirty metaslab lists */
+       txg_list_t      vdev_dtl_list;  /* per-txg dirty DTL lists      */
+       txg_node_t      vdev_txg_node;  /* per-txg dirty vdev linkage   */
+       boolean_t       vdev_remove_wanted; /* async remove wanted?     */
+       boolean_t       vdev_probe_wanted; /* async probe wanted?       */
+       list_node_t     vdev_config_dirty_node; /* config dirty list    */
+       list_node_t     vdev_state_dirty_node; /* state dirty list      */
+       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   */
+
+       /*
+        * Leaf vdev state.
+        */
+       range_tree_t    *vdev_dtl[DTL_TYPES]; /* dirty time logs        */
+       space_map_t     *vdev_dtl_sm;   /* dirty time log space map     */
+       txg_node_t      vdev_dtl_node;  /* per-txg dirty DTL linkage    */
+       uint64_t        vdev_dtl_object; /* DTL object                  */
+       uint64_t        vdev_psize;     /* physical device capacity     */
+       uint64_t        vdev_wholedisk; /* true if this is a whole disk */
+       uint64_t        vdev_offline;   /* persistent offline state     */
+       uint64_t        vdev_faulted;   /* persistent faulted state     */
+       uint64_t        vdev_degraded;  /* persistent degraded state    */
+       uint64_t        vdev_removed;   /* persistent removed state     */
+       uint64_t        vdev_resilver_txg; /* persistent resilvering state */
+       uint64_t        vdev_nparity;   /* number of parity devices for raidz */
+       char            *vdev_path;     /* vdev path (if any)           */
+       char            *vdev_devid;    /* vdev devid (if any)          */
+       char            *vdev_physpath; /* vdev device path (if any)    */
+       char            *vdev_fru;      /* physical FRU location        */
+       uint64_t        vdev_not_present; /* not present during import  */
+       uint64_t        vdev_unspare;   /* unspare when resilvering done */
+       boolean_t       vdev_nowritecache; /* true if flushwritecache failed */
+       boolean_t       vdev_checkremove; /* temporary online test      */
+       boolean_t       vdev_forcefault; /* force online fault          */
+       boolean_t       vdev_splitting; /* split or repair in progress  */
+       boolean_t       vdev_delayed_close; /* delayed device close?    */
+       boolean_t       vdev_tmpoffline; /* device taken offline temporarily? */
+       boolean_t       vdev_detached;  /* device detached?             */
+       boolean_t       vdev_cant_read; /* vdev is failing all reads    */
+       boolean_t       vdev_cant_write; /* vdev is failing all writes  */
+       boolean_t       vdev_isspare;   /* was a hot spare              */
+       boolean_t       vdev_isl2cache; /* was a l2cache device         */
+       vdev_queue_t    vdev_queue;     /* I/O deadline schedule queue  */
+       vdev_cache_t    vdev_cache;     /* physical block cache         */
+       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            */
+
+       /*
+        * For DTrace to work in userland (libzpool) context, these fields must
+        * remain at the end of the structure.  DTrace will use the kernel's
+        * CTF definition for 'struct vdev', and since the size of a kmutex_t is
+        * larger in userland, the offsets for the rest of the fields would be
+        * incorrect.
+        */
+       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     */
+};
+
+#define        VDEV_RAIDZ_MAXPARITY    3
+
+#define        VDEV_PAD_SIZE           (8 << 10)
+/* 2 padding areas (vl_pad1 and vl_pad2) to skip */
+#define        VDEV_SKIP_SIZE          VDEV_PAD_SIZE * 2
+#define        VDEV_PHYS_SIZE          (112 << 10)
+#define        VDEV_UBERBLOCK_RING     (128 << 10)
+
+/* The largest uberblock we support is 8k. */
+#define        MAX_UBERBLOCK_SHIFT (13)
+#define        VDEV_UBERBLOCK_SHIFT(vd)        \
+       MIN(MAX((vd)->vdev_top->vdev_ashift, UBERBLOCK_SHIFT), \
+           MAX_UBERBLOCK_SHIFT)
+#define        VDEV_UBERBLOCK_COUNT(vd)        \
+       (VDEV_UBERBLOCK_RING >> VDEV_UBERBLOCK_SHIFT(vd))
+#define        VDEV_UBERBLOCK_OFFSET(vd, n)    \
+       offsetof(vdev_label_t, vl_uberblock[(n) << VDEV_UBERBLOCK_SHIFT(vd)])
+#define        VDEV_UBERBLOCK_SIZE(vd)         (1ULL << VDEV_UBERBLOCK_SHIFT(vd))
+
+typedef struct vdev_phys {
+       char            vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)];
+       zio_eck_t       vp_zbt;
+} vdev_phys_t;
+
+typedef struct vdev_label {
+       char            vl_pad1[VDEV_PAD_SIZE];                 /*  8K */
+       char            vl_pad2[VDEV_PAD_SIZE];                 /*  8K */
+       vdev_phys_t     vl_vdev_phys;                           /* 112K */
+       char            vl_uberblock[VDEV_UBERBLOCK_RING];      /* 128K */
+} vdev_label_t;                                                        /* 256K total */
+
+/*
+ * vdev_dirty() flags
+ */
+#define        VDD_METASLAB    0x01
+#define        VDD_DTL         0x02
+
+/* Offset of embedded boot loader region on each label */
+#define        VDEV_BOOT_OFFSET        (2 * sizeof (vdev_label_t))
+/*
+ * Size of embedded boot loader region on each label.
+ * The total size of the first two labels plus the boot area is 4MB.
+ */
+#define        VDEV_BOOT_SIZE          (7ULL << 19)                    /* 3.5M */
+
+/*
+ * Size of label regions at the start and end of each leaf device.
+ */
+#define        VDEV_LABEL_START_SIZE   (2 * sizeof (vdev_label_t) + VDEV_BOOT_SIZE)
+#define        VDEV_LABEL_END_SIZE     (2 * sizeof (vdev_label_t))
+#define        VDEV_LABELS             4
+#define        VDEV_BEST_LABEL         VDEV_LABELS
+
+#define        VDEV_ALLOC_LOAD         0
+#define        VDEV_ALLOC_ADD          1
+#define        VDEV_ALLOC_SPARE        2
+#define        VDEV_ALLOC_L2CACHE      3
+#define        VDEV_ALLOC_ROOTPOOL     4
+#define        VDEV_ALLOC_SPLIT        5
+#define        VDEV_ALLOC_ATTACH       6
+
+/*
+ * Allocate or free a vdev
+ */
+extern vdev_t *vdev_alloc_common(spa_t *spa, uint_t id, uint64_t guid,
+    vdev_ops_t *ops);
+extern int vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *config,
+    vdev_t *parent, uint_t id, int alloctype);
+extern void vdev_free(vdev_t *vd);
+
+/*
+ * Add or remove children and parents
+ */
+extern void vdev_add_child(vdev_t *pvd, vdev_t *cvd);
+extern void vdev_remove_child(vdev_t *pvd, vdev_t *cvd);
+extern void vdev_compact_children(vdev_t *pvd);
+extern vdev_t *vdev_add_parent(vdev_t *cvd, vdev_ops_t *ops);
+extern void vdev_remove_parent(vdev_t *cvd);
+
+/*
+ * vdev sync load and sync
+ */
+extern void vdev_load_log_state(vdev_t *nvd, vdev_t *ovd);
+extern boolean_t vdev_log_state_valid(vdev_t *vd);
+extern void vdev_load(vdev_t *vd);
+extern int vdev_dtl_load(vdev_t *vd);
+extern void vdev_sync(vdev_t *vd, uint64_t txg);
+extern void vdev_sync_done(vdev_t *vd, uint64_t txg);
+extern void vdev_dirty(vdev_t *vd, int flags, void *arg, uint64_t txg);
+extern void vdev_dirty_leaves(vdev_t *vd, int flags, uint64_t txg);
+
+/*
+ * Available vdev types.
+ */
+extern vdev_ops_t vdev_root_ops;
+extern vdev_ops_t vdev_mirror_ops;
+extern vdev_ops_t vdev_replacing_ops;
+extern vdev_ops_t vdev_raidz_ops;
+extern vdev_ops_t vdev_disk_ops;
+extern vdev_ops_t vdev_file_ops;
+extern vdev_ops_t vdev_missing_ops;
+extern vdev_ops_t vdev_hole_ops;
+extern vdev_ops_t vdev_spare_ops;
+
+/*
+ * Common size functions
+ */
+extern uint64_t vdev_default_asize(vdev_t *vd, uint64_t psize);
+extern uint64_t vdev_get_min_asize(vdev_t *vd);
+extern void vdev_set_min_asize(vdev_t *vd);
+
+/*
+ * Global variables
+ */
+/* zdb uses this tunable, so it must be declared here to make lint happy. */
+extern int zfs_vdev_cache_size;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VDEV_IMPL_H */
diff --git a/zfs/include/sys/xvattr.h b/zfs/include/sys/xvattr.h
new file mode 100644 (file)
index 0000000..53945d8
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*     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_XVATTR_H
+#define        _SYS_XVATTR_H
+
+#include <sys/vnode.h>
+
+#define        AV_SCANSTAMP_SZ 32              /* length of anti-virus scanstamp */
+
+/*
+ * Structure of all optional attributes.
+ */
+typedef struct xoptattr {
+       timestruc_t     xoa_createtime; /* Create time of file */
+       uint8_t         xoa_archive;
+       uint8_t         xoa_system;
+       uint8_t         xoa_readonly;
+       uint8_t         xoa_hidden;
+       uint8_t         xoa_nounlink;
+       uint8_t         xoa_immutable;
+       uint8_t         xoa_appendonly;
+       uint8_t         xoa_nodump;
+       uint8_t         xoa_opaque;
+       uint8_t         xoa_av_quarantined;
+       uint8_t         xoa_av_modified;
+       uint8_t         xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+       uint8_t         xoa_reparse;
+       uint64_t        xoa_generation;
+       uint8_t         xoa_offline;
+       uint8_t         xoa_sparse;
+} xoptattr_t;
+
+/*
+ * The xvattr structure is really a variable length structure that
+ * is made up of:
+ * - The classic vattr_t (xva_vattr)
+ * - a 32 bit quantity (xva_mapsize) that specifies the size of the
+ *   attribute bitmaps in 32 bit words.
+ * - A pointer to the returned attribute bitmap (needed because the
+ *   previous element, the requested attribute bitmap) is variable lenth.
+ * - The requested attribute bitmap, which is an array of 32 bit words.
+ *   Callers use the XVA_SET_REQ() macro to set the bits corresponding to
+ *   the attributes that are being requested.
+ * - The returned attribute bitmap, which is an array of 32 bit words.
+ *   File systems that support optional attributes use the XVA_SET_RTN()
+ *   macro to set the bits corresponding to the attributes that are being
+ *   returned.
+ * - The xoptattr_t structure which contains the attribute values
+ *
+ * xva_mapsize determines how many words in the attribute bitmaps.
+ * Immediately following the attribute bitmaps is the xoptattr_t.
+ * xva_getxoptattr() is used to get the pointer to the xoptattr_t
+ * section.
+ */
+
+#define        XVA_MAPSIZE     3               /* Size of attr bitmaps */
+#define        XVA_MAGIC       0x78766174      /* Magic # for verification */
+
+/*
+ * The xvattr structure is an extensible structure which permits optional
+ * attributes to be requested/returned.  File systems may or may not support
+ * optional attributes.  They do so at their own discretion but if they do
+ * support optional attributes, they must register the VFSFT_XVATTR feature
+ * so that the optional attributes can be set/retrived.
+ *
+ * The fields of the xvattr structure are:
+ *
+ * xva_vattr - The first element of an xvattr is a legacy vattr structure
+ * which includes the common attributes.  If AT_XVATTR is set in the va_mask
+ * then the entire structure is treated as an xvattr.  If AT_XVATTR is not
+ * set, then only the xva_vattr structure can be used.
+ *
+ * xva_magic - 0x78766174 (hex for "xvat"). Magic number for verification.
+ *
+ * xva_mapsize - Size of requested and returned attribute bitmaps.
+ *
+ * xva_rtnattrmapp - Pointer to xva_rtnattrmap[].  We need this since the
+ * size of the array before it, xva_reqattrmap[], could change which means
+ * the location of xva_rtnattrmap[] could change.  This will allow unbundled
+ * file systems to find the location of xva_rtnattrmap[] when the sizes change.
+ *
+ * xva_reqattrmap[] - Array of requested attributes.  Attributes are
+ * represented by a specific bit in a specific element of the attribute
+ * map array.  Callers set the bits corresponding to the attributes
+ * that the caller wants to get/set.
+ *
+ * xva_rtnattrmap[] - Array of attributes that the file system was able to
+ * process.  Not all file systems support all optional attributes.  This map
+ * informs the caller which attributes the underlying file system was able
+ * to set/get.  (Same structure as the requested attributes array in terms
+ * of each attribute  corresponding to specific bits and array elements.)
+ *
+ * xva_xoptattrs - Structure containing values of optional attributes.
+ * These values are only valid if the corresponding bits in xva_reqattrmap
+ * are set and the underlying file system supports those attributes.
+ */
+typedef struct xvattr {
+       vattr_t         xva_vattr;      /* Embedded vattr structure */
+       uint32_t        xva_magic;      /* Magic Number */
+       uint32_t        xva_mapsize;    /* Size of attr bitmap (32-bit words) */
+       uint32_t        *xva_rtnattrmapp;       /* Ptr to xva_rtnattrmap[] */
+       uint32_t        xva_reqattrmap[XVA_MAPSIZE];    /* Requested attrs */
+       uint32_t        xva_rtnattrmap[XVA_MAPSIZE];    /* Returned attrs */
+       xoptattr_t      xva_xoptattrs;  /* Optional attributes */
+} xvattr_t;
+
+/*
+ * Attribute bits used in the extensible attribute's (xva's) attribute
+ * bitmaps.  Note that the bitmaps are made up of a variable length number
+ * of 32-bit words.  The convention is to use XAT{n}_{attrname} where "n"
+ * is the element in the bitmap (starting at 1).  This convention is for
+ * the convenience of the maintainer to keep track of which element each
+ * attribute belongs to.
+ *
+ * NOTE THAT CONSUMERS MUST *NOT* USE THE XATn_* DEFINES DIRECTLY.  CONSUMERS
+ * MUST USE THE XAT_* DEFINES.
+ */
+#define        XAT0_INDEX      0LL             /* Index into bitmap for XAT0 attrs */
+#define        XAT0_CREATETIME 0x00000001      /* Create time of file */
+#define        XAT0_ARCHIVE    0x00000002      /* Archive */
+#define        XAT0_SYSTEM     0x00000004      /* System */
+#define        XAT0_READONLY   0x00000008      /* Readonly */
+#define        XAT0_HIDDEN     0x00000010      /* Hidden */
+#define        XAT0_NOUNLINK   0x00000020      /* Nounlink */
+#define        XAT0_IMMUTABLE  0x00000040      /* immutable */
+#define        XAT0_APPENDONLY 0x00000080      /* appendonly */
+#define        XAT0_NODUMP     0x00000100      /* nodump */
+#define        XAT0_OPAQUE     0x00000200      /* opaque */
+#define        XAT0_AV_QUARANTINED     0x00000400      /* anti-virus quarantine */
+#define        XAT0_AV_MODIFIED        0x00000800      /* anti-virus modified */
+#define        XAT0_AV_SCANSTAMP       0x00001000      /* anti-virus scanstamp */
+#define        XAT0_REPARSE    0x00002000      /* FS reparse point */
+#define        XAT0_GEN        0x00004000      /* object generation number */
+#define        XAT0_OFFLINE    0x00008000      /* offline */
+#define        XAT0_SPARSE     0x00010000      /* sparse */
+
+#define        XAT0_ALL_ATTRS  (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
+    XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
+    XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED|  XAT0_AV_MODIFIED| \
+    XAT0_AV_SCANSTAMP|XAT0_REPARSE|XATO_GEN|XAT0_OFFLINE|XAT0_SPARSE)
+
+/* Support for XAT_* optional attributes */
+#define        XVA_MASK                0xffffffff      /* Used to mask off 32 bits */
+#define        XVA_SHFT                32              /* Used to shift index */
+
+/*
+ * Used to pry out the index and attribute bits from the XAT_* attributes
+ * defined below.  Note that we're masking things down to 32 bits then
+ * casting to uint32_t.
+ */
+#define        XVA_INDEX(attr)         ((uint32_t)(((attr) >> XVA_SHFT) & XVA_MASK))
+#define        XVA_ATTRBIT(attr)       ((uint32_t)((attr) & XVA_MASK))
+
+/*
+ * The following defines present a "flat namespace" so that consumers don't
+ * need to keep track of which element belongs to which bitmap entry.
+ *
+ * NOTE THAT THESE MUST NEVER BE OR-ed TOGETHER
+ */
+#define        XAT_CREATETIME          ((XAT0_INDEX << XVA_SHFT) | XAT0_CREATETIME)
+#define        XAT_ARCHIVE             ((XAT0_INDEX << XVA_SHFT) | XAT0_ARCHIVE)
+#define        XAT_SYSTEM              ((XAT0_INDEX << XVA_SHFT) | XAT0_SYSTEM)
+#define        XAT_READONLY            ((XAT0_INDEX << XVA_SHFT) | XAT0_READONLY)
+#define        XAT_HIDDEN              ((XAT0_INDEX << XVA_SHFT) | XAT0_HIDDEN)
+#define        XAT_NOUNLINK            ((XAT0_INDEX << XVA_SHFT) | XAT0_NOUNLINK)
+#define        XAT_IMMUTABLE           ((XAT0_INDEX << XVA_SHFT) | XAT0_IMMUTABLE)
+#define        XAT_APPENDONLY          ((XAT0_INDEX << XVA_SHFT) | XAT0_APPENDONLY)
+#define        XAT_NODUMP              ((XAT0_INDEX << XVA_SHFT) | XAT0_NODUMP)
+#define        XAT_OPAQUE              ((XAT0_INDEX << XVA_SHFT) | XAT0_OPAQUE)
+#define        XAT_AV_QUARANTINED      ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
+#define        XAT_AV_MODIFIED         ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
+#define        XAT_AV_SCANSTAMP        ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+#define        XAT_REPARSE             ((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
+#define        XAT_GEN                 ((XAT0_INDEX << XVA_SHFT) | XAT0_GEN)
+#define        XAT_OFFLINE             ((XAT0_INDEX << XVA_SHFT) | XAT0_OFFLINE)
+#define        XAT_SPARSE              ((XAT0_INDEX << XVA_SHFT) | XAT0_SPARSE)
+
+/*
+ * The returned attribute map array (xva_rtnattrmap[]) is located past the
+ * requested attribute map array (xva_reqattrmap[]).  Its location changes
+ * when the array sizes change.  We use a separate pointer in a known location
+ * (xva_rtnattrmapp) to hold the location of xva_rtnattrmap[].  This is
+ * set in xva_init()
+ */
+#define        XVA_RTNATTRMAP(xvap)    ((xvap)->xva_rtnattrmapp)
+
+/*
+ * XVA_SET_REQ() sets an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define        XVA_SET_REQ(xvap, attr)                                 \
+       ASSERT((xvap)->xva_vattr.va_mask & AT_XVATTR);          \
+       ASSERT((xvap)->xva_magic == XVA_MAGIC);                 \
+       (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+/*
+ * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define        XVA_CLR_REQ(xvap, attr)                                 \
+       ASSERT((xvap)->xva_vattr.va_mask & AT_XVATTR);          \
+       ASSERT((xvap)->xva_magic == XVA_MAGIC);                 \
+       (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr)
+
+/*
+ * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap
+ * of returned attributes (xva_rtnattrmap[]).
+ */
+#define        XVA_SET_RTN(xvap, attr)                                 \
+       ASSERT((xvap)->xva_vattr.va_mask & AT_XVATTR);          \
+       ASSERT((xvap)->xva_magic == XVA_MAGIC);                 \
+       (XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+
+/*
+ * XVA_ISSET_REQ() checks the requested attribute bitmap (xva_reqattrmap[])
+ * to see of the corresponding attribute bit is set.  If so, returns non-zero.
+ */
+#define        XVA_ISSET_REQ(xvap, attr)                                       \
+       ((((xvap)->xva_vattr.va_mask & AT_XVATTR) &&                    \
+               ((xvap)->xva_magic == XVA_MAGIC) &&                     \
+               ((xvap)->xva_mapsize > XVA_INDEX(attr))) ?              \
+       ((xvap)->xva_reqattrmap[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * XVA_ISSET_RTN() checks the returned attribute bitmap (xva_rtnattrmap[])
+ * to see of the corresponding attribute bit is set.  If so, returns non-zero.
+ */
+#define        XVA_ISSET_RTN(xvap, attr)                                       \
+       ((((xvap)->xva_vattr.va_mask & AT_XVATTR) &&                    \
+               ((xvap)->xva_magic == XVA_MAGIC) &&                     \
+               ((xvap)->xva_mapsize > XVA_INDEX(attr))) ?              \
+       ((XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * Zero out the structure, set the size of the requested/returned bitmaps,
+ * set AT_XVATTR in the embedded vattr_t's va_mask, and set up the pointer
+ * to the returned attributes array.
+ */
+static inline void
+xva_init(xvattr_t *xvap)
+{
+       bzero(xvap, sizeof (xvattr_t));
+       xvap->xva_mapsize = XVA_MAPSIZE;
+       xvap->xva_magic = XVA_MAGIC;
+       xvap->xva_vattr.va_mask = ATTR_XVATTR;
+       xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0];
+}
+
+/*
+ * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t
+ * structure.  Otherwise, returns NULL.
+ */
+static inline xoptattr_t *
+xva_getxoptattr(xvattr_t *xvap)
+{
+       xoptattr_t *xoap = NULL;
+       if (xvap->xva_vattr.va_mask & AT_XVATTR)
+                       xoap = &xvap->xva_xoptattrs;
+       return (xoap);
+}
+
+#define        MODEMASK        07777           /* mode bits plus permission bits */
+#define        PERMMASK        00777           /* permission bits */
+
+/*
+ * VOP_ACCESS flags
+ */
+#define        V_ACE_MASK      0x1     /* mask represents  NFSv4 ACE permissions */
+#define        V_APPEND        0x2     /* want to do append only check */
+
+/*
+ * Structure used on VOP_GETSECATTR and VOP_SETSECATTR operations
+ */
+
+typedef struct vsecattr {
+       uint_t          vsa_mask;       /* See below */
+       int             vsa_aclcnt;     /* ACL entry count */
+       void            *vsa_aclentp;   /* pointer to ACL entries */
+       int             vsa_dfaclcnt;   /* default ACL entry count */
+       void            *vsa_dfaclentp; /* pointer to default ACL entries */
+       size_t          vsa_aclentsz;   /* ACE size in bytes of vsa_aclentp */
+       uint_t          vsa_aclflags;   /* ACE ACL flags */
+} vsecattr_t;
+
+/* vsa_mask values */
+#define        VSA_ACL                 0x0001
+#define        VSA_ACLCNT              0x0002
+#define        VSA_DFACL               0x0004
+#define        VSA_DFACLCNT            0x0008
+#define        VSA_ACE                 0x0010
+#define        VSA_ACECNT              0x0020
+#define        VSA_ACE_ALLTYPES        0x0040
+#define        VSA_ACE_ACLFLAGS        0x0080  /* get/set ACE ACL flags */
+
+#endif /* _SYS_XVATTR_H */
diff --git a/zfs/include/sys/zap.h b/zfs/include/sys/zap.h
new file mode 100644 (file)
index 0000000..ed60b86
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef        _SYS_ZAP_H
+#define        _SYS_ZAP_H
+
+/*
+ * ZAP - ZFS Attribute Processor
+ *
+ * The ZAP is a module which sits on top of the DMU (Data Management
+ * Unit) and implements a higher-level storage primitive using DMU
+ * objects.  Its primary consumer is the ZPL (ZFS Posix Layer).
+ *
+ * A "zapobj" is a DMU object which the ZAP uses to stores attributes.
+ * Users should use only zap routines to access a zapobj - they should
+ * not access the DMU object directly using DMU routines.
+ *
+ * The attributes stored in a zapobj are name-value pairs.  The name is
+ * a zero-terminated string of up to ZAP_MAXNAMELEN bytes (including
+ * terminating NULL).  The value is an array of integers, which may be
+ * 1, 2, 4, or 8 bytes long.  The total space used by the array (number
+ * of integers * integer length) can be up to ZAP_MAXVALUELEN bytes.
+ * Note that an 8-byte integer value can be used to store the location
+ * (object number) of another dmu object (which may be itself a zapobj).
+ * Note that you can use a zero-length attribute to store a single bit
+ * of information - the attribute is present or not.
+ *
+ * The ZAP routines are thread-safe.  However, you must observe the
+ * DMU's restriction that a transaction may not be operated on
+ * concurrently.
+ *
+ * Any of the routines that return an int may return an I/O error (EIO
+ * or ECHECKSUM).
+ *
+ *
+ * Implementation / Performance Notes:
+ *
+ * The ZAP is intended to operate most efficiently on attributes with
+ * short (49 bytes or less) names and single 8-byte values, for which
+ * the microzap will be used.  The ZAP should be efficient enough so
+ * that the user does not need to cache these attributes.
+ *
+ * The ZAP's locking scheme makes its routines thread-safe.  Operations
+ * on different zapobjs will be processed concurrently.  Operations on
+ * the same zapobj which only read data will be processed concurrently.
+ * Operations on the same zapobj which modify data will be processed
+ * concurrently when there are many attributes in the zapobj (because
+ * the ZAP uses per-block locking - more than 128 * (number of cpus)
+ * small attributes will suffice).
+ */
+
+/*
+ * We're using zero-terminated byte strings (ie. ASCII or UTF-8 C
+ * strings) for the names of attributes, rather than a byte string
+ * bounded by an explicit length.  If some day we want to support names
+ * in character sets which have embedded zeros (eg. UTF-16, UTF-32),
+ * we'll have to add routines for using length-bounded strings.
+ */
+
+#include <sys/dmu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Specifies matching criteria for ZAP lookups.
+ */
+typedef enum matchtype
+{
+       /* Only find an exact match (non-normalized) */
+       MT_EXACT,
+       /*
+        * If there is an exact match, find that, otherwise find the
+        * first normalized match.
+        */
+       MT_BEST,
+       /*
+        * Find the "first" normalized (case and Unicode form) match;
+        * the designated "first" match will not change as long as the
+        * set of entries with this normalization doesn't change.
+        */
+       MT_FIRST
+} matchtype_t;
+
+typedef enum zap_flags {
+       /* Use 64-bit hash value (serialized cursors will always use 64-bits) */
+       ZAP_FLAG_HASH64 = 1 << 0,
+       /* Key is binary, not string (zap_add_uint64() can be used) */
+       ZAP_FLAG_UINT64_KEY = 1 << 1,
+       /*
+        * First word of key (which must be an array of uint64) is
+        * already randomly distributed.
+        */
+       ZAP_FLAG_PRE_HASHED_KEY = 1 << 2,
+} zap_flags_t;
+
+/*
+ * Create a new zapobj with no attributes and return its object number.
+ * MT_EXACT will cause the zap object to only support MT_EXACT lookups,
+ * otherwise any matchtype can be used for lookups.
+ *
+ * normflags specifies what normalization will be done.  values are:
+ * 0: no normalization (legacy on-disk format, supports MT_EXACT matching
+ *     only)
+ * U8_TEXTPREP_TOLOWER: case normalization will be performed.
+ *     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.
+ */
+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_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_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_link(objset_t *os, dmu_object_type_t ot,
+    uint64_t parent_obj, const char *name, dmu_tx_t *tx);
+
+/*
+ * Initialize an already-allocated object.
+ */
+void mzap_create_impl(objset_t *os, uint64_t obj, int normflags,
+    zap_flags_t flags, dmu_tx_t *tx);
+
+/*
+ * Create a new zapobj with no attributes from the given (unallocated)
+ * object number.
+ */
+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_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);
+
+/*
+ * The zapobj passed in must be a valid ZAP object for all of the
+ * following routines.
+ */
+
+/*
+ * Destroy this zapobj and all its attributes.
+ *
+ * Frees the object number using dmu_object_free.
+ */
+int zap_destroy(objset_t *ds, uint64_t zapobj, dmu_tx_t *tx);
+
+/*
+ * Manipulate attributes.
+ *
+ * 'integer_size' is in bytes, and must be 1, 2, 4, or 8.
+ */
+
+/*
+ * Retrieve the contents of the attribute with the given name.
+ *
+ * If the requested attribute does not exist, the call will fail and
+ * return ENOENT.
+ *
+ * If 'integer_size' is smaller than the attribute's integer size, the
+ * call will fail and return EINVAL.
+ *
+ * If 'integer_size' is equal to or larger than the attribute's integer
+ * size, the call will succeed and return 0.
+ *
+ * When converting to a larger integer size, the integers will be treated as
+ * unsigned (ie. no sign-extension will be performed).
+ *
+ * 'num_integers' is the length (in integers) of 'buf'.
+ *
+ * If the attribute is longer than the buffer, as many integers as will
+ * fit will be transferred to 'buf'.  If the entire attribute was not
+ * transferred, the call will return EOVERFLOW.
+ */
+int zap_lookup(objset_t *ds, uint64_t zapobj, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf);
+
+/*
+ * If rn_len is nonzero, realname will be set to the name of the found
+ * entry (which may be different from the requested name if matchtype is
+ * not MT_EXACT).
+ *
+ * If normalization_conflictp is not NULL, it will be set if there is
+ * another name with the same case/unicode normalized form.
+ */
+int zap_lookup_norm(objset_t *ds, 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 *normalization_conflictp);
+int zap_lookup_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, uint64_t integer_size, uint64_t num_integers, void *buf);
+int zap_contains(objset_t *ds, uint64_t zapobj, const char *name);
+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 add, uint64_t *towrite, uint64_t *tooverwrite);
+
+/*
+ * Create an attribute with the given name and value.
+ *
+ * If an attribute with the given name already exists, the call will
+ * fail and return EEXIST.
+ */
+int zap_add(objset_t *ds, uint64_t zapobj, const char *key,
+    int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx);
+int zap_add_uint64(objset_t *ds, uint64_t zapobj, const uint64_t *key,
+    int key_numints, int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx);
+
+/*
+ * Set the attribute with the given name to the given value.  If an
+ * attribute with the given name does not exist, it will be created.  If
+ * an attribute with the given name already exists, the previous value
+ * will be overwritten.  The integer_size may be different from the
+ * existing attribute's integer size, in which case the attribute's
+ * integer size will be updated to the new value.
+ */
+int zap_update(objset_t *ds, uint64_t zapobj, const char *name,
+    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx);
+int zap_update_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints,
+    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx);
+
+/*
+ * Get the length (in integers) and the integer size of the specified
+ * attribute.
+ *
+ * If the requested attribute does not exist, the call will fail and
+ * return ENOENT.
+ */
+int zap_length(objset_t *ds, uint64_t zapobj, const char *name,
+    uint64_t *integer_size, uint64_t *num_integers);
+int zap_length_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, uint64_t *integer_size, uint64_t *num_integers);
+
+/*
+ * Remove the specified attribute.
+ *
+ * If the specified attribute does not exist, the call will fail and
+ * return ENOENT.
+ */
+int zap_remove(objset_t *ds, uint64_t zapobj, const char *name, dmu_tx_t *tx);
+int zap_remove_norm(objset_t *ds, uint64_t zapobj, const char *name,
+    matchtype_t mt, dmu_tx_t *tx);
+int zap_remove_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, dmu_tx_t *tx);
+
+/*
+ * Returns (in *count) the number of attributes in the specified zap
+ * object.
+ */
+int zap_count(objset_t *ds, uint64_t zapobj, uint64_t *count);
+
+/*
+ * Returns (in name) the name of the entry whose (value & mask)
+ * (za_first_integer) is value, or ENOENT if not found.  The string
+ * pointed to by name must be at least 256 bytes long.  If mask==0, the
+ * match must be exact (ie, same as mask=-1ULL).
+ */
+int zap_value_search(objset_t *os, uint64_t zapobj,
+    uint64_t value, uint64_t mask, char *name);
+
+/*
+ * Transfer all the entries from fromobj into intoobj.  Only works on
+ * int_size=8 num_integers=1 values.  Fails if there are any duplicated
+ * entries.
+ */
+int zap_join(objset_t *os, uint64_t fromobj, uint64_t intoobj, dmu_tx_t *tx);
+
+/* Same as zap_join, but set the values to 'value'. */
+int zap_join_key(objset_t *os, uint64_t fromobj, uint64_t intoobj,
+    uint64_t value, dmu_tx_t *tx);
+
+/* Same as zap_join, but add together any duplicated entries. */
+int zap_join_increment(objset_t *os, uint64_t fromobj, uint64_t intoobj,
+    dmu_tx_t *tx);
+
+/*
+ * Manipulate entries where the name + value are the "same" (the name is
+ * a stringified version of the value).
+ */
+int zap_add_int(objset_t *os, uint64_t obj, uint64_t value, dmu_tx_t *tx);
+int zap_remove_int(objset_t *os, uint64_t obj, uint64_t value, dmu_tx_t *tx);
+int zap_lookup_int(objset_t *os, uint64_t obj, uint64_t value);
+int zap_increment_int(objset_t *os, uint64_t obj, uint64_t key, int64_t delta,
+    dmu_tx_t *tx);
+
+/* Here the key is an int and the value is a different int. */
+int zap_add_int_key(objset_t *os, uint64_t obj,
+    uint64_t key, uint64_t value, dmu_tx_t *tx);
+int zap_update_int_key(objset_t *os, uint64_t obj,
+    uint64_t key, uint64_t value, dmu_tx_t *tx);
+int zap_lookup_int_key(objset_t *os, uint64_t obj,
+    uint64_t key, uint64_t *valuep);
+
+int zap_increment(objset_t *os, uint64_t obj, const char *name, int64_t delta,
+    dmu_tx_t *tx);
+
+struct zap;
+struct zap_leaf;
+typedef struct zap_cursor {
+       /* This structure is opaque! */
+       objset_t *zc_objset;
+       struct zap *zc_zap;
+       struct zap_leaf *zc_leaf;
+       uint64_t zc_zapobj;
+       uint64_t zc_serialized;
+       uint64_t zc_hash;
+       uint32_t zc_cd;
+} zap_cursor_t;
+
+typedef struct {
+       int za_integer_length;
+       /*
+        * za_normalization_conflict will be set if there are additional
+        * entries with this normalized form (eg, "foo" and "Foo").
+        */
+       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];
+} zap_attribute_t;
+
+/*
+ * The interface for listing all the attributes of a zapobj can be
+ * thought of as cursor moving down a list of the attributes one by
+ * one.  The cookie returned by the zap_cursor_serialize routine is
+ * persistent across system calls (and across reboot, even).
+ */
+
+/*
+ * Initialize a zap cursor, pointing to the "first" attribute of the
+ * zapobj.  You must _fini the cursor when you are done with it.
+ */
+void zap_cursor_init(zap_cursor_t *zc, objset_t *ds, uint64_t zapobj);
+void zap_cursor_fini(zap_cursor_t *zc);
+
+/*
+ * Get the attribute currently pointed to by the cursor.  Returns
+ * ENOENT if at the end of the attributes.
+ */
+int zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za);
+
+/*
+ * Advance the cursor to the next attribute.
+ */
+void zap_cursor_advance(zap_cursor_t *zc);
+
+/*
+ * Get a persistent cookie pointing to the current position of the zap
+ * cursor.  The low 4 bits in the cookie are always zero, and thus can
+ * be used as to differentiate a serialized cookie from a different type
+ * of value.  The cookie will be less than 2^32 as long as there are
+ * fewer than 2^22 (4.2 million) entries in the zap object.
+ */
+uint64_t zap_cursor_serialize(zap_cursor_t *zc);
+
+/*
+ * Initialize a zap cursor pointing to the position recorded by
+ * zap_cursor_serialize (in the "serialized" argument).  You can also
+ * use a "serialized" argument of 0 to start at the beginning of the
+ * zapobj (ie.  zap_cursor_init_serialized(..., 0) is equivalent to
+ * zap_cursor_init(...).)
+ */
+void zap_cursor_init_serialized(zap_cursor_t *zc, objset_t *ds,
+    uint64_t zapobj, uint64_t serialized);
+
+
+#define        ZAP_HISTOGRAM_SIZE 10
+
+typedef struct zap_stats {
+       /*
+        * Size of the pointer table (in number of entries).
+        * This is always a power of 2, or zero if it's a microzap.
+        * In general, it should be considerably greater than zs_num_leafs.
+        */
+       uint64_t zs_ptrtbl_len;
+
+       uint64_t zs_blocksize;          /* size of zap blocks */
+
+       /*
+        * The number of blocks used.  Note that some blocks may be
+        * wasted because old ptrtbl's and large name/value blocks are
+        * not reused.  (Although their space is reclaimed, we don't
+        * reuse those offsets in the object.)
+        */
+       uint64_t zs_num_blocks;
+
+       /*
+        * Pointer table values from zap_ptrtbl in the zap_phys_t
+        */
+       uint64_t zs_ptrtbl_nextblk;       /* next (larger) copy start block */
+       uint64_t zs_ptrtbl_blks_copied;   /* number source blocks copied */
+       uint64_t zs_ptrtbl_zt_blk;        /* starting block number */
+       uint64_t zs_ptrtbl_zt_numblks;    /* number of blocks */
+       uint64_t zs_ptrtbl_zt_shift;      /* bits to index it */
+
+       /*
+        * Values of the other members of the zap_phys_t
+        */
+       uint64_t zs_block_type;         /* ZBT_HEADER */
+       uint64_t zs_magic;              /* ZAP_MAGIC */
+       uint64_t zs_num_leafs;          /* The number of leaf blocks */
+       uint64_t zs_num_entries;        /* The number of zap entries */
+       uint64_t zs_salt;               /* salt to stir into hash function */
+
+       /*
+        * Histograms.  For all histograms, the last index
+        * (ZAP_HISTOGRAM_SIZE-1) includes any values which are greater
+        * than what can be represented.  For example
+        * zs_leafs_with_n5_entries[ZAP_HISTOGRAM_SIZE-1] is the number
+        * of leafs with more than 45 entries.
+        */
+
+       /*
+        * zs_leafs_with_n_pointers[n] is the number of leafs with
+        * 2^n pointers to it.
+        */
+       uint64_t zs_leafs_with_2n_pointers[ZAP_HISTOGRAM_SIZE];
+
+       /*
+        * zs_leafs_with_n_entries[n] is the number of leafs with
+        * [n*5, (n+1)*5) entries.  In the current implementation, there
+        * can be at most 55 entries in any block, but there may be
+        * fewer if the name or value is large, or the block is not
+        * completely full.
+        */
+       uint64_t zs_blocks_with_n5_entries[ZAP_HISTOGRAM_SIZE];
+
+       /*
+        * zs_leafs_n_tenths_full[n] is the number of leafs whose
+        * fullness is in the range [n/10, (n+1)/10).
+        */
+       uint64_t zs_blocks_n_tenths_full[ZAP_HISTOGRAM_SIZE];
+
+       /*
+        * zs_entries_using_n_chunks[n] is the number of entries which
+        * consume n 24-byte chunks.  (Note, large names/values only use
+        * one chunk, but contribute to zs_num_blocks_large.)
+        */
+       uint64_t zs_entries_using_n_chunks[ZAP_HISTOGRAM_SIZE];
+
+       /*
+        * zs_buckets_with_n_entries[n] is the number of buckets (each
+        * leaf has 64 buckets) with n entries.
+        * zs_buckets_with_n_entries[1] should be very close to
+        * zs_num_entries.
+        */
+       uint64_t zs_buckets_with_n_entries[ZAP_HISTOGRAM_SIZE];
+} zap_stats_t;
+
+/*
+ * Get statistics about a ZAP object.  Note: you need to be aware of the
+ * internal implementation of the ZAP to correctly interpret some of the
+ * statistics.  This interface shouldn't be relied on unless you really
+ * know what you're doing.
+ */
+int zap_get_stats(objset_t *ds, uint64_t zapobj, zap_stats_t *zs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZAP_H */
diff --git a/zfs/include/sys/zap_impl.h b/zfs/include/sys/zap_impl.h
new file mode 100644 (file)
index 0000000..bfd43e3
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_ZAP_IMPL_H
+#define        _SYS_ZAP_IMPL_H
+
+#include <sys/zap.h>
+#include <sys/zfs_context.h>
+#include <sys/avl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int fzap_default_block_shift;
+
+#define        ZAP_MAGIC 0x2F52AB2ABULL
+
+#define        FZAP_BLOCK_SHIFT(zap)   ((zap)->zap_f.zap_block_shift)
+
+#define        MZAP_ENT_LEN            64
+#define        MZAP_NAME_LEN           (MZAP_ENT_LEN - 8 - 4 - 2)
+#define        MZAP_MAX_BLKSZ          SPA_OLD_MAXBLOCKSIZE
+
+#define        ZAP_NEED_CD             (-1U)
+
+typedef struct mzap_ent_phys {
+       uint64_t mze_value;
+       uint32_t mze_cd;
+       uint16_t mze_pad;       /* in case we want to chain them someday */
+       char mze_name[MZAP_NAME_LEN];
+} mzap_ent_phys_t;
+
+typedef struct mzap_phys {
+       uint64_t mz_block_type; /* ZBT_MICRO */
+       uint64_t mz_salt;
+       uint64_t mz_normflags;
+       uint64_t mz_pad[5];
+       mzap_ent_phys_t mz_chunk[1];
+       /* actually variable size depending on block size */
+} mzap_phys_t;
+
+typedef struct mzap_ent {
+       avl_node_t mze_node;
+       int mze_chunkid;
+       uint64_t mze_hash;
+       uint32_t mze_cd; /* copy from mze_phys->mze_cd */
+} mzap_ent_t;
+
+#define        MZE_PHYS(zap, mze) \
+       (&zap_m_phys(zap)->mz_chunk[(mze)->mze_chunkid])
+
+/*
+ * The (fat) zap is stored in one object. It is an array of
+ * 1<<FZAP_BLOCK_SHIFT byte blocks. The layout looks like one of:
+ *
+ * ptrtbl fits in first block:
+ *     [zap_phys_t zap_ptrtbl_shift < 6] [zap_leaf_t] ...
+ *
+ * ptrtbl too big for first block:
+ *     [zap_phys_t zap_ptrtbl_shift >= 6] [zap_leaf_t] [ptrtbl] ...
+ *
+ */
+
+struct dmu_buf;
+struct zap_leaf;
+
+#define        ZBT_LEAF                ((1ULL << 63) + 0)
+#define        ZBT_HEADER              ((1ULL << 63) + 1)
+#define        ZBT_MICRO               ((1ULL << 63) + 3)
+/* any other values are ptrtbl blocks */
+
+/*
+ * the embedded pointer table takes up half a block:
+ * block size / entry size (2^3) / 2
+ */
+#define        ZAP_EMBEDDED_PTRTBL_SHIFT(zap) (FZAP_BLOCK_SHIFT(zap) - 3 - 1)
+
+/*
+ * The embedded pointer table starts half-way through the block.  Since
+ * the pointer table itself is half the block, it starts at (64-bit)
+ * word number (1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap)).
+ */
+#define        ZAP_EMBEDDED_PTRTBL_ENT(zap, idx) \
+       ((uint64_t *)zap_f_phys(zap)) \
+       [(idx) + (1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap))]
+
+/*
+ * TAKE NOTE:
+ * If zap_phys_t is modified, zap_byteswap() must be modified.
+ */
+typedef struct zap_phys {
+       uint64_t zap_block_type;        /* ZBT_HEADER */
+       uint64_t zap_magic;             /* ZAP_MAGIC */
+
+       struct zap_table_phys {
+               uint64_t zt_blk;        /* starting block number */
+               uint64_t zt_numblks;    /* number of blocks */
+               uint64_t zt_shift;      /* bits to index it */
+               uint64_t zt_nextblk;    /* next (larger) copy start block */
+               uint64_t zt_blks_copied; /* number source blocks copied */
+       } zap_ptrtbl;
+
+       uint64_t zap_freeblk;           /* the next free block */
+       uint64_t zap_num_leafs;         /* number of leafs */
+       uint64_t zap_num_entries;       /* number of entries */
+       uint64_t zap_salt;              /* salt to stir into hash function */
+       uint64_t zap_normflags;         /* flags for u8_textprep_str() */
+       uint64_t zap_flags;             /* zap_flags_t */
+       /*
+        * This structure is followed by padding, and then the embedded
+        * pointer table.  The embedded pointer table takes up second
+        * half of the block.  It is accessed using the
+        * ZAP_EMBEDDED_PTRTBL_ENT() macro.
+        */
+} zap_phys_t;
+
+typedef struct zap_table_phys zap_table_phys_t;
+
+typedef struct zap {
+       dmu_buf_user_t zap_dbu;
+       objset_t *zap_objset;
+       uint64_t zap_object;
+       struct dmu_buf *zap_dbuf;
+       krwlock_t zap_rwlock;
+       boolean_t zap_ismicro;
+       int zap_normflags;
+       uint64_t zap_salt;
+       union {
+               struct {
+                       /*
+                        * zap_num_entries_mtx protects
+                        * zap_num_entries
+                        */
+                       kmutex_t zap_num_entries_mtx;
+                       int zap_block_shift;
+               } zap_fat;
+               struct {
+                       int16_t zap_num_entries;
+                       int16_t zap_num_chunks;
+                       int16_t zap_alloc_next;
+                       avl_tree_t zap_avl;
+               } zap_micro;
+       } zap_u;
+} zap_t;
+
+static inline zap_phys_t *
+zap_f_phys(zap_t *zap)
+{
+       return (zap->zap_dbuf->db_data);
+}
+
+static inline mzap_phys_t *
+zap_m_phys(zap_t *zap)
+{
+       return (zap->zap_dbuf->db_data);
+}
+
+typedef struct zap_name {
+       zap_t *zn_zap;
+       int zn_key_intlen;
+       const void *zn_key_orig;
+       int zn_key_orig_numints;
+       const void *zn_key_norm;
+       int zn_key_norm_numints;
+       uint64_t zn_hash;
+       matchtype_t zn_matchtype;
+       char zn_normbuf[ZAP_MAXNAMELEN];
+} zap_name_t;
+
+#define        zap_f   zap_u.zap_fat
+#define        zap_m   zap_u.zap_micro
+
+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);
+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);
+int zap_hashbits(zap_t *zap);
+uint32_t zap_maxcd(zap_t *zap);
+uint64_t zap_getflags(zap_t *zap);
+
+#define        ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n))))
+
+void fzap_byteswap(void *buf, size_t size);
+int fzap_count(zap_t *zap, uint64_t *count);
+int fzap_lookup(zap_name_t *zn,
+    uint64_t integer_size, uint64_t num_integers, void *buf,
+    char *realname, int rn_len, boolean_t *normalization_conflictp);
+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);
+int fzap_update(zap_name_t *zn,
+    int integer_size, uint64_t num_integers, const void *val, 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);
+int fzap_cursor_retrieve(zap_t *zap, zap_cursor_t *zc, zap_attribute_t *za);
+void fzap_get_stats(zap_t *zap, zap_stats_t *zs);
+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);
+void fzap_upgrade(zap_t *zap, dmu_tx_t *tx, zap_flags_t flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZAP_IMPL_H */
diff --git a/zfs/include/sys/zap_leaf.h b/zfs/include/sys/zap_leaf.h
new file mode 100644 (file)
index 0000000..e784c59
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#ifndef        _SYS_ZAP_LEAF_H
+#define        _SYS_ZAP_LEAF_H
+
+#include <sys/zap.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct zap;
+struct zap_name;
+struct zap_stats;
+
+#define        ZAP_LEAF_MAGIC 0x2AB1EAF
+
+/* chunk size = 24 bytes */
+#define        ZAP_LEAF_CHUNKSIZE 24
+
+/*
+ * The amount of space available for chunks is:
+ * block size (1<<l->l_bs) - hash entry size (2) * number of hash
+ * entries - header space (2*chunksize)
+ */
+#define        ZAP_LEAF_NUMCHUNKS(l) \
+       (((1<<(l)->l_bs) - 2*ZAP_LEAF_HASH_NUMENTRIES(l)) / \
+       ZAP_LEAF_CHUNKSIZE - 2)
+
+/*
+ * The amount of space within the chunk available for the array is:
+ * chunk size - space for type (1) - space for next pointer (2)
+ */
+#define        ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3)
+
+#define        ZAP_LEAF_ARRAY_NCHUNKS(bytes) \
+       (((bytes)+ZAP_LEAF_ARRAY_BYTES-1)/ZAP_LEAF_ARRAY_BYTES)
+
+/*
+ * Low water mark:  when there are only this many chunks free, start
+ * growing the ptrtbl.  Ideally, this should be larger than a
+ * "reasonably-sized" entry.  20 chunks is more than enough for the
+ * largest directory entry (MAXNAMELEN (256) byte name, 8-byte value),
+ * while still being only around 3% for 16k blocks.
+ */
+#define        ZAP_LEAF_LOW_WATER (20)
+
+/*
+ * The leaf hash table has block size / 2^5 (32) number of entries,
+ * which should be more than enough for the maximum number of entries,
+ * which is less than block size / CHUNKSIZE (24) / minimum number of
+ * chunks per entry (3).
+ */
+#define        ZAP_LEAF_HASH_SHIFT(l) ((l)->l_bs - 5)
+#define        ZAP_LEAF_HASH_NUMENTRIES(l) (1 << ZAP_LEAF_HASH_SHIFT(l))
+
+/*
+ * The chunks start immediately after the hash table.  The end of the
+ * hash table is at l_hash + HASH_NUMENTRIES, which we simply cast to a
+ * chunk_t.
+ */
+#define        ZAP_LEAF_CHUNK(l, idx) \
+       ((zap_leaf_chunk_t *) \
+       (zap_leaf_phys(l)->l_hash + ZAP_LEAF_HASH_NUMENTRIES(l)))[idx]
+#define        ZAP_LEAF_ENTRY(l, idx) (&ZAP_LEAF_CHUNK(l, idx).l_entry)
+
+typedef enum zap_chunk_type {
+       ZAP_CHUNK_FREE = 253,
+       ZAP_CHUNK_ENTRY = 252,
+       ZAP_CHUNK_ARRAY = 251,
+       ZAP_CHUNK_TYPE_MAX = 250
+} zap_chunk_type_t;
+
+#define        ZLF_ENTRIES_CDSORTED (1<<0)
+
+/*
+ * TAKE NOTE:
+ * If zap_leaf_phys_t is modified, zap_leaf_byteswap() must be modified.
+ */
+typedef struct zap_leaf_phys {
+       struct zap_leaf_header {
+               /* Public to ZAP */
+               uint64_t lh_block_type;         /* ZBT_LEAF */
+               uint64_t lh_pad1;
+               uint64_t lh_prefix;             /* hash prefix of this leaf */
+               uint32_t lh_magic;              /* ZAP_LEAF_MAGIC */
+               uint16_t lh_nfree;              /* number free chunks */
+               uint16_t lh_nentries;           /* number of entries */
+               uint16_t lh_prefix_len;         /* num bits used to id this */
+
+               /* Private to zap_leaf */
+               uint16_t lh_freelist;           /* chunk head of free list */
+               uint8_t lh_flags;               /* ZLF_* flags */
+               uint8_t lh_pad2[11];
+       } l_hdr; /* 2 24-byte chunks */
+
+       /*
+        * The header is followed by a hash table with
+        * ZAP_LEAF_HASH_NUMENTRIES(zap) entries.  The hash table is
+        * followed by an array of ZAP_LEAF_NUMCHUNKS(zap)
+        * zap_leaf_chunk structures.  These structures are accessed
+        * with the ZAP_LEAF_CHUNK() macro.
+        */
+
+       uint16_t l_hash[1];
+} zap_leaf_phys_t;
+
+typedef union zap_leaf_chunk {
+       struct zap_leaf_entry {
+               uint8_t le_type;                /* always ZAP_CHUNK_ENTRY */
+               uint8_t le_value_intlen;        /* size of value's ints */
+               uint16_t le_next;               /* next entry in hash chain */
+               uint16_t le_name_chunk;         /* first chunk of the name */
+               uint16_t le_name_numints;       /* ints in name (incl null) */
+               uint16_t le_value_chunk;        /* first chunk of the value */
+               uint16_t le_value_numints;      /* value length in ints */
+               uint32_t le_cd;                 /* collision differentiator */
+               uint64_t le_hash;               /* hash value of the name */
+       } l_entry;
+       struct zap_leaf_array {
+               uint8_t la_type;                /* always ZAP_CHUNK_ARRAY */
+               uint8_t la_array[ZAP_LEAF_ARRAY_BYTES];
+               uint16_t la_next;               /* next blk or CHAIN_END */
+       } l_array;
+       struct zap_leaf_free {
+               uint8_t lf_type;                /* always ZAP_CHUNK_FREE */
+               uint8_t lf_pad[ZAP_LEAF_ARRAY_BYTES];
+               uint16_t lf_next;       /* next in free list, or CHAIN_END */
+       } l_free;
+} zap_leaf_chunk_t;
+
+typedef struct zap_leaf {
+       dmu_buf_user_t l_dbu;
+       krwlock_t l_rwlock;
+       uint64_t l_blkid;               /* 1<<ZAP_BLOCK_SHIFT byte block off */
+       int l_bs;                       /* block size shift */
+       dmu_buf_t *l_dbuf;
+} zap_leaf_t;
+
+static inline zap_leaf_phys_t *
+zap_leaf_phys(zap_leaf_t *l)
+{
+       return (l->l_dbuf->db_data);
+}
+
+typedef struct zap_entry_handle {
+       /* Set by zap_leaf and public to ZAP */
+       uint64_t zeh_num_integers;
+       uint64_t zeh_hash;
+       uint32_t zeh_cd;
+       uint8_t zeh_integer_size;
+
+       /* Private to zap_leaf */
+       uint16_t zeh_fakechunk;
+       uint16_t *zeh_chunkp;
+       zap_leaf_t *zeh_leaf;
+} zap_entry_handle_t;
+
+/*
+ * Return a handle to the named entry, or ENOENT if not found.  The hash
+ * value must equal zap_hash(name).
+ */
+extern int zap_leaf_lookup(zap_leaf_t *l,
+    struct zap_name *zn, zap_entry_handle_t *zeh);
+
+/*
+ * Return a handle to the entry with this hash+cd, or the entry with the
+ * next closest hash+cd.
+ */
+extern int zap_leaf_lookup_closest(zap_leaf_t *l,
+    uint64_t hash, uint32_t cd, zap_entry_handle_t *zeh);
+
+/*
+ * Read the first num_integers in the attribute.  Integer size
+ * conversion will be done without sign extension.  Return EINVAL if
+ * integer_size is too small.  Return EOVERFLOW if there are more than
+ * num_integers in the attribute.
+ */
+extern int zap_entry_read(const zap_entry_handle_t *zeh,
+    uint8_t integer_size, uint64_t num_integers, void *buf);
+
+extern int zap_entry_read_name(struct zap *zap, const zap_entry_handle_t *zeh,
+    uint16_t buflen, char *buf);
+
+/*
+ * Replace the value of an existing entry.
+ *
+ * May fail if it runs out of space (ENOSPC).
+ */
+extern int zap_entry_update(zap_entry_handle_t *zeh,
+    uint8_t integer_size, uint64_t num_integers, const void *buf);
+
+/*
+ * Remove an entry.
+ */
+extern void zap_entry_remove(zap_entry_handle_t *zeh);
+
+/*
+ * Create an entry. An equal entry must not exist, and this entry must
+ * belong in this leaf (according to its hash value).  Fills in the
+ * entry handle on success.  Returns 0 on success or ENOSPC on failure.
+ */
+extern int zap_entry_create(zap_leaf_t *l, struct zap_name *zn, uint32_t cd,
+    uint8_t integer_size, uint64_t num_integers, const void *buf,
+    zap_entry_handle_t *zeh);
+
+/* Determine whether there is another entry with the same normalized form. */
+extern boolean_t zap_entry_normalization_conflict(zap_entry_handle_t *zeh,
+    struct zap_name *zn, const char *name, struct zap *zap);
+
+/*
+ * Other stuff.
+ */
+
+extern void zap_leaf_init(zap_leaf_t *l, boolean_t sort);
+extern void zap_leaf_byteswap(zap_leaf_phys_t *buf, int len);
+extern void zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl, boolean_t sort);
+extern void zap_leaf_stats(struct zap *zap, zap_leaf_t *l,
+    struct zap_stats *zs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZAP_LEAF_H */
diff --git a/zfs/include/sys/zfeature.h b/zfs/include/sys/zfeature.h
new file mode 100644 (file)
index 0000000..5abde14
--- /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 (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_ZFEATURE_H
+#define        _SYS_ZFEATURE_H
+
+#include <sys/nvpair.h>
+#include <sys/txg.h>
+#include "zfeature_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        VALID_FEATURE_FID(fid)  ((fid) >= 0 && (fid) < SPA_FEATURES)
+#define        VALID_FEATURE_OR_NONE(fid)      ((fid) == SPA_FEATURE_NONE ||   \
+    VALID_FEATURE_FID(fid))
+
+struct spa;
+struct dmu_tx;
+struct objset;
+
+extern void spa_feature_create_zap_objects(struct spa *, struct dmu_tx *);
+extern void spa_feature_enable(struct spa *, spa_feature_t,
+    struct dmu_tx *);
+extern void spa_feature_incr(struct spa *, spa_feature_t, struct dmu_tx *);
+extern void spa_feature_decr(struct spa *, spa_feature_t, struct dmu_tx *);
+extern boolean_t spa_feature_is_enabled(struct spa *, spa_feature_t);
+extern boolean_t spa_feature_is_active(struct spa *, spa_feature_t);
+extern boolean_t spa_feature_enabled_txg(spa_t *spa, spa_feature_t fid,
+    uint64_t *txg);
+extern uint64_t spa_feature_refcount(spa_t *, spa_feature_t, uint64_t);
+extern boolean_t spa_features_check(spa_t *, boolean_t, nvlist_t *, nvlist_t *);
+
+/*
+ * These functions are only exported for zhack and zdb; normal callers should
+ * use the above interfaces.
+ */
+extern int feature_get_refcount(struct spa *, zfeature_info_t *, uint64_t *);
+extern int feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
+    uint64_t *res);
+extern void feature_enable_sync(struct spa *, zfeature_info_t *,
+    struct dmu_tx *);
+extern void feature_sync(struct spa *, zfeature_info_t *, uint64_t,
+    struct dmu_tx *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFEATURE_H */
diff --git a/zfs/include/sys/zfs_acl.h b/zfs/include/sys/zfs_acl.h
new file mode 100644 (file)
index 0000000..2c51f09
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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        _SYS_FS_ZFS_ACL_H
+#define        _SYS_FS_ZFS_ACL_H
+
+#ifdef _KERNEL
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#include <sys/xvattr.h>
+#endif
+#include <sys/acl.h>
+#include <sys/dmu.h>
+#include <sys/zfs_fuid.h>
+#include <sys/sa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct znode_phys;
+
+#define        ACE_SLOT_CNT    6
+#define        ZFS_ACL_VERSION_INITIAL 0ULL
+#define        ZFS_ACL_VERSION_FUID    1ULL
+#define        ZFS_ACL_VERSION         ZFS_ACL_VERSION_FUID
+
+/*
+ * ZFS ACLs (Access Control Lists) are stored in various forms.
+ *
+ * Files created with ACL version ZFS_ACL_VERSION_INITIAL
+ * will all be created with fixed length ACEs of type
+ * zfs_oldace_t.
+ *
+ * Files with ACL version ZFS_ACL_VERSION_FUID will be created
+ * with various sized ACEs.  The abstraction entries will utilize
+ * zfs_ace_hdr_t, normal user/group entries will use zfs_ace_t
+ * and some specialized CIFS ACEs will use zfs_object_ace_t.
+ */
+
+/*
+ * All ACEs have a common hdr.  For
+ * owner@, group@, and everyone@ this is all
+ * thats needed.
+ */
+typedef struct zfs_ace_hdr {
+       uint16_t z_type;
+       uint16_t z_flags;
+       uint32_t z_access_mask;
+} zfs_ace_hdr_t;
+
+typedef zfs_ace_hdr_t zfs_ace_abstract_t;
+
+/*
+ * Standard ACE
+ */
+typedef struct zfs_ace {
+       zfs_ace_hdr_t   z_hdr;
+       uint64_t        z_fuid;
+} zfs_ace_t;
+
+/*
+ * The following type only applies to ACE_ACCESS_ALLOWED|DENIED_OBJECT_ACE_TYPE
+ * and will only be set/retrieved in a CIFS context.
+ */
+
+typedef struct zfs_object_ace {
+       zfs_ace_t       z_ace;
+       uint8_t         z_object_type[16]; /* object type */
+       uint8_t         z_inherit_type[16]; /* inherited object type */
+} zfs_object_ace_t;
+
+typedef struct zfs_oldace {
+       uint32_t        z_fuid;         /* "who" */
+       uint32_t        z_access_mask;  /* access mask */
+       uint16_t        z_flags;        /* flags, i.e inheritance */
+       uint16_t        z_type;         /* type of entry allow/deny */
+} zfs_oldace_t;
+
+typedef struct zfs_acl_phys_v0 {
+       uint64_t        z_acl_extern_obj;       /* ext acl pieces */
+       uint32_t        z_acl_count;            /* Number of ACEs */
+       uint16_t        z_acl_version;          /* acl version */
+       uint16_t        z_acl_pad;              /* pad */
+       zfs_oldace_t    z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
+} zfs_acl_phys_v0_t;
+
+#define        ZFS_ACE_SPACE   (sizeof (zfs_oldace_t) * ACE_SLOT_CNT)
+
+/*
+ * Size of ACL count is always 2 bytes.
+ * Necessary to for dealing with both V0 ACL and V1 ACL layout
+ */
+#define        ZFS_ACL_COUNT_SIZE      (sizeof (uint16_t))
+
+typedef struct zfs_acl_phys {
+       uint64_t        z_acl_extern_obj;         /* ext acl pieces */
+       uint32_t        z_acl_size;               /* Number of bytes in ACL */
+       uint16_t        z_acl_version;            /* acl version */
+       uint16_t        z_acl_count;              /* ace count */
+       uint8_t z_ace_data[ZFS_ACE_SPACE]; /* space for embedded ACEs */
+} zfs_acl_phys_t;
+
+typedef struct acl_ops {
+       uint32_t        (*ace_mask_get) (void *acep); /* get  access mask */
+       void            (*ace_mask_set) (void *acep,
+                           uint32_t mask); /* set access mask */
+       uint16_t        (*ace_flags_get) (void *acep);  /* get flags */
+       void            (*ace_flags_set) (void *acep,
+                           uint16_t flags); /* set flags */
+       uint16_t        (*ace_type_get)(void *acep); /* get type */
+       void            (*ace_type_set)(void *acep,
+                           uint16_t type); /* set type */
+       uint64_t        (*ace_who_get)(void *acep); /* get who/fuid */
+       void            (*ace_who_set)(void *acep,
+                           uint64_t who); /* set who/fuid */
+       size_t          (*ace_size)(void *acep); /* how big is this ace */
+       size_t          (*ace_abstract_size)(void); /* sizeof abstract entry */
+       int             (*ace_mask_off)(void); /* off of access mask in ace */
+       /* ptr to data if any */
+       int             (*ace_data)(void *acep, void **datap);
+} acl_ops_t;
+
+/*
+ * A zfs_acl_t structure is composed of a list of zfs_acl_node_t's.
+ * Each node will have one or more ACEs associated with it.  You will
+ * only have multiple nodes during a chmod operation.   Normally only
+ * one node is required.
+ */
+typedef struct zfs_acl_node {
+       list_node_t     z_next;         /* Next chunk of ACEs */
+       void            *z_acldata;     /* pointer into actual ACE(s) */
+       void            *z_allocdata;   /* pointer to kmem allocated memory */
+       size_t          z_allocsize;    /* Size of blob in bytes */
+       size_t          z_size;         /* length of ACL data */
+       uint64_t        z_ace_count;    /* number of ACEs in this acl node */
+       int             z_ace_idx;      /* ace iterator positioned on */
+} zfs_acl_node_t;
+
+typedef struct zfs_acl {
+       uint64_t        z_acl_count;    /* Number of ACEs */
+       size_t          z_acl_bytes;    /* Number of bytes in ACL */
+       uint_t          z_version;      /* version of ACL */
+       void            *z_next_ace;    /* pointer to next ACE */
+       uint64_t        z_hints;        /* ACL hints (ZFS_INHERIT_ACE ...) */
+       zfs_acl_node_t  *z_curr_node;   /* current node iterator is handling */
+       list_t          z_acl;          /* chunks of ACE data */
+       acl_ops_t       *z_ops;         /* ACL operations */
+} zfs_acl_t;
+
+typedef struct acl_locator_cb {
+       zfs_acl_t *cb_aclp;
+       zfs_acl_node_t *cb_acl_node;
+} zfs_acl_locator_cb_t;
+
+#define        ACL_DATA_ALLOCED        0x1
+#define        ZFS_ACL_SIZE(aclcnt)    (sizeof (ace_t) * (aclcnt))
+
+struct zfs_fuid_info;
+
+typedef struct zfs_acl_ids {
+       uint64_t                z_fuid;         /* file owner fuid */
+       uint64_t                z_fgid;         /* file group owner fuid */
+       uint64_t                z_mode;         /* mode to set on create */
+       zfs_acl_t               *z_aclp;        /* ACL to create with file */
+       struct zfs_fuid_info    *z_fuidp;       /* for tracking fuids for log */
+} zfs_acl_ids_t;
+
+/*
+ * Property values for acl_mode and acl_inherit.
+ *
+ * acl_mode can take discard, noallow, groupmask and passthrough.
+ * whereas acl_inherit has secure instead of groupmask.
+ */
+
+#define        ZFS_ACL_DISCARD         0
+#define        ZFS_ACL_NOALLOW         1
+#define        ZFS_ACL_GROUPMASK       2
+#define        ZFS_ACL_PASSTHROUGH     3
+#define        ZFS_ACL_RESTRICTED      4
+#define        ZFS_ACL_PASSTHROUGH_X   5
+
+struct znode;
+struct zfs_sb;
+
+#ifdef _KERNEL
+int zfs_acl_ids_create(struct znode *, int, vattr_t *,
+    cred_t *, vsecattr_t *, zfs_acl_ids_t *);
+void zfs_acl_ids_free(zfs_acl_ids_t *);
+boolean_t zfs_acl_ids_overquota(struct zfs_sb *, zfs_acl_ids_t *);
+int zfs_getacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
+int zfs_setacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
+void zfs_acl_rele(void *);
+void zfs_oldace_byteswap(ace_t *, int);
+void zfs_ace_byteswap(void *, size_t, boolean_t);
+extern boolean_t zfs_has_access(struct znode *zp, cred_t *cr);
+extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *);
+int zfs_fastaccesschk_execute(struct znode *, cred_t *);
+extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *);
+extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *);
+extern int zfs_acl_access(struct znode *, int, cred_t *);
+void zfs_acl_chmod_setattr(struct znode *, zfs_acl_t **, uint64_t);
+int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *);
+int zfs_zaccess_rename(struct znode *, struct znode *,
+    struct znode *, struct znode *, cred_t *cr);
+void zfs_acl_free(zfs_acl_t *);
+int zfs_vsec_2_aclp(struct zfs_sb *, umode_t, vsecattr_t *, cred_t *,
+    struct zfs_fuid_info **, zfs_acl_t **);
+int zfs_aclset_common(struct znode *, zfs_acl_t *, cred_t *, dmu_tx_t *);
+uint64_t zfs_external_acl(struct znode *);
+int zfs_znode_acl_version(struct znode *);
+int zfs_acl_size(struct znode *, int *);
+zfs_acl_t *zfs_acl_alloc(int);
+zfs_acl_node_t *zfs_acl_node_alloc(size_t);
+void zfs_acl_xform(struct znode *, zfs_acl_t *, cred_t *);
+void zfs_acl_data_locator(void **, uint32_t *, uint32_t, boolean_t, void *);
+uint64_t zfs_mode_compute(uint64_t, zfs_acl_t *,
+    uint64_t *, uint64_t, uint64_t);
+int zfs_acl_chown_setattr(struct znode *);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SYS_FS_ZFS_ACL_H */
diff --git a/zfs/include/sys/zfs_context.h b/zfs/include/sys/zfs_context.h
new file mode 100644 (file)
index 0000000..4f7e328
--- /dev/null
@@ -0,0 +1,753 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_ZFS_CONTEXT_H
+#define        _SYS_ZFS_CONTEXT_H
+
+#ifdef __KERNEL__
+
+#include <sys/note.h>
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+#include <sys/bitmap.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/kmem_cache.h>
+#include <sys/vmem.h>
+#include <sys/taskq.h>
+#include <sys/buf.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/cpuvar.h>
+#include <sys/kobj.h>
+#include <sys/conf.h>
+#include <sys/disp.h>
+#include <sys/debug.h>
+#include <sys/random.h>
+#include <sys/byteorder.h>
+#include <sys/systm.h>
+#include <sys/list.h>
+#include <sys/uio_impl.h>
+#include <sys/dirent.h>
+#include <sys/time.h>
+#include <vm/seg_kmem.h>
+#include <sys/zone.h>
+#include <sys/sdt.h>
+#include <sys/zfs_debug.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/trace.h>
+#include <linux/dcache_compat.h>
+#include <linux/utsname_compat.h>
+
+#else /* _KERNEL */
+
+#define        _SYS_MUTEX_H
+#define        _SYS_RWLOCK_H
+#define        _SYS_CONDVAR_H
+#define        _SYS_SYSTM_H
+#define        _SYS_T_LOCK_H
+#define        _SYS_VNODE_H
+#define        _SYS_VFS_H
+#define        _SYS_SUNDDI_H
+#define        _SYS_CALLB_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+#include <synch.h>
+#include <assert.h>
+#include <alloca.h>
+#include <umem.h>
+#include <limits.h>
+#include <atomic.h>
+#include <dirent.h>
+#include <time.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/note.h>
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/sysmacros.h>
+#include <sys/bitmap.h>
+#include <sys/resource.h>
+#include <sys/byteorder.h>
+#include <sys/list.h>
+#include <sys/uio.h>
+#include <sys/zfs_debug.h>
+#include <sys/sdt.h>
+#include <sys/kstat.h>
+#include <sys/u8_textprep.h>
+#include <sys/fm/fs/zfs.h>
+#include <sys/sunddi.h>
+#include <sys/debug.h>
+#include <sys/utsname.h>
+
+/*
+ * Stack
+ */
+
+#define        noinline        __attribute__((noinline))
+
+/*
+ * Debugging
+ */
+
+/*
+ * Note that we are not using the debugging levels.
+ */
+
+#define        CE_CONT         0       /* continuation         */
+#define        CE_NOTE         1       /* notice               */
+#define        CE_WARN         2       /* warning              */
+#define        CE_PANIC        3       /* panic                */
+#define        CE_IGNORE       4       /* print nothing        */
+
+/*
+ * ZFS debugging
+ */
+
+extern void dprintf_setup(int *argc, char **argv);
+
+extern void cmn_err(int, const char *, ...);
+extern void vcmn_err(int, const char *, va_list);
+extern void panic(const char *, ...);
+extern void vpanic(const char *, va_list);
+
+#define        fm_panic        panic
+
+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
+ * existence for their counterparts in libzpool.
+ */
+
+#ifdef DTRACE_PROBE
+#undef DTRACE_PROBE
+#endif /* DTRACE_PROBE */
+#define        DTRACE_PROBE(a) \
+       ZFS_PROBE0(#a)
+
+#ifdef DTRACE_PROBE1
+#undef DTRACE_PROBE1
+#endif /* DTRACE_PROBE1 */
+#define        DTRACE_PROBE1(a, b, c) \
+       ZFS_PROBE1(#a, (unsigned long)c)
+
+#ifdef DTRACE_PROBE2
+#undef DTRACE_PROBE2
+#endif /* DTRACE_PROBE2 */
+#define        DTRACE_PROBE2(a, b, c, d, e) \
+       ZFS_PROBE2(#a, (unsigned long)c, (unsigned long)e)
+
+#ifdef DTRACE_PROBE3
+#undef DTRACE_PROBE3
+#endif /* DTRACE_PROBE3 */
+#define        DTRACE_PROBE3(a, b, c, d, e, f, g) \
+       ZFS_PROBE3(#a, (unsigned long)c, (unsigned long)e, (unsigned long)g)
+
+#ifdef DTRACE_PROBE4
+#undef DTRACE_PROBE4
+#endif /* DTRACE_PROBE4 */
+#define        DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) \
+       ZFS_PROBE4(#a, (unsigned long)c, (unsigned long)e, (unsigned long)g, \
+       (unsigned long)i)
+
+/*
+ * We use the comma operator so that this macro can be used without much
+ * additional code.  For example, "return (EINVAL);" becomes
+ * "return (SET_ERROR(EINVAL));".  Note that the argument will be evaluated
+ * twice, so it should not have side effects (e.g. something like:
+ * "return (SET_ERROR(log_error(EINVAL, info)));" would log the error twice).
+ */
+#define        SET_ERROR(err) (ZFS_SET_ERROR(err), err)
+
+/*
+ * Threads.  TS_STACK_MIN is dictated by the minimum allowed pthread stack
+ * size.  While TS_STACK_MAX is somewhat arbitrary, it was selected to be
+ * large enough for the expected stack depth while small enough to avoid
+ * exhausting address space with high thread counts.
+ */
+#define        TS_MAGIC                0x72f158ab4261e538ull
+#define        TS_RUN                  0x00000002
+#define        TS_STACK_MIN            PTHREAD_STACK_MIN
+#define        TS_STACK_MAX            (256 * 1024)
+
+/* in libzpool, p0 exists only to have its address taken */
+typedef struct proc {
+       uintptr_t       this_is_never_used_dont_dereference_it;
+} proc_t;
+
+extern struct proc p0;
+#define        curproc         (&p0)
+
+typedef void (*thread_func_t)(void *);
+typedef void (*thread_func_arg_t)(void *);
+typedef pthread_t kt_did_t;
+
+#define        kpreempt(x)     ((void)0)
+
+typedef struct kthread {
+       kt_did_t        t_tid;
+       thread_func_t   t_func;
+       void *          t_arg;
+       pri_t           t_pri;
+} kthread_t;
+
+#define        curthread                       zk_thread_current()
+#define        getcomm()                       "unknown"
+#define        thread_exit                     zk_thread_exit
+#define        thread_create(stk, stksize, func, arg, len, pp, state, pri)     \
+       zk_thread_create(stk, stksize, (thread_func_t)func, arg,        \
+           len, NULL, state, pri, PTHREAD_CREATE_DETACHED)
+#define        thread_join(t)                  zk_thread_join(t)
+#define        newproc(f, a, cid, pri, ctp, pid)       (ENOSYS)
+
+extern kthread_t *zk_thread_current(void);
+extern void zk_thread_exit(void);
+extern 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);
+extern void zk_thread_join(kt_did_t tid);
+
+#define        kpreempt_disable()      ((void)0)
+#define        kpreempt_enable()       ((void)0)
+
+#define        PS_NONE         -1
+
+#define        issig(why)      (FALSE)
+#define        ISSIG(thr, why) (FALSE)
+
+/*
+ * Mutexes
+ */
+#define        MTX_MAGIC       0x9522f51362a6e326ull
+#define        MTX_INIT        ((void *)NULL)
+#define        MTX_DEST        ((void *)-1UL)
+
+typedef struct kmutex {
+       void            *m_owner;
+       uint64_t        m_magic;
+       pthread_mutex_t m_lock;
+} kmutex_t;
+
+#define        MUTEX_DEFAULT   0
+#define        MUTEX_HELD(m)   ((m)->m_owner == curthread)
+#define        MUTEX_NOT_HELD(m) (!MUTEX_HELD(m))
+
+extern void mutex_init(kmutex_t *mp, char *name, int type, void *cookie);
+extern void mutex_destroy(kmutex_t *mp);
+extern void mutex_enter(kmutex_t *mp);
+extern void mutex_exit(kmutex_t *mp);
+extern int mutex_tryenter(kmutex_t *mp);
+extern void *mutex_owner(kmutex_t *mp);
+extern int mutex_held(kmutex_t *mp);
+
+/*
+ * RW locks
+ */
+#define        RW_MAGIC        0x4d31fb123648e78aull
+#define        RW_INIT         ((void *)NULL)
+#define        RW_DEST         ((void *)-1UL)
+
+typedef struct krwlock {
+       void                    *rw_owner;
+       void                    *rw_wr_owner;
+       uint64_t                rw_magic;
+       pthread_rwlock_t        rw_lock;
+       uint_t                  rw_readers;
+} krwlock_t;
+
+typedef int krw_t;
+
+#define        RW_READER       0
+#define        RW_WRITER       1
+#define        RW_DEFAULT      RW_READER
+
+#define        RW_READ_HELD(x)         ((x)->rw_readers > 0)
+#define        RW_WRITE_HELD(x)        ((x)->rw_wr_owner == curthread)
+#define        RW_LOCK_HELD(x)         (RW_READ_HELD(x) || RW_WRITE_HELD(x))
+
+#undef RW_LOCK_HELD
+#define        RW_LOCK_HELD(x)         (RW_READ_HELD(x) || RW_WRITE_HELD(x))
+
+#undef RW_LOCK_HELD
+#define        RW_LOCK_HELD(x)         (RW_READ_HELD(x) || RW_WRITE_HELD(x))
+
+extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg);
+extern void rw_destroy(krwlock_t *rwlp);
+extern void rw_enter(krwlock_t *rwlp, krw_t rw);
+extern int rw_tryenter(krwlock_t *rwlp, krw_t rw);
+extern int rw_tryupgrade(krwlock_t *rwlp);
+extern void rw_exit(krwlock_t *rwlp);
+#define        rw_downgrade(rwlp) do { } while (0)
+
+extern uid_t crgetuid(cred_t *cr);
+extern uid_t crgetruid(cred_t *cr);
+extern gid_t crgetgid(cred_t *cr);
+extern int crgetngroups(cred_t *cr);
+extern gid_t *crgetgroups(cred_t *cr);
+
+/*
+ * Condition variables
+ */
+#define        CV_MAGIC        0xd31ea9a83b1b30c4ull
+
+typedef struct kcondvar {
+       uint64_t                cv_magic;
+       pthread_cond_t          cv;
+} kcondvar_t;
+
+#define        CV_DEFAULT      0
+
+extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg);
+extern void cv_destroy(kcondvar_t *cv);
+extern void cv_wait(kcondvar_t *cv, kmutex_t *mp);
+extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
+extern clock_t cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim,
+    hrtime_t res, int flag);
+extern void cv_signal(kcondvar_t *cv);
+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)
+
+/*
+ * Thread-specific data
+ */
+#define        tsd_get(k) pthread_getspecific(k)
+#define        tsd_set(k, v) pthread_setspecific(k, v)
+#define        tsd_create(kp, d) pthread_key_create(kp, d)
+#define        tsd_destroy(kp) /* nothing */
+
+/*
+ * Thread-specific data
+ */
+#define        tsd_get(k) pthread_getspecific(k)
+#define        tsd_set(k, v) pthread_setspecific(k, v)
+#define        tsd_create(kp, d) pthread_key_create(kp, d)
+#define        tsd_destroy(kp) /* nothing */
+
+/*
+ * kstat creation, installation and deletion
+ */
+extern kstat_t *kstat_create(const char *, int,
+    const char *, const char *, uchar_t, ulong_t, uchar_t);
+extern void kstat_install(kstat_t *);
+extern void kstat_delete(kstat_t *);
+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_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));
+
+/*
+ * Kernel memory
+ */
+#define        KM_SLEEP                UMEM_NOFAIL
+#define        KM_PUSHPAGE             KM_SLEEP
+#define        KM_NOSLEEP              UMEM_DEFAULT
+#define        KMC_NODEBUG             UMC_NODEBUG
+#define        KMC_KMEM                0x0
+#define        KMC_VMEM                0x0
+#define        kmem_alloc(_s, _f)      umem_alloc(_s, _f)
+#define        kmem_zalloc(_s, _f)     umem_zalloc(_s, _f)
+#define        kmem_free(_b, _s)       umem_free(_b, _s)
+#define        vmem_alloc(_s, _f)      kmem_alloc(_s, _f)
+#define        vmem_zalloc(_s, _f)     kmem_zalloc(_s, _f)
+#define        vmem_free(_b, _s)       kmem_free(_b, _s)
+#define        kmem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) \
+       umem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i)
+#define        kmem_cache_destroy(_c)  umem_cache_destroy(_c)
+#define        kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f)
+#define        kmem_cache_free(_c, _b) umem_cache_free(_c, _b)
+#define        kmem_debugging()        0
+#define        kmem_cache_reap_now(_c) umem_cache_reap_now(_c);
+#define        kmem_cache_set_move(_c, _cb)    /* nothing */
+#define        vmem_qcache_reap(_v)            /* nothing */
+#define        POINTER_INVALIDATE(_pp)         /* nothing */
+#define        POINTER_IS_VALID(_p)    0
+
+extern vmem_t *zio_arena;
+
+typedef umem_cache_t kmem_cache_t;
+
+typedef enum kmem_cbrc {
+       KMEM_CBRC_YES,
+       KMEM_CBRC_NO,
+       KMEM_CBRC_LATER,
+       KMEM_CBRC_DONT_NEED,
+       KMEM_CBRC_DONT_KNOW
+} kmem_cbrc_t;
+
+/*
+ * Task queues
+ */
+typedef struct taskq taskq_t;
+typedef uintptr_t taskqid_t;
+typedef void (task_func_t)(void *);
+
+typedef struct taskq_ent {
+       struct taskq_ent        *tqent_next;
+       struct taskq_ent        *tqent_prev;
+       task_func_t             *tqent_func;
+       void                    *tqent_arg;
+       uintptr_t               tqent_flags;
+} taskq_ent_t;
+
+#define        TQENT_FLAG_PREALLOC     0x1     /* taskq_dispatch_ent used */
+
+#define        TASKQ_PREPOPULATE       0x0001
+#define        TASKQ_CPR_SAFE          0x0002  /* Use CPR safe protocol */
+#define        TASKQ_DYNAMIC           0x0004  /* Use dynamic thread scheduling */
+#define        TASKQ_THREADS_CPU_PCT   0x0008  /* Scale # threads by # cpus */
+#define        TASKQ_DC_BATCH          0x0010  /* Mark threads as batch */
+
+#define        TQ_SLEEP        KM_SLEEP        /* Can block for memory */
+#define        TQ_NOSLEEP      KM_NOSLEEP      /* cannot block for memory; may fail */
+#define        TQ_NOQUEUE      0x02            /* Do not enqueue if can't dispatch */
+#define        TQ_FRONT        0x08            /* Queue in front */
+
+extern taskq_t *system_taskq;
+
+extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
+#define        taskq_create_proc(a, b, c, d, e, p, f) \
+           (taskq_create(a, b, c, d, e, f))
+#define        taskq_create_sysdc(a, b, d, e, p, dc, f) \
+           (taskq_create(a, b, maxclsyspri, d, e, f))
+extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
+extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *, uint_t,
+    clock_t);
+extern void    taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
+    taskq_ent_t *);
+extern int     taskq_empty_ent(taskq_ent_t *);
+extern void    taskq_init_ent(taskq_ent_t *);
+extern void    taskq_destroy(taskq_t *);
+extern void    taskq_wait(taskq_t *);
+extern void    taskq_wait_id(taskq_t *, taskqid_t);
+extern void    taskq_wait_outstanding(taskq_t *, taskqid_t);
+extern int     taskq_member(taskq_t *, kthread_t *);
+extern int     taskq_cancel_id(taskq_t *, taskqid_t);
+extern void    system_taskq_init(void);
+extern void    system_taskq_fini(void);
+
+#define        XVA_MAPSIZE     3
+#define        XVA_MAGIC       0x78766174
+
+/*
+ * vnodes
+ */
+typedef struct vnode {
+       uint64_t        v_size;
+       int             v_fd;
+       char            *v_path;
+} vnode_t;
+
+#define        AV_SCANSTAMP_SZ 32              /* length of anti-virus scanstamp */
+
+typedef struct xoptattr {
+       timestruc_t     xoa_createtime; /* Create time of file */
+       uint8_t         xoa_archive;
+       uint8_t         xoa_system;
+       uint8_t         xoa_readonly;
+       uint8_t         xoa_hidden;
+       uint8_t         xoa_nounlink;
+       uint8_t         xoa_immutable;
+       uint8_t         xoa_appendonly;
+       uint8_t         xoa_nodump;
+       uint8_t         xoa_settable;
+       uint8_t         xoa_opaque;
+       uint8_t         xoa_av_quarantined;
+       uint8_t         xoa_av_modified;
+       uint8_t         xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+       uint8_t         xoa_reparse;
+       uint8_t         xoa_offline;
+       uint8_t         xoa_sparse;
+} xoptattr_t;
+
+typedef struct vattr {
+       uint_t          va_mask;        /* bit-mask of attributes */
+       u_offset_t      va_size;        /* file size in bytes */
+} vattr_t;
+
+
+typedef struct xvattr {
+       vattr_t         xva_vattr;      /* Embedded vattr structure */
+       uint32_t        xva_magic;      /* Magic Number */
+       uint32_t        xva_mapsize;    /* Size of attr bitmap (32-bit words) */
+       uint32_t        *xva_rtnattrmapp;       /* Ptr to xva_rtnattrmap[] */
+       uint32_t        xva_reqattrmap[XVA_MAPSIZE];    /* Requested attrs */
+       uint32_t        xva_rtnattrmap[XVA_MAPSIZE];    /* Returned attrs */
+       xoptattr_t      xva_xoptattrs;  /* Optional attributes */
+} xvattr_t;
+
+typedef struct vsecattr {
+       uint_t          vsa_mask;       /* See below */
+       int             vsa_aclcnt;     /* ACL entry count */
+       void            *vsa_aclentp;   /* pointer to ACL entries */
+       int             vsa_dfaclcnt;   /* default ACL entry count */
+       void            *vsa_dfaclentp; /* pointer to default ACL entries */
+       size_t          vsa_aclentsz;   /* ACE size in bytes of vsa_aclentp */
+} vsecattr_t;
+
+#define        AT_TYPE         0x00001
+#define        AT_MODE         0x00002
+#define        AT_UID          0x00004
+#define        AT_GID          0x00008
+#define        AT_FSID         0x00010
+#define        AT_NODEID       0x00020
+#define        AT_NLINK        0x00040
+#define        AT_SIZE         0x00080
+#define        AT_ATIME        0x00100
+#define        AT_MTIME        0x00200
+#define        AT_CTIME        0x00400
+#define        AT_RDEV         0x00800
+#define        AT_BLKSIZE      0x01000
+#define        AT_NBLOCKS      0x02000
+#define        AT_SEQ          0x08000
+#define        AT_XVATTR       0x10000
+
+#define        CRCREAT         0
+
+extern int fop_getattr(vnode_t *vp, vattr_t *vap);
+
+#define        VOP_CLOSE(vp, f, c, o, cr, ct)  vn_close(vp)
+#define        VOP_PUTPAGE(vp, of, sz, fl, cr, ct)     0
+#define        VOP_GETATTR(vp, vap, fl, cr, ct)  fop_getattr((vp), (vap));
+
+#define        VOP_FSYNC(vp, f, cr, ct)        fsync((vp)->v_fd)
+
+#define        VN_RELE(vp)     vn_close(vp)
+
+extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
+    int x2, int x3);
+extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp,
+    int x2, int x3, vnode_t *vp, int fd);
+extern 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);
+extern void vn_close(vnode_t *vp);
+
+#define        vn_remove(path, x1, x2)         remove(path)
+#define        vn_rename(from, to, seg)        rename((from), (to))
+#define        vn_is_readonly(vp)              B_FALSE
+
+extern vnode_t *rootdir;
+
+#include <sys/file.h>          /* for FREAD, FWRITE, etc */
+
+/*
+ * Random stuff
+ */
+#define        ddi_get_lbolt()         (gethrtime() >> 23)
+#define        ddi_get_lbolt64()       (gethrtime() >> 23)
+#define        hz      119     /* frequency when using gethrtime() >> 23 for lbolt */
+
+#define        ddi_time_before(a, b)           (a < b)
+#define        ddi_time_after(a, b)            ddi_time_before(b, a)
+#define        ddi_time_before_eq(a, b)        (!ddi_time_after(a, b))
+#define        ddi_time_after_eq(a, b)         ddi_time_before_eq(b, a)
+
+#define        ddi_time_before64(a, b)         (a < b)
+#define        ddi_time_after64(a, b)          ddi_time_before64(b, a)
+#define        ddi_time_before_eq64(a, b)      (!ddi_time_after64(a, b))
+#define        ddi_time_after_eq64(a, b)       ddi_time_before_eq64(b, a)
+
+extern void delay(clock_t ticks);
+
+#define        SEC_TO_TICK(sec)        ((sec) * hz)
+#define        MSEC_TO_TICK(msec)      ((msec) / (MILLISEC / hz))
+#define        USEC_TO_TICK(usec)      ((usec) / (MICROSEC / hz))
+#define        NSEC_TO_TICK(usec)      ((usec) / (NANOSEC / hz))
+
+#define        gethrestime_sec() time(NULL)
+#define        gethrestime(t) \
+       do {\
+               (t)->tv_sec = gethrestime_sec();\
+               (t)->tv_nsec = 0;\
+       } while (0);
+
+#define        max_ncpus       64
+#define        boot_ncpus      (sysconf(_SC_NPROCESSORS_ONLN))
+
+/*
+ * Process priorities as defined by setpriority(2) and getpriority(2).
+ */
+#define        minclsyspri     19
+#define        maxclsyspri     -20
+#define        defclsyspri     0
+
+#define        CPU_SEQID       (pthread_self() & (max_ncpus - 1))
+
+#define        kcred           NULL
+#define        CRED()          NULL
+
+#define        ptob(x)         ((x) * PAGESIZE)
+
+extern uint64_t physmem;
+
+extern int highbit64(uint64_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);
+
+struct spa;
+extern void nicenum(uint64_t num, char *buf);
+extern void show_pool_stats(struct spa *);
+
+typedef struct callb_cpr {
+       kmutex_t        *cc_lockp;
+} callb_cpr_t;
+
+#define        CALLB_CPR_INIT(cp, lockp, func, name)   {               \
+       (cp)->cc_lockp = lockp;                                 \
+}
+
+#define        CALLB_CPR_SAFE_BEGIN(cp) {                              \
+       ASSERT(MUTEX_HELD((cp)->cc_lockp));                     \
+}
+
+#define        CALLB_CPR_SAFE_END(cp, lockp) {                         \
+       ASSERT(MUTEX_HELD((cp)->cc_lockp));                     \
+}
+
+#define        CALLB_CPR_EXIT(cp) {                                    \
+       ASSERT(MUTEX_HELD((cp)->cc_lockp));                     \
+       mutex_exit((cp)->cc_lockp);                             \
+}
+
+#define        zone_dataset_visible(x, y)      (1)
+#define        INGLOBALZONE(z)                 (1)
+
+extern char *kmem_vasprintf(const char *fmt, va_list adx);
+extern char *kmem_asprintf(const char *fmt, ...);
+#define        strfree(str) kmem_free((str), strlen(str) + 1)
+
+/*
+ * Hostname information
+ */
+extern char hw_serial[];       /* for userland-emulated hostid access */
+extern int ddi_strtoul(const char *str, char **nptr, int base,
+    unsigned long *result);
+
+extern int ddi_strtoull(const char *str, char **nptr, int base,
+    u_longlong_t *result);
+
+typedef struct utsname utsname_t;
+extern utsname_t *utsname(void);
+
+/* ZFS Boot Related stuff. */
+
+struct _buf {
+       intptr_t        _fd;
+};
+
+struct bootstat {
+       uint64_t st_size;
+};
+
+typedef struct ace_object {
+       uid_t           a_who;
+       uint32_t        a_access_mask;
+       uint16_t        a_flags;
+       uint16_t        a_type;
+       uint8_t         a_obj_type[16];
+       uint8_t         a_inherit_obj_type[16];
+} ace_object_t;
+
+
+#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
+
+extern struct _buf *kobj_open_file(char *name);
+extern int kobj_read_file(struct _buf *file, char *buf, unsigned size,
+    unsigned off);
+extern void kobj_close_file(struct _buf *file);
+extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
+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 zoneid_t getzoneid(void);
+
+/* SID stuff */
+typedef struct ksiddomain {
+       uint_t  kd_ref;
+       uint_t  kd_len;
+       char    *kd_name;
+} ksiddomain_t;
+
+ksiddomain_t *ksid_lookupdomain(const char *);
+void ksiddomain_rele(ksiddomain_t *);
+
+#define        DDI_SLEEP       KM_SLEEP
+#define        ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \
+       sysevent_post_event(_c, _d, _b, "libzpool", _e, _f)
+
+#define        zfs_sleep_until(wakeup)                                         \
+       do {                                                            \
+               hrtime_t delta = wakeup - gethrtime();                  \
+               struct timespec ts;                                     \
+               ts.tv_sec = delta / NANOSEC;                            \
+               ts.tv_nsec = delta % NANOSEC;                           \
+               (void) nanosleep(&ts, NULL);                            \
+       } while (0)
+
+typedef int fstrans_cookie_t;
+
+extern fstrans_cookie_t spl_fstrans_mark(void);
+extern void spl_fstrans_unmark(fstrans_cookie_t);
+extern int spl_fstrans_check(void);
+
+#endif /* _KERNEL */
+#endif /* _SYS_ZFS_CONTEXT_H */
diff --git a/zfs/include/sys/zfs_ctldir.h b/zfs/include/sys/zfs_ctldir.h
new file mode 100644 (file)
index 0000000..65c44f3
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (C) 2011 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * LLNL-CODE-403049.
+ * Rewritten for Linux by:
+ *   Rohan Puri <rohan.puri15@gmail.com>
+ *   Brian Behlendorf <behlendorf1@llnl.gov>
+ */
+
+#ifndef        _ZFS_CTLDIR_H
+#define        _ZFS_CTLDIR_H
+
+#include <sys/vnode.h>
+#include <sys/pathname.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_znode.h>
+
+#define        ZFS_CTLDIR_NAME         ".zfs"
+#define        ZFS_SNAPDIR_NAME        "snapshot"
+#define        ZFS_SHAREDIR_NAME       "shares"
+
+#define        zfs_has_ctldir(zdp)     \
+       ((zdp)->z_id == ZTOZSB(zdp)->z_root && \
+       (ZTOZSB(zdp)->z_ctldir != NULL))
+#define        zfs_show_ctldir(zdp)    \
+       (zfs_has_ctldir(zdp) && \
+       (ZTOZSB(zdp)->z_show_ctldir))
+
+extern int zfs_expire_snapshot;
+
+/* zfsctl generic functions */
+extern int zfsctl_create(zfs_sb_t *zsb);
+extern void zfsctl_destroy(zfs_sb_t *zsb);
+extern struct inode *zfsctl_root(znode_t *zp);
+extern void zfsctl_init(void);
+extern void zfsctl_fini(void);
+extern boolean_t zfsctl_is_node(struct inode *ip);
+extern boolean_t zfsctl_is_snapdir(struct inode *ip);
+extern int zfsctl_fid(struct inode *ip, fid_t *fidp);
+
+/* zfsctl '.zfs' functions */
+extern int zfsctl_root_lookup(struct inode *dip, char *name,
+    struct inode **ipp, int flags, cred_t *cr, int *direntflags,
+    pathname_t *realpnp);
+
+/* zfsctl '.zfs/snapshot' functions */
+extern int zfsctl_snapdir_lookup(struct inode *dip, char *name,
+    struct inode **ipp, int flags, cred_t *cr, int *direntflags,
+    pathname_t *realpnp);
+extern int zfsctl_snapdir_rename(struct inode *sdip, char *sname,
+    struct inode *tdip, char *tname, cred_t *cr, int flags);
+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,
+    int delay);
+extern int zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid,
+    zfs_sb_t **zsb);
+
+/* zfsctl '.zfs/shares' functions */
+extern int zfsctl_shares_lookup(struct inode *dip, char *name,
+    struct inode **ipp, int flags, cred_t *cr, int *direntflags,
+    pathname_t *realpnp);
+
+/*
+ * These inodes numbers are reserved for the .zfs control directory.
+ * It is important that they be no larger that 48-bits because only
+ * 6 bytes are reserved in the NFS file handle for the object number.
+ * However, they should be as large as possible to avoid conflicts
+ * with the objects which are assigned monotonically by the dmu.
+ */
+#define        ZFSCTL_INO_ROOT         0x0000FFFFFFFFFFFFULL
+#define        ZFSCTL_INO_SHARES       0x0000FFFFFFFFFFFEULL
+#define        ZFSCTL_INO_SNAPDIR      0x0000FFFFFFFFFFFDULL
+#define        ZFSCTL_INO_SNAPDIRS     0x0000FFFFFFFFFFFCULL
+
+#define        ZFSCTL_EXPIRE_SNAPSHOT  300
+
+#endif /* _ZFS_CTLDIR_H */
diff --git a/zfs/include/sys/zfs_debug.h b/zfs/include/sys/zfs_debug.h
new file mode 100644 (file)
index 0000000..2f0064e
--- /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 (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_ZFS_DEBUG_H
+#define        _SYS_ZFS_DEBUG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef TRUE
+#define        TRUE 1
+#endif
+
+#ifndef FALSE
+#define        FALSE 0
+#endif
+
+extern int zfs_flags;
+extern int zfs_recover;
+extern int zfs_free_leak_on_eio;
+
+#define        ZFS_DEBUG_DPRINTF               (1<<0)
+#define        ZFS_DEBUG_DBUF_VERIFY           (1<<1)
+#define        ZFS_DEBUG_DNODE_VERIFY          (1<<2)
+#define        ZFS_DEBUG_SNAPNAMES             (1<<3)
+#define        ZFS_DEBUG_MODIFY                (1<<4)
+#define        ZFS_DEBUG_SPA                   (1<<5)
+#define        ZFS_DEBUG_ZIO_FREE              (1<<6)
+#define        ZFS_DEBUG_HISTOGRAM_VERIFY      (1<<7)
+
+extern void __dprintf(const char *file, const char *func,
+    int line, const char *fmt, ...);
+#define        dprintf(...) \
+       __dprintf(__FILE__, __func__, __LINE__, __VA_ARGS__)
+#define        zfs_dbgmsg(...) \
+       __dprintf(__FILE__, __func__, __LINE__, __VA_ARGS__)
+
+extern void zfs_panic_recover(const char *fmt, ...);
+
+typedef struct zfs_dbgmsg {
+       list_node_t zdm_node;
+       time_t zdm_timestamp;
+       int zdm_size;
+       char zdm_msg[1]; /* variable length allocation */
+} zfs_dbgmsg_t;
+
+extern void zfs_dbgmsg_init(void);
+extern void zfs_dbgmsg_fini(void);
+
+#ifndef _KERNEL
+extern int dprintf_find_string(const char *string);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_DEBUG_H */
diff --git a/zfs/include/sys/zfs_delay.h b/zfs/include/sys/zfs_delay.h
new file mode 100644 (file)
index 0000000..b56a7da
--- /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
+ */
+
+#ifndef        _SYS_FS_ZFS_DELAY_H
+#define        _SYS_FS_ZFS_DELAY_H
+
+#include <linux/delay_compat.h>
+
+/*
+ * Generic wrapper to sleep until a given time.
+ */
+#define        zfs_sleep_until(wakeup)                                         \
+       do {                                                            \
+               hrtime_t delta = wakeup - gethrtime();                  \
+                                                                       \
+               if (delta > 0) {                                        \
+                       unsigned long delta_us;                         \
+                       delta_us = delta / (NANOSEC / MICROSEC);        \
+                       usleep_range(delta_us, delta_us + 100);         \
+               }                                                       \
+       } while (0)
+
+#endif /* _SYS_FS_ZFS_DELAY_H */
diff --git a/zfs/include/sys/zfs_dir.h b/zfs/include/sys/zfs_dir.h
new file mode 100644 (file)
index 0000000..8610fbe
--- /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
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_FS_ZFS_DIR_H
+#define        _SYS_FS_ZFS_DIR_H
+
+#include <sys/pathname.h>
+#include <sys/dmu.h>
+#include <sys/zfs_znode.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* zfs_dirent_lock() flags */
+#define        ZNEW            0x0001          /* entry should not exist */
+#define        ZEXISTS         0x0002          /* entry should exist */
+#define        ZSHARED         0x0004          /* shared access (zfs_dirlook()) */
+#define        ZXATTR          0x0008          /* we want the xattr dir */
+#define        ZRENAMING       0x0010          /* znode is being renamed */
+#define        ZCILOOK         0x0020          /* case-insensitive lookup requested */
+#define        ZCIEXACT        0x0040          /* c-i requires c-s match (rename) */
+#define        ZHAVELOCK       0x0080          /* z_name_lock is already held */
+
+/* mknode flags */
+#define        IS_ROOT_NODE    0x01            /* create a root node */
+#define        IS_XATTR        0x02            /* create an extended attribute node */
+
+extern int zfs_dirent_lock(zfs_dirlock_t **, znode_t *, char *, znode_t **,
+    int, int *, pathname_t *);
+extern void zfs_dirent_unlock(zfs_dirlock_t *);
+extern int zfs_link_create(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int);
+extern int zfs_link_destroy(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int,
+    boolean_t *);
+extern int zfs_dirlook(znode_t *, char *, struct inode **, int, int *,
+    pathname_t *);
+extern void zfs_mknode(znode_t *, vattr_t *, dmu_tx_t *, cred_t *,
+    uint_t, znode_t **, zfs_acl_ids_t *);
+extern void zfs_rmnode(znode_t *);
+extern void zfs_dl_name_switch(zfs_dirlock_t *dl, char *new, char **old);
+extern boolean_t zfs_dirempty(znode_t *);
+extern void zfs_unlinked_add(znode_t *, dmu_tx_t *);
+extern void zfs_unlinked_drain(zfs_sb_t *);
+extern int zfs_sticky_remove_access(znode_t *, znode_t *, cred_t *cr);
+extern int zfs_get_xattrdir(znode_t *, struct inode **, cred_t *, int);
+extern int zfs_make_xattrdir(znode_t *, vattr_t *, struct inode **, cred_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_DIR_H */
diff --git a/zfs/include/sys/zfs_fuid.h b/zfs/include/sys/zfs_fuid.h
new file mode 100644 (file)
index 0000000..deaebcc
--- /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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_FS_ZFS_FUID_H
+#define        _SYS_FS_ZFS_FUID_H
+
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#include <sys/sid.h>
+#include <sys/dmu.h>
+#include <sys/zfs_vfsops.h>
+#endif
+#include <sys/avl.h>
+#include <sys/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       ZFS_OWNER,
+       ZFS_GROUP,
+       ZFS_ACE_USER,
+       ZFS_ACE_GROUP
+} zfs_fuid_type_t;
+
+/*
+ * Estimate space needed for one more fuid table entry.
+ * for now assume its current size + 1K
+ */
+#define        FUID_SIZE_ESTIMATE(z) ((z)->z_fuid_size + (SPA_MINBLOCKSIZE << 1))
+
+#define        FUID_INDEX(x)   ((x) >> 32)
+#define        FUID_RID(x)     ((x) & 0xffffffff)
+#define        FUID_ENCODE(idx, rid) (((uint64_t)(idx) << 32) | (rid))
+/*
+ * FUIDs cause problems for the intent log
+ * we need to replay the creation of the FUID,
+ * but we can't count on the idmapper to be around
+ * and during replay the FUID index may be different than
+ * before.  Also, if an ACL has 100 ACEs and 12 different
+ * domains we don't want to log 100 domain strings, but rather
+ * just the unique 12.
+ */
+
+/*
+ * The FUIDs in the log will index into
+ * domain string table and the bottom half will be the rid.
+ * Used for mapping ephemeral uid/gid during ACL setting to FUIDs
+ */
+typedef struct zfs_fuid {
+       list_node_t     z_next;
+       uint64_t        z_id;           /* uid/gid being converted to fuid */
+       uint64_t        z_domidx;       /* index in AVL domain table */
+       uint64_t        z_logfuid;      /* index for domain in log */
+} zfs_fuid_t;
+
+/* list of unique domains */
+typedef struct zfs_fuid_domain {
+       list_node_t     z_next;
+       uint64_t        z_domidx;       /* AVL tree idx */
+       const char      *z_domain;      /* domain string */
+} zfs_fuid_domain_t;
+
+/*
+ * FUID information necessary for logging create, setattr, and setacl.
+ */
+typedef struct zfs_fuid_info {
+       list_t  z_fuids;
+       list_t  z_domains;
+       uint64_t z_fuid_owner;
+       uint64_t z_fuid_group;
+       char **z_domain_table;  /* Used during replay */
+       uint32_t z_fuid_cnt;    /* How many fuids in z_fuids */
+       uint32_t z_domain_cnt;  /* How many domains */
+       size_t  z_domain_str_sz; /* len of domain strings z_domain list */
+} zfs_fuid_info_t;
+
+#ifdef _KERNEL
+struct znode;
+extern uid_t zfs_fuid_map_id(zfs_sb_t *, uint64_t, cred_t *, zfs_fuid_type_t);
+extern void zfs_fuid_node_add(zfs_fuid_info_t **, const char *, uint32_t,
+    uint64_t, uint64_t, zfs_fuid_type_t);
+extern void zfs_fuid_destroy(zfs_sb_t *);
+extern uint64_t zfs_fuid_create_cred(zfs_sb_t *, zfs_fuid_type_t,
+    cred_t *, zfs_fuid_info_t **);
+extern uint64_t zfs_fuid_create(zfs_sb_t *, uint64_t, cred_t *, zfs_fuid_type_t,
+    zfs_fuid_info_t **);
+extern void zfs_fuid_map_ids(struct znode *zp, cred_t *cr,
+    uid_t *uid, uid_t *gid);
+extern zfs_fuid_info_t *zfs_fuid_info_alloc(void);
+extern void zfs_fuid_info_free(zfs_fuid_info_t *);
+extern boolean_t zfs_groupmember(zfs_sb_t *, uint64_t, cred_t *);
+void zfs_fuid_sync(zfs_sb_t *, dmu_tx_t *);
+extern int zfs_fuid_find_by_domain(zfs_sb_t *, const char *domain,
+    char **retdomain, boolean_t addok);
+extern const char *zfs_fuid_find_by_idx(zfs_sb_t *zsb, uint32_t idx);
+extern void zfs_fuid_txhold(zfs_sb_t *zsb, dmu_tx_t *tx);
+#endif
+
+char *zfs_fuid_idx_domain(avl_tree_t *, uint32_t);
+void zfs_fuid_avl_tree_create(avl_tree_t *, avl_tree_t *);
+uint64_t zfs_fuid_table_load(objset_t *, uint64_t, avl_tree_t *, avl_tree_t *);
+void zfs_fuid_table_destroy(avl_tree_t *, avl_tree_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_FUID_H */
diff --git a/zfs/include/sys/zfs_ioctl.h b/zfs/include/sys/zfs_ioctl.h
new file mode 100644 (file)
index 0000000..09a96c0
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef        _SYS_ZFS_IOCTL_H
+#define        _SYS_ZFS_IOCTL_H
+
+#include <sys/cred.h>
+#include <sys/dmu.h>
+#include <sys/zio.h>
+#include <sys/dsl_deleg.h>
+#include <sys/spa.h>
+#include <sys/zfs_stat.h>
+
+#ifdef _KERNEL
+#include <sys/nvpair.h>
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The structures in this file are passed between userland and the
+ * kernel.  Userland may be running a 32-bit process, while the kernel
+ * is 64-bit.  Therefore, these structures need to compile the same in
+ * 32-bit and 64-bit.  This means not using type "long", and adding
+ * explicit padding so that the 32-bit structure will not be packed more
+ * tightly than the 64-bit structure (which requires 64-bit alignment).
+ */
+
+/*
+ * Property values for snapdir
+ */
+#define        ZFS_SNAPDIR_HIDDEN              0
+#define        ZFS_SNAPDIR_VISIBLE             1
+
+/*
+ * Property values for snapdev
+ */
+#define        ZFS_SNAPDEV_HIDDEN              0
+#define        ZFS_SNAPDEV_VISIBLE             1
+/*
+ * Property values for acltype
+ */
+#define        ZFS_ACLTYPE_OFF                 0
+#define        ZFS_ACLTYPE_POSIXACL            1
+
+/*
+ * Field manipulation macros for the drr_versioninfo field of the
+ * send stream header.
+ */
+
+/*
+ * Header types for zfs send streams.
+ */
+typedef enum drr_headertype {
+       DMU_SUBSTREAM = 0x1,
+       DMU_COMPOUNDSTREAM = 0x2
+} drr_headertype_t;
+
+#define        DMU_GET_STREAM_HDRTYPE(vi)      BF64_GET((vi), 0, 2)
+#define        DMU_SET_STREAM_HDRTYPE(vi, x)   BF64_SET((vi), 0, 2, x)
+
+#define        DMU_GET_FEATUREFLAGS(vi)        BF64_GET((vi), 2, 30)
+#define        DMU_SET_FEATUREFLAGS(vi, x)     BF64_SET((vi), 2, 30, x)
+
+/*
+ * 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)
+/* 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)
+/* flag #18 is reserved for a Delphix feature */
+#define        DMU_BACKUP_FEATURE_LARGE_BLOCKS         (1<<19)
+
+/*
+ * 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)
+
+/* Are all features in the given flag word currently supported? */
+#define        DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK))
+
+/*
+ * The drr_versioninfo field of the dmu_replay_record has the
+ * following layout:
+ *
+ *     64      56      48      40      32      24      16      8       0
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ *     |               reserved        |        feature-flags      |C|S|
+ *     +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * The low order two bits indicate the header type: SUBSTREAM (0x1)
+ * or COMPOUNDSTREAM (0x2).  Using two bits for this is historical:
+ * this field used to be a version number, where the two version types
+ * were 1 and 2.  Using two bits for this allows earlier versions of
+ * the code to be able to recognize send streams that don't use any
+ * of the features indicated by feature flags.
+ */
+
+#define        DMU_BACKUP_MAGIC 0x2F5bacbacULL
+
+#define        DRR_FLAG_CLONE          (1<<0)
+#define        DRR_FLAG_CI_DATA        (1<<1)
+
+/*
+ * flags in the drr_checksumflags field in the DRR_WRITE and
+ * DRR_WRITE_BYREF blocks
+ */
+#define        DRR_CHECKSUM_DEDUP      (1<<0)
+
+#define        DRR_IS_DEDUP_CAPABLE(flags)     ((flags) & DRR_CHECKSUM_DEDUP)
+
+/*
+ * zfs ioctl command structure
+ */
+typedef struct dmu_replay_record {
+       enum {
+               DRR_BEGIN, DRR_OBJECT, DRR_FREEOBJECTS,
+               DRR_WRITE, DRR_FREE, DRR_END, DRR_WRITE_BYREF,
+               DRR_SPILL, DRR_WRITE_EMBEDDED, DRR_NUMTYPES
+       } drr_type;
+       uint32_t drr_payloadlen;
+       union {
+               struct drr_begin {
+                       uint64_t drr_magic;
+                       uint64_t drr_versioninfo; /* was drr_version */
+                       uint64_t drr_creation_time;
+                       dmu_objset_type_t drr_type;
+                       uint32_t drr_flags;
+                       uint64_t drr_toguid;
+                       uint64_t drr_fromguid;
+                       char drr_toname[MAXNAMELEN];
+               } drr_begin;
+               struct drr_end {
+                       zio_cksum_t drr_checksum;
+                       uint64_t drr_toguid;
+               } drr_end;
+               struct drr_object {
+                       uint64_t drr_object;
+                       dmu_object_type_t drr_type;
+                       dmu_object_type_t drr_bonustype;
+                       uint32_t drr_blksz;
+                       uint32_t drr_bonuslen;
+                       uint8_t drr_checksumtype;
+                       uint8_t drr_compress;
+                       uint8_t drr_pad[6];
+                       uint64_t drr_toguid;
+                       /* bonus content follows */
+               } drr_object;
+               struct drr_freeobjects {
+                       uint64_t drr_firstobj;
+                       uint64_t drr_numobjs;
+                       uint64_t drr_toguid;
+               } drr_freeobjects;
+               struct drr_write {
+                       uint64_t drr_object;
+                       dmu_object_type_t drr_type;
+                       uint32_t drr_pad;
+                       uint64_t drr_offset;
+                       uint64_t drr_length;
+                       uint64_t drr_toguid;
+                       uint8_t drr_checksumtype;
+                       uint8_t drr_checksumflags;
+                       uint8_t drr_pad2[6];
+                       ddt_key_t drr_key; /* deduplication key */
+                       /* content follows */
+               } drr_write;
+               struct drr_free {
+                       uint64_t drr_object;
+                       uint64_t drr_offset;
+                       uint64_t drr_length;
+                       uint64_t drr_toguid;
+               } drr_free;
+               struct drr_write_byref {
+                       /* where to put the data */
+                       uint64_t drr_object;
+                       uint64_t drr_offset;
+                       uint64_t drr_length;
+                       uint64_t drr_toguid;
+                       /* where to find the prior copy of the data */
+                       uint64_t drr_refguid;
+                       uint64_t drr_refobject;
+                       uint64_t drr_refoffset;
+                       /* properties of the data */
+                       uint8_t drr_checksumtype;
+                       uint8_t drr_checksumflags;
+                       uint8_t drr_pad2[6];
+                       ddt_key_t drr_key; /* deduplication key */
+               } drr_write_byref;
+               struct drr_spill {
+                       uint64_t drr_object;
+                       uint64_t drr_length;
+                       uint64_t drr_toguid;
+                       uint64_t drr_pad[4]; /* needed for crypto */
+                       /* spill data follows */
+               } drr_spill;
+               struct drr_write_embedded {
+                       uint64_t drr_object;
+                       uint64_t drr_offset;
+                       /* logical length, should equal blocksize */
+                       uint64_t drr_length;
+                       uint64_t drr_toguid;
+                       uint8_t drr_compression;
+                       uint8_t drr_etype;
+                       uint8_t drr_pad[6];
+                       uint32_t drr_lsize; /* uncompressed size of payload */
+                       uint32_t drr_psize; /* compr. (real) size of payload */
+                       /* (possibly compressed) content follows */
+               } drr_write_embedded;
+       } drr_u;
+} dmu_replay_record_t;
+
+/* diff record range types */
+typedef enum diff_type {
+       DDR_NONE = 0x1,
+       DDR_INUSE = 0x2,
+       DDR_FREE = 0x4
+} diff_type_t;
+
+/*
+ * The diff reports back ranges of free or in-use objects.
+ */
+typedef struct dmu_diff_record {
+       uint64_t ddr_type;
+       uint64_t ddr_first;
+       uint64_t ddr_last;
+} dmu_diff_record_t;
+
+typedef struct zinject_record {
+       uint64_t        zi_objset;
+       uint64_t        zi_object;
+       uint64_t        zi_start;
+       uint64_t        zi_end;
+       uint64_t        zi_guid;
+       uint32_t        zi_level;
+       uint32_t        zi_error;
+       uint64_t        zi_type;
+       uint32_t        zi_freq;
+       uint32_t        zi_failfast;
+       char            zi_func[MAXNAMELEN];
+       uint32_t        zi_iotype;
+       int32_t         zi_duration;
+       uint64_t        zi_timer;
+       uint32_t        zi_cmd;
+       uint32_t        zi_pad;
+} zinject_record_t;
+
+#define        ZINJECT_NULL            0x1
+#define        ZINJECT_FLUSH_ARC       0x2
+#define        ZINJECT_UNLOAD_SPA      0x4
+
+#define        ZEVENT_NONE             0x0
+#define        ZEVENT_NONBLOCK         0x1
+#define        ZEVENT_SIZE             1024
+
+#define        ZEVENT_SEEK_START       0
+#define        ZEVENT_SEEK_END         UINT64_MAX
+
+typedef enum zinject_type {
+       ZINJECT_UNINITIALIZED,
+       ZINJECT_DATA_FAULT,
+       ZINJECT_DEVICE_FAULT,
+       ZINJECT_LABEL_FAULT,
+       ZINJECT_IGNORED_WRITES,
+       ZINJECT_PANIC,
+       ZINJECT_DELAY_IO,
+} zinject_type_t;
+
+typedef struct zfs_share {
+       uint64_t        z_exportdata;
+       uint64_t        z_sharedata;
+       uint64_t        z_sharetype;    /* 0 = share, 1 = unshare */
+       uint64_t        z_sharemax;  /* max length of share string */
+} zfs_share_t;
+
+/*
+ * ZFS file systems may behave the usual, POSIX-compliant way, where
+ * name lookups are case-sensitive.  They may also be set up so that
+ * all the name lookups are case-insensitive, or so that only some
+ * lookups, the ones that set an FIGNORECASE flag, are case-insensitive.
+ */
+typedef enum zfs_case {
+       ZFS_CASE_SENSITIVE,
+       ZFS_CASE_INSENSITIVE,
+       ZFS_CASE_MIXED
+} zfs_case_t;
+
+typedef struct zfs_cmd {
+       char            zc_name[MAXPATHLEN];    /* name of pool or dataset */
+       uint64_t        zc_nvlist_src;          /* really (char *) */
+       uint64_t        zc_nvlist_src_size;
+       uint64_t        zc_nvlist_dst;          /* really (char *) */
+       uint64_t        zc_nvlist_dst_size;
+       boolean_t       zc_nvlist_dst_filled;   /* put an nvlist in dst? */
+       int             zc_pad2;
+
+       /*
+        * The following members are for legacy ioctls which haven't been
+        * converted to the new method.
+        */
+       uint64_t        zc_history;             /* really (char *) */
+       char            zc_value[MAXPATHLEN * 2];
+       char            zc_string[MAXNAMELEN];
+       uint64_t        zc_guid;
+       uint64_t        zc_nvlist_conf;         /* really (char *) */
+       uint64_t        zc_nvlist_conf_size;
+       uint64_t        zc_cookie;
+       uint64_t        zc_objset_type;
+       uint64_t        zc_perm_action;
+       uint64_t        zc_history_len;
+       uint64_t        zc_history_offset;
+       uint64_t        zc_obj;
+       uint64_t        zc_iflags;              /* internal to zfs(7fs) */
+       zfs_share_t     zc_share;
+       dmu_objset_stats_t zc_objset_stats;
+       struct drr_begin zc_begin_record;
+       zinject_record_t zc_inject_record;
+       uint32_t        zc_defer_destroy;
+       uint32_t        zc_flags;
+       uint64_t        zc_action_handle;
+       int             zc_cleanup_fd;
+       uint8_t         zc_simple;
+       uint8_t         zc_pad[3];              /* alignment */
+       uint64_t        zc_sendobj;
+       uint64_t        zc_fromobj;
+       uint64_t        zc_createtxg;
+       zfs_stat_t      zc_stat;
+} zfs_cmd_t;
+
+typedef struct zfs_useracct {
+       char zu_domain[256];
+       uid_t zu_rid;
+       uint32_t zu_pad;
+       uint64_t zu_space;
+} zfs_useracct_t;
+
+#define        ZFSDEV_MAX_MINOR        (1 << 16)
+#define        ZFS_MIN_MINOR   (ZFSDEV_MAX_MINOR + 1)
+
+#define        ZPOOL_EXPORT_AFTER_SPLIT 0x1
+
+#ifdef _KERNEL
+
+typedef struct zfs_creat {
+       nvlist_t        *zct_zplprops;
+       nvlist_t        *zct_props;
+} zfs_creat_t;
+
+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 zfs_unmount_snap(const char *);
+extern void zfs_destroy_unmount_origin(const char *);
+
+extern boolean_t dataset_name_hidden(const char *name);
+
+enum zfsdev_state_type {
+       ZST_ONEXIT,
+       ZST_ZEVENT,
+       ZST_ALL,
+};
+
+/*
+ * The zfsdev_state_t structure is managed as a singly-linked list
+ * from which items are never deleted.  This allows for lock-free
+ * reading of the list so long as assignments to the zs_next and
+ * reads from zs_minor are performed atomically.  Empty items are
+ * indicated by storing -1 into zs_minor.
+ */
+typedef struct zfsdev_state {
+       struct zfsdev_state     *zs_next;       /* next zfsdev_state_t link */
+       struct file             *zs_file;       /* associated file struct */
+       minor_t                 zs_minor;       /* made up minor number */
+       void                    *zs_onexit;     /* onexit data */
+       void                    *zs_zevent;     /* zevent data */
+} zfsdev_state_t;
+
+extern void *zfsdev_get_state(minor_t minor, enum zfsdev_state_type which);
+extern int zfsdev_getminor(struct file *filp, minor_t *minorp);
+extern minor_t zfsdev_minor_alloc(void);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_IOCTL_H */
diff --git a/zfs/include/sys/zfs_onexit.h b/zfs/include/sys/zfs_onexit.h
new file mode 100644 (file)
index 0000000..4982bd4
--- /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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_ZFS_ONEXIT_H
+#define        _SYS_ZFS_ONEXIT_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+typedef struct zfs_onexit {
+       kmutex_t        zo_lock;
+       list_t          zo_actions;
+} zfs_onexit_t;
+
+typedef struct zfs_onexit_action_node {
+       list_node_t     za_link;
+       void            (*za_func)(void *);
+       void            *za_data;
+} zfs_onexit_action_node_t;
+
+extern void zfs_onexit_init(zfs_onexit_t **zo);
+extern void zfs_onexit_destroy(zfs_onexit_t *zo);
+
+#endif
+
+extern int zfs_onexit_fd_hold(int fd, minor_t *minorp);
+extern void zfs_onexit_fd_rele(int fd);
+extern int zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
+    uint64_t *action_handle);
+extern int zfs_onexit_del_cb(minor_t minor, uint64_t action_handle,
+    boolean_t fire);
+extern int zfs_onexit_cb_data(minor_t minor, uint64_t action_handle,
+    void **data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_ONEXIT_H */
diff --git a/zfs/include/sys/zfs_rlock.h b/zfs/include/sys/zfs_rlock.h
new file mode 100644 (file)
index 0000000..5322f3b
--- /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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_FS_ZFS_RLOCK_H
+#define        _SYS_FS_ZFS_RLOCK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+#include <sys/list.h>
+#include <sys/avl.h>
+#include <sys/condvar.h>
+
+typedef enum {
+       RL_READER,
+       RL_WRITER,
+       RL_APPEND
+} rl_type_t;
+
+typedef struct zfs_rlock {
+       kmutex_t zr_mutex;      /* protects changes to zr_avl */
+       avl_tree_t zr_avl;      /* avl tree of range locks */
+       uint64_t *zr_size;      /* points to znode->z_size */
+       uint_t *zr_blksz;       /* points to znode->z_blksz */
+       uint64_t *zr_max_blksz; /* points to zsb->z_max_blksz */
+} zfs_rlock_t;
+
+typedef struct rl {
+       zfs_rlock_t *r_zrl;
+       avl_node_t r_node;      /* avl node link */
+       uint64_t r_off;         /* file range offset */
+       uint64_t r_len;         /* file range length */
+       uint_t r_cnt;           /* range reference count in tree */
+       rl_type_t r_type;       /* range type */
+       kcondvar_t r_wr_cv;     /* cv for waiting writers */
+       kcondvar_t r_rd_cv;     /* cv for waiting readers */
+       uint8_t r_proxy;        /* acting for original range */
+       uint8_t r_write_wanted; /* writer wants to lock this range */
+       uint8_t r_read_wanted;  /* reader wants to lock this range */
+       list_node_t rl_node;    /* used for deferred release */
+} rl_t;
+
+/*
+ * Lock a range (offset, length) as either shared (RL_READER)
+ * or exclusive (RL_WRITER or RL_APPEND).  RL_APPEND is a special type that
+ * is converted to RL_WRITER that specified to lock from the start of the
+ * end of file.  Returns the range lock structure.
+ */
+rl_t *zfs_range_lock(zfs_rlock_t *zrl, uint64_t off, uint64_t len,
+    rl_type_t type);
+
+/* Unlock range and destroy range lock structure. */
+void zfs_range_unlock(rl_t *rl);
+
+/*
+ * Reduce range locked as RW_WRITER from whole file to specified range.
+ * Asserts the whole file was previously locked.
+ */
+void zfs_range_reduce(rl_t *rl, uint64_t off, uint64_t len);
+
+/*
+ * AVL comparison function used to order range locks
+ * Locks are ordered on the start offset of the range.
+ */
+int zfs_range_compare(const void *arg1, const void *arg2);
+
+static inline void
+zfs_rlock_init(zfs_rlock_t *zrl)
+{
+       mutex_init(&zrl->zr_mutex, NULL, MUTEX_DEFAULT, NULL);
+       avl_create(&zrl->zr_avl, zfs_range_compare,
+           sizeof (rl_t), offsetof(rl_t, r_node));
+       zrl->zr_size = NULL;
+       zrl->zr_blksz = NULL;
+       zrl->zr_max_blksz = NULL;
+}
+
+static inline void
+zfs_rlock_destroy(zfs_rlock_t *zrl)
+{
+       avl_destroy(&zrl->zr_avl);
+       mutex_destroy(&zrl->zr_mutex);
+}
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_RLOCK_H */
diff --git a/zfs/include/sys/zfs_sa.h b/zfs/include/sys/zfs_sa.h
new file mode 100644 (file)
index 0000000..06c4d58
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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        _SYS_ZFS_SA_H
+#define        _SYS_ZFS_SA_H
+
+#ifdef _KERNEL
+#include <sys/types32.h>
+#include <sys/list.h>
+#include <sys/dmu.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_znode.h>
+#include <sys/sa.h>
+#include <sys/zil.h>
+
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is the list of known attributes
+ * to the ZPL.  The values of the actual
+ * attributes are not defined by the order
+ * the enums.  It is controlled by the attribute
+ * registration mechanism.  Two different file system
+ * could have different numeric values for the same
+ * attributes.  this list is only used for dereferencing
+ * into the table that will hold the actual numeric value.
+ */
+typedef enum zpl_attr {
+       ZPL_ATIME,
+       ZPL_MTIME,
+       ZPL_CTIME,
+       ZPL_CRTIME,
+       ZPL_GEN,
+       ZPL_MODE,
+       ZPL_SIZE,
+       ZPL_PARENT,
+       ZPL_LINKS,
+       ZPL_XATTR,
+       ZPL_RDEV,
+       ZPL_FLAGS,
+       ZPL_UID,
+       ZPL_GID,
+       ZPL_PAD,
+       ZPL_ZNODE_ACL,
+       ZPL_DACL_COUNT,
+       ZPL_SYMLINK,
+       ZPL_SCANSTAMP,
+       ZPL_DACL_ACES,
+       ZPL_DXATTR,
+       ZPL_END
+} zpl_attr_t;
+
+#define        ZFS_OLD_ZNODE_PHYS_SIZE 0x108
+#define        ZFS_SA_BASE_ATTR_SIZE   (ZFS_OLD_ZNODE_PHYS_SIZE - \
+    sizeof (zfs_acl_phys_t))
+
+#define        SA_MODE_OFFSET          0
+#define        SA_SIZE_OFFSET          8
+#define        SA_GEN_OFFSET           16
+#define        SA_UID_OFFSET           24
+#define        SA_GID_OFFSET           32
+#define        SA_PARENT_OFFSET        40
+
+extern sa_attr_reg_t zfs_attr_table[ZPL_END + 1];
+extern sa_attr_reg_t zfs_legacy_attr_table[ZPL_END + 1];
+
+/*
+ * This is a deprecated data structure that only exists for
+ * dealing with file systems create prior to ZPL version 5.
+ */
+typedef struct znode_phys {
+       uint64_t zp_atime[2];           /*  0 - last file access time */
+       uint64_t zp_mtime[2];           /* 16 - last file modification time */
+       uint64_t zp_ctime[2];           /* 32 - last file change time */
+       uint64_t zp_crtime[2];          /* 48 - creation time */
+       uint64_t zp_gen;                /* 64 - generation (txg of creation) */
+       uint64_t zp_mode;               /* 72 - file mode bits */
+       uint64_t zp_size;               /* 80 - size of file */
+       uint64_t zp_parent;             /* 88 - directory parent (`..') */
+       uint64_t zp_links;              /* 96 - number of links to file */
+       uint64_t zp_xattr;              /* 104 - DMU object for xattrs */
+       uint64_t zp_rdev;               /* 112 - dev_t for VBLK & VCHR files */
+       uint64_t zp_flags;              /* 120 - persistent flags */
+       uint64_t zp_uid;                /* 128 - file owner */
+       uint64_t zp_gid;                /* 136 - owning group */
+       uint64_t zp_zap;                /* 144 - extra attributes */
+       uint64_t zp_pad[3];             /* 152 - future */
+       zfs_acl_phys_t zp_acl;          /* 176 - 263 ACL */
+       /*
+        * Data may pad out any remaining bytes in the znode buffer, eg:
+        *
+        * |<---------------------- dnode_phys (512) ------------------------>|
+        * |<-- dnode (192) --->|<----------- "bonus" buffer (320) ---------->|
+        *                      |<---- znode (264) ---->|<---- data (56) ---->|
+        *
+        * At present, we use this space for the following:
+        *  - symbolic links
+        *  - 32-byte anti-virus scanstamp (regular files only)
+        */
+} znode_phys_t;
+
+#ifdef _KERNEL
+
+#define        DXATTR_MAX_ENTRY_SIZE   (32768)
+#define        DXATTR_MAX_SA_SIZE      (SPA_OLD_MAXBLOCKSIZE >> 1)
+
+int zfs_sa_readlink(struct znode *, uio_t *);
+void zfs_sa_symlink(struct znode *, char *link, int len, dmu_tx_t *);
+void zfs_sa_get_scanstamp(struct znode *, xvattr_t *);
+void zfs_sa_set_scanstamp(struct znode *, xvattr_t *, dmu_tx_t *);
+int zfs_sa_get_xattr(struct znode *);
+int zfs_sa_set_xattr(struct znode *);
+void zfs_sa_upgrade(struct sa_handle  *, dmu_tx_t *);
+void zfs_sa_upgrade_txholds(dmu_tx_t *, struct znode *);
+void zfs_sa_init(void);
+void zfs_sa_fini(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_SA_H */
diff --git a/zfs/include/sys/zfs_stat.h b/zfs/include/sys/zfs_stat.h
new file mode 100644 (file)
index 0000000..465aefa
--- /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) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_FS_ZFS_STAT_H
+#define        _SYS_FS_ZFS_STAT_H
+
+#ifdef _KERNEL
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#include <sys/dmu.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A limited number of zpl level stats are retrievable
+ * with an ioctl.  zfs diff is the current consumer.
+ */
+typedef struct zfs_stat {
+       uint64_t        zs_gen;
+       uint64_t        zs_mode;
+       uint64_t        zs_links;
+       uint64_t        zs_ctime[2];
+} zfs_stat_t;
+
+extern int zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
+    char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_STAT_H */
diff --git a/zfs/include/sys/zfs_vfsops.h b/zfs/include/sys/zfs_vfsops.h
new file mode 100644 (file)
index 0000000..efaefda
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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        _SYS_FS_ZFS_VFSOPS_H
+#define        _SYS_FS_ZFS_VFSOPS_H
+
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#include <sys/list.h>
+#include <sys/vfs.h>
+#include <sys/zil.h>
+#include <sys/sa.h>
+#include <sys/rrwlock.h>
+#include <sys/zfs_ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct zfs_sb;
+struct znode;
+
+typedef struct zfs_mntopts {
+       char            *z_osname;      /* Objset name */
+       char            *z_mntpoint;    /* Primary mount point */
+       uint64_t        z_xattr;
+       boolean_t       z_readonly;
+       boolean_t       z_do_readonly;
+       boolean_t       z_setuid;
+       boolean_t       z_do_setuid;
+       boolean_t       z_exec;
+       boolean_t       z_do_exec;
+       boolean_t       z_devices;
+       boolean_t       z_do_devices;
+       boolean_t       z_do_xattr;
+       boolean_t       z_atime;
+       boolean_t       z_do_atime;
+       boolean_t       z_relatime;
+       boolean_t       z_do_relatime;
+       boolean_t       z_nbmand;
+       boolean_t       z_do_nbmand;
+} zfs_mntopts_t;
+
+typedef struct zfs_sb {
+       struct super_block *z_sb;       /* generic super_block */
+       struct backing_dev_info z_bdi;  /* generic backing dev info */
+       struct zfs_sb   *z_parent;      /* parent fs */
+       objset_t        *z_os;          /* objset reference */
+       zfs_mntopts_t   *z_mntopts;     /* passed mount options */
+       uint64_t        z_flags;        /* super_block flags */
+       uint64_t        z_root;         /* id of root znode */
+       uint64_t        z_unlinkedobj;  /* id of unlinked zapobj */
+       uint64_t        z_max_blksz;    /* maximum block size for files */
+       uint64_t        z_fuid_obj;     /* fuid table object number */
+       uint64_t        z_fuid_size;    /* fuid table size */
+       avl_tree_t      z_fuid_idx;     /* fuid tree keyed by index */
+       avl_tree_t      z_fuid_domain;  /* fuid tree keyed by domain */
+       krwlock_t       z_fuid_lock;    /* fuid lock */
+       boolean_t       z_fuid_loaded;  /* fuid tables are loaded */
+       boolean_t       z_fuid_dirty;   /* need to sync fuid table ? */
+       struct zfs_fuid_info    *z_fuid_replay; /* fuid info for replay */
+       zilog_t         *z_log;         /* intent log pointer */
+       uint_t          z_acl_inherit;  /* acl inheritance behavior */
+       uint_t          z_acl_type;     /* type of ACL usable on this FS */
+       zfs_case_t      z_case;         /* case-sense */
+       boolean_t       z_utf8;         /* utf8-only */
+       int             z_norm;         /* normalization flags */
+       boolean_t       z_atime;        /* enable atimes mount option */
+       boolean_t       z_relatime;     /* enable relatime mount option */
+       boolean_t       z_unmounted;    /* unmounted */
+       rrmlock_t       z_teardown_lock;
+       krwlock_t       z_teardown_inactive_lock;
+       list_t          z_all_znodes;   /* all znodes in the fs */
+       uint64_t        z_nr_znodes;    /* number of znodes in the fs */
+       unsigned long   z_rollback_time; /* last online rollback time */
+       unsigned long   z_snap_defer_time; /* last snapshot unmount deferal */
+       kmutex_t        z_znodes_lock;  /* lock for z_all_znodes */
+       arc_prune_t     *z_arc_prune;   /* called by ARC to prune caches */
+       struct inode    *z_ctldir;      /* .zfs directory inode */
+       boolean_t       z_show_ctldir;  /* expose .zfs in the root dir */
+       boolean_t       z_issnap;       /* true if this is a snapshot */
+       boolean_t       z_vscan;        /* virus scan on/off */
+       boolean_t       z_use_fuids;    /* version allows fuids */
+       boolean_t       z_replay;       /* set during ZIL replay */
+       boolean_t       z_use_sa;       /* version allow system attributes */
+       boolean_t       z_xattr_sa;     /* allow xattrs to be stores as SA */
+       uint64_t        z_version;      /* ZPL version */
+       uint64_t        z_shares_dir;   /* hidden shares dir */
+       kmutex_t        z_lock;
+       uint64_t        z_userquota_obj;
+       uint64_t        z_groupquota_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 */
+       avl_tree_t      *z_hold_trees;  /* znode hold trees */
+       kmutex_t        *z_hold_locks;  /* znode hold locks */
+} zfs_sb_t;
+
+#define        ZFS_SUPER_MAGIC 0x2fc12fc1
+
+#define        ZSB_XATTR       0x0001          /* Enable user xattrs */
+
+/*
+ * Allow a maximum number of links.  While ZFS does not internally limit
+ * this the inode->i_nlink member is defined as an unsigned int.  To be
+ * safe we use 2^31-1 as the limit.
+ */
+#define        ZFS_LINK_MAX            ((1U << 31) - 1U)
+
+/*
+ * Normal filesystems (those not under .zfs/snapshot) have a total
+ * file ID size limited to 12 bytes (including the length field) due to
+ * NFSv2 protocol's limitation of 32 bytes for a filehandle.  For historical
+ * reasons, this same limit is being imposed by the Solaris NFSv3 implementation
+ * (although the NFSv3 protocol actually permits a maximum of 64 bytes).  It
+ * is not possible to expand beyond 12 bytes without abandoning support
+ * of NFSv2.
+ *
+ * For normal filesystems, we partition up the available space as follows:
+ *     2 bytes         fid length (required)
+ *     6 bytes         object number (48 bits)
+ *     4 bytes         generation number (32 bits)
+ *
+ * We reserve only 48 bits for the object number, as this is the limit
+ * currently defined and imposed by the DMU.
+ */
+typedef struct zfid_short {
+       uint16_t        zf_len;
+       uint8_t         zf_object[6];           /* obj[i] = obj >> (8 * i) */
+       uint8_t         zf_gen[4];              /* gen[i] = gen >> (8 * i) */
+} zfid_short_t;
+
+/*
+ * Filesystems under .zfs/snapshot have a total file ID size of 22 bytes
+ * (including the length field).  This makes files under .zfs/snapshot
+ * accessible by NFSv3 and NFSv4, but not NFSv2.
+ *
+ * For files under .zfs/snapshot, we partition up the available space
+ * as follows:
+ *     2 bytes         fid length (required)
+ *     6 bytes         object number (48 bits)
+ *     4 bytes         generation number (32 bits)
+ *     6 bytes         objset id (48 bits)
+ *     4 bytes         currently just zero (32 bits)
+ *
+ * We reserve only 48 bits for the object number and objset id, as these are
+ * the limits currently defined and imposed by the DMU.
+ */
+typedef struct zfid_long {
+       zfid_short_t    z_fid;
+       uint8_t         zf_setid[6];            /* obj[i] = obj >> (8 * i) */
+       uint8_t         zf_setgen[4];           /* gen[i] = gen >> (8 * i) */
+} zfid_long_t;
+
+#define        SHORT_FID_LEN   (sizeof (zfid_short_t) - sizeof (uint16_t))
+#define        LONG_FID_LEN    (sizeof (zfid_long_t) - sizeof (uint16_t))
+
+extern uint_t zfs_fsyncer_key;
+
+extern int zfs_suspend_fs(zfs_sb_t *zsb);
+extern int zfs_resume_fs(zfs_sb_t *zsb, const char *osname);
+extern int zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
+    const char *domain, uint64_t rid, uint64_t *valuep);
+extern int zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
+    uint64_t *cookiep, void *vbuf, uint64_t *bufsizep);
+extern int zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type,
+    const char *domain, uint64_t rid, uint64_t quota);
+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 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);
+extern zfs_mntopts_t *zfs_mntopts_alloc(void);
+extern void zfs_mntopts_free(zfs_mntopts_t *zmo);
+extern int zfs_sb_create(const char *name, zfs_mntopts_t *zmo,
+    zfs_sb_t **zsbp);
+extern int zfs_sb_setup(zfs_sb_t *zsb, boolean_t mounting);
+extern void zfs_sb_free(zfs_sb_t *zsb);
+extern int zfs_sb_prune(struct super_block *sb, unsigned long nr_to_scan,
+    int *objects);
+extern int zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting);
+extern int zfs_check_global_label(const char *dsname, const char *hexsl);
+extern boolean_t zfs_is_readonly(zfs_sb_t *zsb);
+
+extern int zfs_register_callbacks(zfs_sb_t *zsb);
+extern void zfs_unregister_callbacks(zfs_sb_t *zsb);
+extern int zfs_domount(struct super_block *sb, zfs_mntopts_t *zmo, int silent);
+extern void zfs_preumount(struct super_block *sb);
+extern int zfs_umount(struct super_block *sb);
+extern int zfs_remount(struct super_block *sb, int *flags, zfs_mntopts_t *zmo);
+extern int zfs_root(zfs_sb_t *zsb, struct inode **ipp);
+extern int zfs_statvfs(struct dentry *dentry, struct kstatfs *statp);
+extern int zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_VFSOPS_H */
diff --git a/zfs/include/sys/zfs_vnops.h b/zfs/include/sys/zfs_vnops.h
new file mode 100644 (file)
index 0000000..c331035
--- /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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_FS_ZFS_VNOPS_H
+#define        _SYS_FS_ZFS_VNOPS_H
+
+#include <sys/vnode.h>
+#include <sys/xvattr.h>
+#include <sys/uio.h>
+#include <sys/cred.h>
+#include <sys/fcntl.h>
+#include <sys/pathname.h>
+#include <sys/zpl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int zfs_open(struct inode *ip, int mode, int flag, cred_t *cr);
+extern int zfs_close(struct inode *ip, int flag, cred_t *cr);
+extern int zfs_holey(struct inode *ip, int cmd, loff_t *off);
+extern int zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr);
+extern int zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr);
+extern int zfs_access(struct inode *ip, int mode, int flag, cred_t *cr);
+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_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,
+    cred_t *cr, int flags);
+extern int zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr);
+extern int zfs_fsync(struct inode *ip, int syncflag, cred_t *cr);
+extern int zfs_getattr(struct inode *ip, vattr_t *vap, int flag, cred_t *cr);
+extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp);
+extern int zfs_setattr(struct inode *ip, vattr_t *vap, int flag, cred_t *cr);
+extern int zfs_rename(struct inode *sdip, char *snm, struct inode *tdip,
+    char *tnm, cred_t *cr, int flags);
+extern int zfs_symlink(struct inode *dip, char *name, vattr_t *vap,
+    char *link, struct inode **ipp, cred_t *cr, int flags);
+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);
+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);
+extern int zfs_fid(struct inode *ip, fid_t *fidp);
+extern int zfs_getsecattr(struct inode *ip, vsecattr_t *vsecp, int flag,
+    cred_t *cr);
+extern int zfs_setsecattr(struct inode *ip, vsecattr_t *vsecp, int flag,
+    cred_t *cr);
+extern int zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages);
+extern int zfs_putpage(struct inode *ip, struct page *pp,
+    struct writeback_control *wbc);
+extern int zfs_dirty_inode(struct inode *ip, int flags);
+extern int zfs_map(struct inode *ip, offset_t off, caddr_t *addrp,
+    size_t len, unsigned long vm_flags);
+extern void zfs_iput_async(struct inode *ip);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_VNOPS_H */
diff --git a/zfs/include/sys/zfs_znode.h b/zfs/include/sys/zfs_znode.h
new file mode 100644 (file)
index 0000000..0b8bd24
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#ifndef        _SYS_FS_ZFS_ZNODE_H
+#define        _SYS_FS_ZFS_ZNODE_H
+
+#ifdef _KERNEL
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#include <sys/attr.h>
+#include <sys/list.h>
+#include <sys/dmu.h>
+#include <sys/sa.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/rrwlock.h>
+#include <sys/zfs_sa.h>
+#include <sys/zfs_stat.h>
+#include <sys/zfs_rlock.h>
+#endif
+#include <sys/zfs_acl.h>
+#include <sys/zil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Additional file level attributes, that are stored
+ * in the upper half of zp_flags
+ */
+#define        ZFS_READONLY            0x0000000100000000ull
+#define        ZFS_HIDDEN              0x0000000200000000ull
+#define        ZFS_SYSTEM              0x0000000400000000ull
+#define        ZFS_ARCHIVE             0x0000000800000000ull
+#define        ZFS_IMMUTABLE           0x0000001000000000ull
+#define        ZFS_NOUNLINK            0x0000002000000000ull
+#define        ZFS_APPENDONLY          0x0000004000000000ull
+#define        ZFS_NODUMP              0x0000008000000000ull
+#define        ZFS_OPAQUE              0x0000010000000000ull
+#define        ZFS_AV_QUARANTINED      0x0000020000000000ull
+#define        ZFS_AV_MODIFIED         0x0000040000000000ull
+#define        ZFS_REPARSE             0x0000080000000000ull
+#define        ZFS_OFFLINE             0x0000100000000000ull
+#define        ZFS_SPARSE              0x0000200000000000ull
+
+#define        ZFS_ATTR_SET(zp, attr, value, pflags, tx) \
+{ \
+       if (value) \
+               pflags |= attr; \
+       else \
+               pflags &= ~attr; \
+       VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_FLAGS(ZTOZSB(zp)), \
+           &pflags, sizeof (pflags), tx)); \
+}
+
+/*
+ * Define special zfs pflags
+ */
+#define        ZFS_XATTR               0x1             /* is an extended attribute */
+#define        ZFS_INHERIT_ACE         0x2             /* ace has inheritable ACEs */
+#define        ZFS_ACL_TRIVIAL         0x4             /* files ACL is trivial */
+#define        ZFS_ACL_OBJ_ACE         0x8             /* ACL has CMPLX Object ACE */
+#define        ZFS_ACL_PROTECTED       0x10            /* ACL protected */
+#define        ZFS_ACL_DEFAULTED       0x20            /* ACL should be defaulted */
+#define        ZFS_ACL_AUTO_INHERIT    0x40            /* ACL should be inherited */
+#define        ZFS_BONUS_SCANSTAMP     0x80            /* Scanstamp in bonus area */
+#define        ZFS_NO_EXECS_DENIED     0x100           /* exec was given to everyone */
+
+#define        SA_ZPL_ATIME(z)         z->z_attr_table[ZPL_ATIME]
+#define        SA_ZPL_MTIME(z)         z->z_attr_table[ZPL_MTIME]
+#define        SA_ZPL_CTIME(z)         z->z_attr_table[ZPL_CTIME]
+#define        SA_ZPL_CRTIME(z)        z->z_attr_table[ZPL_CRTIME]
+#define        SA_ZPL_GEN(z)           z->z_attr_table[ZPL_GEN]
+#define        SA_ZPL_DACL_ACES(z)     z->z_attr_table[ZPL_DACL_ACES]
+#define        SA_ZPL_XATTR(z)         z->z_attr_table[ZPL_XATTR]
+#define        SA_ZPL_SYMLINK(z)       z->z_attr_table[ZPL_SYMLINK]
+#define        SA_ZPL_RDEV(z)          z->z_attr_table[ZPL_RDEV]
+#define        SA_ZPL_SCANSTAMP(z)     z->z_attr_table[ZPL_SCANSTAMP]
+#define        SA_ZPL_UID(z)           z->z_attr_table[ZPL_UID]
+#define        SA_ZPL_GID(z)           z->z_attr_table[ZPL_GID]
+#define        SA_ZPL_PARENT(z)        z->z_attr_table[ZPL_PARENT]
+#define        SA_ZPL_LINKS(z)         z->z_attr_table[ZPL_LINKS]
+#define        SA_ZPL_MODE(z)          z->z_attr_table[ZPL_MODE]
+#define        SA_ZPL_DACL_COUNT(z)    z->z_attr_table[ZPL_DACL_COUNT]
+#define        SA_ZPL_FLAGS(z)         z->z_attr_table[ZPL_FLAGS]
+#define        SA_ZPL_SIZE(z)          z->z_attr_table[ZPL_SIZE]
+#define        SA_ZPL_ZNODE_ACL(z)     z->z_attr_table[ZPL_ZNODE_ACL]
+#define        SA_ZPL_DXATTR(z)        z->z_attr_table[ZPL_DXATTR]
+#define        SA_ZPL_PAD(z)           z->z_attr_table[ZPL_PAD]
+
+/*
+ * Is ID ephemeral?
+ */
+#define        IS_EPHEMERAL(x)         (x > MAXUID)
+
+/*
+ * Should we use FUIDs?
+ */
+#define        USE_FUIDS(version, os)  (version >= ZPL_VERSION_FUID && \
+    spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
+#define        USE_SA(version, os) (version >= ZPL_VERSION_SA && \
+    spa_version(dmu_objset_spa(os)) >= SPA_VERSION_SA)
+
+#define        MASTER_NODE_OBJ 1
+
+/*
+ * Special attributes for master node.
+ * "userquota@" and "groupquota@" are also valid (from
+ * zfs_userquota_prop_prefixes[]).
+ */
+#define        ZFS_FSID                "FSID"
+#define        ZFS_UNLINKED_SET        "DELETE_QUEUE"
+#define        ZFS_ROOT_OBJ            "ROOT"
+#define        ZPL_VERSION_STR         "VERSION"
+#define        ZFS_FUID_TABLES         "FUID"
+#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
+ * defined correctly as part of the /usr/include/dirent.h header file.
+ */
+#ifndef IFTODT
+#define        IFTODT(mode) (((mode) & S_IFMT) >> 12)
+#endif
+
+/*
+ * The directory entry has the type (currently unused on Solaris) in the
+ * top 4 bits, and the object number in the low 48 bits.  The "middle"
+ * 12 bits are unused.
+ */
+#define        ZFS_DIRENT_TYPE(de) BF64_GET(de, 60, 4)
+#define        ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48)
+
+/*
+ * Directory entry locks control access to directory entries.
+ * They are used to protect creates, deletes, and renames.
+ * Each directory znode has a mutex and a list of locked names.
+ */
+#ifdef _KERNEL
+typedef struct zfs_dirlock {
+       char            *dl_name;       /* directory entry being locked */
+       uint32_t        dl_sharecnt;    /* 0 if exclusive, > 0 if shared */
+       uint8_t         dl_namelock;    /* 1 if z_name_lock is NOT held */
+       uint16_t        dl_namesize;    /* set if dl_name was allocated */
+       kcondvar_t      dl_cv;          /* wait for entry to be unlocked */
+       struct znode    *dl_dzp;        /* directory znode */
+       struct zfs_dirlock *dl_next;    /* next in z_dirlocks list */
+} zfs_dirlock_t;
+
+typedef struct znode {
+       uint64_t        z_id;           /* object ID for this znode */
+       kmutex_t        z_lock;         /* znode modification lock */
+       krwlock_t       z_parent_lock;  /* parent lock for directories */
+       krwlock_t       z_name_lock;    /* "master" lock for dirent locks */
+       zfs_dirlock_t   *z_dirlocks;    /* directory entry lock list */
+       zfs_rlock_t     z_range_lock;   /* file range lock */
+       uint8_t         z_unlinked;     /* file has been unlinked */
+       uint8_t         z_atime_dirty;  /* atime needs to be synced */
+       uint8_t         z_zn_prefetch;  /* Prefetch znodes? */
+       uint8_t         z_moved;        /* Has this znode been moved? */
+       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_size;         /* file size (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 */
+       zfs_acl_t       *z_acl_cached;  /* cached acl */
+       krwlock_t       z_xattr_lock;   /* xattr data lock */
+       nvlist_t        *z_xattr_cached; /* cached xattrs */
+       list_node_t     z_link_node;    /* all znodes in fs link */
+       sa_handle_t     *z_sa_hdl;      /* handle to sa data */
+       boolean_t       z_is_sa;        /* are we native sa? */
+       boolean_t       z_is_mapped;    /* are we mmap'ed */
+       boolean_t       z_is_ctldir;    /* are we .zfs entry */
+       boolean_t       z_is_stale;     /* are we stale due to rollback? */
+       struct inode    z_inode;        /* generic vfs inode */
+} znode_t;
+
+typedef struct znode_hold {
+       uint64_t        zh_obj;         /* object id */
+       kmutex_t        zh_lock;        /* lock serializing object access */
+       avl_node_t      zh_node;        /* avl tree linkage */
+       refcount_t      zh_refcount;    /* active consumer reference count */
+} znode_hold_t;
+
+/*
+ * Range locking rules
+ * --------------------
+ * 1. When truncating a file (zfs_create, zfs_setattr, zfs_space) the whole
+ *    file range needs to be locked as RL_WRITER. Only then can the pages be
+ *    freed etc and zp_size reset. zp_size must be set within range lock.
+ * 2. For writes and punching holes (zfs_write & zfs_space) just the range
+ *    being written or freed needs to be locked as RL_WRITER.
+ *    Multiple writes at the end of the file must coordinate zp_size updates
+ *    to ensure data isn't lost. A compare and swap loop is currently used
+ *    to ensure the file size is at least the offset last written.
+ * 3. For reads (zfs_read, zfs_get_data & zfs_putapage) just the range being
+ *    read needs to be locked as RL_READER. A check against zp_size can then
+ *    be made for reading beyond end of file.
+ */
+
+/*
+ * Convert between znode pointers and inode pointers
+ */
+#define        ZTOI(znode)     (&((znode)->z_inode))
+#define        ITOZ(inode)     (container_of((inode), znode_t, z_inode))
+#define        ZTOZSB(znode)   ((zfs_sb_t *)(ZTOI(znode)->i_sb->s_fs_info))
+#define        ITOZSB(inode)   ((zfs_sb_t *)((inode)->i_sb->s_fs_info))
+
+#define        S_ISDEV(mode)   (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode))
+
+/* Called on entry to each ZFS vnode and vfs operation  */
+#define        ZFS_ENTER(zsb) \
+       { \
+               rrm_enter_read(&(zsb)->z_teardown_lock, FTAG); \
+               if ((zsb)->z_unmounted) { \
+                       ZFS_EXIT(zsb); \
+                       return (EIO); \
+               } \
+       }
+
+/* Must be called before exiting the vop */
+#define        ZFS_EXIT(zsb) \
+       { \
+               rrm_exit(&(zsb)->z_teardown_lock, FTAG); \
+       }
+
+/* Verifies the znode is valid */
+#define        ZFS_VERIFY_ZP(zp) \
+       if ((zp)->z_sa_hdl == NULL) { \
+               ZFS_EXIT(ZTOZSB(zp)); \
+               return (EIO); \
+       }
+
+/*
+ * Macros for dealing with dmu_buf_hold
+ */
+#define        ZFS_OBJ_MTX_SZ          64
+#define        ZFS_OBJ_MTX_MAX         (1024 * 1024)
+#define        ZFS_OBJ_HASH(zsb, obj)  ((obj) & ((zsb->z_hold_size) - 1))
+
+extern unsigned int zfs_object_mutex_size;
+
+/* Encode ZFS stored time values from a struct timespec */
+#define        ZFS_TIME_ENCODE(tp, stmp)               \
+{                                              \
+       (stmp)[0] = (uint64_t)(tp)->tv_sec;     \
+       (stmp)[1] = (uint64_t)(tp)->tv_nsec;    \
+}
+
+/* Decode ZFS stored time values to a struct timespec */
+#define        ZFS_TIME_DECODE(tp, stmp)               \
+{                                              \
+       (tp)->tv_sec = (time_t)(stmp)[0];               \
+       (tp)->tv_nsec = (long)(stmp)[1];                \
+}
+
+/*
+ * Timestamp defines
+ */
+#define        ACCESSED                (ATTR_ATIME)
+#define        STATE_CHANGED           (ATTR_CTIME)
+#define        CONTENT_MODIFIED        (ATTR_MTIME | ATTR_CTIME)
+
+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]);
+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);
+extern void    zfs_znode_fini(void);
+extern int     zfs_znode_hold_compare(const void *, const void *);
+extern int     zfs_zget(zfs_sb_t *, uint64_t, znode_t **);
+extern int     zfs_rezget(znode_t *);
+extern void    zfs_zinactive(znode_t *);
+extern void    zfs_znode_delete(znode_t *, dmu_tx_t *);
+extern void    zfs_remove_op_tables(void);
+extern int     zfs_create_op_tables(void);
+extern int     zfs_sync(struct super_block *, int, cred_t *);
+extern dev_t   zfs_cmpldev(uint64_t);
+extern int     zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value);
+extern int     zfs_get_stats(objset_t *os, nvlist_t *nv);
+extern void    zfs_znode_dmu_fini(znode_t *);
+extern int     zfs_inode_alloc(struct super_block *, struct inode **ip);
+extern void    zfs_inode_destroy(struct inode *);
+extern void    zfs_inode_update(znode_t *);
+extern void    zfs_mark_inode_dirty(struct inode *);
+
+extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *dzp, znode_t *zp, char *name, vsecattr_t *, zfs_fuid_info_t *,
+    vattr_t *vap);
+extern int zfs_log_create_txtype(zil_create_t, vsecattr_t *vsecp,
+    vattr_t *vap);
+extern void zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *dzp, char *name, uint64_t foid);
+#define        ZFS_NO_OBJECT   0       /* no object id */
+extern void zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *dzp, znode_t *zp, char *name);
+extern void zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *dzp, znode_t *zp, char *name, char *link);
+extern void zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *sdzp, char *sname, znode_t *tdzp, char *dname, znode_t *szp);
+extern void zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+    znode_t *zp, offset_t off, ssize_t len, int ioflag,
+    zil_callback_t callback, void *callback_data);
+extern void zfs_log_truncate(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+    znode_t *zp, uint64_t off, uint64_t len);
+extern void zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+    znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp);
+extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
+    vsecattr_t *vsecp, zfs_fuid_info_t *fuidp);
+extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx);
+extern void zfs_upgrade(zfs_sb_t *zsb, dmu_tx_t *tx);
+extern int zfs_create_share_dir(zfs_sb_t *zsb, dmu_tx_t *tx);
+
+#if defined(HAVE_UIO_RW)
+extern caddr_t zfs_map_page(page_t *, enum seg_rw);
+extern void zfs_unmap_page(page_t *, caddr_t);
+#endif /* HAVE_UIO_RW */
+
+extern zil_get_data_t zfs_get_data;
+extern zil_replay_func_t zfs_replay_vector[TX_MAX_TYPE];
+extern int zfsfstype;
+
+#endif /* _KERNEL */
+
+extern int zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_ZNODE_H */
diff --git a/zfs/include/sys/zil.h b/zfs/include/sys/zil.h
new file mode 100644 (file)
index 0000000..65b14f1
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#ifndef        _SYS_ZIL_H
+#define        _SYS_ZIL_H
+
+#include <sys/types.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/dmu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dsl_pool;
+struct dsl_dataset;
+
+/*
+ * Intent log format:
+ *
+ * Each objset has its own intent log.  The log header (zil_header_t)
+ * for objset N's intent log is kept in the Nth object of the SPA's
+ * intent_log objset.  The log header points to a chain of log blocks,
+ * each of which contains log records (i.e., transactions) followed by
+ * a log block trailer (zil_trailer_t).  The format of a log record
+ * depends on the record (or transaction) type, but all records begin
+ * with a common structure that defines the type, length, and txg.
+ */
+
+/*
+ * Intent log header - this on disk structure holds fields to manage
+ * the log.  All fields are 64 bit to easily handle cross architectures.
+ */
+typedef struct zil_header {
+       uint64_t zh_claim_txg;  /* txg in which log blocks were claimed */
+       uint64_t zh_replay_seq; /* highest replayed sequence number */
+       blkptr_t zh_log;        /* log chain */
+       uint64_t zh_claim_blk_seq; /* highest claimed block sequence number */
+       uint64_t zh_flags;      /* header flags */
+       uint64_t zh_claim_lr_seq; /* highest claimed lr sequence number */
+       uint64_t zh_pad[3];
+} zil_header_t;
+
+/*
+ * zh_flags bit settings
+ */
+#define        ZIL_REPLAY_NEEDED       0x1     /* replay needed - internal only */
+#define        ZIL_CLAIM_LR_SEQ_VALID  0x2     /* zh_claim_lr_seq field is valid */
+
+/*
+ * Log block chaining.
+ *
+ * Log blocks are chained together. Originally they were chained at the
+ * end of the block. For performance reasons the chain was moved to the
+ * beginning of the block which allows writes for only the data being used.
+ * The older position is supported for backwards compatability.
+ *
+ * The zio_eck_t contains a zec_cksum which for the intent log is
+ * the sequence number of this log block. A seq of 0 is invalid.
+ * The zec_cksum is checked by the SPA against the sequence
+ * number passed in the blk_cksum field of the blkptr_t
+ */
+typedef struct zil_chain {
+       uint64_t zc_pad;
+       blkptr_t zc_next_blk;   /* next block in chain */
+       uint64_t zc_nused;      /* bytes in log block used */
+       zio_eck_t zc_eck;       /* block trailer */
+} zil_chain_t;
+
+#define        ZIL_MIN_BLKSZ   4096ULL
+
+/*
+ * The words of a log block checksum.
+ */
+#define        ZIL_ZC_GUID_0   0
+#define        ZIL_ZC_GUID_1   1
+#define        ZIL_ZC_OBJSET   2
+#define        ZIL_ZC_SEQ      3
+
+typedef enum zil_create {
+       Z_FILE,
+       Z_DIR,
+       Z_XATTRDIR,
+} zil_create_t;
+
+/*
+ * size of xvattr log section.
+ * its composed of lr_attr_t + xvattr bitmap + 2 64 bit timestamps
+ * for create time and a single 64 bit integer for all of the attributes,
+ * and 4 64 bit integers (32 bytes) for the scanstamp.
+ *
+ */
+
+#define        ZIL_XVAT_SIZE(mapsize) \
+       sizeof (lr_attr_t) + (sizeof (uint32_t) * (mapsize - 1)) + \
+       (sizeof (uint64_t) * 7)
+
+/*
+ * Size of ACL in log.  The ACE data is padded out to properly align
+ * on 8 byte boundary.
+ */
+
+#define        ZIL_ACE_LENGTH(x)       (roundup(x, sizeof (uint64_t)))
+
+/*
+ * Intent log transaction types and record structures
+ */
+#define        TX_CREATE               1       /* Create file */
+#define        TX_MKDIR                2       /* Make directory */
+#define        TX_MKXATTR              3       /* Make XATTR directory */
+#define        TX_SYMLINK              4       /* Create symbolic link to a file */
+#define        TX_REMOVE               5       /* Remove file */
+#define        TX_RMDIR                6       /* Remove directory */
+#define        TX_LINK                 7       /* Create hard link to a file */
+#define        TX_RENAME               8       /* Rename a file */
+#define        TX_WRITE                9       /* File write */
+#define        TX_TRUNCATE             10      /* Truncate a file */
+#define        TX_SETATTR              11      /* Set file attributes */
+#define        TX_ACL_V0               12      /* Set old formatted ACL */
+#define        TX_ACL                  13      /* Set ACL */
+#define        TX_CREATE_ACL           14      /* create with ACL */
+#define        TX_CREATE_ATTR          15      /* create + attrs */
+#define        TX_CREATE_ACL_ATTR      16      /* create with ACL + attrs */
+#define        TX_MKDIR_ACL            17      /* mkdir with ACL */
+#define        TX_MKDIR_ATTR           18      /* mkdir with attr */
+#define        TX_MKDIR_ACL_ATTR       19      /* mkdir with ACL + attrs */
+#define        TX_WRITE2               20      /* dmu_sync EALREADY write */
+#define        TX_MAX_TYPE             21      /* Max transaction type */
+
+/*
+ * The transactions for mkdir, symlink, remove, rmdir, link, and rename
+ * may have the following bit set, indicating the original request
+ * specified case-insensitive handling of names.
+ */
+#define        TX_CI   ((uint64_t)0x1 << 63) /* case-insensitive behavior requested */
+
+/*
+ * Transactions for write, truncate, setattr, acl_v0, and acl can be logged
+ * out of order.  For convenience in the code, all such records must have
+ * lr_foid at the same offset.
+ */
+#define        TX_OOO(txtype)                  \
+       ((txtype) == TX_WRITE ||        \
+       (txtype) == TX_TRUNCATE ||      \
+       (txtype) == TX_SETATTR ||       \
+       (txtype) == TX_ACL_V0 ||        \
+       (txtype) == TX_ACL ||           \
+       (txtype) == TX_WRITE2)
+
+/*
+ * Format of log records.
+ * The fields are carefully defined to allow them to be aligned
+ * and sized the same on sparc & intel architectures.
+ * Each log record has a common structure at the beginning.
+ *
+ * The log record on disk (lrc_seq) holds the sequence number of all log
+ * records which is used to ensure we don't replay the same record.
+ */
+typedef struct {                       /* common log record header */
+       uint64_t        lrc_txtype;     /* intent log transaction type */
+       uint64_t        lrc_reclen;     /* transaction record length */
+       uint64_t        lrc_txg;        /* dmu transaction group number */
+       uint64_t        lrc_seq;        /* see comment above */
+} lr_t;
+
+/*
+ * Common start of all out-of-order record types (TX_OOO() above).
+ */
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_foid;        /* object id */
+} lr_ooo_t;
+
+/*
+ * Handle option extended vattr attributes.
+ *
+ * Whenever new attributes are added the version number
+ * will need to be updated as will code in
+ * zfs_log.c and zfs_replay.c
+ */
+typedef struct {
+       uint32_t        lr_attr_masksize; /* number of elements in array */
+       uint32_t        lr_attr_bitmap; /* First entry of array */
+       /* remainder of array and any additional fields */
+} lr_attr_t;
+
+/*
+ * log record for creates without optional ACL.
+ * This log record does support optional xvattr_t attributes.
+ */
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_doid;        /* object id of directory */
+       uint64_t        lr_foid;        /* object id of created file object */
+       uint64_t        lr_mode;        /* mode of object */
+       uint64_t        lr_uid;         /* uid of object */
+       uint64_t        lr_gid;         /* gid of object */
+       uint64_t        lr_gen;         /* generation (txg of creation) */
+       uint64_t        lr_crtime[2];   /* creation time */
+       uint64_t        lr_rdev;        /* rdev of object to create */
+       /* name of object to create follows this */
+       /* for symlinks, link content follows name */
+       /* for creates with xvattr data, the name follows the xvattr info */
+} lr_create_t;
+
+/*
+ * FUID ACL record will be an array of ACEs from the original ACL.
+ * If this array includes ephemeral IDs, the record will also include
+ * an array of log-specific FUIDs to replace the ephemeral IDs.
+ * Only one copy of each unique domain will be present, so the log-specific
+ * FUIDs will use an index into a compressed domain table.  On replay this
+ * information will be used to construct real FUIDs (and bypass idmap,
+ * since it may not be available).
+ */
+
+/*
+ * Log record for creates with optional ACL
+ * This log record is also used for recording any FUID
+ * information needed for replaying the create.  If the
+ * file doesn't have any actual ACEs then the lr_aclcnt
+ * would be zero.
+ *
+ * After lr_acl_flags, there are a lr_acl_bytes number of variable sized ace's.
+ * If create is also setting xvattr's, then acl data follows xvattr.
+ * If ACE FUIDs are needed then they will follow the xvattr_t.  Following
+ * the FUIDs will be the domain table information.  The FUIDs for the owner
+ * and group will be in lr_create.  Name follows ACL data.
+ */
+typedef struct {
+       lr_create_t     lr_create;      /* common create portion */
+       uint64_t        lr_aclcnt;      /* number of ACEs in ACL */
+       uint64_t        lr_domcnt;      /* number of unique domains */
+       uint64_t        lr_fuidcnt;     /* number of real fuids */
+       uint64_t        lr_acl_bytes;   /* number of bytes in ACL */
+       uint64_t        lr_acl_flags;   /* ACL flags */
+} lr_acl_create_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_doid;        /* obj id of directory */
+       /* name of object to remove follows this */
+} lr_remove_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_doid;        /* obj id of directory */
+       uint64_t        lr_link_obj;    /* obj id of link */
+       /* name of object to link follows this */
+} lr_link_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_sdoid;       /* obj id of source directory */
+       uint64_t        lr_tdoid;       /* obj id of target directory */
+       /* 2 strings: names of source and destination follow this */
+} lr_rename_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_foid;        /* file object to write */
+       uint64_t        lr_offset;      /* offset to write to */
+       uint64_t        lr_length;      /* user data length to write */
+       uint64_t        lr_blkoff;      /* no longer used */
+       blkptr_t        lr_blkptr;      /* spa block pointer for replay */
+       /* write data will follow for small writes */
+} lr_write_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_foid;        /* object id of file to truncate */
+       uint64_t        lr_offset;      /* offset to truncate from */
+       uint64_t        lr_length;      /* length to truncate */
+} lr_truncate_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_foid;        /* file object to change attributes */
+       uint64_t        lr_mask;        /* mask of attributes to set */
+       uint64_t        lr_mode;        /* mode to set */
+       uint64_t        lr_uid;         /* uid to set */
+       uint64_t        lr_gid;         /* gid to set */
+       uint64_t        lr_size;        /* size to set */
+       uint64_t        lr_atime[2];    /* access time */
+       uint64_t        lr_mtime[2];    /* modification time */
+       /* optional attribute lr_attr_t may be here */
+} lr_setattr_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_foid;        /* obj id of file */
+       uint64_t        lr_aclcnt;      /* number of acl entries */
+       /* lr_aclcnt number of ace_t entries follow this */
+} lr_acl_v0_t;
+
+typedef struct {
+       lr_t            lr_common;      /* common portion of log record */
+       uint64_t        lr_foid;        /* obj id of file */
+       uint64_t        lr_aclcnt;      /* number of ACEs in ACL */
+       uint64_t        lr_domcnt;      /* number of unique domains */
+       uint64_t        lr_fuidcnt;     /* number of real fuids */
+       uint64_t        lr_acl_bytes;   /* number of bytes in ACL */
+       uint64_t        lr_acl_flags;   /* ACL flags */
+       /* lr_acl_bytes number of variable sized ace's follows */
+} lr_acl_t;
+
+/*
+ * ZIL structure definitions, interface function prototype and globals.
+ */
+
+/*
+ * Writes are handled in three different ways:
+ *
+ * WR_INDIRECT:
+ *    In this mode, if we need to commit the write later, then the block
+ *    is immediately written into the file system (using dmu_sync),
+ *    and a pointer to the block is put into the log record.
+ *    When the txg commits the block is linked in.
+ *    This saves additionally writing the data into the log record.
+ *    There are a few requirements for this to occur:
+ *     - write is greater than zfs/zvol_immediate_write_sz
+ *     - not using slogs (as slogs are assumed to always be faster
+ *       than writing into the main pool)
+ *     - 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
+ *    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
+ *    flush the write later then a buffer is allocated and
+ *    we retrieve the data using the dmu.
+ */
+typedef enum {
+       WR_INDIRECT,    /* indirect - a large write (dmu_sync() data */
+                       /* and put blkptr in log, rather than actual data) */
+       WR_COPIED,      /* immediate - data is copied into lr_write_t */
+       WR_NEED_COPY,   /* immediate - data needs to be copied if pushed */
+       WR_NUM_STATES   /* number of states */
+} itx_wr_state_t;
+
+typedef void (*zil_callback_t)(void *data);
+
+typedef struct itx {
+       list_node_t     itx_node;       /* linkage on zl_itx_list */
+       void            *itx_private;   /* type-specific opaque data */
+       itx_wr_state_t  itx_wr_state;   /* write state */
+       uint8_t         itx_sync;       /* synchronous transaction */
+       zil_callback_t  itx_callback;   /* Called when the itx is persistent */
+       void            *itx_callback_data; /* User data for the callback */
+       uint64_t        itx_sod;        /* record size on disk */
+       uint64_t        itx_oid;        /* object id */
+       lr_t            itx_lr;         /* common part of log record */
+       /* followed by type-specific part of lr_xx_t and its immediate data */
+} itx_t;
+
+/*
+ * Used for zil kstat.
+ */
+typedef struct zil_stats {
+       /*
+        * Number of times a ZIL commit (e.g. fsync) has been requested.
+        */
+       kstat_named_t zil_commit_count;
+
+       /*
+        * Number of times the ZIL has been flushed to stable storage.
+        * This is less than zil_commit_count when commits are "merged"
+        * (see the documentation above zil_commit()).
+        */
+       kstat_named_t zil_commit_writer_count;
+
+       /*
+        * Number of transactions (reads, writes, renames, etc.)
+        * that have been commited.
+        */
+       kstat_named_t zil_itx_count;
+
+       /*
+        * See the documentation for itx_wr_state_t above.
+        * Note that "bytes" accumulates the length of the transactions
+        * (i.e. data), not the actual log record sizes.
+        */
+       kstat_named_t zil_itx_indirect_count;
+       kstat_named_t zil_itx_indirect_bytes;
+       kstat_named_t zil_itx_copied_count;
+       kstat_named_t zil_itx_copied_bytes;
+       kstat_named_t zil_itx_needcopy_count;
+       kstat_named_t zil_itx_needcopy_bytes;
+
+       /*
+        * Transactions which have been allocated to the "normal"
+        * (i.e. not slog) storage pool. Note that "bytes" accumulate
+        * the actual log record sizes - which do not include the actual
+        * data in case of indirect writes.
+        */
+       kstat_named_t zil_itx_metaslab_normal_count;
+       kstat_named_t zil_itx_metaslab_normal_bytes;
+
+       /*
+        * Transactions which have been allocated to the "slog" storage pool.
+        * If there are no separate log devices, this is the same as the
+        * "normal" pool.
+        */
+       kstat_named_t zil_itx_metaslab_slog_count;
+       kstat_named_t zil_itx_metaslab_slog_bytes;
+} zil_stats_t;
+
+extern zil_stats_t zil_stats;
+
+#define        ZIL_STAT_INCR(stat, val) \
+    atomic_add_64(&zil_stats.stat.value.ui64, (val));
+#define        ZIL_STAT_BUMP(stat) \
+    ZIL_STAT_INCR(stat, 1);
+
+typedef int zil_parse_blk_func_t(zilog_t *zilog, blkptr_t *bp, void *arg,
+    uint64_t txg);
+typedef int zil_parse_lr_func_t(zilog_t *zilog, lr_t *lr, void *arg,
+    uint64_t txg);
+typedef int (*const zil_replay_func_t)(void *, char *, boolean_t);
+typedef int zil_get_data_t(void *arg, lr_write_t *lr, char *dbuf, zio_t *zio);
+
+extern int zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func,
+    zil_parse_lr_func_t *parse_lr_func, void *arg, uint64_t txg);
+
+extern void    zil_init(void);
+extern void    zil_fini(void);
+
+extern zilog_t *zil_alloc(objset_t *os, zil_header_t *zh_phys);
+extern void    zil_free(zilog_t *zilog);
+
+extern zilog_t *zil_open(objset_t *os, zil_get_data_t *get_data);
+extern void    zil_close(zilog_t *zilog);
+
+extern void    zil_replay(objset_t *os, void *arg,
+    zil_replay_func_t replay_func[TX_MAX_TYPE]);
+extern boolean_t zil_replaying(zilog_t *zilog, dmu_tx_t *tx);
+extern void    zil_destroy(zilog_t *zilog, boolean_t keep_first);
+extern void    zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx);
+
+extern itx_t   *zil_itx_create(uint64_t txtype, size_t lrsize);
+extern void    zil_itx_destroy(itx_t *itx);
+extern void    zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx);
+
+extern void    zil_commit(zilog_t *zilog, uint64_t oid);
+
+extern int     zil_vdev_offline(const char *osname, void *txarg);
+extern int     zil_claim(struct dsl_pool *dp,
+    struct dsl_dataset *ds, void *txarg);
+extern int     zil_check_log_chain(struct dsl_pool *dp,
+    struct dsl_dataset *ds, void *tx);
+extern void    zil_sync(zilog_t *zilog, dmu_tx_t *tx);
+extern void    zil_clean(zilog_t *zilog, uint64_t synced_txg);
+
+extern int     zil_suspend(const char *osname, void **cookiep);
+extern void    zil_resume(void *cookie);
+
+extern void    zil_add_block(zilog_t *zilog, const blkptr_t *bp);
+extern int     zil_bp_tree_add(zilog_t *zilog, const blkptr_t *bp);
+
+extern void    zil_set_sync(zilog_t *zilog, uint64_t syncval);
+
+extern void    zil_set_logbias(zilog_t *zilog, uint64_t slogval);
+
+extern int zil_replay_disable;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZIL_H */
diff --git a/zfs/include/sys/zil_impl.h b/zfs/include/sys/zil_impl.h
new file mode 100644 (file)
index 0000000..0c426a1
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#ifndef        _SYS_ZIL_IMPL_H
+#define        _SYS_ZIL_IMPL_H
+
+#include <sys/zil.h>
+#include <sys/dmu_objset.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Log write buffer.
+ */
+typedef struct lwb {
+       zilog_t         *lwb_zilog;     /* back pointer to log struct */
+       blkptr_t        lwb_blk;        /* on disk address of this log blk */
+       boolean_t       lwb_fastwrite;  /* is blk marked for fastwrite? */
+       int             lwb_nused;      /* # used bytes in buffer */
+       int             lwb_sz;         /* size of block and buffer */
+       char            *lwb_buf;       /* log write buffer */
+       zio_t           *lwb_zio;       /* zio for this buffer */
+       dmu_tx_t        *lwb_tx;        /* tx for log block allocation */
+       uint64_t        lwb_max_txg;    /* highest txg in this lwb */
+       list_node_t     lwb_node;       /* zilog->zl_lwb_list linkage */
+} lwb_t;
+
+/*
+ * Intent log transaction lists
+ */
+typedef struct itxs {
+       list_t          i_sync_list;    /* list of synchronous itxs */
+       avl_tree_t      i_async_tree;   /* tree of foids for async itxs */
+} itxs_t;
+
+typedef struct itxg {
+       kmutex_t        itxg_lock;      /* lock for this structure */
+       uint64_t        itxg_txg;       /* txg for this chain */
+       uint64_t        itxg_sod;       /* total size on disk for this txg */
+       itxs_t          *itxg_itxs;     /* sync and async itxs */
+} itxg_t;
+
+/* for async nodes we build up an AVL tree of lists of async itxs per file */
+typedef struct itx_async_node {
+       uint64_t        ia_foid;        /* file object id */
+       list_t          ia_list;        /* list of async itxs for this foid */
+       avl_node_t      ia_node;        /* AVL tree linkage */
+} itx_async_node_t;
+
+/*
+ * Vdev flushing: during a zil_commit(), we build up an AVL tree of the vdevs
+ * we've touched so we know which ones need a write cache flush at the end.
+ */
+typedef struct zil_vdev_node {
+       uint64_t        zv_vdev;        /* vdev to be flushed */
+       avl_node_t      zv_node;        /* AVL tree linkage */
+} zil_vdev_node_t;
+
+#define        ZIL_PREV_BLKS 16
+
+/*
+ * Stable storage intent log management structure.  One per dataset.
+ */
+struct zilog {
+       kmutex_t        zl_lock;        /* protects most zilog_t fields */
+       struct dsl_pool *zl_dmu_pool;   /* DSL pool */
+       spa_t           *zl_spa;        /* handle for read/write log */
+       const zil_header_t *zl_header;  /* log header buffer */
+       objset_t        *zl_os;         /* object set we're logging */
+       zil_get_data_t  *zl_get_data;   /* callback to get object content */
+       zio_t           *zl_root_zio;   /* log writer root zio */
+       uint64_t        zl_lr_seq;      /* on-disk log record sequence number */
+       uint64_t        zl_commit_lr_seq; /* last committed on-disk lr seq */
+       uint64_t        zl_destroy_txg; /* txg of last zil_destroy() */
+       uint64_t        zl_replayed_seq[TXG_SIZE]; /* last replayed rec seq */
+       uint64_t        zl_replaying_seq; /* current replay seq number */
+       uint32_t        zl_suspend;     /* log suspend count */
+       kcondvar_t      zl_cv_writer;   /* log writer thread completion */
+       kcondvar_t      zl_cv_suspend;  /* log suspend completion */
+       uint8_t         zl_suspending;  /* log is currently suspending */
+       uint8_t         zl_keep_first;  /* keep first log block in destroy */
+       uint8_t         zl_replay;      /* replaying records while set */
+       uint8_t         zl_stop_sync;   /* for debugging */
+       uint8_t         zl_writer;      /* boolean: write setup in progress */
+       uint8_t         zl_logbias;     /* latency or throughput */
+       uint8_t         zl_sync;        /* synchronous or asynchronous */
+       int             zl_parse_error; /* last zil_parse() error */
+       uint64_t        zl_parse_blk_seq; /* highest blk seq on last parse */
+       uint64_t        zl_parse_lr_seq; /* highest lr seq on last parse */
+       uint64_t        zl_parse_blk_count; /* number of blocks parsed */
+       uint64_t        zl_parse_lr_count; /* number of log records parsed */
+       uint64_t        zl_next_batch;  /* next batch number */
+       uint64_t        zl_com_batch;   /* committed batch number */
+       kcondvar_t      zl_cv_batch[2]; /* batch condition variables */
+       itxg_t          zl_itxg[TXG_SIZE]; /* intent log txg chains */
+       list_t          zl_itx_commit_list; /* itx list to be committed */
+       uint64_t        zl_itx_list_sz; /* total size of records on list */
+       uint64_t        zl_cur_used;    /* current commit log size used */
+       list_t          zl_lwb_list;    /* in-flight log write list */
+       kmutex_t        zl_vdev_lock;   /* protects zl_vdev_tree */
+       avl_tree_t      zl_vdev_tree;   /* vdevs to flush in zil_commit() */
+       taskq_t         *zl_clean_taskq; /* runs lwb and itx clean tasks */
+       avl_tree_t      zl_bp_tree;     /* track bps during log parse */
+       clock_t         zl_replay_time; /* lbolt of when replay started */
+       uint64_t        zl_replay_blks; /* number of log blocks replayed */
+       zil_header_t    zl_old_header;  /* debugging aid */
+       uint_t          zl_prev_blks[ZIL_PREV_BLKS]; /* size - sector rounded */
+       uint_t          zl_prev_rotor;  /* rotor for zl_prev[] */
+       txg_node_t      zl_dirty_link;  /* protected by dp_dirty_zilogs list */
+};
+
+typedef struct zil_bp_node {
+       dva_t           zn_dva;
+       avl_node_t      zn_node;
+} zil_bp_node_t;
+
+#define        ZIL_MAX_LOG_DATA (SPA_OLD_MAXBLOCKSIZE - sizeof (zil_chain_t) - \
+    sizeof (lr_write_t))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZIL_IMPL_H */
diff --git a/zfs/include/sys/zio.h b/zfs/include/sys/zio.h
new file mode 100644 (file)
index 0000000..4916d87
--- /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) 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) 2013 by Saso Kiselkov. All rights reserved.
+ */
+
+#ifndef _ZIO_H
+#define        _ZIO_H
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/avl.h>
+#include <sys/fs/zfs.h>
+#include <sys/zio_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Embedded checksum
+ */
+#define        ZEC_MAGIC       0x210da7ab10c7a11ULL
+
+typedef struct zio_eck {
+       uint64_t        zec_magic;      /* for validation, endianness   */
+       zio_cksum_t     zec_cksum;      /* 256-bit checksum             */
+} zio_eck_t;
+
+/*
+ * Gang block headers are self-checksumming and contain an array
+ * of block pointers.
+ */
+#define        SPA_GANGBLOCKSIZE       SPA_MINBLOCKSIZE
+#define        SPA_GBH_NBLKPTRS        ((SPA_GANGBLOCKSIZE - \
+       sizeof (zio_eck_t)) / sizeof (blkptr_t))
+#define        SPA_GBH_FILLER          ((SPA_GANGBLOCKSIZE - \
+       sizeof (zio_eck_t) - \
+       (SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\
+       sizeof (uint64_t))
+
+typedef struct zio_gbh {
+       blkptr_t                zg_blkptr[SPA_GBH_NBLKPTRS];
+       uint64_t                zg_filler[SPA_GBH_FILLER];
+       zio_eck_t               zg_tail;
+} zio_gbh_phys_t;
+
+enum zio_checksum {
+       ZIO_CHECKSUM_INHERIT = 0,
+       ZIO_CHECKSUM_ON,
+       ZIO_CHECKSUM_OFF,
+       ZIO_CHECKSUM_LABEL,
+       ZIO_CHECKSUM_GANG_HEADER,
+       ZIO_CHECKSUM_ZILOG,
+       ZIO_CHECKSUM_FLETCHER_2,
+       ZIO_CHECKSUM_FLETCHER_4,
+       ZIO_CHECKSUM_SHA256,
+       ZIO_CHECKSUM_ZILOG2,
+       ZIO_CHECKSUM_FUNCTIONS
+};
+
+/*
+ * The number of "legacy" compression functions which can be set on individual
+ * objects.
+ */
+#define        ZIO_CHECKSUM_LEGACY_FUNCTIONS ZIO_CHECKSUM_ZILOG2
+
+#define        ZIO_CHECKSUM_ON_VALUE   ZIO_CHECKSUM_FLETCHER_4
+#define        ZIO_CHECKSUM_DEFAULT    ZIO_CHECKSUM_ON
+
+#define        ZIO_CHECKSUM_MASK       0xffULL
+#define        ZIO_CHECKSUM_VERIFY     (1 << 8)
+
+#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.
+ */
+#define        ZIO_COMPRESS_LEGACY_FUNCTIONS ZIO_COMPRESS_LZ4
+
+/*
+ * The meaning of "compress = on" selected by the compression features enabled
+ * on a given pool.
+ */
+#define        ZIO_COMPRESS_LEGACY_ON_VALUE    ZIO_COMPRESS_LZJB
+#define        ZIO_COMPRESS_LZ4_ON_VALUE       ZIO_COMPRESS_LZ4
+
+#define        ZIO_COMPRESS_DEFAULT            ZIO_COMPRESS_OFF
+
+#define        BOOTFS_COMPRESS_VALID(compress)                 \
+       ((compress) == ZIO_COMPRESS_LZJB ||             \
+       (compress) == ZIO_COMPRESS_LZ4 ||               \
+       (compress) == ZIO_COMPRESS_ON ||                \
+       (compress) == ZIO_COMPRESS_OFF)
+
+/*
+ * Default Linux timeout for a sd device.
+ */
+#define        ZIO_DELAY_MAX                   (30 * MILLISEC)
+
+#define        ZIO_FAILURE_MODE_WAIT           0
+#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,
+        * and that must be equal for two zios to aggregate
+        */
+       ZIO_FLAG_DONT_AGGREGATE = 1 << 0,
+       ZIO_FLAG_IO_REPAIR      = 1 << 1,
+       ZIO_FLAG_SELF_HEAL      = 1 << 2,
+       ZIO_FLAG_RESILVER       = 1 << 3,
+       ZIO_FLAG_SCRUB          = 1 << 4,
+       ZIO_FLAG_SCAN_THREAD    = 1 << 5,
+       ZIO_FLAG_PHYSICAL       = 1 << 6,
+
+#define        ZIO_FLAG_AGG_INHERIT    (ZIO_FLAG_CANFAIL - 1)
+
+       /*
+        * Flags inherited by ddt, gang, and vdev children.
+        */
+       ZIO_FLAG_CANFAIL        = 1 << 7,       /* must be first for INHERIT */
+       ZIO_FLAG_SPECULATIVE    = 1 << 8,
+       ZIO_FLAG_CONFIG_WRITER  = 1 << 9,
+       ZIO_FLAG_DONT_RETRY     = 1 << 10,
+       ZIO_FLAG_DONT_CACHE     = 1 << 11,
+       ZIO_FLAG_NODATA         = 1 << 12,
+       ZIO_FLAG_INDUCE_DAMAGE  = 1 << 13,
+
+#define        ZIO_FLAG_DDT_INHERIT    (ZIO_FLAG_IO_RETRY - 1)
+#define        ZIO_FLAG_GANG_INHERIT   (ZIO_FLAG_IO_RETRY - 1)
+
+       /*
+        * 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,
+
+#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,
+};
+
+#define        ZIO_FLAG_MUSTSUCCEED            0
+
+#define        ZIO_DDT_CHILD_FLAGS(zio)                                \
+       (((zio)->io_flags & ZIO_FLAG_DDT_INHERIT) |             \
+       ZIO_FLAG_DDT_CHILD | ZIO_FLAG_CANFAIL)
+
+#define        ZIO_GANG_CHILD_FLAGS(zio)                               \
+       (((zio)->io_flags & ZIO_FLAG_GANG_INHERIT) |            \
+       ZIO_FLAG_GANG_CHILD | ZIO_FLAG_CANFAIL)
+
+#define        ZIO_VDEV_CHILD_FLAGS(zio)                               \
+       (((zio)->io_flags & ZIO_FLAG_VDEV_INHERIT) |            \
+       ZIO_FLAG_CANFAIL)
+
+enum zio_child {
+       ZIO_CHILD_VDEV = 0,
+       ZIO_CHILD_GANG,
+       ZIO_CHILD_DDT,
+       ZIO_CHILD_LOGICAL,
+       ZIO_CHILD_TYPES
+};
+
+enum zio_wait_type {
+       ZIO_WAIT_READY = 0,
+       ZIO_WAIT_DONE,
+       ZIO_WAIT_TYPES
+};
+
+/*
+ * We'll take the unused errnos, 'EBADE' and 'EBADR' (from the Convergent
+ * graveyard) to indicate checksum errors and fragmentation.
+ */
+#define        ECKSUM  EBADE
+#define        EFRAGS  EBADR
+
+typedef void zio_done_func_t(zio_t *zio);
+
+extern const char *zio_type_name[ZIO_TYPES];
+
+/*
+ * A bookmark is a four-tuple <objset, object, level, blkid> that uniquely
+ * identifies any block in the pool.  By convention, the meta-objset (MOS)
+ * is objset 0, and the meta-dnode is object 0.  This covers all blocks
+ * except root blocks and ZIL blocks, which are defined as follows:
+ *
+ * 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>.
+ *
+ * Note: this structure is called a bookmark because its original purpose
+ * was to remember where to resume a pool-wide traverse.
+ *
+ * Note: this structure is passed between userland and the kernel, and is
+ * stored on disk (by virtue of being incorporated into other on-disk
+ * structures, e.g. dsl_scan_phys_t).
+ */
+struct zbookmark_phys {
+       uint64_t        zb_objset;
+       uint64_t        zb_object;
+       int64_t         zb_level;
+       uint64_t        zb_blkid;
+};
+
+#define        SET_BOOKMARK(zb, objset, object, level, blkid)  \
+{                                                       \
+       (zb)->zb_objset = objset;                       \
+       (zb)->zb_object = object;                       \
+       (zb)->zb_level = level;                         \
+       (zb)->zb_blkid = blkid;                         \
+}
+
+#define        ZB_DESTROYED_OBJSET     (-1ULL)
+
+#define        ZB_ROOT_OBJECT          (0ULL)
+#define        ZB_ROOT_LEVEL           (-1LL)
+#define        ZB_ROOT_BLKID           (0ULL)
+
+#define        ZB_ZIL_OBJECT           (0ULL)
+#define        ZB_ZIL_LEVEL            (-2LL)
+
+#define        ZB_IS_ZERO(zb)                                          \
+       ((zb)->zb_objset == 0 && (zb)->zb_object == 0 &&        \
+       (zb)->zb_level == 0 && (zb)->zb_blkid == 0)
+#define        ZB_IS_ROOT(zb)                          \
+       ((zb)->zb_object == ZB_ROOT_OBJECT &&   \
+       (zb)->zb_level == ZB_ROOT_LEVEL &&      \
+       (zb)->zb_blkid == ZB_ROOT_BLKID)
+
+typedef struct zio_prop {
+       enum zio_checksum       zp_checksum;
+       enum zio_compress       zp_compress;
+       dmu_object_type_t       zp_type;
+       uint8_t                 zp_level;
+       uint8_t                 zp_copies;
+       boolean_t               zp_dedup;
+       boolean_t               zp_dedup_verify;
+       boolean_t               zp_nopwrite;
+} zio_prop_t;
+
+typedef struct zio_cksum_report zio_cksum_report_t;
+
+typedef void zio_cksum_finish_f(zio_cksum_report_t *rep,
+    const void *good_data);
+typedef void zio_cksum_free_f(void *cbdata, size_t size);
+
+struct zio_bad_cksum;                          /* defined in zio_checksum.h */
+struct dnode_phys;
+
+struct zio_cksum_report {
+       struct zio_cksum_report *zcr_next;
+       nvlist_t                *zcr_ereport;
+       nvlist_t                *zcr_detector;
+       void                    *zcr_cbdata;
+       size_t                  zcr_cbinfo;     /* passed to zcr_free() */
+       uint64_t                zcr_align;
+       uint64_t                zcr_length;
+       zio_cksum_finish_f      *zcr_finish;
+       zio_cksum_free_f        *zcr_free;
+
+       /* internal use only */
+       struct zio_bad_cksum    *zcr_ckinfo;    /* information from failure */
+};
+
+typedef void zio_vsd_cksum_report_f(zio_t *zio, zio_cksum_report_t *zcr,
+    void *arg);
+
+zio_vsd_cksum_report_f zio_vsd_default_cksum_report;
+
+typedef struct zio_vsd_ops {
+       zio_done_func_t         *vsd_free;
+       zio_vsd_cksum_report_f  *vsd_cksum_report;
+} zio_vsd_ops_t;
+
+typedef struct zio_gang_node {
+       zio_gbh_phys_t          *gn_gbh;
+       struct zio_gang_node    *gn_child[SPA_GBH_NBLKPTRS];
+} zio_gang_node_t;
+
+typedef zio_t *zio_gang_issue_func_t(zio_t *zio, blkptr_t *bp,
+    zio_gang_node_t *gn, void *data);
+
+typedef void zio_transform_func_t(zio_t *zio, void *data, uint64_t size);
+
+typedef struct zio_transform {
+       void                    *zt_orig_data;
+       uint64_t                zt_orig_size;
+       uint64_t                zt_bufsize;
+       zio_transform_func_t    *zt_transform;
+       struct zio_transform    *zt_next;
+} zio_transform_t;
+
+typedef int zio_pipe_stage_t(zio_t *zio);
+
+/*
+ * The io_reexecute flags are distinct from io_flags because the child must
+ * be able to propagate them to the parent.  The normal io_flags are local
+ * to the zio, not protected by any lock, and not modifiable by children;
+ * the reexecute flags are protected by io_lock, modifiable by children,
+ * and always propagated -- even when ZIO_FLAG_DONT_PROPAGATE is set.
+ */
+#define        ZIO_REEXECUTE_NOW       0x01
+#define        ZIO_REEXECUTE_SUSPEND   0x02
+
+typedef struct zio_link {
+       zio_t           *zl_parent;
+       zio_t           *zl_child;
+       list_node_t     zl_parent_node;
+       list_node_t     zl_child_node;
+} zio_link_t;
+
+struct zio {
+       /* Core information about this I/O */
+       zbookmark_phys_t        io_bookmark;
+       zio_prop_t      io_prop;
+       zio_type_t      io_type;
+       enum zio_child  io_child_type;
+       int             io_cmd;
+       zio_priority_t  io_priority;
+       uint8_t         io_reexecute;
+       uint8_t         io_state[ZIO_WAIT_TYPES];
+       uint64_t        io_txg;
+       spa_t           *io_spa;
+       blkptr_t        *io_bp;
+       blkptr_t        *io_bp_override;
+       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_physdone;
+       zio_done_func_t *io_done;
+       void            *io_private;
+       int64_t         io_prev_space_delta;    /* DMU private */
+       blkptr_t        io_bp_orig;
+
+       /* Data represented by this I/O */
+       void            *io_data;
+       void            *io_orig_data;
+       uint64_t        io_size;
+       uint64_t        io_orig_size;
+
+       /* Stuff for the vdev stack */
+       vdev_t          *io_vd;
+       void            *io_vsd;
+       const zio_vsd_ops_t *io_vsd_ops;
+
+       uint64_t        io_offset;
+       hrtime_t        io_timestamp;   /* submitted at */
+       hrtime_t        io_delta;       /* vdev queue service delta */
+       uint64_t        io_delay;       /* vdev disk service delta (ticks) */
+       avl_node_t      io_queue_node;
+       avl_node_t      io_offset_node;
+
+       /* Internal pipeline state */
+       enum zio_flag   io_flags;
+       enum zio_stage  io_stage;
+       enum zio_stage  io_pipeline;
+       enum zio_flag   io_orig_flags;
+       enum zio_stage  io_orig_stage;
+       enum zio_stage  io_orig_pipeline;
+       int             io_error;
+       int             io_child_error[ZIO_CHILD_TYPES];
+       uint64_t        io_children[ZIO_CHILD_TYPES][ZIO_WAIT_TYPES];
+       uint64_t        io_child_count;
+       uint64_t        io_phys_children;
+       uint64_t        io_parent_count;
+       uint64_t        *io_stall;
+       zio_t           *io_gang_leader;
+       zio_gang_node_t *io_gang_tree;
+       void            *io_executor;
+       void            *io_waiter;
+       kmutex_t        io_lock;
+       kcondvar_t      io_cv;
+
+       /* FMA state */
+       zio_cksum_report_t *io_cksum_report;
+       uint64_t        io_ena;
+
+       /* Taskq dispatching state */
+       taskq_ent_t     io_tqent;
+};
+
+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);
+
+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,
+    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);
+
+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,
+    zio_priority_t priority, enum zio_flag flags, zbookmark_phys_t *zb);
+
+extern void zio_write_override(zio_t *zio, blkptr_t *bp, int copies,
+    boolean_t nopwrite);
+
+extern void zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp);
+
+extern zio_t *zio_claim(zio_t *pio, spa_t *spa, uint64_t txg,
+    const blkptr_t *bp,
+    zio_done_func_t *done, void *private, enum zio_flag flags);
+
+extern zio_t *zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd,
+    zio_done_func_t *done, void *private, enum zio_flag flags);
+
+extern zio_t *zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset,
+    uint64_t size, void *data, int checksum,
+    zio_done_func_t *done, void *private, zio_priority_t priority,
+    enum zio_flag flags, boolean_t labels);
+
+extern zio_t *zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset,
+    uint64_t size, void *data, int checksum,
+    zio_done_func_t *done, void *private, zio_priority_t priority,
+    enum zio_flag flags, boolean_t labels);
+
+extern zio_t *zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg,
+    const blkptr_t *bp, enum zio_flag flags);
+
+extern int zio_alloc_zil(spa_t *spa, uint64_t txg, blkptr_t *new_bp,
+    uint64_t size, boolean_t use_slog);
+extern void zio_free_zil(spa_t *spa, uint64_t txg, blkptr_t *bp);
+extern void zio_flush(zio_t *zio, vdev_t *vd);
+extern void zio_shrink(zio_t *zio, uint64_t size);
+
+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 zio_t *zio_walk_parents(zio_t *cio);
+extern zio_t *zio_walk_children(zio_t *pio);
+extern zio_t *zio_unique_parent(zio_t *cio);
+extern void zio_add_child(zio_t *pio, zio_t *cio);
+
+extern void *zio_buf_alloc(size_t size);
+extern void zio_buf_free(void *buf, size_t size);
+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_resubmit_stage_async(void *);
+
+extern zio_t *zio_vdev_child_io(zio_t *zio, blkptr_t *bp, vdev_t *vd,
+    uint64_t offset, void *data, uint64_t size, int type,
+    zio_priority_t priority, enum zio_flag flags,
+    zio_done_func_t *done, void *private);
+
+extern zio_t *zio_vdev_delegated_io(vdev_t *vd, uint64_t offset,
+    void *data, uint64_t size, int type, zio_priority_t priority,
+    enum zio_flag flags, zio_done_func_t *done, void *private);
+
+extern void zio_vdev_io_bypass(zio_t *zio);
+extern void zio_vdev_io_reissue(zio_t *zio);
+extern void zio_vdev_io_redone(zio_t *zio);
+
+extern void zio_checksum_verified(zio_t *zio);
+extern int zio_worst_error(int e1, int e2);
+
+extern enum zio_checksum zio_checksum_select(enum zio_checksum child,
+    enum zio_checksum parent);
+extern enum zio_checksum zio_checksum_dedup_select(spa_t *spa,
+    enum zio_checksum child, enum zio_checksum parent);
+extern enum zio_compress zio_compress_select(spa_t *spa,
+    enum zio_compress child, enum zio_compress parent);
+
+extern void zio_suspend(spa_t *spa, zio_t *zio);
+extern int zio_resume(spa_t *spa);
+extern void zio_resume_wait(spa_t *spa);
+
+/*
+ * Initial setup and teardown.
+ */
+extern void zio_init(void);
+extern void zio_fini(void);
+
+/*
+ * Fault injection
+ */
+struct zinject_record;
+extern uint32_t zio_injection_enabled;
+extern int zio_inject_fault(char *name, int flags, int *id,
+    struct zinject_record *record);
+extern int zio_inject_list_next(int *id, char *name, size_t buflen,
+    struct zinject_record *record);
+extern int zio_clear_fault(int id);
+extern void zio_handle_panic_injection(spa_t *spa, char *tag, uint64_t type);
+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);
+
+/*
+ * Checksum ereport functions
+ */
+extern void zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd, struct zio *zio,
+    uint64_t offset, uint64_t length, void *arg, struct zio_bad_cksum *info);
+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 */
+extern void zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
+    struct zio *zio, uint64_t offset, uint64_t length,
+    const void *good_data, const void *bad_data, struct zio_bad_cksum *info);
+
+/* Called from spa_sync(), but primarily an injection handler */
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIO_H */
diff --git a/zfs/include/sys/zio_checksum.h b/zfs/include/sys/zio_checksum.h
new file mode 100644 (file)
index 0000000..de89bc9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 _SYS_ZIO_CHECKSUM_H
+#define        _SYS_ZIO_CHECKSUM_H
+
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Signature for checksum functions.
+ */
+typedef void zio_checksum_t(const void *data, uint64_t size, zio_cksum_t *zcp);
+
+/*
+ * 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 */
+} zio_checksum_info_t;
+
+typedef struct zio_bad_cksum {
+       zio_cksum_t             zbc_expected;
+       zio_cksum_t             zbc_actual;
+       const char              *zbc_checksum_name;
+       uint8_t                 zbc_byteswapped;
+       uint8_t                 zbc_injected;
+       uint8_t                 zbc_has_cksum;  /* expected/actual valid */
+} zio_bad_cksum_t;
+
+extern zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS];
+
+/*
+ * Checksum routines.
+ */
+extern zio_checksum_t zio_checksum_SHA256;
+
+extern void zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
+    void *data, uint64_t size);
+extern int zio_checksum_error(zio_t *zio, zio_bad_cksum_t *out);
+extern enum zio_checksum spa_dedup_checksum(spa_t *spa);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZIO_CHECKSUM_H */
diff --git a/zfs/include/sys/zio_compress.h b/zfs/include/sys/zio_compress.h
new file mode 100644 (file)
index 0000000..63863c7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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_ZIO_COMPRESS_H
+#define        _SYS_ZIO_COMPRESS_H
+
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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);
+/* Common signature for all zio decompress functions. */
+typedef int zio_decompress_func_t(void *src, void *dst,
+    size_t s_len, size_t d_len, int);
+
+/*
+ * Information about each compression function.
+ */
+typedef const struct zio_compress_info {
+       zio_compress_func_t     *ci_compress;   /* compression function */
+       zio_decompress_func_t   *ci_decompress; /* decompression function */
+       int                     ci_level;       /* level parameter */
+       char                    *ci_name;       /* algorithm name */
+} zio_compress_info_t;
+
+extern zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS];
+
+/*
+ * lz4 compression init & free
+ */
+extern void lz4_init(void);
+extern void lz4_fini(void);
+
+/*
+ * Compression routines.
+ */
+extern size_t lzjb_compress(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern int lzjb_decompress(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern size_t gzip_compress(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern int gzip_decompress(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern size_t zle_compress(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern int zle_decompress(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern size_t lz4_compress_zfs(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+extern int lz4_decompress_zfs(void *src, void *dst, size_t s_len, size_t d_len,
+    int level);
+
+/*
+ * Compress and decompress data if necessary.
+ */
+extern size_t zio_compress_data(enum zio_compress c, void *src, void *dst,
+    size_t s_len);
+extern int zio_decompress_data(enum zio_compress c, void *src, void *dst,
+    size_t s_len, size_t d_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZIO_COMPRESS_H */
diff --git a/zfs/include/sys/zio_impl.h b/zfs/include/sys/zio_impl.h
new file mode 100644 (file)
index 0000000..08f8201
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+#ifndef _ZIO_IMPL_H
+#define        _ZIO_IMPL_H
+
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * XXX -- Describe ZFS I/O pipeline here. Fill in as needed.
+ *
+ * The ZFS I/O pipeline is comprised of various stages which are defined
+ * in the zio_stage enum below. The individual stages are used to construct
+ * these basic I/O operations: Read, Write, Free, Claim, and Ioctl.
+ *
+ * I/O operations: (XXX - provide detail for each of the operations)
+ *
+ * Read:
+ * Write:
+ * Free:
+ * Claim:
+ * Ioctl:
+ *
+ * Although the most common pipeline are used by the basic I/O operations
+ * above, there are some helper pipelines (one could consider them
+ * sub-pipelines) which are used internally by the ZIO module and are
+ * explained below:
+ *
+ * Interlock Pipeline:
+ * The interlock pipeline is the most basic pipeline and is used by all
+ * of the I/O operations. The interlock pipeline does not perform any I/O
+ * and is used to coordinate the dependencies between I/Os that are being
+ * issued (i.e. the parent/child relationship).
+ *
+ * Vdev child Pipeline:
+ * The vdev child pipeline is responsible for performing the physical I/O.
+ * It is in this pipeline where the I/O are queued and possibly cached.
+ *
+ * In addition to performing I/O, the pipeline is also responsible for
+ * data transformations. The transformations performed are based on the
+ * specific properties that user may have selected and modify the
+ * behavior of the pipeline. Examples of supported transformations are
+ * compression, dedup, and nop writes. Transformations will either modify
+ * the data or the pipeline. This list below further describes each of
+ * the supported transformations:
+ *
+ * Compression:
+ * ZFS supports three different flavors of compression -- gzip, lzjb, and
+ * zle. Compression occurs as part of the write pipeline and is performed
+ * in the ZIO_STAGE_WRITE_BP_INIT stage.
+ *
+ * Dedup:
+ * Dedup reads are handled by the ZIO_STAGE_DDT_READ_START and
+ * ZIO_STAGE_DDT_READ_DONE stages. These stages are added to an existing
+ * read pipeline if the dedup bit is set on the block pointer.
+ * Writing a dedup block is performed by the ZIO_STAGE_DDT_WRITE stage
+ * and added to a write pipeline if a user has enabled dedup on that
+ * particular dataset.
+ *
+ * NOP Write:
+ * The NOP write feature is performed by the ZIO_STAGE_NOP_WRITE stage
+ * and is added to an existing write pipeline if a crypographically
+ * secure checksum (i.e. SHA256) is enabled and compression is turned on.
+ * The NOP write stage will compare the checksums of the current data
+ * on-disk (level-0 blocks only) and the data that is currently being written.
+ * If the checksum values are identical then the pipeline is converted to
+ * an interlock pipeline skipping block allocation and bypassing the
+ * physical I/O.  The nop write feature can handle writes in either
+ * syncing or open context (i.e. zil writes) and as a result is mutually
+ * exclusive with dedup.
+ */
+
+/*
+ * zio pipeline stage definitions
+ */
+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_CHECKSUM_GENERATE     = 1 << 5,       /* -W--- */
+
+       ZIO_STAGE_NOP_WRITE             = 1 << 6,       /* -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_GANG_ASSEMBLE         = 1 << 11,      /* RWFC- */
+       ZIO_STAGE_GANG_ISSUE            = 1 << 12,      /* RWFC- */
+
+       ZIO_STAGE_DVA_ALLOCATE          = 1 << 13,      /* -W--- */
+       ZIO_STAGE_DVA_FREE              = 1 << 14,      /* --F-- */
+       ZIO_STAGE_DVA_CLAIM             = 1 << 15,      /* ---C- */
+
+       ZIO_STAGE_READY                 = 1 << 16,      /* 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_CHECKSUM_VERIFY       = 1 << 20,      /* R---- */
+
+       ZIO_STAGE_DONE                  = 1 << 21       /* RWFCI */
+};
+
+#define        ZIO_INTERLOCK_STAGES                    \
+       (ZIO_STAGE_READY |                      \
+       ZIO_STAGE_DONE)
+
+#define        ZIO_INTERLOCK_PIPELINE                  \
+       ZIO_INTERLOCK_STAGES
+
+#define        ZIO_VDEV_IO_STAGES                      \
+       (ZIO_STAGE_VDEV_IO_START |              \
+       ZIO_STAGE_VDEV_IO_DONE |                \
+       ZIO_STAGE_VDEV_IO_ASSESS)
+
+#define        ZIO_VDEV_CHILD_PIPELINE                 \
+       (ZIO_VDEV_IO_STAGES |                   \
+       ZIO_STAGE_DONE)
+
+#define        ZIO_READ_COMMON_STAGES                  \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_VDEV_IO_STAGES |                    \
+       ZIO_STAGE_CHECKSUM_VERIFY)
+
+#define        ZIO_READ_PHYS_PIPELINE                  \
+       ZIO_READ_COMMON_STAGES
+
+#define        ZIO_READ_PIPELINE                       \
+       (ZIO_READ_COMMON_STAGES |               \
+       ZIO_STAGE_READ_BP_INIT)
+
+#define        ZIO_DDT_CHILD_READ_PIPELINE             \
+       ZIO_READ_COMMON_STAGES
+
+#define        ZIO_DDT_READ_PIPELINE                   \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_STAGE_READ_BP_INIT |                \
+       ZIO_STAGE_DDT_READ_START |              \
+       ZIO_STAGE_DDT_READ_DONE)
+
+#define        ZIO_WRITE_COMMON_STAGES                 \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_VDEV_IO_STAGES |                    \
+       ZIO_STAGE_ISSUE_ASYNC |                 \
+       ZIO_STAGE_CHECKSUM_GENERATE)
+
+#define        ZIO_WRITE_PHYS_PIPELINE                 \
+       ZIO_WRITE_COMMON_STAGES
+
+#define        ZIO_REWRITE_PIPELINE                    \
+       (ZIO_WRITE_COMMON_STAGES |              \
+       ZIO_STAGE_WRITE_BP_INIT)
+
+#define        ZIO_WRITE_PIPELINE                      \
+       (ZIO_WRITE_COMMON_STAGES |              \
+       ZIO_STAGE_WRITE_BP_INIT |               \
+       ZIO_STAGE_DVA_ALLOCATE)
+
+#define        ZIO_DDT_CHILD_WRITE_PIPELINE            \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_VDEV_IO_STAGES |                    \
+       ZIO_STAGE_DVA_ALLOCATE)
+
+#define        ZIO_DDT_WRITE_PIPELINE                  \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_STAGE_ISSUE_ASYNC |                 \
+       ZIO_STAGE_WRITE_BP_INIT |               \
+       ZIO_STAGE_CHECKSUM_GENERATE |           \
+       ZIO_STAGE_DDT_WRITE)
+
+#define        ZIO_GANG_STAGES                         \
+       (ZIO_STAGE_GANG_ASSEMBLE |              \
+       ZIO_STAGE_GANG_ISSUE)
+
+#define        ZIO_FREE_PIPELINE                       \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_STAGE_FREE_BP_INIT |                \
+       ZIO_STAGE_DVA_FREE)
+
+#define        ZIO_DDT_FREE_PIPELINE                   \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_STAGE_FREE_BP_INIT |                \
+       ZIO_STAGE_ISSUE_ASYNC |                 \
+       ZIO_STAGE_DDT_FREE)
+
+#define        ZIO_CLAIM_PIPELINE                      \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_STAGE_DVA_CLAIM)
+
+#define        ZIO_IOCTL_PIPELINE                      \
+       (ZIO_INTERLOCK_STAGES |                 \
+       ZIO_STAGE_VDEV_IO_START |               \
+       ZIO_STAGE_VDEV_IO_ASSESS)
+
+#define        ZIO_BLOCKING_STAGES                     \
+       (ZIO_STAGE_DVA_ALLOCATE |               \
+       ZIO_STAGE_DVA_CLAIM |                   \
+       ZIO_STAGE_VDEV_IO_START)
+
+extern void zio_inject_init(void);
+extern void zio_inject_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIO_IMPL_H */
diff --git a/zfs/include/sys/zpl.h b/zfs/include/sys/zpl.h
new file mode 100644 (file)
index 0000000..9f0ac77
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef        _SYS_ZPL_H
+#define        _SYS_ZPL_H
+
+#include <sys/mntent.h>
+#include <sys/vfs.h>
+#include <linux/aio.h>
+#include <linux/dcache_compat.h>
+#include <linux/exportfs.h>
+#include <linux/falloc.h>
+#include <linux/file_compat.h>
+#include <linux/parser.h>
+#include <linux/task_io_accounting_ops.h>
+#include <linux/vfs_compat.h>
+#include <linux/writeback.h>
+#include <linux/xattr_compat.h>
+
+/* zpl_inode.c */
+extern void zpl_vap_init(vattr_t *vap, struct inode *dir,
+    zpl_umode_t mode, cred_t *cr);
+
+extern const struct inode_operations zpl_inode_operations;
+extern const struct inode_operations zpl_dir_inode_operations;
+extern const struct inode_operations zpl_symlink_inode_operations;
+extern const struct inode_operations zpl_special_inode_operations;
+extern dentry_operations_t zpl_dentry_operations;
+
+/* zpl_file.c */
+extern ssize_t zpl_read_common(struct inode *ip, const char *buf,
+    size_t len, loff_t *ppos, uio_seg_t segment, int flags,
+    cred_t *cr);
+extern ssize_t zpl_write_common(struct inode *ip, const char *buf,
+    size_t len, loff_t *ppos, uio_seg_t segment, int flags,
+    cred_t *cr);
+#if defined(HAVE_FILE_FALLOCATE) || defined(HAVE_INODE_FALLOCATE)
+extern long zpl_fallocate_common(struct inode *ip, int mode,
+    loff_t offset, loff_t len);
+#endif /* defined(HAVE_FILE_FALLOCATE) || defined(HAVE_INODE_FALLOCATE) */
+
+extern const struct address_space_operations zpl_address_space_operations;
+extern const struct file_operations zpl_file_operations;
+extern const struct file_operations zpl_dir_file_operations;
+
+/* zpl_super.c */
+extern void zpl_prune_sb(int64_t nr_to_scan, void *arg);
+
+extern const struct super_operations zpl_super_operations;
+extern const struct export_operations zpl_export_operations;
+extern struct file_system_type zpl_fs_type;
+
+/* zpl_xattr.c */
+extern ssize_t zpl_xattr_list(struct dentry *dentry, char *buf, size_t size);
+extern int zpl_xattr_security_init(struct inode *ip, struct inode *dip,
+    const struct qstr *qstr);
+#if defined(CONFIG_FS_POSIX_ACL)
+extern int zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type);
+extern struct posix_acl *zpl_get_acl(struct inode *ip, int type);
+#if !defined(HAVE_GET_ACL)
+#if defined(HAVE_CHECK_ACL_WITH_FLAGS)
+extern int zpl_check_acl(struct inode *inode, int mask, unsigned int flags);
+#elif defined(HAVE_CHECK_ACL)
+extern int zpl_check_acl(struct inode *inode, int mask);
+#elif defined(HAVE_PERMISSION_WITH_NAMEIDATA)
+extern int zpl_permission(struct inode *ip, int mask, struct nameidata *nd);
+#elif defined(HAVE_PERMISSION)
+extern int zpl_permission(struct inode *ip, int mask);
+#endif /*  HAVE_CHECK_ACL | HAVE_PERMISSION */
+#endif /* HAVE_GET_ACL */
+
+extern int zpl_init_acl(struct inode *ip, struct inode *dir);
+extern int zpl_chmod_acl(struct inode *ip);
+#else
+static inline int
+zpl_init_acl(struct inode *ip, struct inode *dir)
+{
+       return (0);
+}
+
+static inline int
+zpl_chmod_acl(struct inode *ip)
+{
+       return (0);
+}
+#endif /* CONFIG_FS_POSIX_ACL */
+
+extern xattr_handler_t *zpl_xattr_handlers[];
+
+/* zpl_ctldir.c */
+extern const struct file_operations zpl_fops_root;
+extern const struct inode_operations zpl_ops_root;
+
+extern const struct file_operations zpl_fops_snapdir;
+extern const struct inode_operations zpl_ops_snapdir;
+#ifdef HAVE_AUTOMOUNT
+extern const struct dentry_operations zpl_dops_snapdirs;
+#else
+extern const struct inode_operations zpl_ops_snapdirs;
+#endif /* HAVE_AUTOMOUNT */
+
+extern const struct file_operations zpl_fops_shares;
+extern const struct inode_operations zpl_ops_shares;
+
+#if defined(HAVE_VFS_ITERATE) || defined(HAVE_VFS_ITERATE_SHARED)
+
+#define        DIR_CONTEXT_INIT(_dirent, _actor, _pos) {       \
+       .actor = _actor,                                \
+       .pos = _pos,                                    \
+}
+
+#else
+
+typedef struct dir_context {
+       void *dirent;
+       const filldir_t actor;
+       loff_t pos;
+} dir_context_t;
+
+#define        DIR_CONTEXT_INIT(_dirent, _actor, _pos) {       \
+       .dirent = _dirent,                              \
+       .actor = _actor,                                \
+       .pos = _pos,                                    \
+}
+
+static inline bool
+dir_emit(struct dir_context *ctx, const char *name, int namelen,
+    uint64_t ino, unsigned type)
+{
+       return (ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type)
+               == 0);
+}
+
+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);
+}
+
+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);
+}
+
+static inline bool
+dir_emit_dots(struct file *file, struct dir_context *ctx)
+{
+       if (ctx->pos == 0) {
+               if (!dir_emit_dot(file, ctx))
+                       return (false);
+               ctx->pos = 1;
+       }
+       if (ctx->pos == 1) {
+               if (!dir_emit_dotdot(file, ctx))
+                       return (false);
+               ctx->pos = 2;
+       }
+       return (true);
+}
+#endif /* HAVE_VFS_ITERATE */
+
+#endif /* _SYS_ZPL_H */
diff --git a/zfs/include/sys/zrlock.h b/zfs/include/sys/zrlock.h
new file mode 100644 (file)
index 0000000..dcd63f7
--- /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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _SYS_ZRLOCK_H
+#define        _SYS_ZRLOCK_H
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zrlock {
+       kmutex_t zr_mtx;
+       volatile int32_t zr_refcount;
+       kcondvar_t zr_cv;
+       uint16_t zr_pad;
+#ifdef ZFS_DEBUG
+       kthread_t *zr_owner;
+       const char *zr_caller;
+#endif
+} zrlock_t;
+
+extern void zrl_init(zrlock_t *);
+extern void zrl_destroy(zrlock_t *);
+#ifdef ZFS_DEBUG
+#define        zrl_add(_z)     zrl_add_debug((_z), __func__)
+extern void zrl_add_debug(zrlock_t *, const char *);
+#else
+extern void zrl_add(zrlock_t *);
+#endif
+extern void zrl_remove(zrlock_t *);
+extern int zrl_tryenter(zrlock_t *);
+extern void zrl_exit(zrlock_t *);
+extern int zrl_is_zero(zrlock_t *);
+extern int zrl_is_locked(zrlock_t *);
+#ifdef ZFS_DEBUG
+extern kthread_t *zrl_owner(zrlock_t *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZRLOCK_H */
diff --git a/zfs/include/sys/zvol.h b/zfs/include/sys/zvol.h
new file mode 100644 (file)
index 0000000..c3e386f
--- /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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+#ifndef        _SYS_ZVOL_H
+#define        _SYS_ZVOL_H
+
+#include <sys/zfs_context.h>
+
+#define        ZVOL_OBJ                1ULL
+#define        ZVOL_ZAP_OBJ            2ULL
+
+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,
+    const char *newname, boolean_t async);
+
+#ifdef _KERNEL
+extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize);
+extern int zvol_check_volblocksize(const char *name, uint64_t volblocksize);
+extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
+extern boolean_t zvol_is_zvol(const char *);
+extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
+extern int zvol_set_volsize(const char *, uint64_t);
+extern int zvol_set_volblocksize(const char *, uint64_t);
+extern int zvol_set_snapdev(const char *, zprop_source_t, uint64_t);
+
+extern int zvol_init(void);
+extern void zvol_fini(void);
+#endif /* _KERNEL */
+#endif /* _SYS_ZVOL_H */
diff --git a/zfs/include/zfeature_common.h b/zfs/include/zfeature_common.h
new file mode 100644 (file)
index 0000000..e383c4f
--- /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 (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ */
+
+#ifndef _ZFEATURE_COMMON_H
+#define        _ZFEATURE_COMMON_H
+
+#include <sys/fs/zfs.h>
+#include <sys/inttypes.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct zfeature_info;
+
+typedef enum spa_feature {
+       SPA_FEATURE_NONE = -1,
+       SPA_FEATURE_ASYNC_DESTROY,
+       SPA_FEATURE_EMPTY_BPOBJ,
+       SPA_FEATURE_LZ4_COMPRESS,
+       SPA_FEATURE_SPACEMAP_HISTOGRAM,
+       SPA_FEATURE_ENABLED_TXG,
+       SPA_FEATURE_HOLE_BIRTH,
+       SPA_FEATURE_EXTENSIBLE_DATASET,
+       SPA_FEATURE_EMBEDDED_DATA,
+       SPA_FEATURE_BOOKMARKS,
+       SPA_FEATURE_FS_SS_LIMIT,
+       SPA_FEATURE_LARGE_BLOCKS,
+       SPA_FEATURES
+} spa_feature_t;
+
+#define        SPA_FEATURE_DISABLED    (-1ULL)
+
+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;
+       /* array of dependencies, terminated by SPA_FEATURE_NONE */
+       const spa_feature_t *fi_depends;
+} zfeature_info_t;
+
+typedef int (zfeature_func_t)(zfeature_info_t *, void *);
+
+#define        ZFS_FEATURE_DEBUG
+
+extern zfeature_info_t spa_feature_table[SPA_FEATURES];
+
+extern boolean_t zfeature_is_valid_guid(const char *);
+
+extern boolean_t zfeature_is_supported(const char *);
+extern int zfeature_lookup_name(const char *, spa_feature_t *);
+extern boolean_t zfeature_depends_on(spa_feature_t, spa_feature_t);
+
+extern void zpool_feature_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFEATURE_COMMON_H */
diff --git a/zfs/include/zfs_comutil.h b/zfs/include/zfs_comutil.h
new file mode 100644 (file)
index 0000000..f890543
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef        _ZFS_COMUTIL_H
+#define        _ZFS_COMUTIL_H
+
+#include <sys/fs/zfs.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern boolean_t zfs_allocatable_devs(nvlist_t *);
+extern void zpool_get_rewind_policy(nvlist_t *, zpool_rewind_policy_t *);
+
+extern int zfs_zpl_version_map(int spa_version);
+extern int zfs_spa_version_map(int zpl_version);
+#define        ZFS_NUM_LEGACY_HISTORY_EVENTS 41
+extern const char *zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_COMUTIL_H */
diff --git a/zfs/include/zfs_deleg.h b/zfs/include/zfs_deleg.h
new file mode 100644 (file)
index 0000000..16133c5
--- /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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _ZFS_DELEG_H
+#define        _ZFS_DELEG_H
+
+#include <sys/fs/zfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        ZFS_DELEG_SET_NAME_CHR          '@'             /* set name lead char */
+#define        ZFS_DELEG_FIELD_SEP_CHR         '$'             /* field separator */
+
+/*
+ * Max name length for a delegation attribute
+ */
+#define        ZFS_MAX_DELEG_NAME      128
+
+#define        ZFS_DELEG_LOCAL         'l'
+#define        ZFS_DELEG_DESCENDENT    'd'
+#define        ZFS_DELEG_NA            '-'
+
+typedef enum {
+       ZFS_DELEG_NOTE_CREATE,
+       ZFS_DELEG_NOTE_DESTROY,
+       ZFS_DELEG_NOTE_SNAPSHOT,
+       ZFS_DELEG_NOTE_ROLLBACK,
+       ZFS_DELEG_NOTE_CLONE,
+       ZFS_DELEG_NOTE_PROMOTE,
+       ZFS_DELEG_NOTE_RENAME,
+       ZFS_DELEG_NOTE_SEND,
+       ZFS_DELEG_NOTE_RECEIVE,
+       ZFS_DELEG_NOTE_ALLOW,
+       ZFS_DELEG_NOTE_USERPROP,
+       ZFS_DELEG_NOTE_MOUNT,
+       ZFS_DELEG_NOTE_SHARE,
+       ZFS_DELEG_NOTE_USERQUOTA,
+       ZFS_DELEG_NOTE_GROUPQUOTA,
+       ZFS_DELEG_NOTE_USERUSED,
+       ZFS_DELEG_NOTE_GROUPUSED,
+       ZFS_DELEG_NOTE_HOLD,
+       ZFS_DELEG_NOTE_RELEASE,
+       ZFS_DELEG_NOTE_DIFF,
+       ZFS_DELEG_NOTE_BOOKMARK,
+       ZFS_DELEG_NOTE_NONE
+} zfs_deleg_note_t;
+
+typedef struct zfs_deleg_perm_tab {
+       char *z_perm;
+       zfs_deleg_note_t z_note;
+} zfs_deleg_perm_tab_t;
+
+extern zfs_deleg_perm_tab_t zfs_deleg_perm_tab[];
+
+int zfs_deleg_verify_nvlist(nvlist_t *nvlist);
+void zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
+    char checkflag, void *data);
+const char *zfs_deleg_canonicalize_perm(const char *perm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_DELEG_H */
diff --git a/zfs/include/zfs_fletcher.h b/zfs/include/zfs_fletcher.h
new file mode 100644 (file)
index 0000000..b49df0c
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _ZFS_FLETCHER_H
+#define        _ZFS_FLETCHER_H
+
+#include <sys/types.h>
+#include <sys/spa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * fletcher checksum functions
+ */
+
+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_4_incremental_native(const void *, uint64_t,
+    zio_cksum_t *);
+void fletcher_4_incremental_byteswap(const void *, uint64_t,
+    zio_cksum_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_FLETCHER_H */
diff --git a/zfs/include/zfs_namecheck.h b/zfs/include/zfs_namecheck.h
new file mode 100644 (file)
index 0000000..cbefbaa
--- /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 (c) 2013 by Delphix. All rights reserved.
+ */
+
+#ifndef        _ZFS_NAMECHECK_H
+#define        _ZFS_NAMECHECK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       NAME_ERR_LEADING_SLASH,         /* name begins with leading slash */
+       NAME_ERR_EMPTY_COMPONENT,       /* name contains an empty component */
+       NAME_ERR_TRAILING_SLASH,        /* name ends with a slash */
+       NAME_ERR_INVALCHAR,             /* invalid character found */
+       NAME_ERR_MULTIPLE_AT,           /* multiple '@' characters found */
+       NAME_ERR_NOLETTER,              /* pool doesn't begin with a letter */
+       NAME_ERR_RESERVED,              /* entire name is reserved */
+       NAME_ERR_DISKLIKE,              /* reserved disk name (c[0-9].*) */
+       NAME_ERR_TOOLONG,               /* name is too long */
+       NAME_ERR_NO_AT,                 /* permission set is missing '@' */
+} namecheck_err_t;
+
+#define        ZFS_PERMSET_MAXLEN      64
+
+int pool_namecheck(const char *, namecheck_err_t *, char *);
+int dataset_namecheck(const char *, namecheck_err_t *, char *);
+int mountpoint_namecheck(const char *, namecheck_err_t *);
+int zfs_component_namecheck(const char *, namecheck_err_t *, char *);
+int permset_namecheck(const char *, namecheck_err_t *, char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_NAMECHECK_H */
diff --git a/zfs/include/zfs_prop.h b/zfs/include/zfs_prop.h
new file mode 100644 (file)
index 0000000..5e7d3f5
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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        _ZFS_PROP_H
+#define        _ZFS_PROP_H
+
+#include <sys/fs/zfs.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * For index types (e.g. compression and checksum), we want the numeric value
+ * in the kernel, but the string value in userland.
+ */
+typedef enum {
+       PROP_TYPE_NUMBER,       /* numeric value */
+       PROP_TYPE_STRING,       /* string value */
+       PROP_TYPE_INDEX         /* numeric value indexed by string */
+} zprop_type_t;
+
+typedef enum {
+       PROP_DEFAULT,
+       PROP_READONLY,
+       PROP_INHERIT,
+       /*
+        * ONETIME properties are a sort of conglomeration of READONLY
+        * and INHERIT.  They can be set only during object creation,
+        * after that they are READONLY.  If not explicitly set during
+        * creation, they can be inherited.
+        */
+       PROP_ONETIME
+} zprop_attr_t;
+
+typedef struct zfs_index {
+       const char *pi_name;
+       uint64_t pi_value;
+} zprop_index_t;
+
+typedef struct {
+       const char *pd_name;            /* human-readable property name */
+       int pd_propnum;                 /* property number */
+       zprop_type_t pd_proptype;       /* string, boolean, index, number */
+       const char *pd_strdefault;      /* default for strings */
+       uint64_t pd_numdefault;         /* for boolean / index / number */
+       zprop_attr_t pd_attr;           /* default, readonly, inherit */
+       int pd_types;                   /* bitfield of valid dataset types */
+                                       /* fs | vol | snap; or pool */
+       const char *pd_values;          /* string telling acceptable values */
+       const char *pd_colname;         /* column header for "zfs list" */
+       boolean_t pd_rightalign;        /* column alignment for "zfs list" */
+       boolean_t pd_visible;           /* do we list this property with the */
+                                       /* "zfs get" help message */
+       const zprop_index_t *pd_table;  /* for index properties, a table */
+                                       /* defining the possible values */
+       size_t pd_table_size;           /* number of entries in pd_table[] */
+} zprop_desc_t;
+
+/*
+ * zfs dataset property functions
+ */
+void zfs_prop_init(void);
+zprop_type_t zfs_prop_get_type(zfs_prop_t);
+boolean_t zfs_prop_delegatable(zfs_prop_t prop);
+zprop_desc_t *zfs_prop_get_table(void);
+
+/*
+ * zpool property functions
+ */
+void zpool_prop_init(void);
+zprop_type_t zpool_prop_get_type(zpool_prop_t);
+zprop_desc_t *zpool_prop_get_table(void);
+
+/*
+ * Common routines to initialize property tables
+ */
+void zprop_register_impl(int, const char *, zprop_type_t, uint64_t,
+    const char *, zprop_attr_t, int, const char *, const char *,
+    boolean_t, boolean_t, const zprop_index_t *);
+void zprop_register_string(int, const char *, const char *,
+    zprop_attr_t attr, int, const char *, const char *);
+void zprop_register_number(int, const char *, uint64_t, zprop_attr_t, int,
+    const char *, const char *);
+void zprop_register_index(int, const char *, uint64_t, zprop_attr_t, int,
+    const char *, const char *, const zprop_index_t *);
+void zprop_register_hidden(int, const char *, zprop_type_t, zprop_attr_t,
+    int, const char *);
+
+/*
+ * Common routines for zfs and zpool property management
+ */
+int zprop_iter_common(zprop_func, void *, boolean_t, boolean_t, zfs_type_t);
+int zprop_name_to_prop(const char *, zfs_type_t);
+int zprop_string_to_index(int, const char *, uint64_t *, zfs_type_t);
+int zprop_index_to_string(int, uint64_t, const char **, zfs_type_t);
+uint64_t zprop_random_value(int, uint64_t, zfs_type_t);
+const char *zprop_values(int, zfs_type_t);
+size_t zprop_width(int, boolean_t *, zfs_type_t);
+boolean_t zprop_valid_for_type(int, zfs_type_t, boolean_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_PROP_H */
diff --git a/zfs/include/zpios-ctl.h b/zfs/include/zpios-ctl.h
new file mode 100644 (file)
index 0000000..9a47ff9
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  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/>.
+ */
+
+#ifndef _ZPIOS_CTL_H
+#define        _ZPIOS_CTL_H
+
+/*
+ * Contains shared definitions which both the userspace
+ * and kernelspace portions of zpios must agree on.
+ */
+#ifndef _KERNEL
+#include <stdint.h>
+#endif
+
+#define        ZPIOS_NAME                      "zpios"
+#define        ZPIOS_DEV                       "/dev/zpios"
+
+#define        DMU_IO                          0x01
+
+#define        DMU_WRITE                       0x0001
+#define        DMU_READ                        0x0002
+#define        DMU_VERIFY                      0x0004
+#define        DMU_REMOVE                      0x0008
+#define        DMU_FPP                         0x0010
+#define        DMU_WRITE_ZC                    0x0020 /* Incompatible w/DMU_VERIFY */
+#define        DMU_READ_ZC                     0x0040 /* Incompatible w/DMU_VERIFY */
+#define        DMU_WRITE_NOWAIT                0x0080
+#define        DMU_READ_NOPF                   0x0100
+
+#define        ZPIOS_NAME_SIZE                 16
+#define        ZPIOS_PATH_SIZE                 128
+
+#define        PHASE_PRE_RUN                   "pre-run"
+#define        PHASE_PRE_CREATE                "pre-create"
+#define        PHASE_PRE_WRITE                 "pre-write"
+#define        PHASE_PRE_READ                  "pre-read"
+#define        PHASE_PRE_REMOVE                "pre-remove"
+#define        PHASE_POST_RUN                  "post-run"
+#define        PHASE_POST_CREATE               "post-create"
+#define        PHASE_POST_WRITE                "post-write"
+#define        PHASE_POST_READ                 "post-read"
+#define        PHASE_POST_REMOVE               "post-remove"
+
+#define        ZPIOS_CFG_MAGIC                 0x87237190U
+typedef struct zpios_cfg {
+       uint32_t cfg_magic;             /* Unique magic */
+       int32_t cfg_cmd;                /* Config command */
+       int32_t cfg_arg1;               /* Config command arg 1 */
+       int32_t cfg_rc1;                /* Config response 1 */
+} zpios_cfg_t;
+
+typedef struct zpios_timespec {
+       uint32_t ts_sec;
+       uint32_t ts_nsec;
+} zpios_timespec_t;
+
+typedef struct zpios_time {
+       zpios_timespec_t start;
+       zpios_timespec_t stop;
+       zpios_timespec_t delta;
+} zpios_time_t;
+
+typedef struct zpios_stats {
+       zpios_time_t total_time;
+       zpios_time_t cr_time;
+       zpios_time_t rm_time;
+       zpios_time_t wr_time;
+       zpios_time_t rd_time;
+       uint64_t wr_data;
+       uint64_t wr_chunks;
+       uint64_t rd_data;
+       uint64_t rd_chunks;
+} zpios_stats_t;
+
+#define        ZPIOS_CMD_MAGIC                 0x49715385U
+typedef struct zpios_cmd {
+       uint32_t cmd_magic;             /* Unique magic */
+       uint32_t cmd_id;                /* Run ID */
+       char cmd_pool[ZPIOS_NAME_SIZE]; /* Pool name */
+       uint64_t cmd_chunk_size;        /* Chunk size */
+       uint32_t cmd_thread_count;      /* Thread count */
+       uint32_t cmd_region_count;      /* Region count */
+       uint64_t cmd_region_size;       /* Region size */
+       uint64_t cmd_offset;            /* Region offset */
+       uint32_t cmd_region_noise;      /* Region noise */
+       uint32_t cmd_chunk_noise;       /* Chunk noise */
+       uint32_t cmd_thread_delay;      /* Thread delay */
+       uint32_t cmd_flags;             /* Test flags */
+       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 */
+       uint64_t cmd_data_size;         /* Opaque data size */
+       char cmd_data_str[0];           /* Opaque data region */
+} zpios_cmd_t;
+
+/* Valid ioctls */
+#define        ZPIOS_CFG                       _IOWR('f', 101, zpios_cfg_t)
+#define        ZPIOS_CMD                       _IOWR('f', 102, zpios_cmd_t)
+
+/* Valid configuration commands */
+#define        ZPIOS_CFG_BUFFER_CLEAR          0x001   /* Clear text buffer */
+#define        ZPIOS_CFG_BUFFER_SIZE           0x002   /* Resize text buffer */
+
+#ifndef NSEC_PER_SEC
+#define        NSEC_PER_SEC    1000000000L
+#endif
+
+static inline
+void
+zpios_timespec_normalize(zpios_timespec_t *ts, uint32_t sec, uint32_t nsec)
+{
+       while (nsec >= NSEC_PER_SEC) {
+               nsec -= NSEC_PER_SEC;
+               sec++;
+       }
+       while (nsec < 0) {
+               nsec += NSEC_PER_SEC;
+               sec--;
+       }
+       ts->ts_sec = sec;
+       ts->ts_nsec = nsec;
+}
+
+static inline
+zpios_timespec_t
+zpios_timespec_add(zpios_timespec_t lhs, zpios_timespec_t rhs)
+{
+       zpios_timespec_t ts_delta;
+       zpios_timespec_normalize(&ts_delta, lhs.ts_sec + rhs.ts_sec,
+           lhs.ts_nsec + rhs.ts_nsec);
+       return (ts_delta);
+}
+
+static inline
+zpios_timespec_t
+zpios_timespec_sub(zpios_timespec_t lhs, zpios_timespec_t rhs)
+{
+       zpios_timespec_t ts_delta;
+       zpios_timespec_normalize(&ts_delta, lhs.ts_sec - rhs.ts_sec,
+           lhs.ts_nsec - rhs.ts_nsec);
+       return (ts_delta);
+}
+
+#ifdef _KERNEL
+
+static inline
+zpios_timespec_t
+zpios_timespec_now(void)
+{
+       zpios_timespec_t zts_now;
+       struct timespec ts_now;
+
+       ts_now = current_kernel_time();
+       zts_now.ts_sec  = ts_now.tv_sec;
+       zts_now.ts_nsec = ts_now.tv_nsec;
+
+       return (zts_now);
+}
+
+#else
+
+static inline
+double
+zpios_timespec_to_double(zpios_timespec_t ts)
+{
+       return
+           ((double)(ts.ts_sec) +
+           ((double)(ts.ts_nsec) / (double)(NSEC_PER_SEC)));
+}
+
+#endif /* _KERNEL */
+
+#endif /* _ZPIOS_CTL_H */
diff --git a/zfs/include/zpios-internal.h b/zfs/include/zpios-internal.h
new file mode 100644 (file)
index 0000000..4b99b4c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  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/>.
+ */
+
+#ifndef _ZPIOS_INTERNAL_H
+#define        _ZPIOS_INTERNAL_H
+
+#include "zpios-ctl.h"
+
+#define        OBJ_SIZE        64
+
+struct run_args;
+
+typedef struct dmu_obj {
+       objset_t *os;
+       uint64_t obj;
+} dmu_obj_t;
+
+/* thread doing the IO data */
+typedef struct thread_data {
+       struct run_args *run_args;
+       int thread_no;
+       int rc;
+       zpios_stats_t stats;
+       kmutex_t lock;
+} thread_data_t;
+
+/* region for IO data */
+typedef struct zpios_region {
+       __u64 wr_offset;
+       __u64 rd_offset;
+       __u64 init_offset;
+       __u64 max_offset;
+       dmu_obj_t obj;
+       zpios_stats_t stats;
+       kmutex_t lock;
+} zpios_region_t;
+
+/* arguments for one run */
+typedef struct run_args {
+       /* Config args */
+       int id;
+       char pool[ZPIOS_NAME_SIZE];
+       __u64 chunk_size;
+       __u32 thread_count;
+       __u32 region_count;
+       __u64 region_size;
+       __u64 offset;
+       __u32 region_noise;
+       __u32 chunk_noise;
+       __u32 thread_delay;
+       __u32 flags;
+       char pre[ZPIOS_PATH_SIZE];
+       char post[ZPIOS_PATH_SIZE];
+       char log[ZPIOS_PATH_SIZE];
+
+       /* Control data */
+       objset_t *os;
+       wait_queue_head_t waitq;
+       volatile uint64_t threads_done;
+       kmutex_t lock_work;
+       kmutex_t lock_ctl;
+       __u32 region_next;
+
+       /* Results data */
+       struct file *file;
+       zpios_stats_t stats;
+
+       thread_data_t **threads;
+       zpios_region_t regions[0]; /* Must be last element */
+} run_args_t;
+
+#define        ZPIOS_INFO_BUFFER_SIZE          65536
+#define        ZPIOS_INFO_BUFFER_REDZONE       1024
+
+typedef struct zpios_info {
+       spinlock_t info_lock;
+       int info_size;
+       char *info_buffer;
+       char *info_head;        /* Internal kernel use only */
+} zpios_info_t;
+
+#endif /* _ZPIOS_INTERNAL_H */
diff --git a/zfs/module/Makefile.in b/zfs/module/Makefile.in
new file mode 100644 (file)
index 0000000..d4ddee2
--- /dev/null
@@ -0,0 +1,75 @@
+subdir-m += avl
+subdir-m += nvpair
+subdir-m += unicode
+subdir-m += zcommon
+subdir-m += zfs
+subdir-m += zpios
+
+INSTALL_MOD_DIR ?= extra
+
+ZFS_MODULE_CFLAGS += -include @SPL_OBJ@/spl_config.h
+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
+
+modules:
+       @# Make the exported SPL symbols available to these modules.
+       @# They may be in the root of SPL_OBJ when building against
+       @# installed devel headers, or they may be in the module
+       @# subdirectory when building against the spl source tree.
+       @if [ -f @SPL_OBJ@/@SPL_SYMBOLS@ ]; then \
+               /bin/cp @SPL_OBJ@/@SPL_SYMBOLS@ .; \
+       elif [ -f @SPL_OBJ@/module/@SPL_SYMBOLS@ ]; then \
+               /bin/cp @SPL_OBJ@/module/@SPL_SYMBOLS@ .; \
+       else \
+               echo -e "\n" \
+               "*** Missing spl symbols ensure you have built the spl:\n" \
+               "*** - @SPL_OBJ@/@SPL_SYMBOLS@, or\n" \
+               "*** - @SPL_OBJ@/module/@SPL_SYMBOLS@\n"; \
+               exit 1; \
+       fi
+       $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ CONFIG_ZFS=m $@
+
+clean:
+       @# Only cleanup the kernel build directories when CONFIG_KERNEL
+       @# is defined.  This indicates that kernel modules should be built.
+@CONFIG_KERNEL_TRUE@   $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ $@
+
+       if [ -f @SPL_SYMBOLS@ ]; then $(RM) @SPL_SYMBOLS@; fi
+       if [ -f @LINUX_SYMBOLS@ ]; then $(RM) @LINUX_SYMBOLS@; fi
+       if [ -f Module.markers ]; then $(RM) Module.markers; fi
+
+modules_install:
+       @# Install the kernel modules
+       $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` $@ \
+               INSTALL_MOD_PATH=$(DESTDIR)$(INSTALL_MOD_PATH) \
+               INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \
+               KERNELRELEASE=@LINUX_VERSION@
+       @# Remove extraneous build products when packaging
+       kmoddir=$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@; \
+       if [ -n "$(DESTDIR)" ]; then \
+               find $$kmoddir -name 'modules.*' | xargs $(RM); \
+       fi
+       sysmap=$(DESTDIR)$(INSTALL_MOD_PATH)/boot/System.map-@LINUX_VERSION@; \
+       if [ -f $$sysmap ]; then \
+               depmod -ae -F $$sysmap @LINUX_VERSION@; \
+       fi
+
+modules_uninstall:
+       @# Uninstall the kernel modules
+       kmoddir=$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@
+       list='$(subdir-m)'; for subdir in $$list; do \
+               $(RM) -R $$kmoddir/$(INSTALL_MOD_DIR)/$$subdir; \
+       done
+
+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); \
+       done
+
+distclean maintainer-clean: clean
+install: modules_install
+uninstall: modules_uninstall
+all: modules
+check:
diff --git a/zfs/module/avl/Makefile.in b/zfs/module/avl/Makefile.in
new file mode 100644 (file)
index 0000000..98c011e
--- /dev/null
@@ -0,0 +1,10 @@
+src = @abs_top_srcdir@/module/avl
+obj = @abs_builddir@
+
+MODULE := zavl
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+$(MODULE)-objs += avl.o
diff --git a/zfs/module/avl/avl.c b/zfs/module/avl/avl.c
new file mode 100644 (file)
index 0000000..86183fe
--- /dev/null
@@ -0,0 +1,1096 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+/*
+ * AVL - generic AVL tree implementation for kernel use
+ *
+ * A complete description of AVL trees can be found in many CS textbooks.
+ *
+ * Here is a very brief overview. An AVL tree is a binary search tree that is
+ * almost perfectly balanced. By "almost" perfectly balanced, we mean that at
+ * any given node, the left and right subtrees are allowed to differ in height
+ * by at most 1 level.
+ *
+ * This relaxation from a perfectly balanced binary tree allows doing
+ * insertion and deletion relatively efficiently. Searching the tree is
+ * still a fast operation, roughly O(log(N)).
+ *
+ * The key to insertion and deletion is a set of tree manipulations called
+ * rotations, which bring unbalanced subtrees back into the semi-balanced state.
+ *
+ * This implementation of AVL trees has the following peculiarities:
+ *
+ *     - The AVL specific data structures are physically embedded as fields
+ *       in the "using" data structures.  To maintain generality the code
+ *       must constantly translate between "avl_node_t *" and containing
+ *       data structure "void *"s by adding/subtracting the avl_offset.
+ *
+ *     - Since the AVL data is always embedded in other structures, there is
+ *       no locking or memory allocation in the AVL routines. This must be
+ *       provided for by the enclosing data structure's semantics. Typically,
+ *       avl_insert()/_add()/_remove()/avl_insert_here() require some kind of
+ *       exclusive write lock. Other operations require a read lock.
+ *
+ *      - The implementation uses iteration instead of explicit recursion,
+ *       since it is intended to run on limited size kernel stacks. Since
+ *       there is no recursion stack present to move "up" in the tree,
+ *       there is an explicit "parent" link in the avl_node_t.
+ *
+ *      - The left/right children pointers of a node are in an array.
+ *       In the code, variables (instead of constants) are used to represent
+ *       left and right indices.  The implementation is written as if it only
+ *       dealt with left handed manipulations.  By changing the value assigned
+ *       to "left", the code also works for right handed trees.  The
+ *       following variables/terms are frequently used:
+ *
+ *             int left;       // 0 when dealing with left children,
+ *                             // 1 for dealing with right children
+ *
+ *             int left_heavy; // -1 when left subtree is taller at some node,
+ *                             // +1 when right subtree is taller
+ *
+ *             int right;      // will be the opposite of left (0 or 1)
+ *             int right_heavy;// will be the opposite of left_heavy (-1 or 1)
+ *
+ *             int direction;  // 0 for "<" (ie. left child); 1 for ">" (right)
+ *
+ *       Though it is a little more confusing to read the code, the approach
+ *       allows using half as much code (and hence cache footprint) for tree
+ *       manipulations and eliminates many conditional branches.
+ *
+ *     - The avl_index_t is an opaque "cookie" used to find nodes at or
+ *       adjacent to where a new value would be inserted in the tree. The value
+ *       is a modified "avl_node_t *".  The bottom bit (normally 0 for a
+ *       pointer) is set to indicate if that the new node has a value greater
+ *       than the value of the indicated "avl_node_t *".
+ *
+ * Note - in addition to userland (e.g. libavl and libutil) and the kernel
+ * (e.g. genunix), avl.c is compiled into ld.so and kmdb's genunix module,
+ * which each have their own compilation environments and subsequent
+ * requirements. Each of these environments must be considered when adding
+ * dependencies from avl.c.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/debug.h>
+#include <sys/avl.h>
+#include <sys/cmn_err.h>
+
+/*
+ * Small arrays to translate between balance (or diff) values and child indices.
+ *
+ * Code that deals with binary tree data structures will randomly use
+ * left and right children when examining a tree.  C "if()" statements
+ * which evaluate randomly suffer from very poor hardware branch prediction.
+ * In this code we avoid some of the branch mispredictions by using the
+ * following translation arrays. They replace random branches with an
+ * additional memory reference. Since the translation arrays are both very
+ * small the data should remain efficiently in cache.
+ */
+static const int  avl_child2balance[2] = {-1, 1};
+static const int  avl_balance2child[]  = {0, 0, 1};
+
+
+/*
+ * Walk from one node to the previous valued node (ie. an infix walk
+ * towards the left). At any given node we do one of 2 things:
+ *
+ * - If there is a left child, go to it, then to it's rightmost descendant.
+ *
+ * - otherwise we return through parent nodes until we've come from a right
+ *   child.
+ *
+ * Return Value:
+ * NULL - if at the end of the nodes
+ * otherwise next node
+ */
+void *
+avl_walk(avl_tree_t *tree, void        *oldnode, int left)
+{
+       size_t off = tree->avl_offset;
+       avl_node_t *node = AVL_DATA2NODE(oldnode, off);
+       int right = 1 - left;
+       int was_child;
+
+
+       /*
+        * nowhere to walk to if tree is empty
+        */
+       if (node == NULL)
+               return (NULL);
+
+       /*
+        * Visit the previous valued node. There are two possibilities:
+        *
+        * If this node has a left child, go down one left, then all
+        * the way right.
+        */
+       if (node->avl_child[left] != NULL) {
+               for (node = node->avl_child[left];
+                   node->avl_child[right] != NULL;
+                   node = node->avl_child[right])
+                       ;
+       /*
+        * Otherwise, return thru left children as far as we can.
+        */
+       } else {
+               for (;;) {
+                       was_child = AVL_XCHILD(node);
+                       node = AVL_XPARENT(node);
+                       if (node == NULL)
+                               return (NULL);
+                       if (was_child == right)
+                               break;
+               }
+       }
+
+       return (AVL_NODE2DATA(node, off));
+}
+
+/*
+ * Return the lowest valued node in a tree or NULL.
+ * (leftmost child from root of tree)
+ */
+void *
+avl_first(avl_tree_t *tree)
+{
+       avl_node_t *node;
+       avl_node_t *prev = NULL;
+       size_t off = tree->avl_offset;
+
+       for (node = tree->avl_root; node != NULL; node = node->avl_child[0])
+               prev = node;
+
+       if (prev != NULL)
+               return (AVL_NODE2DATA(prev, off));
+       return (NULL);
+}
+
+/*
+ * Return the highest valued node in a tree or NULL.
+ * (rightmost child from root of tree)
+ */
+void *
+avl_last(avl_tree_t *tree)
+{
+       avl_node_t *node;
+       avl_node_t *prev = NULL;
+       size_t off = tree->avl_offset;
+
+       for (node = tree->avl_root; node != NULL; node = node->avl_child[1])
+               prev = node;
+
+       if (prev != NULL)
+               return (AVL_NODE2DATA(prev, off));
+       return (NULL);
+}
+
+/*
+ * Access the node immediately before or after an insertion point.
+ *
+ * "avl_index_t" is a (avl_node_t *) with the bottom bit indicating a child
+ *
+ * Return value:
+ *     NULL: no node in the given direction
+ *     "void *"  of the found tree node
+ */
+void *
+avl_nearest(avl_tree_t *tree, avl_index_t where, int direction)
+{
+       int child = AVL_INDEX2CHILD(where);
+       avl_node_t *node = AVL_INDEX2NODE(where);
+       void *data;
+       size_t off = tree->avl_offset;
+
+       if (node == NULL) {
+               ASSERT(tree->avl_root == NULL);
+               return (NULL);
+       }
+       data = AVL_NODE2DATA(node, off);
+       if (child != direction)
+               return (data);
+
+       return (avl_walk(tree, data, direction));
+}
+
+
+/*
+ * Search for the node which contains "value".  The algorithm is a
+ * simple binary tree search.
+ *
+ * return value:
+ *     NULL: the value is not in the AVL tree
+ *             *where (if not NULL)  is set to indicate the insertion point
+ *     "void *"  of the found tree node
+ */
+void *
+avl_find(avl_tree_t *tree, const void *value, avl_index_t *where)
+{
+       avl_node_t *node;
+       avl_node_t *prev = NULL;
+       int child = 0;
+       int diff;
+       size_t off = tree->avl_offset;
+
+       for (node = tree->avl_root; node != NULL;
+           node = node->avl_child[child]) {
+
+               prev = node;
+
+               diff = tree->avl_compar(value, AVL_NODE2DATA(node, off));
+               ASSERT(-1 <= diff && diff <= 1);
+               if (diff == 0) {
+#ifdef DEBUG
+                       if (where != NULL)
+                               *where = 0;
+#endif
+                       return (AVL_NODE2DATA(node, off));
+               }
+               child = avl_balance2child[1 + diff];
+
+       }
+
+       if (where != NULL)
+               *where = AVL_MKINDEX(prev, child);
+
+       return (NULL);
+}
+
+
+/*
+ * Perform a rotation to restore balance at the subtree given by depth.
+ *
+ * This routine is used by both insertion and deletion. The return value
+ * indicates:
+ *      0 : subtree did not change height
+ *     !0 : subtree was reduced in height
+ *
+ * The code is written as if handling left rotations, right rotations are
+ * symmetric and handled by swapping values of variables right/left[_heavy]
+ *
+ * On input balance is the "new" balance at "node". This value is either
+ * -2 or +2.
+ */
+static int
+avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
+{
+       int left = !(balance < 0);      /* when balance = -2, left will be 0 */
+       int right = 1 - left;
+       int left_heavy = balance >> 1;
+       int right_heavy = -left_heavy;
+       avl_node_t *parent = AVL_XPARENT(node);
+       avl_node_t *child = node->avl_child[left];
+       avl_node_t *cright;
+       avl_node_t *gchild;
+       avl_node_t *gright;
+       avl_node_t *gleft;
+       int which_child = AVL_XCHILD(node);
+       int child_bal = AVL_XBALANCE(child);
+
+       /* BEGIN CSTYLED */
+       /*
+        * case 1 : node is overly left heavy, the left child is balanced or
+        * also left heavy. This requires the following rotation.
+        *
+        *                   (node bal:-2)
+        *                    /           \
+        *                   /             \
+        *              (child bal:0 or -1)
+        *              /    \
+        *             /      \
+        *                     cright
+        *
+        * becomes:
+        *
+        *              (child bal:1 or 0)
+        *              /        \
+        *             /          \
+        *                        (node bal:-1 or 0)
+        *                         /     \
+        *                        /       \
+        *                     cright
+        *
+        * we detect this situation by noting that child's balance is not
+        * right_heavy.
+        */
+       /* END CSTYLED */
+       if (child_bal != right_heavy) {
+
+               /*
+                * compute new balance of nodes
+                *
+                * If child used to be left heavy (now balanced) we reduced
+                * the height of this sub-tree -- used in "return...;" below
+                */
+               child_bal += right_heavy; /* adjust towards right */
+
+               /*
+                * move "cright" to be node's left child
+                */
+               cright = child->avl_child[right];
+               node->avl_child[left] = cright;
+               if (cright != NULL) {
+                       AVL_SETPARENT(cright, node);
+                       AVL_SETCHILD(cright, left);
+               }
+
+               /*
+                * move node to be child's right child
+                */
+               child->avl_child[right] = node;
+               AVL_SETBALANCE(node, -child_bal);
+               AVL_SETCHILD(node, right);
+               AVL_SETPARENT(node, child);
+
+               /*
+                * update the pointer into this subtree
+                */
+               AVL_SETBALANCE(child, child_bal);
+               AVL_SETCHILD(child, which_child);
+               AVL_SETPARENT(child, parent);
+               if (parent != NULL)
+                       parent->avl_child[which_child] = child;
+               else
+                       tree->avl_root = child;
+
+               return (child_bal == 0);
+       }
+
+       /* BEGIN CSTYLED */
+       /*
+        * case 2 : When node is left heavy, but child is right heavy we use
+        * a different rotation.
+        *
+        *                   (node b:-2)
+        *                    /   \
+        *                   /     \
+        *                  /       \
+        *             (child b:+1)
+        *              /     \
+        *             /       \
+        *                   (gchild b: != 0)
+        *                     /  \
+        *                    /    \
+        *                 gleft   gright
+        *
+        * becomes:
+        *
+        *              (gchild b:0)
+        *              /       \
+        *             /         \
+        *            /           \
+        *        (child b:?)   (node b:?)
+        *         /  \          /   \
+        *        /    \        /     \
+        *            gleft   gright
+        *
+        * computing the new balances is more complicated. As an example:
+        *       if gchild was right_heavy, then child is now left heavy
+        *              else it is balanced
+        */
+       /* END CSTYLED */
+       gchild = child->avl_child[right];
+       gleft = gchild->avl_child[left];
+       gright = gchild->avl_child[right];
+
+       /*
+        * move gright to left child of node and
+        *
+        * move gleft to right child of node
+        */
+       node->avl_child[left] = gright;
+       if (gright != NULL) {
+               AVL_SETPARENT(gright, node);
+               AVL_SETCHILD(gright, left);
+       }
+
+       child->avl_child[right] = gleft;
+       if (gleft != NULL) {
+               AVL_SETPARENT(gleft, child);
+               AVL_SETCHILD(gleft, right);
+       }
+
+       /*
+        * move child to left child of gchild and
+        *
+        * move node to right child of gchild and
+        *
+        * fixup parent of all this to point to gchild
+        */
+       balance = AVL_XBALANCE(gchild);
+       gchild->avl_child[left] = child;
+       AVL_SETBALANCE(child, (balance == right_heavy ? left_heavy : 0));
+       AVL_SETPARENT(child, gchild);
+       AVL_SETCHILD(child, left);
+
+       gchild->avl_child[right] = node;
+       AVL_SETBALANCE(node, (balance == left_heavy ? right_heavy : 0));
+       AVL_SETPARENT(node, gchild);
+       AVL_SETCHILD(node, right);
+
+       AVL_SETBALANCE(gchild, 0);
+       AVL_SETPARENT(gchild, parent);
+       AVL_SETCHILD(gchild, which_child);
+       if (parent != NULL)
+               parent->avl_child[which_child] = gchild;
+       else
+               tree->avl_root = gchild;
+
+       return (1);     /* the new tree is always shorter */
+}
+
+
+/*
+ * Insert a new node into an AVL tree at the specified (from avl_find()) place.
+ *
+ * Newly inserted nodes are always leaf nodes in the tree, since avl_find()
+ * searches out to the leaf positions.  The avl_index_t indicates the node
+ * which will be the parent of the new node.
+ *
+ * After the node is inserted, a single rotation further up the tree may
+ * be necessary to maintain an acceptable AVL balance.
+ */
+void
+avl_insert(avl_tree_t *tree, void *new_data, avl_index_t where)
+{
+       avl_node_t *node;
+       avl_node_t *parent = AVL_INDEX2NODE(where);
+       int old_balance;
+       int new_balance;
+       int which_child = AVL_INDEX2CHILD(where);
+       size_t off = tree->avl_offset;
+
+       ASSERT(tree);
+#ifdef _LP64
+       ASSERT(((uintptr_t)new_data & 0x7) == 0);
+#endif
+
+       node = AVL_DATA2NODE(new_data, off);
+
+       /*
+        * First, add the node to the tree at the indicated position.
+        */
+       ++tree->avl_numnodes;
+
+       node->avl_child[0] = NULL;
+       node->avl_child[1] = NULL;
+
+       AVL_SETCHILD(node, which_child);
+       AVL_SETBALANCE(node, 0);
+       AVL_SETPARENT(node, parent);
+       if (parent != NULL) {
+               ASSERT(parent->avl_child[which_child] == NULL);
+               parent->avl_child[which_child] = node;
+       } else {
+               ASSERT(tree->avl_root == NULL);
+               tree->avl_root = node;
+       }
+       /*
+        * Now, back up the tree modifying the balance of all nodes above the
+        * insertion point. If we get to a highly unbalanced ancestor, we
+        * need to do a rotation.  If we back out of the tree we are done.
+        * If we brought any subtree into perfect balance (0), we are also done.
+        */
+       for (;;) {
+               node = parent;
+               if (node == NULL)
+                       return;
+
+               /*
+                * Compute the new balance
+                */
+               old_balance = AVL_XBALANCE(node);
+               new_balance = old_balance + avl_child2balance[which_child];
+
+               /*
+                * If we introduced equal balance, then we are done immediately
+                */
+               if (new_balance == 0) {
+                       AVL_SETBALANCE(node, 0);
+                       return;
+               }
+
+               /*
+                * If both old and new are not zero we went
+                * from -1 to -2 balance, do a rotation.
+                */
+               if (old_balance != 0)
+                       break;
+
+               AVL_SETBALANCE(node, new_balance);
+               parent = AVL_XPARENT(node);
+               which_child = AVL_XCHILD(node);
+       }
+
+       /*
+        * perform a rotation to fix the tree and return
+        */
+       (void) avl_rotation(tree, node, new_balance);
+}
+
+/*
+ * Insert "new_data" in "tree" in the given "direction" either after or
+ * before (AVL_AFTER, AVL_BEFORE) the data "here".
+ *
+ * Insertions can only be done at empty leaf points in the tree, therefore
+ * if the given child of the node is already present we move to either
+ * the AVL_PREV or AVL_NEXT and reverse the insertion direction. Since
+ * every other node in the tree is a leaf, this always works.
+ *
+ * To help developers using this interface, we assert that the new node
+ * is correctly ordered at every step of the way in DEBUG kernels.
+ */
+void
+avl_insert_here(
+       avl_tree_t *tree,
+       void *new_data,
+       void *here,
+       int direction)
+{
+       avl_node_t *node;
+       int child = direction;  /* rely on AVL_BEFORE == 0, AVL_AFTER == 1 */
+#ifdef DEBUG
+       int diff;
+#endif
+
+       ASSERT(tree != NULL);
+       ASSERT(new_data != NULL);
+       ASSERT(here != NULL);
+       ASSERT(direction == AVL_BEFORE || direction == AVL_AFTER);
+
+       /*
+        * If corresponding child of node is not NULL, go to the neighboring
+        * node and reverse the insertion direction.
+        */
+       node = AVL_DATA2NODE(here, tree->avl_offset);
+
+#ifdef DEBUG
+       diff = tree->avl_compar(new_data, here);
+       ASSERT(-1 <= diff && diff <= 1);
+       ASSERT(diff != 0);
+       ASSERT(diff > 0 ? child == 1 : child == 0);
+#endif
+
+       if (node->avl_child[child] != NULL) {
+               node = node->avl_child[child];
+               child = 1 - child;
+               while (node->avl_child[child] != NULL) {
+#ifdef DEBUG
+                       diff = tree->avl_compar(new_data,
+                           AVL_NODE2DATA(node, tree->avl_offset));
+                       ASSERT(-1 <= diff && diff <= 1);
+                       ASSERT(diff != 0);
+                       ASSERT(diff > 0 ? child == 1 : child == 0);
+#endif
+                       node = node->avl_child[child];
+               }
+#ifdef DEBUG
+               diff = tree->avl_compar(new_data,
+                   AVL_NODE2DATA(node, tree->avl_offset));
+               ASSERT(-1 <= diff && diff <= 1);
+               ASSERT(diff != 0);
+               ASSERT(diff > 0 ? child == 1 : child == 0);
+#endif
+       }
+       ASSERT(node->avl_child[child] == NULL);
+
+       avl_insert(tree, new_data, AVL_MKINDEX(node, child));
+}
+
+/*
+ * Add a new node to an AVL tree.
+ */
+void
+avl_add(avl_tree_t *tree, void *new_node)
+{
+       avl_index_t where = 0;
+
+       /*
+        * This is unfortunate.  We want to call panic() here, even for
+        * non-DEBUG kernels.  In userland, however, we can't depend on anything
+        * in libc or else the rtld build process gets confused.  So, all we can
+        * do in userland is resort to a normal ASSERT().
+        */
+       if (avl_find(tree, new_node, &where) != NULL)
+#ifdef _KERNEL
+               panic("avl_find() succeeded inside avl_add()");
+#else
+               ASSERT(0);
+#endif
+       avl_insert(tree, new_node, where);
+}
+
+/*
+ * Delete a node from the AVL tree.  Deletion is similar to insertion, but
+ * with 2 complications.
+ *
+ * First, we may be deleting an interior node. Consider the following subtree:
+ *
+ *     d           c            c
+ *    / \         / \          / \
+ *   b   e       b   e        b   e
+ *  / \                / \          /
+ * a   c       a            a
+ *
+ * When we are deleting node (d), we find and bring up an adjacent valued leaf
+ * node, say (c), to take the interior node's place. In the code this is
+ * handled by temporarily swapping (d) and (c) in the tree and then using
+ * common code to delete (d) from the leaf position.
+ *
+ * Secondly, an interior deletion from a deep tree may require more than one
+ * rotation to fix the balance. This is handled by moving up the tree through
+ * parents and applying rotations as needed. The return value from
+ * avl_rotation() is used to detect when a subtree did not change overall
+ * height due to a rotation.
+ */
+void
+avl_remove(avl_tree_t *tree, void *data)
+{
+       avl_node_t *delete;
+       avl_node_t *parent;
+       avl_node_t *node;
+       avl_node_t tmp;
+       int old_balance;
+       int new_balance;
+       int left;
+       int right;
+       int which_child;
+       size_t off = tree->avl_offset;
+
+       ASSERT(tree);
+
+       delete = AVL_DATA2NODE(data, off);
+
+       /*
+        * Deletion is easiest with a node that has at most 1 child.
+        * We swap a node with 2 children with a sequentially valued
+        * neighbor node. That node will have at most 1 child. Note this
+        * has no effect on the ordering of the remaining nodes.
+        *
+        * As an optimization, we choose the greater neighbor if the tree
+        * is right heavy, otherwise the left neighbor. This reduces the
+        * number of rotations needed.
+        */
+       if (delete->avl_child[0] != NULL && delete->avl_child[1] != NULL) {
+
+               /*
+                * choose node to swap from whichever side is taller
+                */
+               old_balance = AVL_XBALANCE(delete);
+               left = avl_balance2child[old_balance + 1];
+               right = 1 - left;
+
+               /*
+                * get to the previous value'd node
+                * (down 1 left, as far as possible right)
+                */
+               for (node = delete->avl_child[left];
+                   node->avl_child[right] != NULL;
+                   node = node->avl_child[right])
+                       ;
+
+               /*
+                * create a temp placeholder for 'node'
+                * move 'node' to delete's spot in the tree
+                */
+               tmp = *node;
+
+               *node = *delete;
+               if (node->avl_child[left] == node)
+                       node->avl_child[left] = &tmp;
+
+               parent = AVL_XPARENT(node);
+               if (parent != NULL)
+                       parent->avl_child[AVL_XCHILD(node)] = node;
+               else
+                       tree->avl_root = node;
+               AVL_SETPARENT(node->avl_child[left], node);
+               AVL_SETPARENT(node->avl_child[right], node);
+
+               /*
+                * Put tmp where node used to be (just temporary).
+                * It always has a parent and at most 1 child.
+                */
+               delete = &tmp;
+               parent = AVL_XPARENT(delete);
+               parent->avl_child[AVL_XCHILD(delete)] = delete;
+               which_child = (delete->avl_child[1] != 0);
+               if (delete->avl_child[which_child] != NULL)
+                       AVL_SETPARENT(delete->avl_child[which_child], delete);
+       }
+
+
+       /*
+        * Here we know "delete" is at least partially a leaf node. It can
+        * be easily removed from the tree.
+        */
+       ASSERT(tree->avl_numnodes > 0);
+       --tree->avl_numnodes;
+       parent = AVL_XPARENT(delete);
+       which_child = AVL_XCHILD(delete);
+       if (delete->avl_child[0] != NULL)
+               node = delete->avl_child[0];
+       else
+               node = delete->avl_child[1];
+
+       /*
+        * Connect parent directly to node (leaving out delete).
+        */
+       if (node != NULL) {
+               AVL_SETPARENT(node, parent);
+               AVL_SETCHILD(node, which_child);
+       }
+       if (parent == NULL) {
+               tree->avl_root = node;
+               return;
+       }
+       parent->avl_child[which_child] = node;
+
+
+       /*
+        * Since the subtree is now shorter, begin adjusting parent balances
+        * and performing any needed rotations.
+        */
+       do {
+
+               /*
+                * Move up the tree and adjust the balance
+                *
+                * Capture the parent and which_child values for the next
+                * iteration before any rotations occur.
+                */
+               node = parent;
+               old_balance = AVL_XBALANCE(node);
+               new_balance = old_balance - avl_child2balance[which_child];
+               parent = AVL_XPARENT(node);
+               which_child = AVL_XCHILD(node);
+
+               /*
+                * If a node was in perfect balance but isn't anymore then
+                * we can stop, since the height didn't change above this point
+                * due to a deletion.
+                */
+               if (old_balance == 0) {
+                       AVL_SETBALANCE(node, new_balance);
+                       break;
+               }
+
+               /*
+                * If the new balance is zero, we don't need to rotate
+                * else
+                * need a rotation to fix the balance.
+                * If the rotation doesn't change the height
+                * of the sub-tree we have finished adjusting.
+                */
+               if (new_balance == 0)
+                       AVL_SETBALANCE(node, new_balance);
+               else if (!avl_rotation(tree, node, new_balance))
+                       break;
+       } while (parent != NULL);
+}
+
+#define        AVL_REINSERT(tree, obj)         \
+       avl_remove((tree), (obj));      \
+       avl_add((tree), (obj))
+
+boolean_t
+avl_update_lt(avl_tree_t *t, void *obj)
+{
+       void *neighbor;
+
+       ASSERT(((neighbor = AVL_NEXT(t, obj)) == NULL) ||
+           (t->avl_compar(obj, neighbor) <= 0));
+
+       neighbor = AVL_PREV(t, obj);
+       if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) < 0)) {
+               AVL_REINSERT(t, obj);
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+boolean_t
+avl_update_gt(avl_tree_t *t, void *obj)
+{
+       void *neighbor;
+
+       ASSERT(((neighbor = AVL_PREV(t, obj)) == NULL) ||
+           (t->avl_compar(obj, neighbor) >= 0));
+
+       neighbor = AVL_NEXT(t, obj);
+       if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) > 0)) {
+               AVL_REINSERT(t, obj);
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+boolean_t
+avl_update(avl_tree_t *t, void *obj)
+{
+       void *neighbor;
+
+       neighbor = AVL_PREV(t, obj);
+       if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) < 0)) {
+               AVL_REINSERT(t, obj);
+               return (B_TRUE);
+       }
+
+       neighbor = AVL_NEXT(t, obj);
+       if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) > 0)) {
+               AVL_REINSERT(t, obj);
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+void
+avl_swap(avl_tree_t *tree1, avl_tree_t *tree2)
+{
+       avl_node_t *temp_node;
+       ulong_t temp_numnodes;
+
+       ASSERT3P(tree1->avl_compar, ==, tree2->avl_compar);
+       ASSERT3U(tree1->avl_offset, ==, tree2->avl_offset);
+       ASSERT3U(tree1->avl_size, ==, tree2->avl_size);
+
+       temp_node = tree1->avl_root;
+       temp_numnodes = tree1->avl_numnodes;
+       tree1->avl_root = tree2->avl_root;
+       tree1->avl_numnodes = tree2->avl_numnodes;
+       tree2->avl_root = temp_node;
+       tree2->avl_numnodes = temp_numnodes;
+}
+
+/*
+ * initialize a new AVL tree
+ */
+void
+avl_create(avl_tree_t *tree, int (*compar) (const void *, const void *),
+    size_t size, size_t offset)
+{
+       ASSERT(tree);
+       ASSERT(compar);
+       ASSERT(size > 0);
+       ASSERT(size >= offset + sizeof (avl_node_t));
+#ifdef _LP64
+       ASSERT((offset & 0x7) == 0);
+#endif
+
+       tree->avl_compar = compar;
+       tree->avl_root = NULL;
+       tree->avl_numnodes = 0;
+       tree->avl_size = size;
+       tree->avl_offset = offset;
+}
+
+/*
+ * Delete a tree.
+ */
+/* ARGSUSED */
+void
+avl_destroy(avl_tree_t *tree)
+{
+       ASSERT(tree);
+       ASSERT(tree->avl_numnodes == 0);
+       ASSERT(tree->avl_root == NULL);
+}
+
+
+/*
+ * Return the number of nodes in an AVL tree.
+ */
+ulong_t
+avl_numnodes(avl_tree_t *tree)
+{
+       ASSERT(tree);
+       return (tree->avl_numnodes);
+}
+
+boolean_t
+avl_is_empty(avl_tree_t *tree)
+{
+       ASSERT(tree);
+       return (tree->avl_numnodes == 0);
+}
+
+#define        CHILDBIT        (1L)
+
+/*
+ * Post-order tree walk used to visit all tree nodes and destroy the tree
+ * in post order. This is used for destroying a tree without paying any cost
+ * for rebalancing it.
+ *
+ * example:
+ *
+ *     void *cookie = NULL;
+ *     my_data_t *node;
+ *
+ *     while ((node = avl_destroy_nodes(tree, &cookie)) != NULL)
+ *             free(node);
+ *     avl_destroy(tree);
+ *
+ * The cookie is really an avl_node_t to the current node's parent and
+ * an indication of which child you looked at last.
+ *
+ * On input, a cookie value of CHILDBIT indicates the tree is done.
+ */
+void *
+avl_destroy_nodes(avl_tree_t *tree, void **cookie)
+{
+       avl_node_t      *node;
+       avl_node_t      *parent;
+       int             child;
+       void            *first;
+       size_t          off = tree->avl_offset;
+
+       /*
+        * Initial calls go to the first node or it's right descendant.
+        */
+       if (*cookie == NULL) {
+               first = avl_first(tree);
+
+               /*
+                * deal with an empty tree
+                */
+               if (first == NULL) {
+                       *cookie = (void *)CHILDBIT;
+                       return (NULL);
+               }
+
+               node = AVL_DATA2NODE(first, off);
+               parent = AVL_XPARENT(node);
+               goto check_right_side;
+       }
+
+       /*
+        * If there is no parent to return to we are done.
+        */
+       parent = (avl_node_t *)((uintptr_t)(*cookie) & ~CHILDBIT);
+       if (parent == NULL) {
+               if (tree->avl_root != NULL) {
+                       ASSERT(tree->avl_numnodes == 1);
+                       tree->avl_root = NULL;
+                       tree->avl_numnodes = 0;
+               }
+               return (NULL);
+       }
+
+       /*
+        * Remove the child pointer we just visited from the parent and tree.
+        */
+       child = (uintptr_t)(*cookie) & CHILDBIT;
+       parent->avl_child[child] = NULL;
+       ASSERT(tree->avl_numnodes > 1);
+       --tree->avl_numnodes;
+
+       /*
+        * If we just did a right child or there isn't one, go up to parent.
+        */
+       if (child == 1 || parent->avl_child[1] == NULL) {
+               node = parent;
+               parent = AVL_XPARENT(parent);
+               goto done;
+       }
+
+       /*
+        * Do parent's right child, then leftmost descendent.
+        */
+       node = parent->avl_child[1];
+       while (node->avl_child[0] != NULL) {
+               parent = node;
+               node = node->avl_child[0];
+       }
+
+       /*
+        * If here, we moved to a left child. It may have one
+        * child on the right (when balance == +1).
+        */
+check_right_side:
+       if (node->avl_child[1] != NULL) {
+               ASSERT(AVL_XBALANCE(node) == 1);
+               parent = node;
+               node = node->avl_child[1];
+               ASSERT(node->avl_child[0] == NULL &&
+                   node->avl_child[1] == NULL);
+       } else {
+               ASSERT(AVL_XBALANCE(node) <= 0);
+       }
+
+done:
+       if (parent == NULL) {
+               *cookie = (void *)CHILDBIT;
+               ASSERT(node == tree->avl_root);
+       } else {
+               *cookie = (void *)((uintptr_t)parent | AVL_XCHILD(node));
+       }
+
+       return (AVL_NODE2DATA(node, off));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+static int __init
+avl_init(void)
+{
+       return (0);
+}
+
+static void __exit
+avl_fini(void)
+{
+}
+
+module_init(avl_init);
+module_exit(avl_fini);
+
+MODULE_DESCRIPTION("Generic AVL tree implementation");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
+
+EXPORT_SYMBOL(avl_create);
+EXPORT_SYMBOL(avl_find);
+EXPORT_SYMBOL(avl_insert);
+EXPORT_SYMBOL(avl_insert_here);
+EXPORT_SYMBOL(avl_walk);
+EXPORT_SYMBOL(avl_first);
+EXPORT_SYMBOL(avl_last);
+EXPORT_SYMBOL(avl_nearest);
+EXPORT_SYMBOL(avl_add);
+EXPORT_SYMBOL(avl_swap);
+EXPORT_SYMBOL(avl_is_empty);
+EXPORT_SYMBOL(avl_remove);
+EXPORT_SYMBOL(avl_numnodes);
+EXPORT_SYMBOL(avl_destroy_nodes);
+EXPORT_SYMBOL(avl_destroy);
+#endif
diff --git a/zfs/module/nvpair/Makefile.in b/zfs/module/nvpair/Makefile.in
new file mode 100644 (file)
index 0000000..a814445
--- /dev/null
@@ -0,0 +1,13 @@
+src = @abs_top_srcdir@/module/nvpair
+obj = @abs_builddir@
+
+MODULE := znvpair
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+$(MODULE)-objs += nvpair.o
+$(MODULE)-objs += fnvpair.o
+$(MODULE)-objs += nvpair_alloc_spl.o
+$(MODULE)-objs += nvpair_alloc_fixed.o
diff --git a/zfs/module/nvpair/fnvpair.c b/zfs/module/nvpair/fnvpair.c
new file mode 100644 (file)
index 0000000..a91b952
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#include <sys/nvpair.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/*
+ * "Force" nvlist wrapper.
+ *
+ * These functions wrap the nvlist_* functions with assertions that assume
+ * the operation is successful.  This allows the caller's code to be much
+ * more readable, especially for the fnvlist_lookup_* and fnvpair_value_*
+ * functions, which can return the requested value (rather than filling in
+ * a pointer).
+ *
+ * These functions use NV_UNIQUE_NAME, encoding NV_ENCODE_NATIVE, and allocate
+ * with KM_SLEEP.
+ *
+ * More wrappers should be added as needed -- for example
+ * nvlist_lookup_*_array and nvpair_value_*_array.
+ */
+
+nvlist_t *
+fnvlist_alloc(void)
+{
+       nvlist_t *nvl;
+       VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP));
+       return (nvl);
+}
+
+void
+fnvlist_free(nvlist_t *nvl)
+{
+       nvlist_free(nvl);
+}
+
+size_t
+fnvlist_size(nvlist_t *nvl)
+{
+       size_t size;
+       VERIFY0(nvlist_size(nvl, &size, NV_ENCODE_NATIVE));
+       return (size);
+}
+
+/*
+ * Returns allocated buffer of size *sizep.  Caller must free the buffer with
+ * fnvlist_pack_free().
+ */
+char *
+fnvlist_pack(nvlist_t *nvl, size_t *sizep)
+{
+       char *packed = 0;
+       VERIFY3U(nvlist_pack(nvl, &packed, sizep, NV_ENCODE_NATIVE,
+           KM_SLEEP), ==, 0);
+       return (packed);
+}
+
+/*ARGSUSED*/
+void
+fnvlist_pack_free(char *pack, size_t size)
+{
+#ifdef _KERNEL
+       kmem_free(pack, size);
+#else
+       free(pack);
+#endif
+}
+
+nvlist_t *
+fnvlist_unpack(char *buf, size_t buflen)
+{
+       nvlist_t *rv;
+       VERIFY0(nvlist_unpack(buf, buflen, &rv, KM_SLEEP));
+       return (rv);
+}
+
+nvlist_t *
+fnvlist_dup(nvlist_t *nvl)
+{
+       nvlist_t *rv;
+       VERIFY0(nvlist_dup(nvl, &rv, KM_SLEEP));
+       return (rv);
+}
+
+void
+fnvlist_merge(nvlist_t *dst, nvlist_t *src)
+{
+       VERIFY0(nvlist_merge(dst, src, KM_SLEEP));
+}
+
+size_t
+fnvlist_num_pairs(nvlist_t *nvl)
+{
+       size_t count = 0;
+       nvpair_t *pair;
+
+       for (pair = nvlist_next_nvpair(nvl, 0); pair != NULL;
+           pair = nvlist_next_nvpair(nvl, pair))
+               count++;
+       return (count);
+}
+
+void
+fnvlist_add_boolean(nvlist_t *nvl, const char *name)
+{
+       VERIFY0(nvlist_add_boolean(nvl, name));
+}
+
+void
+fnvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
+{
+       VERIFY0(nvlist_add_boolean_value(nvl, name, val));
+}
+
+void
+fnvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
+{
+       VERIFY0(nvlist_add_byte(nvl, name, val));
+}
+
+void
+fnvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
+{
+       VERIFY0(nvlist_add_int8(nvl, name, val));
+}
+
+void
+fnvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
+{
+       VERIFY0(nvlist_add_uint8(nvl, name, val));
+}
+
+void
+fnvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
+{
+       VERIFY0(nvlist_add_int16(nvl, name, val));
+}
+
+void
+fnvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
+{
+       VERIFY0(nvlist_add_uint16(nvl, name, val));
+}
+
+void
+fnvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
+{
+       VERIFY0(nvlist_add_int32(nvl, name, val));
+}
+
+void
+fnvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
+{
+       VERIFY0(nvlist_add_uint32(nvl, name, val));
+}
+
+void
+fnvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
+{
+       VERIFY0(nvlist_add_int64(nvl, name, val));
+}
+
+void
+fnvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
+{
+       VERIFY0(nvlist_add_uint64(nvl, name, val));
+}
+
+void
+fnvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
+{
+       VERIFY0(nvlist_add_string(nvl, name, val));
+}
+
+void
+fnvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
+{
+       VERIFY0(nvlist_add_nvlist(nvl, name, val));
+}
+
+void
+fnvlist_add_nvpair(nvlist_t *nvl, nvpair_t *pair)
+{
+       VERIFY0(nvlist_add_nvpair(nvl, pair));
+}
+
+void
+fnvlist_add_boolean_array(nvlist_t *nvl, const char *name,
+    boolean_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_boolean_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_byte_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_int8_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_uint8_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_int16_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint16_array(nvlist_t *nvl, const char *name,
+    uint16_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_uint16_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_int32_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint32_array(nvlist_t *nvl, const char *name,
+    uint32_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_uint32_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_int64_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint64_array(nvlist_t *nvl, const char *name,
+    uint64_t *val, uint_t n)
+{
+       VERIFY0(nvlist_add_uint64_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_string_array(nvlist_t *nvl, const char *name,
+    char * const *val, uint_t n)
+{
+       VERIFY0(nvlist_add_string_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_nvlist_array(nvlist_t *nvl, const char *name,
+    nvlist_t **val, uint_t n)
+{
+       VERIFY0(nvlist_add_nvlist_array(nvl, name, val, n));
+}
+
+void
+fnvlist_remove(nvlist_t *nvl, const char *name)
+{
+       VERIFY0(nvlist_remove_all(nvl, name));
+}
+
+void
+fnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *pair)
+{
+       VERIFY0(nvlist_remove_nvpair(nvl, pair));
+}
+
+nvpair_t *
+fnvlist_lookup_nvpair(nvlist_t *nvl, const char *name)
+{
+       nvpair_t *rv;
+       VERIFY0(nvlist_lookup_nvpair(nvl, name, &rv));
+       return (rv);
+}
+
+/* returns B_TRUE if the entry exists */
+boolean_t
+fnvlist_lookup_boolean(nvlist_t *nvl, const char *name)
+{
+       return (nvlist_lookup_boolean(nvl, name) == 0);
+}
+
+boolean_t
+fnvlist_lookup_boolean_value(nvlist_t *nvl, const char *name)
+{
+       boolean_t rv;
+       VERIFY0(nvlist_lookup_boolean_value(nvl, name, &rv));
+       return (rv);
+}
+
+uchar_t
+fnvlist_lookup_byte(nvlist_t *nvl, const char *name)
+{
+       uchar_t rv;
+       VERIFY0(nvlist_lookup_byte(nvl, name, &rv));
+       return (rv);
+}
+
+int8_t
+fnvlist_lookup_int8(nvlist_t *nvl, const char *name)
+{
+       int8_t rv;
+       VERIFY0(nvlist_lookup_int8(nvl, name, &rv));
+       return (rv);
+}
+
+int16_t
+fnvlist_lookup_int16(nvlist_t *nvl, const char *name)
+{
+       int16_t rv;
+       VERIFY0(nvlist_lookup_int16(nvl, name, &rv));
+       return (rv);
+}
+
+int32_t
+fnvlist_lookup_int32(nvlist_t *nvl, const char *name)
+{
+       int32_t rv;
+       VERIFY0(nvlist_lookup_int32(nvl, name, &rv));
+       return (rv);
+}
+
+int64_t
+fnvlist_lookup_int64(nvlist_t *nvl, const char *name)
+{
+       int64_t rv;
+       VERIFY0(nvlist_lookup_int64(nvl, name, &rv));
+       return (rv);
+}
+
+uint8_t
+fnvlist_lookup_uint8(nvlist_t *nvl, const char *name)
+{
+       uint8_t rv;
+       VERIFY0(nvlist_lookup_uint8(nvl, name, &rv));
+       return (rv);
+}
+
+uint16_t
+fnvlist_lookup_uint16(nvlist_t *nvl, const char *name)
+{
+       uint16_t rv;
+       VERIFY0(nvlist_lookup_uint16(nvl, name, &rv));
+       return (rv);
+}
+
+uint32_t
+fnvlist_lookup_uint32(nvlist_t *nvl, const char *name)
+{
+       uint32_t rv;
+       VERIFY0(nvlist_lookup_uint32(nvl, name, &rv));
+       return (rv);
+}
+
+uint64_t
+fnvlist_lookup_uint64(nvlist_t *nvl, const char *name)
+{
+       uint64_t rv;
+       VERIFY0(nvlist_lookup_uint64(nvl, name, &rv));
+       return (rv);
+}
+
+char *
+fnvlist_lookup_string(nvlist_t *nvl, const char *name)
+{
+       char *rv;
+       VERIFY0(nvlist_lookup_string(nvl, name, &rv));
+       return (rv);
+}
+
+nvlist_t *
+fnvlist_lookup_nvlist(nvlist_t *nvl, const char *name)
+{
+       nvlist_t *rv;
+       VERIFY0(nvlist_lookup_nvlist(nvl, name, &rv));
+       return (rv);
+}
+
+boolean_t
+fnvpair_value_boolean_value(nvpair_t *nvp)
+{
+       boolean_t rv;
+       VERIFY0(nvpair_value_boolean_value(nvp, &rv));
+       return (rv);
+}
+
+uchar_t
+fnvpair_value_byte(nvpair_t *nvp)
+{
+       uchar_t rv;
+       VERIFY0(nvpair_value_byte(nvp, &rv));
+       return (rv);
+}
+
+int8_t
+fnvpair_value_int8(nvpair_t *nvp)
+{
+       int8_t rv;
+       VERIFY0(nvpair_value_int8(nvp, &rv));
+       return (rv);
+}
+
+int16_t
+fnvpair_value_int16(nvpair_t *nvp)
+{
+       int16_t rv;
+       VERIFY0(nvpair_value_int16(nvp, &rv));
+       return (rv);
+}
+
+int32_t
+fnvpair_value_int32(nvpair_t *nvp)
+{
+       int32_t rv;
+       VERIFY0(nvpair_value_int32(nvp, &rv));
+       return (rv);
+}
+
+int64_t
+fnvpair_value_int64(nvpair_t *nvp)
+{
+       int64_t rv;
+       VERIFY0(nvpair_value_int64(nvp, &rv));
+       return (rv);
+}
+
+uint8_t
+fnvpair_value_uint8(nvpair_t *nvp)
+{
+       uint8_t rv;
+       VERIFY0(nvpair_value_uint8(nvp, &rv));
+       return (rv);
+}
+
+uint16_t
+fnvpair_value_uint16(nvpair_t *nvp)
+{
+       uint16_t rv;
+       VERIFY0(nvpair_value_uint16(nvp, &rv));
+       return (rv);
+}
+
+uint32_t
+fnvpair_value_uint32(nvpair_t *nvp)
+{
+       uint32_t rv;
+       VERIFY0(nvpair_value_uint32(nvp, &rv));
+       return (rv);
+}
+
+uint64_t
+fnvpair_value_uint64(nvpair_t *nvp)
+{
+       uint64_t rv;
+       VERIFY0(nvpair_value_uint64(nvp, &rv));
+       return (rv);
+}
+
+char *
+fnvpair_value_string(nvpair_t *nvp)
+{
+       char *rv;
+       VERIFY0(nvpair_value_string(nvp, &rv));
+       return (rv);
+}
+
+nvlist_t *
+fnvpair_value_nvlist(nvpair_t *nvp)
+{
+       nvlist_t *rv;
+       VERIFY0(nvpair_value_nvlist(nvp, &rv));
+       return (rv);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+
+EXPORT_SYMBOL(fnvlist_alloc);
+EXPORT_SYMBOL(fnvlist_free);
+EXPORT_SYMBOL(fnvlist_size);
+EXPORT_SYMBOL(fnvlist_pack);
+EXPORT_SYMBOL(fnvlist_pack_free);
+EXPORT_SYMBOL(fnvlist_unpack);
+EXPORT_SYMBOL(fnvlist_dup);
+EXPORT_SYMBOL(fnvlist_merge);
+
+EXPORT_SYMBOL(fnvlist_add_nvpair);
+EXPORT_SYMBOL(fnvlist_add_boolean);
+EXPORT_SYMBOL(fnvlist_add_boolean_value);
+EXPORT_SYMBOL(fnvlist_add_byte);
+EXPORT_SYMBOL(fnvlist_add_int8);
+EXPORT_SYMBOL(fnvlist_add_uint8);
+EXPORT_SYMBOL(fnvlist_add_int16);
+EXPORT_SYMBOL(fnvlist_add_uint16);
+EXPORT_SYMBOL(fnvlist_add_int32);
+EXPORT_SYMBOL(fnvlist_add_uint32);
+EXPORT_SYMBOL(fnvlist_add_int64);
+EXPORT_SYMBOL(fnvlist_add_uint64);
+EXPORT_SYMBOL(fnvlist_add_string);
+EXPORT_SYMBOL(fnvlist_add_nvlist);
+EXPORT_SYMBOL(fnvlist_add_boolean_array);
+EXPORT_SYMBOL(fnvlist_add_byte_array);
+EXPORT_SYMBOL(fnvlist_add_int8_array);
+EXPORT_SYMBOL(fnvlist_add_uint8_array);
+EXPORT_SYMBOL(fnvlist_add_int16_array);
+EXPORT_SYMBOL(fnvlist_add_uint16_array);
+EXPORT_SYMBOL(fnvlist_add_int32_array);
+EXPORT_SYMBOL(fnvlist_add_uint32_array);
+EXPORT_SYMBOL(fnvlist_add_int64_array);
+EXPORT_SYMBOL(fnvlist_add_uint64_array);
+EXPORT_SYMBOL(fnvlist_add_string_array);
+EXPORT_SYMBOL(fnvlist_add_nvlist_array);
+
+EXPORT_SYMBOL(fnvlist_remove);
+EXPORT_SYMBOL(fnvlist_remove_nvpair);
+
+EXPORT_SYMBOL(fnvlist_lookup_nvpair);
+EXPORT_SYMBOL(fnvlist_lookup_boolean);
+EXPORT_SYMBOL(fnvlist_lookup_boolean_value);
+EXPORT_SYMBOL(fnvlist_lookup_byte);
+EXPORT_SYMBOL(fnvlist_lookup_int8);
+EXPORT_SYMBOL(fnvlist_lookup_uint8);
+EXPORT_SYMBOL(fnvlist_lookup_int16);
+EXPORT_SYMBOL(fnvlist_lookup_uint16);
+EXPORT_SYMBOL(fnvlist_lookup_int32);
+EXPORT_SYMBOL(fnvlist_lookup_uint32);
+EXPORT_SYMBOL(fnvlist_lookup_int64);
+EXPORT_SYMBOL(fnvlist_lookup_uint64);
+EXPORT_SYMBOL(fnvlist_lookup_string);
+EXPORT_SYMBOL(fnvlist_lookup_nvlist);
+
+EXPORT_SYMBOL(fnvpair_value_boolean_value);
+EXPORT_SYMBOL(fnvpair_value_byte);
+EXPORT_SYMBOL(fnvpair_value_int8);
+EXPORT_SYMBOL(fnvpair_value_uint8);
+EXPORT_SYMBOL(fnvpair_value_int16);
+EXPORT_SYMBOL(fnvpair_value_uint16);
+EXPORT_SYMBOL(fnvpair_value_int32);
+EXPORT_SYMBOL(fnvpair_value_uint32);
+EXPORT_SYMBOL(fnvpair_value_int64);
+EXPORT_SYMBOL(fnvpair_value_uint64);
+EXPORT_SYMBOL(fnvpair_value_string);
+EXPORT_SYMBOL(fnvpair_value_nvlist);
+EXPORT_SYMBOL(fnvlist_num_pairs);
+
+#endif
diff --git a/zfs/module/nvpair/nvpair.c b/zfs/module/nvpair/nvpair.c
new file mode 100644 (file)
index 0000000..16a0fc3
--- /dev/null
@@ -0,0 +1,3448 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2015, 2016 by Delphix. All rights reserved.
+ */
+
+#include <sys/stropts.h>
+#include <sys/debug.h>
+#include <sys/isa_defs.h>
+#include <sys/int_limits.h>
+#include <sys/nvpair.h>
+#include <sys/nvpair_impl.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#if defined(_KERNEL) && !defined(_BOOT)
+#include <sys/varargs.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#else
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#endif
+
+#ifndef        offsetof
+#define        offsetof(s, m)          ((size_t)(&(((s *)0)->m)))
+#endif
+#define        skip_whitespace(p)      while ((*(p) == ' ') || (*(p) == '\t')) p++
+
+/*
+ * nvpair.c - Provides kernel & userland interfaces for manipulating
+ *     name-value pairs.
+ *
+ * Overview Diagram
+ *
+ *  +--------------+
+ *  |  nvlist_t    |
+ *  |--------------|
+ *  | nvl_version  |
+ *  | nvl_nvflag   |
+ *  | nvl_priv    -+-+
+ *  | nvl_flag     | |
+ *  | nvl_pad      | |
+ *  +--------------+ |
+ *                   V
+ *      +--------------+      last i_nvp in list
+ *      | nvpriv_t     |  +--------------------->
+ *      |--------------|  |
+ *   +--+- nvp_list    |  |   +------------+
+ *   |  |  nvp_last   -+--+   + nv_alloc_t |
+ *   |  |  nvp_curr    |      |------------|
+ *   |  |  nvp_nva    -+----> | nva_ops    |
+ *   |  |  nvp_stat    |      | nva_arg    |
+ *   |  +--------------+      +------------+
+ *   |
+ *   +-------+
+ *           V
+ *   +---------------------+      +-------------------+
+ *   |  i_nvp_t            |  +-->|  i_nvp_t          |  +-->
+ *   |---------------------|  |   |-------------------|  |
+ *   | nvi_next           -+--+   | nvi_next         -+--+
+ *   | nvi_prev (NULL)     | <----+ nvi_prev          |
+ *   | . . . . . . . . . . |      | . . . . . . . . . |
+ *   | nvp (nvpair_t)      |      | nvp (nvpair_t)    |
+ *   |  - nvp_size         |      |  - nvp_size       |
+ *   |  - nvp_name_sz      |      |  - nvp_name_sz    |
+ *   |  - nvp_value_elem   |      |  - nvp_value_elem |
+ *   |  - nvp_type         |      |  - nvp_type       |
+ *   |  - data ...         |      |  - data ...       |
+ *   +---------------------+      +-------------------+
+ *
+ *
+ *
+ *   +---------------------+              +---------------------+
+ *   |  i_nvp_t            |  +-->    +-->|  i_nvp_t (last)     |
+ *   |---------------------|  |       |   |---------------------|
+ *   |  nvi_next          -+--+ ... --+   | nvi_next (NULL)     |
+ * <-+- nvi_prev           |<-- ...  <----+ nvi_prev            |
+ *   | . . . . . . . . .   |              | . . . . . . . . .   |
+ *   | nvp (nvpair_t)      |              | nvp (nvpair_t)      |
+ *   |  - nvp_size         |              |  - nvp_size         |
+ *   |  - nvp_name_sz      |              |  - nvp_name_sz      |
+ *   |  - nvp_value_elem   |              |  - nvp_value_elem   |
+ *   |  - DATA_TYPE_NVLIST |              |  - nvp_type         |
+ *   |  - data (embedded)  |              |  - data ...         |
+ *   |    nvlist name      |              +---------------------+
+ *   |  +--------------+   |
+ *   |  |  nvlist_t    |   |
+ *   |  |--------------|   |
+ *   |  | nvl_version  |   |
+ *   |  | nvl_nvflag   |   |
+ *   |  | nvl_priv   --+---+---->
+ *   |  | nvl_flag     |   |
+ *   |  | nvl_pad      |   |
+ *   |  +--------------+   |
+ *   +---------------------+
+ *
+ *
+ * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
+ * allow value to be aligned on 8 byte boundary
+ *
+ * name_len is the length of the name string including the null terminator
+ * so it must be >= 1
+ */
+#define        NVP_SIZE_CALC(name_len, data_len) \
+       (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
+
+static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
+static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
+    uint_t nelem, const void *data);
+
+#define        NV_STAT_EMBEDDED        0x1
+#define        EMBEDDED_NVL(nvp)       ((nvlist_t *)(void *)NVP_VALUE(nvp))
+#define        EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp))
+
+#define        NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
+#define        NVPAIR2I_NVP(nvp) \
+       ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
+
+#ifdef _KERNEL
+int nvpair_max_recursion = 20;
+#else
+int nvpair_max_recursion = 100;
+#endif
+
+int
+nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
+{
+       va_list valist;
+       int err = 0;
+
+       nva->nva_ops = nvo;
+       nva->nva_arg = NULL;
+
+       va_start(valist, nvo);
+       if (nva->nva_ops->nv_ao_init != NULL)
+               err = nva->nva_ops->nv_ao_init(nva, valist);
+       va_end(valist);
+
+       return (err);
+}
+
+void
+nv_alloc_reset(nv_alloc_t *nva)
+{
+       if (nva->nva_ops->nv_ao_reset != NULL)
+               nva->nva_ops->nv_ao_reset(nva);
+}
+
+void
+nv_alloc_fini(nv_alloc_t *nva)
+{
+       if (nva->nva_ops->nv_ao_fini != NULL)
+               nva->nva_ops->nv_ao_fini(nva);
+}
+
+nv_alloc_t *
+nvlist_lookup_nv_alloc(nvlist_t *nvl)
+{
+       nvpriv_t *priv;
+
+       if (nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (NULL);
+
+       return (priv->nvp_nva);
+}
+
+static void *
+nv_mem_zalloc(nvpriv_t *nvp, size_t size)
+{
+       nv_alloc_t *nva = nvp->nvp_nva;
+       void *buf;
+
+       if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
+               bzero(buf, size);
+
+       return (buf);
+}
+
+static void
+nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
+{
+       nv_alloc_t *nva = nvp->nvp_nva;
+
+       nva->nva_ops->nv_ao_free(nva, buf, size);
+}
+
+static void
+nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
+{
+       bzero(priv, sizeof (nvpriv_t));
+
+       priv->nvp_nva = nva;
+       priv->nvp_stat = stat;
+}
+
+static nvpriv_t *
+nv_priv_alloc(nv_alloc_t *nva)
+{
+       nvpriv_t *priv;
+
+       /*
+        * nv_mem_alloc() cannot called here because it needs the priv
+        * argument.
+        */
+       if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
+               return (NULL);
+
+       nv_priv_init(priv, nva, 0);
+
+       return (priv);
+}
+
+/*
+ * Embedded lists need their own nvpriv_t's.  We create a new
+ * nvpriv_t using the parameters and allocator from the parent
+ * list's nvpriv_t.
+ */
+static nvpriv_t *
+nv_priv_alloc_embedded(nvpriv_t *priv)
+{
+       nvpriv_t *emb_priv;
+
+       if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
+               return (NULL);
+
+       nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
+
+       return (emb_priv);
+}
+
+static void
+nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
+{
+       nvl->nvl_version = NV_VERSION;
+       nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
+       nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
+       nvl->nvl_flag = 0;
+       nvl->nvl_pad = 0;
+}
+
+uint_t
+nvlist_nvflag(nvlist_t *nvl)
+{
+       return (nvl->nvl_nvflag);
+}
+
+static nv_alloc_t *
+nvlist_nv_alloc(int kmflag)
+{
+#if defined(_KERNEL) && !defined(_BOOT)
+       switch (kmflag) {
+       case KM_SLEEP:
+               return (nv_alloc_sleep);
+       case KM_PUSHPAGE:
+               return (nv_alloc_pushpage);
+       default:
+               return (nv_alloc_nosleep);
+       }
+#else
+       return (nv_alloc_nosleep);
+#endif /* _KERNEL && !_BOOT */
+}
+
+/*
+ * nvlist_alloc - Allocate nvlist.
+ */
+int
+nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
+{
+       return (nvlist_xalloc(nvlp, nvflag, nvlist_nv_alloc(kmflag)));
+}
+
+int
+nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
+{
+       nvpriv_t *priv;
+
+       if (nvlp == NULL || nva == NULL)
+               return (EINVAL);
+
+       if ((priv = nv_priv_alloc(nva)) == NULL)
+               return (ENOMEM);
+
+       if ((*nvlp = nv_mem_zalloc(priv,
+           NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
+               nv_mem_free(priv, priv, sizeof (nvpriv_t));
+               return (ENOMEM);
+       }
+
+       nvlist_init(*nvlp, nvflag, priv);
+
+       return (0);
+}
+
+/*
+ * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
+ */
+static nvpair_t *
+nvp_buf_alloc(nvlist_t *nvl, size_t len)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       i_nvp_t *buf;
+       nvpair_t *nvp;
+       size_t nvsize;
+
+       /*
+        * Allocate the buffer
+        */
+       nvsize = len + offsetof(i_nvp_t, nvi_nvp);
+
+       if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
+               return (NULL);
+
+       nvp = &buf->nvi_nvp;
+       nvp->nvp_size = len;
+
+       return (nvp);
+}
+
+/*
+ * nvp_buf_free - de-Allocate an i_nvp_t.
+ */
+static void
+nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
+
+       nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
+}
+
+/*
+ * nvp_buf_link - link a new nv pair into the nvlist.
+ */
+static void
+nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       i_nvp_t *curr = NVPAIR2I_NVP(nvp);
+
+       /* Put element at end of nvlist */
+       if (priv->nvp_list == NULL) {
+               priv->nvp_list = priv->nvp_last = curr;
+       } else {
+               curr->nvi_prev = priv->nvp_last;
+               priv->nvp_last->nvi_next = curr;
+               priv->nvp_last = curr;
+       }
+}
+
+/*
+ * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
+ */
+static void
+nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       i_nvp_t *curr = NVPAIR2I_NVP(nvp);
+
+       /*
+        * protect nvlist_next_nvpair() against walking on freed memory.
+        */
+       if (priv->nvp_curr == curr)
+               priv->nvp_curr = curr->nvi_next;
+
+       if (curr == priv->nvp_list)
+               priv->nvp_list = curr->nvi_next;
+       else
+               curr->nvi_prev->nvi_next = curr->nvi_next;
+
+       if (curr == priv->nvp_last)
+               priv->nvp_last = curr->nvi_prev;
+       else
+               curr->nvi_next->nvi_prev = curr->nvi_prev;
+}
+
+/*
+ * take a nvpair type and number of elements and make sure the are valid
+ */
+static int
+i_validate_type_nelem(data_type_t type, uint_t nelem)
+{
+       switch (type) {
+       case DATA_TYPE_BOOLEAN:
+               if (nelem != 0)
+                       return (EINVAL);
+               break;
+       case DATA_TYPE_BOOLEAN_VALUE:
+       case DATA_TYPE_BYTE:
+       case DATA_TYPE_INT8:
+       case DATA_TYPE_UINT8:
+       case DATA_TYPE_INT16:
+       case DATA_TYPE_UINT16:
+       case DATA_TYPE_INT32:
+       case DATA_TYPE_UINT32:
+       case DATA_TYPE_INT64:
+       case DATA_TYPE_UINT64:
+       case DATA_TYPE_STRING:
+       case DATA_TYPE_HRTIME:
+       case DATA_TYPE_NVLIST:
+#if !defined(_KERNEL)
+       case DATA_TYPE_DOUBLE:
+#endif
+               if (nelem != 1)
+                       return (EINVAL);
+               break;
+       case DATA_TYPE_BOOLEAN_ARRAY:
+       case DATA_TYPE_BYTE_ARRAY:
+       case DATA_TYPE_INT8_ARRAY:
+       case DATA_TYPE_UINT8_ARRAY:
+       case DATA_TYPE_INT16_ARRAY:
+       case DATA_TYPE_UINT16_ARRAY:
+       case DATA_TYPE_INT32_ARRAY:
+       case DATA_TYPE_UINT32_ARRAY:
+       case DATA_TYPE_INT64_ARRAY:
+       case DATA_TYPE_UINT64_ARRAY:
+       case DATA_TYPE_STRING_ARRAY:
+       case DATA_TYPE_NVLIST_ARRAY:
+               /* we allow arrays with 0 elements */
+               break;
+       default:
+               return (EINVAL);
+       }
+       return (0);
+}
+
+/*
+ * Verify nvp_name_sz and check the name string length.
+ */
+static int
+i_validate_nvpair_name(nvpair_t *nvp)
+{
+       if ((nvp->nvp_name_sz <= 0) ||
+           (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
+               return (EFAULT);
+
+       /* verify the name string, make sure its terminated */
+       if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
+               return (EFAULT);
+
+       return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
+}
+
+static int
+i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
+{
+       switch (type) {
+       case DATA_TYPE_BOOLEAN_VALUE:
+               if (*(boolean_t *)data != B_TRUE &&
+                   *(boolean_t *)data != B_FALSE)
+                       return (EINVAL);
+               break;
+       case DATA_TYPE_BOOLEAN_ARRAY: {
+               int i;
+
+               for (i = 0; i < nelem; i++)
+                       if (((boolean_t *)data)[i] != B_TRUE &&
+                           ((boolean_t *)data)[i] != B_FALSE)
+                               return (EINVAL);
+               break;
+       }
+       default:
+               break;
+       }
+
+       return (0);
+}
+
+/*
+ * This function takes a pointer to what should be a nvpair and it's size
+ * and then verifies that all the nvpair fields make sense and can be
+ * trusted.  This function is used when decoding packed nvpairs.
+ */
+static int
+i_validate_nvpair(nvpair_t *nvp)
+{
+       data_type_t type = NVP_TYPE(nvp);
+       int size1, size2;
+
+       /* verify nvp_name_sz, check the name string length */
+       if (i_validate_nvpair_name(nvp) != 0)
+               return (EFAULT);
+
+       if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
+               return (EFAULT);
+
+       /*
+        * verify nvp_type, nvp_value_elem, and also possibly
+        * verify string values and get the value size.
+        */
+       size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
+       size1 = nvp->nvp_size - NVP_VALOFF(nvp);
+       if (size2 < 0 || size1 != NV_ALIGN(size2))
+               return (EFAULT);
+
+       return (0);
+}
+
+static int
+nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
+{
+       nvpriv_t *priv;
+       i_nvp_t *curr;
+
+       if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
+               return (EINVAL);
+
+       for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+               nvpair_t *nvp = &curr->nvi_nvp;
+               int err;
+
+               if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
+                   NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
+                       return (err);
+       }
+
+       return (0);
+}
+
+/*
+ * Frees all memory allocated for an nvpair (like embedded lists) with
+ * the exception of the nvpair buffer itself.
+ */
+static void
+nvpair_free(nvpair_t *nvp)
+{
+       switch (NVP_TYPE(nvp)) {
+       case DATA_TYPE_NVLIST:
+               nvlist_free(EMBEDDED_NVL(nvp));
+               break;
+       case DATA_TYPE_NVLIST_ARRAY: {
+               nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
+               int i;
+
+               for (i = 0; i < NVP_NELEM(nvp); i++)
+                       if (nvlp[i] != NULL)
+                               nvlist_free(nvlp[i]);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * nvlist_free - free an unpacked nvlist
+ */
+void
+nvlist_free(nvlist_t *nvl)
+{
+       nvpriv_t *priv;
+       i_nvp_t *curr;
+
+       if (nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return;
+
+       /*
+        * Unpacked nvlist are linked through i_nvp_t
+        */
+       curr = priv->nvp_list;
+       while (curr != NULL) {
+               nvpair_t *nvp = &curr->nvi_nvp;
+               curr = curr->nvi_next;
+
+               nvpair_free(nvp);
+               nvp_buf_free(nvl, nvp);
+       }
+
+       if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
+               nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
+       else
+               nvl->nvl_priv = 0;
+
+       nv_mem_free(priv, priv, sizeof (nvpriv_t));
+}
+
+static int
+nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       i_nvp_t *curr;
+
+       if (nvp == NULL)
+               return (0);
+
+       for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
+               if (&curr->nvi_nvp == nvp)
+                       return (1);
+
+       return (0);
+}
+
+/*
+ * Make a copy of nvlist
+ */
+int
+nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
+{
+       return (nvlist_xdup(nvl, nvlp, nvlist_nv_alloc(kmflag)));
+}
+
+int
+nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
+{
+       int err;
+       nvlist_t *ret;
+
+       if (nvl == NULL || nvlp == NULL)
+               return (EINVAL);
+
+       if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
+               return (err);
+
+       if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
+               nvlist_free(ret);
+       else
+               *nvlp = ret;
+
+       return (err);
+}
+
+/*
+ * Remove all with matching name
+ */
+int
+nvlist_remove_all(nvlist_t *nvl, const char *name)
+{
+       nvpriv_t *priv;
+       i_nvp_t *curr;
+       int error = ENOENT;
+
+       if (nvl == NULL || name == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (EINVAL);
+
+       curr = priv->nvp_list;
+       while (curr != NULL) {
+               nvpair_t *nvp = &curr->nvi_nvp;
+
+               curr = curr->nvi_next;
+               if (strcmp(name, NVP_NAME(nvp)) != 0)
+                       continue;
+
+               nvp_buf_unlink(nvl, nvp);
+               nvpair_free(nvp);
+               nvp_buf_free(nvl, nvp);
+
+               error = 0;
+       }
+
+       return (error);
+}
+
+/*
+ * Remove first one with matching name and type
+ */
+int
+nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
+{
+       nvpriv_t *priv;
+       i_nvp_t *curr;
+
+       if (nvl == NULL || name == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (EINVAL);
+
+       curr = priv->nvp_list;
+       while (curr != NULL) {
+               nvpair_t *nvp = &curr->nvi_nvp;
+
+               if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) {
+                       nvp_buf_unlink(nvl, nvp);
+                       nvpair_free(nvp);
+                       nvp_buf_free(nvl, nvp);
+
+                       return (0);
+               }
+               curr = curr->nvi_next;
+       }
+
+       return (ENOENT);
+}
+
+int
+nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+       if (nvl == NULL || nvp == NULL)
+               return (EINVAL);
+
+       nvp_buf_unlink(nvl, nvp);
+       nvpair_free(nvp);
+       nvp_buf_free(nvl, nvp);
+       return (0);
+}
+
+/*
+ * This function calculates the size of an nvpair value.
+ *
+ * The data argument controls the behavior in case of the data types
+ *     DATA_TYPE_STRING        and
+ *     DATA_TYPE_STRING_ARRAY
+ * Is data == NULL then the size of the string(s) is excluded.
+ */
+static int
+i_get_value_size(data_type_t type, const void *data, uint_t nelem)
+{
+       uint64_t value_sz;
+
+       if (i_validate_type_nelem(type, nelem) != 0)
+               return (-1);
+
+       /* Calculate required size for holding value */
+       switch (type) {
+       case DATA_TYPE_BOOLEAN:
+               value_sz = 0;
+               break;
+       case DATA_TYPE_BOOLEAN_VALUE:
+               value_sz = sizeof (boolean_t);
+               break;
+       case DATA_TYPE_BYTE:
+               value_sz = sizeof (uchar_t);
+               break;
+       case DATA_TYPE_INT8:
+               value_sz = sizeof (int8_t);
+               break;
+       case DATA_TYPE_UINT8:
+               value_sz = sizeof (uint8_t);
+               break;
+       case DATA_TYPE_INT16:
+               value_sz = sizeof (int16_t);
+               break;
+       case DATA_TYPE_UINT16:
+               value_sz = sizeof (uint16_t);
+               break;
+       case DATA_TYPE_INT32:
+               value_sz = sizeof (int32_t);
+               break;
+       case DATA_TYPE_UINT32:
+               value_sz = sizeof (uint32_t);
+               break;
+       case DATA_TYPE_INT64:
+               value_sz = sizeof (int64_t);
+               break;
+       case DATA_TYPE_UINT64:
+               value_sz = sizeof (uint64_t);
+               break;
+#if !defined(_KERNEL)
+       case DATA_TYPE_DOUBLE:
+               value_sz = sizeof (double);
+               break;
+#endif
+       case DATA_TYPE_STRING:
+               if (data == NULL)
+                       value_sz = 0;
+               else
+                       value_sz = strlen(data) + 1;
+               break;
+       case DATA_TYPE_BOOLEAN_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (boolean_t);
+               break;
+       case DATA_TYPE_BYTE_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uchar_t);
+               break;
+       case DATA_TYPE_INT8_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (int8_t);
+               break;
+       case DATA_TYPE_UINT8_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uint8_t);
+               break;
+       case DATA_TYPE_INT16_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (int16_t);
+               break;
+       case DATA_TYPE_UINT16_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uint16_t);
+               break;
+       case DATA_TYPE_INT32_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (int32_t);
+               break;
+       case DATA_TYPE_UINT32_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uint32_t);
+               break;
+       case DATA_TYPE_INT64_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (int64_t);
+               break;
+       case DATA_TYPE_UINT64_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uint64_t);
+               break;
+       case DATA_TYPE_STRING_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uint64_t);
+
+               if (data != NULL) {
+                       char *const *strs = data;
+                       uint_t i;
+
+                       /* no alignment requirement for strings */
+                       for (i = 0; i < nelem; i++) {
+                               if (strs[i] == NULL)
+                                       return (-1);
+                               value_sz += strlen(strs[i]) + 1;
+                       }
+               }
+               break;
+       case DATA_TYPE_HRTIME:
+               value_sz = sizeof (hrtime_t);
+               break;
+       case DATA_TYPE_NVLIST:
+               value_sz = NV_ALIGN(sizeof (nvlist_t));
+               break;
+       case DATA_TYPE_NVLIST_ARRAY:
+               value_sz = (uint64_t)nelem * sizeof (uint64_t) +
+                   (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
+               break;
+       default:
+               return (-1);
+       }
+
+       return (value_sz > INT32_MAX ? -1 : (int)value_sz);
+}
+
+static int
+nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
+{
+       nvpriv_t *priv;
+       int err;
+
+       if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
+           nvl->nvl_priv)) == NULL)
+               return (ENOMEM);
+
+       nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
+
+       if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
+               nvlist_free(emb_nvl);
+               emb_nvl->nvl_priv = 0;
+       }
+
+       return (err);
+}
+
+/*
+ * nvlist_add_common - Add new <name,value> pair to nvlist
+ */
+static int
+nvlist_add_common(nvlist_t *nvl, const char *name,
+    data_type_t type, uint_t nelem, const void *data)
+{
+       nvpair_t *nvp;
+       uint_t i;
+
+       int nvp_sz, name_sz, value_sz;
+       int err = 0;
+
+       if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
+               return (EINVAL);
+
+       if (nelem != 0 && data == NULL)
+               return (EINVAL);
+
+       /*
+        * Verify type and nelem and get the value size.
+        * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
+        * is the size of the string(s) included.
+        */
+       if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
+               return (EINVAL);
+
+       if (i_validate_nvpair_value(type, nelem, data) != 0)
+               return (EINVAL);
+
+       /*
+        * If we're adding an nvlist or nvlist array, ensure that we are not
+        * adding the input nvlist to itself, which would cause recursion,
+        * and ensure that no NULL nvlist pointers are present.
+        */
+       switch (type) {
+       case DATA_TYPE_NVLIST:
+               if (data == nvl || data == NULL)
+                       return (EINVAL);
+               break;
+       case DATA_TYPE_NVLIST_ARRAY: {
+               nvlist_t **onvlp = (nvlist_t **)data;
+               for (i = 0; i < nelem; i++) {
+                       if (onvlp[i] == nvl || onvlp[i] == NULL)
+                               return (EINVAL);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+       /* calculate sizes of the nvpair elements and the nvpair itself */
+       name_sz = strlen(name) + 1;
+
+       nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
+
+       if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
+               return (ENOMEM);
+
+       ASSERT(nvp->nvp_size == nvp_sz);
+       nvp->nvp_name_sz = name_sz;
+       nvp->nvp_value_elem = nelem;
+       nvp->nvp_type = type;
+       bcopy(name, NVP_NAME(nvp), name_sz);
+
+       switch (type) {
+       case DATA_TYPE_BOOLEAN:
+               break;
+       case DATA_TYPE_STRING_ARRAY: {
+               char *const *strs = data;
+               char *buf = NVP_VALUE(nvp);
+               char **cstrs = (void *)buf;
+
+               /* skip pre-allocated space for pointer array */
+               buf += nelem * sizeof (uint64_t);
+               for (i = 0; i < nelem; i++) {
+                       int slen = strlen(strs[i]) + 1;
+                       bcopy(strs[i], buf, slen);
+                       cstrs[i] = buf;
+                       buf += slen;
+               }
+               break;
+       }
+       case DATA_TYPE_NVLIST: {
+               nvlist_t *nnvl = EMBEDDED_NVL(nvp);
+               nvlist_t *onvl = (nvlist_t *)data;
+
+               if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
+                       nvp_buf_free(nvl, nvp);
+                       return (err);
+               }
+               break;
+       }
+       case DATA_TYPE_NVLIST_ARRAY: {
+               nvlist_t **onvlp = (nvlist_t **)data;
+               nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
+               nvlist_t *embedded = (nvlist_t *)
+                   ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
+
+               for (i = 0; i < nelem; i++) {
+                       if ((err = nvlist_copy_embedded(nvl,
+                           onvlp[i], embedded)) != 0) {
+                               /*
+                                * Free any successfully created lists
+                                */
+                               nvpair_free(nvp);
+                               nvp_buf_free(nvl, nvp);
+                               return (err);
+                       }
+
+                       nvlp[i] = embedded++;
+               }
+               break;
+       }
+       default:
+               bcopy(data, NVP_VALUE(nvp), value_sz);
+       }
+
+       /* if unique name, remove before add */
+       if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
+               (void) nvlist_remove_all(nvl, name);
+       else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
+               (void) nvlist_remove(nvl, name, type);
+
+       nvp_buf_link(nvl, nvp);
+
+       return (0);
+}
+
+int
+nvlist_add_boolean(nvlist_t *nvl, const char *name)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
+}
+
+int
+nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
+}
+
+int
+nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
+}
+
+int
+nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
+}
+
+int
+nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
+}
+
+int
+nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
+}
+
+int
+nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
+}
+
+int
+nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
+}
+
+int
+nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
+}
+
+int
+nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
+}
+
+int
+nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
+}
+
+#if !defined(_KERNEL)
+int
+nvlist_add_double(nvlist_t *nvl, const char *name, double val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
+}
+#endif
+
+int
+nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
+}
+
+int
+nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
+    boolean_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
+}
+
+int
+nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
+}
+
+int
+nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
+}
+
+int
+nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
+}
+
+int
+nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
+}
+
+int
+nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
+}
+
+int
+nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
+}
+
+int
+nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
+}
+
+int
+nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
+}
+
+int
+nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
+}
+
+int
+nvlist_add_string_array(nvlist_t *nvl, const char *name,
+    char *const *a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
+}
+
+int
+nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
+}
+
+int
+nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
+}
+
+int
+nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n)
+{
+       return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
+}
+
+/* reading name-value pairs */
+nvpair_t *
+nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+       nvpriv_t *priv;
+       i_nvp_t *curr;
+
+       if (nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (NULL);
+
+       curr = NVPAIR2I_NVP(nvp);
+
+       /*
+        * Ensure that nvp is a valid nvpair on this nvlist.
+        * NB: nvp_curr is used only as a hint so that we don't always
+        * have to walk the list to determine if nvp is still on the list.
+        */
+       if (nvp == NULL)
+               curr = priv->nvp_list;
+       else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
+               curr = curr->nvi_next;
+       else
+               curr = NULL;
+
+       priv->nvp_curr = curr;
+
+       return (curr != NULL ? &curr->nvi_nvp : NULL);
+}
+
+nvpair_t *
+nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+       nvpriv_t *priv;
+       i_nvp_t *curr;
+
+       if (nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (NULL);
+
+       curr = NVPAIR2I_NVP(nvp);
+
+       if (nvp == NULL)
+               curr = priv->nvp_last;
+       else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
+               curr = curr->nvi_prev;
+       else
+               curr = NULL;
+
+       priv->nvp_curr = curr;
+
+       return (curr != NULL ? &curr->nvi_nvp : NULL);
+}
+
+boolean_t
+nvlist_empty(nvlist_t *nvl)
+{
+       nvpriv_t *priv;
+
+       if (nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (B_TRUE);
+
+       return (priv->nvp_list == NULL);
+}
+
+char *
+nvpair_name(nvpair_t *nvp)
+{
+       return (NVP_NAME(nvp));
+}
+
+data_type_t
+nvpair_type(nvpair_t *nvp)
+{
+       return (NVP_TYPE(nvp));
+}
+
+int
+nvpair_type_is_array(nvpair_t *nvp)
+{
+       data_type_t type = NVP_TYPE(nvp);
+
+       if ((type == DATA_TYPE_BYTE_ARRAY) ||
+           (type == DATA_TYPE_UINT8_ARRAY) ||
+           (type == DATA_TYPE_INT16_ARRAY) ||
+           (type == DATA_TYPE_UINT16_ARRAY) ||
+           (type == DATA_TYPE_INT32_ARRAY) ||
+           (type == DATA_TYPE_UINT32_ARRAY) ||
+           (type == DATA_TYPE_INT64_ARRAY) ||
+           (type == DATA_TYPE_UINT64_ARRAY) ||
+           (type == DATA_TYPE_BOOLEAN_ARRAY) ||
+           (type == DATA_TYPE_STRING_ARRAY) ||
+           (type == DATA_TYPE_NVLIST_ARRAY))
+               return (1);
+       return (0);
+
+}
+
+static int
+nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
+{
+       if (nvp == NULL || nvpair_type(nvp) != type)
+               return (EINVAL);
+
+       /*
+        * For non-array types, we copy the data.
+        * For array types (including string), we set a pointer.
+        */
+       switch (type) {
+       case DATA_TYPE_BOOLEAN:
+               if (nelem != NULL)
+                       *nelem = 0;
+               break;
+
+       case DATA_TYPE_BOOLEAN_VALUE:
+       case DATA_TYPE_BYTE:
+       case DATA_TYPE_INT8:
+       case DATA_TYPE_UINT8:
+       case DATA_TYPE_INT16:
+       case DATA_TYPE_UINT16:
+       case DATA_TYPE_INT32:
+       case DATA_TYPE_UINT32:
+       case DATA_TYPE_INT64:
+       case DATA_TYPE_UINT64:
+       case DATA_TYPE_HRTIME:
+#if !defined(_KERNEL)
+       case DATA_TYPE_DOUBLE:
+#endif
+               if (data == NULL)
+                       return (EINVAL);
+               bcopy(NVP_VALUE(nvp), data,
+                   (size_t)i_get_value_size(type, NULL, 1));
+               if (nelem != NULL)
+                       *nelem = 1;
+               break;
+
+       case DATA_TYPE_NVLIST:
+       case DATA_TYPE_STRING:
+               if (data == NULL)
+                       return (EINVAL);
+               *(void **)data = (void *)NVP_VALUE(nvp);
+               if (nelem != NULL)
+                       *nelem = 1;
+               break;
+
+       case DATA_TYPE_BOOLEAN_ARRAY:
+       case DATA_TYPE_BYTE_ARRAY:
+       case DATA_TYPE_INT8_ARRAY:
+       case DATA_TYPE_UINT8_ARRAY:
+       case DATA_TYPE_INT16_ARRAY:
+       case DATA_TYPE_UINT16_ARRAY:
+       case DATA_TYPE_INT32_ARRAY:
+       case DATA_TYPE_UINT32_ARRAY:
+       case DATA_TYPE_INT64_ARRAY:
+       case DATA_TYPE_UINT64_ARRAY:
+       case DATA_TYPE_STRING_ARRAY:
+       case DATA_TYPE_NVLIST_ARRAY:
+               if (nelem == NULL || data == NULL)
+                       return (EINVAL);
+               if ((*nelem = NVP_NELEM(nvp)) != 0)
+                       *(void **)data = (void *)NVP_VALUE(nvp);
+               else
+                       *(void **)data = NULL;
+               break;
+
+       default:
+               return (ENOTSUP);
+       }
+
+       return (0);
+}
+
+static int
+nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type,
+    uint_t *nelem, void *data)
+{
+       nvpriv_t *priv;
+       nvpair_t *nvp;
+       i_nvp_t *curr;
+
+       if (name == NULL || nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (EINVAL);
+
+       if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
+               return (ENOTSUP);
+
+       for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+               nvp = &curr->nvi_nvp;
+
+               if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type)
+                       return (nvpair_value_common(nvp, type, nelem, data));
+       }
+
+       return (ENOENT);
+}
+
+int
+nvlist_lookup_boolean(nvlist_t *nvl, const char *name)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
+}
+
+int
+nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val)
+{
+       return (nvlist_lookup_common(nvl, name,
+           DATA_TYPE_BOOLEAN_VALUE, NULL, val));
+}
+
+int
+nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
+}
+
+int
+nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
+}
+
+int
+nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
+}
+
+int
+nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
+}
+
+int
+nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
+}
+
+int
+nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
+}
+
+int
+nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
+}
+
+int
+nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
+}
+
+int
+nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
+}
+
+#if !defined(_KERNEL)
+int
+nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));
+}
+#endif
+
+int
+nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
+}
+
+int
+nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
+}
+
+int
+nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
+    boolean_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name,
+           DATA_TYPE_BOOLEAN_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
+    uchar_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
+    uint8_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
+    int16_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
+    uint16_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
+    int32_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
+    uint32_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
+    int64_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
+    uint64_t **a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
+    char ***a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
+    nvlist_t ***a, uint_t *n)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
+{
+       return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
+}
+
+int
+nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
+{
+       va_list ap;
+       char *name;
+       int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
+       int ret = 0;
+
+       va_start(ap, flag);
+       while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+               data_type_t type;
+               void *val;
+               uint_t *nelem;
+
+               switch (type = va_arg(ap, data_type_t)) {
+               case DATA_TYPE_BOOLEAN:
+                       ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
+                       break;
+
+               case DATA_TYPE_BOOLEAN_VALUE:
+               case DATA_TYPE_BYTE:
+               case DATA_TYPE_INT8:
+               case DATA_TYPE_UINT8:
+               case DATA_TYPE_INT16:
+               case DATA_TYPE_UINT16:
+               case DATA_TYPE_INT32:
+               case DATA_TYPE_UINT32:
+               case DATA_TYPE_INT64:
+               case DATA_TYPE_UINT64:
+               case DATA_TYPE_HRTIME:
+               case DATA_TYPE_STRING:
+               case DATA_TYPE_NVLIST:
+#if !defined(_KERNEL)
+               case DATA_TYPE_DOUBLE:
+#endif
+                       val = va_arg(ap, void *);
+                       ret = nvlist_lookup_common(nvl, name, type, NULL, val);
+                       break;
+
+               case DATA_TYPE_BYTE_ARRAY:
+               case DATA_TYPE_BOOLEAN_ARRAY:
+               case DATA_TYPE_INT8_ARRAY:
+               case DATA_TYPE_UINT8_ARRAY:
+               case DATA_TYPE_INT16_ARRAY:
+               case DATA_TYPE_UINT16_ARRAY:
+               case DATA_TYPE_INT32_ARRAY:
+               case DATA_TYPE_UINT32_ARRAY:
+               case DATA_TYPE_INT64_ARRAY:
+               case DATA_TYPE_UINT64_ARRAY:
+               case DATA_TYPE_STRING_ARRAY:
+               case DATA_TYPE_NVLIST_ARRAY:
+                       val = va_arg(ap, void *);
+                       nelem = va_arg(ap, uint_t *);
+                       ret = nvlist_lookup_common(nvl, name, type, nelem, val);
+                       break;
+
+               default:
+                       ret = EINVAL;
+               }
+
+               if (ret == ENOENT && noentok)
+                       ret = 0;
+       }
+       va_end(ap);
+
+       return (ret);
+}
+
+/*
+ * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function
+ * returns zero and a pointer to the matching nvpair is returned in '*ret'
+ * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate
+ * multiple levels of embedded nvlists, with 'sep' as the separator. As an
+ * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or
+ * "a.d[3].e[1]".  This matches the C syntax for array embed (for convience,
+ * code also supports "a.d[3]e[1]" syntax).
+ *
+ * If 'ip' is non-NULL and the last name component is an array, return the
+ * value of the "...[index]" array index in *ip. For an array reference that
+ * is not indexed, *ip will be returned as -1. If there is a syntax error in
+ * 'name', and 'ep' is non-NULL then *ep will be set to point to the location
+ * inside the 'name' string where the syntax error was detected.
+ */
+static int
+nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
+    nvpair_t **ret, int *ip, char **ep)
+{
+       nvpair_t        *nvp;
+       const char      *np;
+       char            *sepp = NULL;
+       char            *idxp, *idxep;
+       nvlist_t        **nva;
+       long            idx = 0;
+       int             n;
+
+       if (ip)
+               *ip = -1;                       /* not indexed */
+       if (ep)
+               *ep = NULL;
+
+       if ((nvl == NULL) || (name == NULL))
+               return (EINVAL);
+
+       /* step through components of name */
+       for (np = name; np && *np; np = sepp) {
+               /* ensure unique names */
+               if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
+                       return (ENOTSUP);
+
+               /* skip white space */
+               skip_whitespace(np);
+               if (*np == 0)
+                       break;
+
+               /* set 'sepp' to end of current component 'np' */
+               if (sep)
+                       sepp = strchr(np, sep);
+               else
+                       sepp = NULL;
+
+               /* find start of next "[ index ]..." */
+               idxp = strchr(np, '[');
+
+               /* if sepp comes first, set idxp to NULL */
+               if (sepp && idxp && (sepp < idxp))
+                       idxp = NULL;
+
+               /*
+                * At this point 'idxp' is set if there is an index
+                * expected for the current component.
+                */
+               if (idxp) {
+                       /* set 'n' to length of current 'np' name component */
+                       n = idxp++ - np;
+
+                       /* keep sepp up to date for *ep use as we advance */
+                       skip_whitespace(idxp);
+                       sepp = idxp;
+
+                       /* determine the index value */
+#if defined(_KERNEL) && !defined(_BOOT)
+                       if (ddi_strtol(idxp, &idxep, 0, &idx))
+                               goto fail;
+#else
+                       idx = strtol(idxp, &idxep, 0);
+#endif
+                       if (idxep == idxp)
+                               goto fail;
+
+                       /* keep sepp up to date for *ep use as we advance */
+                       sepp = idxep;
+
+                       /* skip white space index value and check for ']' */
+                       skip_whitespace(sepp);
+                       if (*sepp++ != ']')
+                               goto fail;
+
+                       /* for embedded arrays, support C syntax: "a[1].b" */
+                       skip_whitespace(sepp);
+                       if (sep && (*sepp == sep))
+                               sepp++;
+               } else if (sepp) {
+                       n = sepp++ - np;
+               } else {
+                       n = strlen(np);
+               }
+
+               /* trim trailing whitespace by reducing length of 'np' */
+               if (n == 0)
+                       goto fail;
+               for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
+                       ;
+               n++;
+
+               /* skip whitespace, and set sepp to NULL if complete */
+               if (sepp) {
+                       skip_whitespace(sepp);
+                       if (*sepp == 0)
+                               sepp = NULL;
+               }
+
+               /*
+                * At this point:
+                * o  'n' is the length of current 'np' component.
+                * o  'idxp' is set if there was an index, and value 'idx'.
+                * o  'sepp' is set to the beginning of the next component,
+                *    and set to NULL if we have no more components.
+                *
+                * Search for nvpair with matching component name.
+                */
+               for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+                   nvp = nvlist_next_nvpair(nvl, nvp)) {
+
+                       /* continue if no match on name */
+                       if (strncmp(np, nvpair_name(nvp), n) ||
+                           (strlen(nvpair_name(nvp)) != n))
+                               continue;
+
+                       /* if indexed, verify type is array oriented */
+                       if (idxp && !nvpair_type_is_array(nvp))
+                               goto fail;
+
+                       /*
+                        * Full match found, return nvp and idx if this
+                        * was the last component.
+                        */
+                       if (sepp == NULL) {
+                               if (ret)
+                                       *ret = nvp;
+                               if (ip && idxp)
+                                       *ip = (int)idx; /* return index */
+                               return (0);             /* found */
+                       }
+
+                       /*
+                        * More components: current match must be
+                        * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
+                        * to support going deeper.
+                        */
+                       if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
+                               nvl = EMBEDDED_NVL(nvp);
+                               break;
+                       } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
+                               (void) nvpair_value_nvlist_array(nvp,
+                                   &nva, (uint_t *)&n);
+                               if ((n < 0) || (idx >= n))
+                                       goto fail;
+                               nvl = nva[idx];
+                               break;
+                       }
+
+                       /* type does not support more levels */
+                       goto fail;
+               }
+               if (nvp == NULL)
+                       goto fail;              /* 'name' not found */
+
+               /* search for match of next component in embedded 'nvl' list */
+       }
+
+fail:  if (ep && sepp)
+               *ep = sepp;
+       return (EINVAL);
+}
+
+/*
+ * Return pointer to nvpair with specified 'name'.
+ */
+int
+nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
+{
+       return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
+}
+
+/*
+ * Determine if named nvpair exists in nvlist (use embedded separator of '.'
+ * and return array index).  See nvlist_lookup_nvpair_ei_sep for more detailed
+ * description.
+ */
+int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
+    const char *name, nvpair_t **ret, int *ip, char **ep)
+{
+       return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
+}
+
+boolean_t
+nvlist_exists(nvlist_t *nvl, const char *name)
+{
+       nvpriv_t *priv;
+       nvpair_t *nvp;
+       i_nvp_t *curr;
+
+       if (name == NULL || nvl == NULL ||
+           (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (B_FALSE);
+
+       for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+               nvp = &curr->nvi_nvp;
+
+               if (strcmp(name, NVP_NAME(nvp)) == 0)
+                       return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+int
+nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
+}
+
+int
+nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
+}
+
+int
+nvpair_value_int8(nvpair_t *nvp, int8_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
+}
+
+int
+nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
+}
+
+int
+nvpair_value_int16(nvpair_t *nvp, int16_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
+}
+
+int
+nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
+}
+
+int
+nvpair_value_int32(nvpair_t *nvp, int32_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
+}
+
+int
+nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
+}
+
+int
+nvpair_value_int64(nvpair_t *nvp, int64_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
+}
+
+int
+nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
+}
+
+#if !defined(_KERNEL)
+int
+nvpair_value_double(nvpair_t *nvp, double *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
+}
+#endif
+
+int
+nvpair_value_string(nvpair_t *nvp, char **val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
+}
+
+int
+nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
+}
+
+int
+nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
+{
+       return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
+}
+
+/*
+ * Add specified pair to the list.
+ */
+int
+nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+       if (nvl == NULL || nvp == NULL)
+               return (EINVAL);
+
+       return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
+           NVP_NELEM(nvp), NVP_VALUE(nvp)));
+}
+
+/*
+ * Merge the supplied nvlists and put the result in dst.
+ * The merged list will contain all names specified in both lists,
+ * the values are taken from nvl in the case of duplicates.
+ * Return 0 on success.
+ */
+/*ARGSUSED*/
+int
+nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
+{
+       if (nvl == NULL || dst == NULL)
+               return (EINVAL);
+
+       if (dst != nvl)
+               return (nvlist_copy_pairs(nvl, dst));
+
+       return (0);
+}
+
+/*
+ * Encoding related routines
+ */
+#define        NVS_OP_ENCODE   0
+#define        NVS_OP_DECODE   1
+#define        NVS_OP_GETSIZE  2
+
+typedef struct nvs_ops nvs_ops_t;
+
+typedef struct {
+       int             nvs_op;
+       const nvs_ops_t *nvs_ops;
+       void            *nvs_private;
+       nvpriv_t        *nvs_priv;
+       int             nvs_recursion;
+} nvstream_t;
+
+/*
+ * nvs operations are:
+ *   - nvs_nvlist
+ *     encoding / decoding of a nvlist header (nvlist_t)
+ *     calculates the size used for header and end detection
+ *
+ *   - nvs_nvpair
+ *     responsible for the first part of encoding / decoding of an nvpair
+ *     calculates the decoded size of an nvpair
+ *
+ *   - nvs_nvp_op
+ *     second part of encoding / decoding of an nvpair
+ *
+ *   - nvs_nvp_size
+ *     calculates the encoding size of an nvpair
+ *
+ *   - nvs_nvl_fini
+ *     encodes the end detection mark (zeros).
+ */
+struct nvs_ops {
+       int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
+       int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
+       int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
+       int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
+       int (*nvs_nvl_fini)(nvstream_t *);
+};
+
+typedef struct {
+       char    nvh_encoding;   /* nvs encoding method */
+       char    nvh_endian;     /* nvs endian */
+       char    nvh_reserved1;  /* reserved for future use */
+       char    nvh_reserved2;  /* reserved for future use */
+} nvs_header_t;
+
+static int
+nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       i_nvp_t *curr;
+
+       /*
+        * Walk nvpair in list and encode each nvpair
+        */
+       for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
+               if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
+                       return (EFAULT);
+
+       return (nvs->nvs_ops->nvs_nvl_fini(nvs));
+}
+
+static int
+nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
+{
+       nvpair_t *nvp;
+       size_t nvsize;
+       int err;
+
+       /*
+        * Get decoded size of next pair in stream, alloc
+        * memory for nvpair_t, then decode the nvpair
+        */
+       while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
+               if (nvsize == 0) /* end of list */
+                       break;
+
+               /* make sure len makes sense */
+               if (nvsize < NVP_SIZE_CALC(1, 0))
+                       return (EFAULT);
+
+               if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
+                       return (ENOMEM);
+
+               if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
+                       nvp_buf_free(nvl, nvp);
+                       return (err);
+               }
+
+               if (i_validate_nvpair(nvp) != 0) {
+                       nvpair_free(nvp);
+                       nvp_buf_free(nvl, nvp);
+                       return (EFAULT);
+               }
+
+               nvp_buf_link(nvl, nvp);
+       }
+       return (err);
+}
+
+static int
+nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
+{
+       nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+       i_nvp_t *curr;
+       uint64_t nvsize = *buflen;
+       size_t size;
+
+       /*
+        * Get encoded size of nvpairs in nvlist
+        */
+       for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+               if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
+                       return (EINVAL);
+
+               if ((nvsize += size) > INT32_MAX)
+                       return (EINVAL);
+       }
+
+       *buflen = nvsize;
+       return (0);
+}
+
+static int
+nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
+{
+       int err;
+
+       if (nvl->nvl_priv == 0)
+               return (EFAULT);
+
+       /*
+        * Perform the operation, starting with header, then each nvpair
+        */
+       if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
+               return (err);
+
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+               err = nvs_encode_pairs(nvs, nvl);
+               break;
+
+       case NVS_OP_DECODE:
+               err = nvs_decode_pairs(nvs, nvl);
+               break;
+
+       case NVS_OP_GETSIZE:
+               err = nvs_getsize_pairs(nvs, nvl, buflen);
+               break;
+
+       default:
+               err = EINVAL;
+       }
+
+       return (err);
+}
+
+static int
+nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
+{
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE: {
+               int err;
+
+               if (nvs->nvs_recursion >= nvpair_max_recursion)
+                       return (EINVAL);
+               nvs->nvs_recursion++;
+               err = nvs_operation(nvs, embedded, NULL);
+               nvs->nvs_recursion--;
+               return (err);
+       }
+       case NVS_OP_DECODE: {
+               nvpriv_t *priv;
+               int err;
+
+               if (embedded->nvl_version != NV_VERSION)
+                       return (ENOTSUP);
+
+               if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
+                       return (ENOMEM);
+
+               nvlist_init(embedded, embedded->nvl_nvflag, priv);
+
+               if (nvs->nvs_recursion >= nvpair_max_recursion)
+                       return (EINVAL);
+               nvs->nvs_recursion++;
+               if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
+                       nvlist_free(embedded);
+               nvs->nvs_recursion--;
+               return (err);
+       }
+       default:
+               break;
+       }
+
+       return (EINVAL);
+}
+
+static int
+nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+       size_t nelem = NVP_NELEM(nvp);
+       nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
+       int i;
+
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+               for (i = 0; i < nelem; i++)
+                       if (nvs_embedded(nvs, nvlp[i]) != 0)
+                               return (EFAULT);
+               break;
+
+       case NVS_OP_DECODE: {
+               size_t len = nelem * sizeof (uint64_t);
+               nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
+
+               bzero(nvlp, len);       /* don't trust packed data */
+               for (i = 0; i < nelem; i++) {
+                       if (nvs_embedded(nvs, embedded) != 0) {
+                               nvpair_free(nvp);
+                               return (EFAULT);
+                       }
+
+                       nvlp[i] = embedded++;
+               }
+               break;
+       }
+       case NVS_OP_GETSIZE: {
+               uint64_t nvsize = 0;
+
+               for (i = 0; i < nelem; i++) {
+                       size_t nvp_sz = 0;
+
+                       if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
+                               return (EINVAL);
+
+                       if ((nvsize += nvp_sz) > INT32_MAX)
+                               return (EINVAL);
+               }
+
+               *size = nvsize;
+               break;
+       }
+       default:
+               return (EINVAL);
+       }
+
+       return (0);
+}
+
+static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
+static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
+
+/*
+ * Common routine for nvlist operations:
+ * encode, decode, getsize (encoded size).
+ */
+static int
+nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
+    int nvs_op)
+{
+       int err = 0;
+       nvstream_t nvs;
+       int nvl_endian;
+#ifdef _LITTLE_ENDIAN
+       int host_endian = 1;
+#else
+       int host_endian = 0;
+#endif /* _LITTLE_ENDIAN */
+       nvs_header_t *nvh = (void *)buf;
+
+       if (buflen == NULL || nvl == NULL ||
+           (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+               return (EINVAL);
+
+       nvs.nvs_op = nvs_op;
+       nvs.nvs_recursion = 0;
+
+       /*
+        * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
+        * a buffer is allocated.  The first 4 bytes in the buffer are
+        * used for encoding method and host endian.
+        */
+       switch (nvs_op) {
+       case NVS_OP_ENCODE:
+               if (buf == NULL || *buflen < sizeof (nvs_header_t))
+                       return (EINVAL);
+
+               nvh->nvh_encoding = encoding;
+               nvh->nvh_endian = nvl_endian = host_endian;
+               nvh->nvh_reserved1 = 0;
+               nvh->nvh_reserved2 = 0;
+               break;
+
+       case NVS_OP_DECODE:
+               if (buf == NULL || *buflen < sizeof (nvs_header_t))
+                       return (EINVAL);
+
+               /* get method of encoding from first byte */
+               encoding = nvh->nvh_encoding;
+               nvl_endian = nvh->nvh_endian;
+               break;
+
+       case NVS_OP_GETSIZE:
+               nvl_endian = host_endian;
+
+               /*
+                * add the size for encoding
+                */
+               *buflen = sizeof (nvs_header_t);
+               break;
+
+       default:
+               return (ENOTSUP);
+       }
+
+       /*
+        * Create an nvstream with proper encoding method
+        */
+       switch (encoding) {
+       case NV_ENCODE_NATIVE:
+               /*
+                * check endianness, in case we are unpacking
+                * from a file
+                */
+               if (nvl_endian != host_endian)
+                       return (ENOTSUP);
+               err = nvs_native(&nvs, nvl, buf, buflen);
+               break;
+       case NV_ENCODE_XDR:
+               err = nvs_xdr(&nvs, nvl, buf, buflen);
+               break;
+       default:
+               err = ENOTSUP;
+               break;
+       }
+
+       return (err);
+}
+
+int
+nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
+{
+       return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
+}
+
+/*
+ * Pack nvlist into contiguous memory
+ */
+int
+nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
+    int kmflag)
+{
+       return (nvlist_xpack(nvl, bufp, buflen, encoding,
+           nvlist_nv_alloc(kmflag)));
+}
+
+int
+nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
+    nv_alloc_t *nva)
+{
+       nvpriv_t nvpriv;
+       size_t alloc_size;
+       char *buf;
+       int err;
+
+       if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
+               return (EINVAL);
+
+       if (*bufp != NULL)
+               return (nvlist_common(nvl, *bufp, buflen, encoding,
+                   NVS_OP_ENCODE));
+
+       /*
+        * Here is a difficult situation:
+        * 1. The nvlist has fixed allocator properties.
+        *    All other nvlist routines (like nvlist_add_*, ...) use
+        *    these properties.
+        * 2. When using nvlist_pack() the user can specify his own
+        *    allocator properties (e.g. by using KM_NOSLEEP).
+        *
+        * We use the user specified properties (2). A clearer solution
+        * will be to remove the kmflag from nvlist_pack(), but we will
+        * not change the interface.
+        */
+       nv_priv_init(&nvpriv, nva, 0);
+
+       if ((err = nvlist_size(nvl, &alloc_size, encoding)))
+               return (err);
+
+       if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
+               return (ENOMEM);
+
+       if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
+           NVS_OP_ENCODE)) != 0) {
+               nv_mem_free(&nvpriv, buf, alloc_size);
+       } else {
+               *buflen = alloc_size;
+               *bufp = buf;
+       }
+
+       return (err);
+}
+
+/*
+ * Unpack buf into an nvlist_t
+ */
+int
+nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
+{
+       return (nvlist_xunpack(buf, buflen, nvlp, nvlist_nv_alloc(kmflag)));
+}
+
+int
+nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
+{
+       nvlist_t *nvl;
+       int err;
+
+       if (nvlp == NULL)
+               return (EINVAL);
+
+       if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
+               return (err);
+
+       if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
+               nvlist_free(nvl);
+       else
+               *nvlp = nvl;
+
+       return (err);
+}
+
+/*
+ * Native encoding functions
+ */
+typedef struct {
+       /*
+        * This structure is used when decoding a packed nvpair in
+        * the native format.  n_base points to a buffer containing the
+        * packed nvpair.  n_end is a pointer to the end of the buffer.
+        * (n_end actually points to the first byte past the end of the
+        * buffer.)  n_curr is a pointer that lies between n_base and n_end.
+        * It points to the current data that we are decoding.
+        * The amount of data left in the buffer is equal to n_end - n_curr.
+        * n_flag is used to recognize a packed embedded list.
+        */
+       caddr_t n_base;
+       caddr_t n_end;
+       caddr_t n_curr;
+       uint_t  n_flag;
+} nvs_native_t;
+
+static int
+nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
+    size_t buflen)
+{
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+       case NVS_OP_DECODE:
+               nvs->nvs_private = native;
+               native->n_curr = native->n_base = buf;
+               native->n_end = buf + buflen;
+               native->n_flag = 0;
+               return (0);
+
+       case NVS_OP_GETSIZE:
+               nvs->nvs_private = native;
+               native->n_curr = native->n_base = native->n_end = NULL;
+               native->n_flag = 0;
+               return (0);
+       default:
+               return (EINVAL);
+       }
+}
+
+/*ARGSUSED*/
+static void
+nvs_native_destroy(nvstream_t *nvs)
+{
+}
+
+static int
+native_cp(nvstream_t *nvs, void *buf, size_t size)
+{
+       nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+
+       if (native->n_curr + size > native->n_end)
+               return (EFAULT);
+
+       /*
+        * The bcopy() below eliminates alignment requirement
+        * on the buffer (stream) and is preferred over direct access.
+        */
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+               bcopy(buf, native->n_curr, size);
+               break;
+       case NVS_OP_DECODE:
+               bcopy(native->n_curr, buf, size);
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       native->n_curr += size;
+       return (0);
+}
+
+/*
+ * operate on nvlist_t header
+ */
+static int
+nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
+{
+       nvs_native_t *native = nvs->nvs_private;
+
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+       case NVS_OP_DECODE:
+               if (native->n_flag)
+                       return (0);     /* packed embedded list */
+
+               native->n_flag = 1;
+
+               /* copy version and nvflag of the nvlist_t */
+               if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
+                   native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
+                       return (EFAULT);
+
+               return (0);
+
+       case NVS_OP_GETSIZE:
+               /*
+                * if calculate for packed embedded list
+                *      4 for end of the embedded list
+                * else
+                *      2 * sizeof (int32_t) for nvl_version and nvl_nvflag
+                *      and 4 for end of the entire list
+                */
+               if (native->n_flag) {
+                       *size += 4;
+               } else {
+                       native->n_flag = 1;
+                       *size += 2 * sizeof (int32_t) + 4;
+               }
+
+               return (0);
+
+       default:
+               return (EINVAL);
+       }
+}
+
+static int
+nvs_native_nvl_fini(nvstream_t *nvs)
+{
+       if (nvs->nvs_op == NVS_OP_ENCODE) {
+               nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+               /*
+                * Add 4 zero bytes at end of nvlist. They are used
+                * for end detection by the decode routine.
+                */
+               if (native->n_curr + sizeof (int) > native->n_end)
+                       return (EFAULT);
+
+               bzero(native->n_curr, sizeof (int));
+               native->n_curr += sizeof (int);
+       }
+
+       return (0);
+}
+
+static int
+nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
+{
+       if (nvs->nvs_op == NVS_OP_ENCODE) {
+               nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+               nvlist_t *packed = (void *)
+                   (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
+               /*
+                * Null out the pointer that is meaningless in the packed
+                * structure. The address may not be aligned, so we have
+                * to use bzero.
+                */
+               bzero((char *)packed + offsetof(nvlist_t, nvl_priv),
+                   sizeof (uint64_t));
+       }
+
+       return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
+}
+
+static int
+nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
+{
+       if (nvs->nvs_op == NVS_OP_ENCODE) {
+               nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+               char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
+               size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
+               nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len);
+               int i;
+               /*
+                * Null out pointers that are meaningless in the packed
+                * structure. The addresses may not be aligned, so we have
+                * to use bzero.
+                */
+               bzero(value, len);
+
+               for (i = 0; i < NVP_NELEM(nvp); i++, packed++)
+                       /*
+                        * Null out the pointer that is meaningless in the
+                        * packed structure. The address may not be aligned,
+                        * so we have to use bzero.
+                        */
+                       bzero((char *)packed + offsetof(nvlist_t, nvl_priv),
+                           sizeof (uint64_t));
+       }
+
+       return (nvs_embedded_nvl_array(nvs, nvp, NULL));
+}
+
+static void
+nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
+{
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE: {
+               nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+               uint64_t *strp = (void *)
+                   (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
+               /*
+                * Null out pointers that are meaningless in the packed
+                * structure. The addresses may not be aligned, so we have
+                * to use bzero.
+                */
+               bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
+               break;
+       }
+       case NVS_OP_DECODE: {
+               char **strp = (void *)NVP_VALUE(nvp);
+               char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
+               int i;
+
+               for (i = 0; i < NVP_NELEM(nvp); i++) {
+                       strp[i] = buf;
+                       buf += strlen(buf) + 1;
+               }
+               break;
+       }
+       }
+}
+
+static int
+nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
+{
+       data_type_t type;
+       int value_sz;
+       int ret = 0;
+
+       /*
+        * We do the initial bcopy of the data before we look at
+        * the nvpair type, because when we're decoding, we won't
+        * have the correct values for the pair until we do the bcopy.
+        */
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+       case NVS_OP_DECODE:
+               if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
+                       return (EFAULT);
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       /* verify nvp_name_sz, check the name string length */
+       if (i_validate_nvpair_name(nvp) != 0)
+               return (EFAULT);
+
+       type = NVP_TYPE(nvp);
+
+       /*
+        * Verify type and nelem and get the value size.
+        * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
+        * is the size of the string(s) excluded.
+        */
+       if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
+               return (EFAULT);
+
+       if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
+               return (EFAULT);
+
+       switch (type) {
+       case DATA_TYPE_NVLIST:
+               ret = nvpair_native_embedded(nvs, nvp);
+               break;
+       case DATA_TYPE_NVLIST_ARRAY:
+               ret = nvpair_native_embedded_array(nvs, nvp);
+               break;
+       case DATA_TYPE_STRING_ARRAY:
+               nvpair_native_string_array(nvs, nvp);
+               break;
+       default:
+               break;
+       }
+
+       return (ret);
+}
+
+static int
+nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+       uint64_t nvp_sz = nvp->nvp_size;
+
+       switch (NVP_TYPE(nvp)) {
+       case DATA_TYPE_NVLIST: {
+               size_t nvsize = 0;
+
+               if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
+                       return (EINVAL);
+
+               nvp_sz += nvsize;
+               break;
+       }
+       case DATA_TYPE_NVLIST_ARRAY: {
+               size_t nvsize;
+
+               if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
+                       return (EINVAL);
+
+               nvp_sz += nvsize;
+               break;
+       }
+       default:
+               break;
+       }
+
+       if (nvp_sz > INT32_MAX)
+               return (EINVAL);
+
+       *size = nvp_sz;
+
+       return (0);
+}
+
+static int
+nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+               return (nvs_native_nvp_op(nvs, nvp));
+
+       case NVS_OP_DECODE: {
+               nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+               int32_t decode_len;
+
+               /* try to read the size value from the stream */
+               if (native->n_curr + sizeof (int32_t) > native->n_end)
+                       return (EFAULT);
+               bcopy(native->n_curr, &decode_len, sizeof (int32_t));
+
+               /* sanity check the size value */
+               if (decode_len < 0 ||
+                   decode_len > native->n_end - native->n_curr)
+                       return (EFAULT);
+
+               *size = decode_len;
+
+               /*
+                * If at the end of the stream then move the cursor
+                * forward, otherwise nvpair_native_op() will read
+                * the entire nvpair at the same cursor position.
+                */
+               if (*size == 0)
+                       native->n_curr += sizeof (int32_t);
+               break;
+       }
+
+       default:
+               return (EINVAL);
+       }
+
+       return (0);
+}
+
+static const nvs_ops_t nvs_native_ops = {
+       nvs_native_nvlist,
+       nvs_native_nvpair,
+       nvs_native_nvp_op,
+       nvs_native_nvp_size,
+       nvs_native_nvl_fini
+};
+
+static int
+nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
+{
+       nvs_native_t native;
+       int err;
+
+       nvs->nvs_ops = &nvs_native_ops;
+
+       if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
+           *buflen - sizeof (nvs_header_t))) != 0)
+               return (err);
+
+       err = nvs_operation(nvs, nvl, buflen);
+
+       nvs_native_destroy(nvs);
+
+       return (err);
+}
+
+/*
+ * XDR encoding functions
+ *
+ * An xdr packed nvlist is encoded as:
+ *
+ *  - encoding methode and host endian (4 bytes)
+ *  - nvl_version (4 bytes)
+ *  - nvl_nvflag (4 bytes)
+ *
+ *  - encoded nvpairs, the format of one xdr encoded nvpair is:
+ *     - encoded size of the nvpair (4 bytes)
+ *     - decoded size of the nvpair (4 bytes)
+ *     - name string, (4 + sizeof(NV_ALIGN4(string))
+ *       a string is coded as size (4 bytes) and data
+ *     - data type (4 bytes)
+ *     - number of elements in the nvpair (4 bytes)
+ *     - data
+ *
+ *  - 2 zero's for end of the entire list (8 bytes)
+ */
+static int
+nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
+{
+       /* xdr data must be 4 byte aligned */
+       if ((ulong_t)buf % 4 != 0)
+               return (EFAULT);
+
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+               xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
+               nvs->nvs_private = xdr;
+               return (0);
+       case NVS_OP_DECODE:
+               xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
+               nvs->nvs_private = xdr;
+               return (0);
+       case NVS_OP_GETSIZE:
+               nvs->nvs_private = NULL;
+               return (0);
+       default:
+               return (EINVAL);
+       }
+}
+
+static void
+nvs_xdr_destroy(nvstream_t *nvs)
+{
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+       case NVS_OP_DECODE:
+               xdr_destroy((XDR *)nvs->nvs_private);
+               break;
+       default:
+               break;
+       }
+}
+
+static int
+nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
+{
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE:
+       case NVS_OP_DECODE: {
+               XDR     *xdr = nvs->nvs_private;
+
+               if (!xdr_int(xdr, &nvl->nvl_version) ||
+                   !xdr_u_int(xdr, &nvl->nvl_nvflag))
+                       return (EFAULT);
+               break;
+       }
+       case NVS_OP_GETSIZE: {
+               /*
+                * 2 * 4 for nvl_version + nvl_nvflag
+                * and 8 for end of the entire list
+                */
+               *size += 2 * 4 + 8;
+               break;
+       }
+       default:
+               return (EINVAL);
+       }
+       return (0);
+}
+
+static int
+nvs_xdr_nvl_fini(nvstream_t *nvs)
+{
+       if (nvs->nvs_op == NVS_OP_ENCODE) {
+               XDR *xdr = nvs->nvs_private;
+               int zero = 0;
+
+               if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
+                       return (EFAULT);
+       }
+
+       return (0);
+}
+
+/*
+ * The format of xdr encoded nvpair is:
+ * encode_size, decode_size, name string, data type, nelem, data
+ */
+static int
+nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
+{
+       data_type_t type;
+       char    *buf;
+       char    *buf_end = (char *)nvp + nvp->nvp_size;
+       int     value_sz;
+       uint_t  nelem, buflen;
+       bool_t  ret = FALSE;
+       XDR     *xdr = nvs->nvs_private;
+
+       ASSERT(xdr != NULL && nvp != NULL);
+
+       /* name string */
+       if ((buf = NVP_NAME(nvp)) >= buf_end)
+               return (EFAULT);
+       buflen = buf_end - buf;
+
+       if (!xdr_string(xdr, &buf, buflen - 1))
+               return (EFAULT);
+       nvp->nvp_name_sz = strlen(buf) + 1;
+
+       /* type and nelem */
+       if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
+           !xdr_int(xdr, &nvp->nvp_value_elem))
+               return (EFAULT);
+
+       type = NVP_TYPE(nvp);
+       nelem = nvp->nvp_value_elem;
+
+       /*
+        * Verify type and nelem and get the value size.
+        * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
+        * is the size of the string(s) excluded.
+        */
+       if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
+               return (EFAULT);
+
+       /* if there is no data to extract then return */
+       if (nelem == 0)
+               return (0);
+
+       /* value */
+       if ((buf = NVP_VALUE(nvp)) >= buf_end)
+               return (EFAULT);
+       buflen = buf_end - buf;
+
+       if (buflen < value_sz)
+               return (EFAULT);
+
+       switch (type) {
+       case DATA_TYPE_NVLIST:
+               if (nvs_embedded(nvs, (void *)buf) == 0)
+                       return (0);
+               break;
+
+       case DATA_TYPE_NVLIST_ARRAY:
+               if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
+                       return (0);
+               break;
+
+       case DATA_TYPE_BOOLEAN:
+               ret = TRUE;
+               break;
+
+       case DATA_TYPE_BYTE:
+       case DATA_TYPE_INT8:
+       case DATA_TYPE_UINT8:
+               ret = xdr_char(xdr, buf);
+               break;
+
+       case DATA_TYPE_INT16:
+               ret = xdr_short(xdr, (void *)buf);
+               break;
+
+       case DATA_TYPE_UINT16:
+               ret = xdr_u_short(xdr, (void *)buf);
+               break;
+
+       case DATA_TYPE_BOOLEAN_VALUE:
+       case DATA_TYPE_INT32:
+               ret = xdr_int(xdr, (void *)buf);
+               break;
+
+       case DATA_TYPE_UINT32:
+               ret = xdr_u_int(xdr, (void *)buf);
+               break;
+
+       case DATA_TYPE_INT64:
+               ret = xdr_longlong_t(xdr, (void *)buf);
+               break;
+
+       case DATA_TYPE_UINT64:
+               ret = xdr_u_longlong_t(xdr, (void *)buf);
+               break;
+
+       case DATA_TYPE_HRTIME:
+               /*
+                * NOTE: must expose the definition of hrtime_t here
+                */
+               ret = xdr_longlong_t(xdr, (void *)buf);
+               break;
+#if !defined(_KERNEL)
+       case DATA_TYPE_DOUBLE:
+               ret = xdr_double(xdr, (void *)buf);
+               break;
+#endif
+       case DATA_TYPE_STRING:
+               ret = xdr_string(xdr, &buf, buflen - 1);
+               break;
+
+       case DATA_TYPE_BYTE_ARRAY:
+               ret = xdr_opaque(xdr, buf, nelem);
+               break;
+
+       case DATA_TYPE_INT8_ARRAY:
+       case DATA_TYPE_UINT8_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
+                   (xdrproc_t)xdr_char);
+               break;
+
+       case DATA_TYPE_INT16_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
+                   sizeof (int16_t), (xdrproc_t)xdr_short);
+               break;
+
+       case DATA_TYPE_UINT16_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
+                   sizeof (uint16_t), (xdrproc_t)xdr_u_short);
+               break;
+
+       case DATA_TYPE_BOOLEAN_ARRAY:
+       case DATA_TYPE_INT32_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
+                   sizeof (int32_t), (xdrproc_t)xdr_int);
+               break;
+
+       case DATA_TYPE_UINT32_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
+                   sizeof (uint32_t), (xdrproc_t)xdr_u_int);
+               break;
+
+       case DATA_TYPE_INT64_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
+                   sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
+               break;
+
+       case DATA_TYPE_UINT64_ARRAY:
+               ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
+                   sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
+               break;
+
+       case DATA_TYPE_STRING_ARRAY: {
+               size_t len = nelem * sizeof (uint64_t);
+               char **strp = (void *)buf;
+               int i;
+
+               if (nvs->nvs_op == NVS_OP_DECODE)
+                       bzero(buf, len);        /* don't trust packed data */
+
+               for (i = 0; i < nelem; i++) {
+                       if (buflen <= len)
+                               return (EFAULT);
+
+                       buf += len;
+                       buflen -= len;
+
+                       if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
+                               return (EFAULT);
+
+                       if (nvs->nvs_op == NVS_OP_DECODE)
+                               strp[i] = buf;
+                       len = strlen(buf) + 1;
+               }
+               ret = TRUE;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return (ret == TRUE ? 0 : EFAULT);
+}
+
+static int
+nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+       data_type_t type = NVP_TYPE(nvp);
+       /*
+        * encode_size + decode_size + name string size + data type + nelem
+        * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
+        */
+       uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
+
+       switch (type) {
+       case DATA_TYPE_BOOLEAN:
+               break;
+
+       case DATA_TYPE_BOOLEAN_VALUE:
+       case DATA_TYPE_BYTE:
+       case DATA_TYPE_INT8:
+       case DATA_TYPE_UINT8:
+       case DATA_TYPE_INT16:
+       case DATA_TYPE_UINT16:
+       case DATA_TYPE_INT32:
+       case DATA_TYPE_UINT32:
+               nvp_sz += 4;    /* 4 is the minimum xdr unit */
+               break;
+
+       case DATA_TYPE_INT64:
+       case DATA_TYPE_UINT64:
+       case DATA_TYPE_HRTIME:
+#if !defined(_KERNEL)
+       case DATA_TYPE_DOUBLE:
+#endif
+               nvp_sz += 8;
+               break;
+
+       case DATA_TYPE_STRING:
+               nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
+               break;
+
+       case DATA_TYPE_BYTE_ARRAY:
+               nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
+               break;
+
+       case DATA_TYPE_BOOLEAN_ARRAY:
+       case DATA_TYPE_INT8_ARRAY:
+       case DATA_TYPE_UINT8_ARRAY:
+       case DATA_TYPE_INT16_ARRAY:
+       case DATA_TYPE_UINT16_ARRAY:
+       case DATA_TYPE_INT32_ARRAY:
+       case DATA_TYPE_UINT32_ARRAY:
+               nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
+               break;
+
+       case DATA_TYPE_INT64_ARRAY:
+       case DATA_TYPE_UINT64_ARRAY:
+               nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
+               break;
+
+       case DATA_TYPE_STRING_ARRAY: {
+               int i;
+               char **strs = (void *)NVP_VALUE(nvp);
+
+               for (i = 0; i < NVP_NELEM(nvp); i++)
+                       nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
+
+               break;
+       }
+
+       case DATA_TYPE_NVLIST:
+       case DATA_TYPE_NVLIST_ARRAY: {
+               size_t nvsize = 0;
+               int old_nvs_op = nvs->nvs_op;
+               int err;
+
+               nvs->nvs_op = NVS_OP_GETSIZE;
+               if (type == DATA_TYPE_NVLIST)
+                       err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
+               else
+                       err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
+               nvs->nvs_op = old_nvs_op;
+
+               if (err != 0)
+                       return (EINVAL);
+
+               nvp_sz += nvsize;
+               break;
+       }
+
+       default:
+               return (EINVAL);
+       }
+
+       if (nvp_sz > INT32_MAX)
+               return (EINVAL);
+
+       *size = nvp_sz;
+
+       return (0);
+}
+
+
+/*
+ * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
+ * the largest nvpair that could be encoded in the buffer.
+ *
+ * See comments above nvpair_xdr_op() for the format of xdr encoding.
+ * The size of a xdr packed nvpair without any data is 5 words.
+ *
+ * Using the size of the data directly as an estimate would be ok
+ * in all cases except one.  If the data type is of DATA_TYPE_STRING_ARRAY
+ * then the actual nvpair has space for an array of pointers to index
+ * the strings.  These pointers are not encoded into the packed xdr buffer.
+ *
+ * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
+ * of length 0, then each string is endcoded in xdr format as a single word.
+ * Therefore when expanded to an nvpair there will be 2.25 word used for
+ * each string.  (a int64_t allocated for pointer usage, and a single char
+ * for the null termination.)
+ *
+ * This is the calculation performed by the NVS_XDR_MAX_LEN macro.
+ */
+#define        NVS_XDR_HDR_LEN         ((size_t)(5 * 4))
+#define        NVS_XDR_DATA_LEN(y)     (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
+                                       0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
+#define        NVS_XDR_MAX_LEN(x)      (NVP_SIZE_CALC(1, 0) + \
+                                       (NVS_XDR_DATA_LEN(x) * 2) + \
+                                       NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
+
+static int
+nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+       XDR     *xdr = nvs->nvs_private;
+       int32_t encode_len, decode_len;
+
+       switch (nvs->nvs_op) {
+       case NVS_OP_ENCODE: {
+               size_t nvsize;
+
+               if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
+                       return (EFAULT);
+
+               decode_len = nvp->nvp_size;
+               encode_len = nvsize;
+               if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
+                       return (EFAULT);
+
+               return (nvs_xdr_nvp_op(nvs, nvp));
+       }
+       case NVS_OP_DECODE: {
+               struct xdr_bytesrec bytesrec;
+
+               /* get the encode and decode size */
+               if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
+                       return (EFAULT);
+               *size = decode_len;
+
+               /* are we at the end of the stream? */
+               if (*size == 0)
+                       return (0);
+
+               /* sanity check the size parameter */
+               if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
+                       return (EFAULT);
+
+               if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
+                       return (EFAULT);
+               break;
+       }
+
+       default:
+               return (EINVAL);
+       }
+       return (0);
+}
+
+static const struct nvs_ops nvs_xdr_ops = {
+       nvs_xdr_nvlist,
+       nvs_xdr_nvpair,
+       nvs_xdr_nvp_op,
+       nvs_xdr_nvp_size,
+       nvs_xdr_nvl_fini
+};
+
+static int
+nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
+{
+       XDR xdr;
+       int err;
+
+       nvs->nvs_ops = &nvs_xdr_ops;
+
+       if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
+           *buflen - sizeof (nvs_header_t))) != 0)
+               return (err);
+
+       err = nvs_operation(nvs, nvl, buflen);
+
+       nvs_xdr_destroy(nvs);
+
+       return (err);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+static int __init
+nvpair_init(void)
+{
+       return (0);
+}
+
+static void __exit
+nvpair_fini(void)
+{
+}
+
+module_init(nvpair_init);
+module_exit(nvpair_fini);
+
+MODULE_DESCRIPTION("Generic name/value pair implementation");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
+
+EXPORT_SYMBOL(nv_alloc_init);
+EXPORT_SYMBOL(nv_alloc_reset);
+EXPORT_SYMBOL(nv_alloc_fini);
+
+/* list management */
+EXPORT_SYMBOL(nvlist_alloc);
+EXPORT_SYMBOL(nvlist_free);
+EXPORT_SYMBOL(nvlist_size);
+EXPORT_SYMBOL(nvlist_pack);
+EXPORT_SYMBOL(nvlist_unpack);
+EXPORT_SYMBOL(nvlist_dup);
+EXPORT_SYMBOL(nvlist_merge);
+
+EXPORT_SYMBOL(nvlist_xalloc);
+EXPORT_SYMBOL(nvlist_xpack);
+EXPORT_SYMBOL(nvlist_xunpack);
+EXPORT_SYMBOL(nvlist_xdup);
+EXPORT_SYMBOL(nvlist_lookup_nv_alloc);
+
+EXPORT_SYMBOL(nvlist_add_nvpair);
+EXPORT_SYMBOL(nvlist_add_boolean);
+EXPORT_SYMBOL(nvlist_add_boolean_value);
+EXPORT_SYMBOL(nvlist_add_byte);
+EXPORT_SYMBOL(nvlist_add_int8);
+EXPORT_SYMBOL(nvlist_add_uint8);
+EXPORT_SYMBOL(nvlist_add_int16);
+EXPORT_SYMBOL(nvlist_add_uint16);
+EXPORT_SYMBOL(nvlist_add_int32);
+EXPORT_SYMBOL(nvlist_add_uint32);
+EXPORT_SYMBOL(nvlist_add_int64);
+EXPORT_SYMBOL(nvlist_add_uint64);
+EXPORT_SYMBOL(nvlist_add_string);
+EXPORT_SYMBOL(nvlist_add_nvlist);
+EXPORT_SYMBOL(nvlist_add_boolean_array);
+EXPORT_SYMBOL(nvlist_add_byte_array);
+EXPORT_SYMBOL(nvlist_add_int8_array);
+EXPORT_SYMBOL(nvlist_add_uint8_array);
+EXPORT_SYMBOL(nvlist_add_int16_array);
+EXPORT_SYMBOL(nvlist_add_uint16_array);
+EXPORT_SYMBOL(nvlist_add_int32_array);
+EXPORT_SYMBOL(nvlist_add_uint32_array);
+EXPORT_SYMBOL(nvlist_add_int64_array);
+EXPORT_SYMBOL(nvlist_add_uint64_array);
+EXPORT_SYMBOL(nvlist_add_string_array);
+EXPORT_SYMBOL(nvlist_add_nvlist_array);
+EXPORT_SYMBOL(nvlist_next_nvpair);
+EXPORT_SYMBOL(nvlist_prev_nvpair);
+EXPORT_SYMBOL(nvlist_empty);
+EXPORT_SYMBOL(nvlist_add_hrtime);
+
+EXPORT_SYMBOL(nvlist_remove);
+EXPORT_SYMBOL(nvlist_remove_nvpair);
+EXPORT_SYMBOL(nvlist_remove_all);
+
+EXPORT_SYMBOL(nvlist_lookup_boolean);
+EXPORT_SYMBOL(nvlist_lookup_boolean_value);
+EXPORT_SYMBOL(nvlist_lookup_byte);
+EXPORT_SYMBOL(nvlist_lookup_int8);
+EXPORT_SYMBOL(nvlist_lookup_uint8);
+EXPORT_SYMBOL(nvlist_lookup_int16);
+EXPORT_SYMBOL(nvlist_lookup_uint16);
+EXPORT_SYMBOL(nvlist_lookup_int32);
+EXPORT_SYMBOL(nvlist_lookup_uint32);
+EXPORT_SYMBOL(nvlist_lookup_int64);
+EXPORT_SYMBOL(nvlist_lookup_uint64);
+EXPORT_SYMBOL(nvlist_lookup_string);
+EXPORT_SYMBOL(nvlist_lookup_nvlist);
+EXPORT_SYMBOL(nvlist_lookup_boolean_array);
+EXPORT_SYMBOL(nvlist_lookup_byte_array);
+EXPORT_SYMBOL(nvlist_lookup_int8_array);
+EXPORT_SYMBOL(nvlist_lookup_uint8_array);
+EXPORT_SYMBOL(nvlist_lookup_int16_array);
+EXPORT_SYMBOL(nvlist_lookup_uint16_array);
+EXPORT_SYMBOL(nvlist_lookup_int32_array);
+EXPORT_SYMBOL(nvlist_lookup_uint32_array);
+EXPORT_SYMBOL(nvlist_lookup_int64_array);
+EXPORT_SYMBOL(nvlist_lookup_uint64_array);
+EXPORT_SYMBOL(nvlist_lookup_string_array);
+EXPORT_SYMBOL(nvlist_lookup_nvlist_array);
+EXPORT_SYMBOL(nvlist_lookup_hrtime);
+EXPORT_SYMBOL(nvlist_lookup_pairs);
+
+EXPORT_SYMBOL(nvlist_lookup_nvpair);
+EXPORT_SYMBOL(nvlist_exists);
+
+/* processing nvpair */
+EXPORT_SYMBOL(nvpair_name);
+EXPORT_SYMBOL(nvpair_type);
+EXPORT_SYMBOL(nvpair_value_boolean_value);
+EXPORT_SYMBOL(nvpair_value_byte);
+EXPORT_SYMBOL(nvpair_value_int8);
+EXPORT_SYMBOL(nvpair_value_uint8);
+EXPORT_SYMBOL(nvpair_value_int16);
+EXPORT_SYMBOL(nvpair_value_uint16);
+EXPORT_SYMBOL(nvpair_value_int32);
+EXPORT_SYMBOL(nvpair_value_uint32);
+EXPORT_SYMBOL(nvpair_value_int64);
+EXPORT_SYMBOL(nvpair_value_uint64);
+EXPORT_SYMBOL(nvpair_value_string);
+EXPORT_SYMBOL(nvpair_value_nvlist);
+EXPORT_SYMBOL(nvpair_value_boolean_array);
+EXPORT_SYMBOL(nvpair_value_byte_array);
+EXPORT_SYMBOL(nvpair_value_int8_array);
+EXPORT_SYMBOL(nvpair_value_uint8_array);
+EXPORT_SYMBOL(nvpair_value_int16_array);
+EXPORT_SYMBOL(nvpair_value_uint16_array);
+EXPORT_SYMBOL(nvpair_value_int32_array);
+EXPORT_SYMBOL(nvpair_value_uint32_array);
+EXPORT_SYMBOL(nvpair_value_int64_array);
+EXPORT_SYMBOL(nvpair_value_uint64_array);
+EXPORT_SYMBOL(nvpair_value_string_array);
+EXPORT_SYMBOL(nvpair_value_nvlist_array);
+EXPORT_SYMBOL(nvpair_value_hrtime);
+
+#endif
diff --git a/zfs/module/nvpair/nvpair_alloc_fixed.c b/zfs/module/nvpair/nvpair_alloc_fixed.c
new file mode 100644 (file)
index 0000000..20081ba
--- /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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#include <sys/stropts.h>
+#include <sys/isa_defs.h>
+#include <sys/nvpair.h>
+#include <sys/sysmacros.h>
+#if defined(_KERNEL) && !defined(_BOOT)
+#include <sys/varargs.h>
+#else
+#include <stdarg.h>
+#include <strings.h>
+#endif
+
+/*
+ * This allocator is very simple.
+ *  - it uses a pre-allocated buffer for memory allocations.
+ *  - it does _not_ free memory in the pre-allocated buffer.
+ *
+ * The reason for the selected implemention is simplicity.
+ * This allocator is designed for the usage in interrupt context when
+ * the caller may not wait for free memory.
+ */
+
+/* pre-allocated buffer for memory allocations */
+typedef struct nvbuf {
+       uintptr_t       nvb_buf;        /* address of pre-allocated buffer */
+       uintptr_t       nvb_lim;        /* limit address in the buffer */
+       uintptr_t       nvb_cur;        /* current address in the buffer */
+} nvbuf_t;
+
+/*
+ * Initialize the pre-allocated buffer allocator. The caller needs to supply
+ *
+ *   buf       address of pre-allocated buffer
+ *   bufsz     size of pre-allocated buffer
+ *
+ * nv_fixed_init() calculates the remaining members of nvbuf_t.
+ */
+static int
+nv_fixed_init(nv_alloc_t *nva, va_list valist)
+{
+       uintptr_t base = va_arg(valist, uintptr_t);
+       uintptr_t lim = base + va_arg(valist, size_t);
+       nvbuf_t *nvb = (nvbuf_t *)P2ROUNDUP(base, sizeof (uintptr_t));
+
+       if (base == 0 || (uintptr_t)&nvb[1] > lim)
+               return (EINVAL);
+
+       nvb->nvb_buf = (uintptr_t)&nvb[0];
+       nvb->nvb_cur = (uintptr_t)&nvb[1];
+       nvb->nvb_lim = lim;
+       nva->nva_arg = nvb;
+
+       return (0);
+}
+
+static void *
+nv_fixed_alloc(nv_alloc_t *nva, size_t size)
+{
+       nvbuf_t *nvb = nva->nva_arg;
+       uintptr_t new = nvb->nvb_cur;
+
+       if (size == 0 || new + size > nvb->nvb_lim)
+               return (NULL);
+
+       nvb->nvb_cur = P2ROUNDUP(new + size, sizeof (uintptr_t));
+
+       return ((void *)new);
+}
+
+/*ARGSUSED*/
+static void
+nv_fixed_free(nv_alloc_t *nva, void *buf, size_t size)
+{
+       /* don't free memory in the pre-allocated buffer */
+}
+
+static void
+nv_fixed_reset(nv_alloc_t *nva)
+{
+       nvbuf_t *nvb = nva->nva_arg;
+
+       nvb->nvb_cur = (uintptr_t)&nvb[1];
+}
+
+const nv_alloc_ops_t nv_fixed_ops_def = {
+       nv_fixed_init,  /* nv_ao_init() */
+       NULL,           /* nv_ao_fini() */
+       nv_fixed_alloc, /* nv_ao_alloc() */
+       nv_fixed_free,  /* nv_ao_free() */
+       nv_fixed_reset  /* nv_ao_reset() */
+};
+
+const nv_alloc_ops_t *nv_fixed_ops = &nv_fixed_ops_def;
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(nv_fixed_ops);
+#endif
diff --git a/zfs/module/nvpair/nvpair_alloc_spl.c b/zfs/module/nvpair/nvpair_alloc_spl.c
new file mode 100644 (file)
index 0000000..bc377ab
--- /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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/nvpair.h>
+#include <sys/kmem.h>
+#include <sys/vmem.h>
+
+static void *
+nv_alloc_sleep_spl(nv_alloc_t *nva, size_t size)
+{
+       return (vmem_alloc(size, KM_SLEEP));
+}
+
+static void *
+nv_alloc_pushpage_spl(nv_alloc_t *nva, size_t size)
+{
+       return (vmem_alloc(size, KM_PUSHPAGE));
+}
+
+static void *
+nv_alloc_nosleep_spl(nv_alloc_t *nva, size_t size)
+{
+       return (kmem_alloc(size, KM_NOSLEEP));
+}
+
+static void
+nv_free_spl(nv_alloc_t *nva, void *buf, size_t size)
+{
+       kmem_free(buf, size);
+}
+
+const nv_alloc_ops_t spl_sleep_ops_def = {
+       NULL,                   /* nv_ao_init() */
+       NULL,                   /* nv_ao_fini() */
+       nv_alloc_sleep_spl,     /* nv_ao_alloc() */
+       nv_free_spl,            /* nv_ao_free() */
+       NULL                    /* nv_ao_reset() */
+};
+
+const nv_alloc_ops_t spl_pushpage_ops_def = {
+       NULL,                   /* nv_ao_init() */
+       NULL,                   /* nv_ao_fini() */
+       nv_alloc_pushpage_spl,  /* nv_ao_alloc() */
+       nv_free_spl,            /* nv_ao_free() */
+       NULL                    /* nv_ao_reset() */
+};
+
+const nv_alloc_ops_t spl_nosleep_ops_def = {
+       NULL,                   /* nv_ao_init() */
+       NULL,                   /* nv_ao_fini() */
+       nv_alloc_nosleep_spl,   /* nv_ao_alloc() */
+       nv_free_spl,            /* nv_ao_free() */
+       NULL                    /* nv_ao_reset() */
+};
+
+nv_alloc_t nv_alloc_sleep_def = {
+       &spl_sleep_ops_def,
+       NULL
+};
+
+nv_alloc_t nv_alloc_pushpage_def = {
+       &spl_pushpage_ops_def,
+       NULL
+};
+
+nv_alloc_t nv_alloc_nosleep_def = {
+       &spl_nosleep_ops_def,
+       NULL
+};
+
+nv_alloc_t *nv_alloc_sleep = &nv_alloc_sleep_def;
+nv_alloc_t *nv_alloc_pushpage = &nv_alloc_pushpage_def;
+nv_alloc_t *nv_alloc_nosleep = &nv_alloc_nosleep_def;
diff --git a/zfs/module/unicode/Makefile.in b/zfs/module/unicode/Makefile.in
new file mode 100644 (file)
index 0000000..b26e669
--- /dev/null
@@ -0,0 +1,11 @@
+src = @abs_top_srcdir@/module/unicode
+obj = @abs_builddir@
+
+MODULE := zunicode
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+$(MODULE)-objs += u8_textprep.o
+$(MODULE)-objs += uconv.o
diff --git a/zfs/module/unicode/u8_textprep.c b/zfs/module/unicode/u8_textprep.c
new file mode 100644 (file)
index 0000000..26cc39f
--- /dev/null
@@ -0,0 +1,2157 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+
+
+
+/*
+ * UTF-8 text preparation functions (PSARC/2007/149, PSARC/2007/458).
+ *
+ * Man pages: u8_textprep_open(9F), u8_textprep_buf(9F), u8_textprep_close(9F),
+ * u8_textprep_str(9F), u8_strcmp(9F), and u8_validate(9F). See also
+ * the section 3C man pages.
+ * Interface stability: Committed.
+ */
+
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#else
+#include <sys/u8_textprep.h>
+#include <strings.h>
+#endif /* _KERNEL */
+#include <sys/byteorder.h>
+#include <sys/errno.h>
+#include <sys/u8_textprep_data.h>
+
+
+/* The maximum possible number of bytes in a UTF-8 character. */
+#define        U8_MB_CUR_MAX                   (4)
+
+/*
+ * The maximum number of bytes needed for a UTF-8 character to cover
+ * U+0000 - U+FFFF, i.e., the coding space of now deprecated UCS-2.
+ */
+#define        U8_MAX_BYTES_UCS2               (3)
+
+/* The maximum possible number of bytes in a Stream-Safe Text. */
+#define        U8_STREAM_SAFE_TEXT_MAX         (128)
+
+/*
+ * The maximum number of characters in a combining/conjoining sequence and
+ * the actual upperbound limit of a combining/conjoining sequence.
+ */
+#define        U8_MAX_CHARS_A_SEQ              (32)
+#define        U8_UPPER_LIMIT_IN_A_SEQ         (31)
+
+/* The combining class value for Starter. */
+#define        U8_COMBINING_CLASS_STARTER      (0)
+
+/*
+ * Some Hangul related macros at below.
+ *
+ * The first and the last of Hangul syllables, Hangul Jamo Leading consonants,
+ * Vowels, and optional Trailing consonants in Unicode scalar values.
+ *
+ * Please be noted that the U8_HANGUL_JAMO_T_FIRST is 0x11A7 at below not
+ * the actual U+11A8. This is due to that the trailing consonant is optional
+ * and thus we are doing a pre-calculation of subtracting one.
+ *
+ * Each of 19 modern leading consonants has total 588 possible syllables since
+ * Hangul has 21 modern vowels and 27 modern trailing consonants plus 1 for
+ * no trailing consonant case, i.e., 21 x 28 = 588.
+ *
+ * We also have bunch of Hangul related macros at below. Please bear in mind
+ * that the U8_HANGUL_JAMO_1ST_BYTE can be used to check whether it is
+ * a Hangul Jamo or not but the value does not guarantee that it is a Hangul
+ * Jamo; it just guarantee that it will be most likely.
+ */
+#define        U8_HANGUL_SYL_FIRST             (0xAC00U)
+#define        U8_HANGUL_SYL_LAST              (0xD7A3U)
+
+#define        U8_HANGUL_JAMO_L_FIRST          (0x1100U)
+#define        U8_HANGUL_JAMO_L_LAST           (0x1112U)
+#define        U8_HANGUL_JAMO_V_FIRST          (0x1161U)
+#define        U8_HANGUL_JAMO_V_LAST           (0x1175U)
+#define        U8_HANGUL_JAMO_T_FIRST          (0x11A7U)
+#define        U8_HANGUL_JAMO_T_LAST           (0x11C2U)
+
+#define        U8_HANGUL_V_COUNT               (21)
+#define        U8_HANGUL_VT_COUNT              (588)
+#define        U8_HANGUL_T_COUNT               (28)
+
+#define        U8_HANGUL_JAMO_1ST_BYTE         (0xE1U)
+
+#define        U8_SAVE_HANGUL_AS_UTF8(s, i, j, k, b) \
+       (s)[(i)] = (uchar_t)(0xE0U | ((uint32_t)(b) & 0xF000U) >> 12); \
+       (s)[(j)] = (uchar_t)(0x80U | ((uint32_t)(b) & 0x0FC0U) >> 6); \
+       (s)[(k)] = (uchar_t)(0x80U | ((uint32_t)(b) & 0x003FU));
+
+#define        U8_HANGUL_JAMO_L(u) \
+       ((u) >= U8_HANGUL_JAMO_L_FIRST && (u) <= U8_HANGUL_JAMO_L_LAST)
+
+#define        U8_HANGUL_JAMO_V(u) \
+       ((u) >= U8_HANGUL_JAMO_V_FIRST && (u) <= U8_HANGUL_JAMO_V_LAST)
+
+#define        U8_HANGUL_JAMO_T(u) \
+       ((u) > U8_HANGUL_JAMO_T_FIRST && (u) <= U8_HANGUL_JAMO_T_LAST)
+
+#define        U8_HANGUL_JAMO(u) \
+       ((u) >= U8_HANGUL_JAMO_L_FIRST && (u) <= U8_HANGUL_JAMO_T_LAST)
+
+#define        U8_HANGUL_SYLLABLE(u) \
+       ((u) >= U8_HANGUL_SYL_FIRST && (u) <= U8_HANGUL_SYL_LAST)
+
+#define        U8_HANGUL_COMPOSABLE_L_V(s, u) \
+       ((s) == U8_STATE_HANGUL_L && U8_HANGUL_JAMO_V((u)))
+
+#define        U8_HANGUL_COMPOSABLE_LV_T(s, u) \
+       ((s) == U8_STATE_HANGUL_LV && U8_HANGUL_JAMO_T((u)))
+
+/* The types of decomposition mappings. */
+#define        U8_DECOMP_BOTH                  (0xF5U)
+#define        U8_DECOMP_CANONICAL             (0xF6U)
+
+/* The indicator for 16-bit table. */
+#define        U8_16BIT_TABLE_INDICATOR        (0x8000U)
+
+/* The following are some convenience macros. */
+#define        U8_PUT_3BYTES_INTO_UTF32(u, b1, b2, b3)  \
+       (u) = ((((uint32_t)(b1) & 0x0F) << 12) | \
+               (((uint32_t)(b2) & 0x3F) << 6)  | \
+               ((uint32_t)(b3) & 0x3F));
+
+#define        U8_SIMPLE_SWAP(a, b, t) \
+       (t) = (a); \
+       (a) = (b); \
+       (b) = (t);
+
+#define        U8_ASCII_TOUPPER(c) \
+       (((c) >= 'a' && (c) <= 'z') ? (c) - 'a' + 'A' : (c))
+
+#define        U8_ASCII_TOLOWER(c) \
+       (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
+
+#define        U8_ISASCII(c)                   (((uchar_t)(c)) < 0x80U)
+/*
+ * The following macro assumes that the two characters that are to be
+ * swapped are adjacent to each other and 'a' comes before 'b'.
+ *
+ * If the assumptions are not met, then, the macro will fail.
+ */
+#define        U8_SWAP_COMB_MARKS(a, b) \
+       for (k = 0; k < disp[(a)]; k++) \
+               u8t[k] = u8s[start[(a)] + k]; \
+       for (k = 0; k < disp[(b)]; k++) \
+               u8s[start[(a)] + k] = u8s[start[(b)] + k]; \
+       start[(b)] = start[(a)] + disp[(b)]; \
+       for (k = 0; k < disp[(a)]; k++) \
+               u8s[start[(b)] + k] = u8t[k]; \
+       U8_SIMPLE_SWAP(comb_class[(a)], comb_class[(b)], tc); \
+       U8_SIMPLE_SWAP(disp[(a)], disp[(b)], tc);
+
+/* The possible states during normalization. */
+typedef enum {
+       U8_STATE_START = 0,
+       U8_STATE_HANGUL_L = 1,
+       U8_STATE_HANGUL_LV = 2,
+       U8_STATE_HANGUL_LVT = 3,
+       U8_STATE_HANGUL_V = 4,
+       U8_STATE_HANGUL_T = 5,
+       U8_STATE_COMBINING_MARK = 6
+} u8_normalization_states_t;
+
+/*
+ * The three vectors at below are used to check bytes of a given UTF-8
+ * character are valid and not containing any malformed byte values.
+ *
+ * We used to have a quite relaxed UTF-8 binary representation but then there
+ * was some security related issues and so the Unicode Consortium defined
+ * and announced the UTF-8 Corrigendum at Unicode 3.1 and then refined it
+ * one more time at the Unicode 3.2. The following three tables are based on
+ * that.
+ */
+
+#define        U8_ILLEGAL_NEXT_BYTE_COMMON(c)  ((c) < 0x80 || (c) > 0xBF)
+
+#define        I_                              U8_ILLEGAL_CHAR
+#define        O_                              U8_OUT_OF_RANGE_CHAR
+
+const int8_t u8_number_of_bytes[0x100] = {
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+
+/*     80  81  82  83  84  85  86  87  88  89  8A  8B  8C  8D  8E  8F  */
+       I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
+
+/*     90  91  92  93  94  95  96  97  98  99  9A  9B  9C  9D  9E  9F  */
+       I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
+
+/*     A0  A1  A2  A3  A4  A5  A6  A7  A8  A9  AA  AB  AC  AD  AE  AF  */
+       I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
+
+/*     B0  B1  B2  B3  B4  B5  B6  B7  B8  B9  BA  BB  BC  BD  BE  BF  */
+       I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
+
+/*     C0  C1  C2  C3  C4  C5  C6  C7  C8  C9  CA  CB  CC  CD  CE  CF  */
+       I_, I_, 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+
+/*     D0  D1  D2  D3  D4  D5  D6  D7  D8  D9  DA  DB  DC  DD  DE  DF  */
+       2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+
+/*     E0  E1  E2  E3  E4  E5  E6  E7  E8  E9  EA  EB  EC  ED  EE  EF  */
+       3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+
+/*     F0  F1  F2  F3  F4  F5  F6  F7  F8  F9  FA  FB  FC  FD  FE  FF  */
+       4,  4,  4,  4,  4,  O_, O_, O_, O_, O_, O_, O_, O_, O_, O_, O_,
+};
+
+#undef I_
+#undef O_
+
+const uint8_t u8_valid_min_2nd_byte[0x100] = {
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+/*     C0    C1    C2    C3    C4    C5    C6    C7    */
+       0,    0,    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/*     C8    C9    CA    CB    CC    CD    CE    CF    */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/*     D0    D1    D2    D3    D4    D5    D6    D7    */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/*     D8    D9    DA    DB    DC    DD    DE    DF    */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/*     E0    E1    E2    E3    E4    E5    E6    E7    */
+       0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/*     E8    E9    EA    EB    EC    ED    EE    EF    */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/*     F0    F1    F2    F3    F4    F5    F6    F7    */
+       0x90, 0x80, 0x80, 0x80, 0x80, 0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+};
+
+const uint8_t u8_valid_max_2nd_byte[0x100] = {
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+/*     C0    C1    C2    C3    C4    C5    C6    C7    */
+       0,    0,    0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+/*     C8    C9    CA    CB    CC    CD    CE    CF    */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+/*     D0    D1    D2    D3    D4    D5    D6    D7    */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+/*     D8    D9    DA    DB    DC    DD    DE    DF    */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+/*     E0    E1    E2    E3    E4    E5    E6    E7    */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+/*     E8    E9    EA    EB    EC    ED    EE    EF    */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x9f, 0xbf, 0xbf,
+/*     F0    F1    F2    F3    F4    F5    F6    F7    */
+       0xbf, 0xbf, 0xbf, 0xbf, 0x8f, 0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+};
+
+
+/*
+ * The u8_validate() validates on the given UTF-8 character string and
+ * calculate the byte length. It is quite similar to mblen(3C) except that
+ * this will validate against the list of characters if required and
+ * specific to UTF-8 and Unicode.
+ */
+int
+u8_validate(char *u8str, size_t n, char **list, int flag, int *errnum)
+{
+       uchar_t *ib;
+       uchar_t *ibtail;
+       uchar_t **p;
+       uchar_t *s1;
+       uchar_t *s2;
+       uchar_t f;
+       int sz;
+       size_t i;
+       int ret_val;
+       boolean_t second;
+       boolean_t no_need_to_validate_entire;
+       boolean_t check_additional;
+       boolean_t validate_ucs2_range_only;
+
+       if (! u8str)
+               return (0);
+
+       ib = (uchar_t *)u8str;
+       ibtail = ib + n;
+
+       ret_val = 0;
+
+       no_need_to_validate_entire = ! (flag & U8_VALIDATE_ENTIRE);
+       check_additional = flag & U8_VALIDATE_CHECK_ADDITIONAL;
+       validate_ucs2_range_only = flag & U8_VALIDATE_UCS2_RANGE;
+
+       while (ib < ibtail) {
+               /*
+                * The first byte of a UTF-8 character tells how many
+                * bytes will follow for the character. If the first byte
+                * is an illegal byte value or out of range value, we just
+                * return -1 with an appropriate error number.
+                */
+               sz = u8_number_of_bytes[*ib];
+               if (sz == U8_ILLEGAL_CHAR) {
+                       *errnum = EILSEQ;
+                       return (-1);
+               }
+
+               if (sz == U8_OUT_OF_RANGE_CHAR ||
+                   (validate_ucs2_range_only && sz > U8_MAX_BYTES_UCS2)) {
+                       *errnum = ERANGE;
+                       return (-1);
+               }
+
+               /*
+                * If we don't have enough bytes to check on, that's also
+                * an error. As you can see, we give illegal byte sequence
+                * checking higher priority then EINVAL cases.
+                */
+               if ((ibtail - ib) < sz) {
+                       *errnum = EINVAL;
+                       return (-1);
+               }
+
+               if (sz == 1) {
+                       ib++;
+                       ret_val++;
+               } else {
+                       /*
+                        * Check on the multi-byte UTF-8 character. For more
+                        * details on this, see comment added for the used
+                        * data structures at the beginning of the file.
+                        */
+                       f = *ib++;
+                       ret_val++;
+                       second = B_TRUE;
+                       for (i = 1; i < sz; i++) {
+                               if (second) {
+                                       if (*ib < u8_valid_min_2nd_byte[f] ||
+                                           *ib > u8_valid_max_2nd_byte[f]) {
+                                               *errnum = EILSEQ;
+                                               return (-1);
+                                       }
+                                       second = B_FALSE;
+                               } else if (U8_ILLEGAL_NEXT_BYTE_COMMON(*ib)) {
+                                       *errnum = EILSEQ;
+                                       return (-1);
+                               }
+                               ib++;
+                               ret_val++;
+                       }
+               }
+
+               if (check_additional) {
+                       for (p = (uchar_t **)list, i = 0; p[i]; i++) {
+                               s1 = ib - sz;
+                               s2 = p[i];
+                               while (s1 < ib) {
+                                       if (*s1 != *s2 || *s2 == '\0')
+                                               break;
+                                       s1++;
+                                       s2++;
+                               }
+
+                               if (s1 >= ib && *s2 == '\0') {
+                                       *errnum = EBADF;
+                                       return (-1);
+                               }
+                       }
+               }
+
+               if (no_need_to_validate_entire)
+                       break;
+       }
+
+       return (ret_val);
+}
+
+/*
+ * The do_case_conv() looks at the mapping tables and returns found
+ * bytes if any. If not found, the input bytes are returned. The function
+ * always terminate the return bytes with a null character assuming that
+ * there are plenty of room to do so.
+ *
+ * The case conversions are simple case conversions mapping a character to
+ * another character as specified in the Unicode data. The byte size of
+ * the mapped character could be different from that of the input character.
+ *
+ * The return value is the byte length of the returned character excluding
+ * the terminating null byte.
+ */
+static size_t
+do_case_conv(int uv, uchar_t *u8s, uchar_t *s, int sz, boolean_t is_it_toupper)
+{
+       size_t i;
+       uint16_t b1 = 0;
+       uint16_t b2 = 0;
+       uint16_t b3 = 0;
+       uint16_t b3_tbl;
+       uint16_t b3_base;
+       uint16_t b4 = 0;
+       size_t start_id;
+       size_t end_id;
+
+       /*
+        * At this point, the only possible values for sz are 2, 3, and 4.
+        * The u8s should point to a vector that is well beyond the size of
+        * 5 bytes.
+        */
+       if (sz == 2) {
+               b3 = u8s[0] = s[0];
+               b4 = u8s[1] = s[1];
+       } else if (sz == 3) {
+               b2 = u8s[0] = s[0];
+               b3 = u8s[1] = s[1];
+               b4 = u8s[2] = s[2];
+       } else if (sz == 4) {
+               b1 = u8s[0] = s[0];
+               b2 = u8s[1] = s[1];
+               b3 = u8s[2] = s[2];
+               b4 = u8s[3] = s[3];
+       } else {
+               /* This is not possible but just in case as a fallback. */
+               if (is_it_toupper)
+                       *u8s = U8_ASCII_TOUPPER(*s);
+               else
+                       *u8s = U8_ASCII_TOLOWER(*s);
+               u8s[1] = '\0';
+
+               return (1);
+       }
+       u8s[sz] = '\0';
+
+       /*
+        * Let's find out if we have a corresponding character.
+        */
+       b1 = u8_common_b1_tbl[uv][b1];
+       if (b1 == U8_TBL_ELEMENT_NOT_DEF)
+               return ((size_t)sz);
+
+       b2 = u8_case_common_b2_tbl[uv][b1][b2];
+       if (b2 == U8_TBL_ELEMENT_NOT_DEF)
+               return ((size_t)sz);
+
+       if (is_it_toupper) {
+               b3_tbl = u8_toupper_b3_tbl[uv][b2][b3].tbl_id;
+               if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
+                       return ((size_t)sz);
+
+               start_id = u8_toupper_b4_tbl[uv][b3_tbl][b4];
+               end_id = u8_toupper_b4_tbl[uv][b3_tbl][b4 + 1];
+
+               /* Either there is no match or an error at the table. */
+               if (start_id >= end_id || (end_id - start_id) > U8_MB_CUR_MAX)
+                       return ((size_t)sz);
+
+               b3_base = u8_toupper_b3_tbl[uv][b2][b3].base;
+
+               for (i = 0; start_id < end_id; start_id++)
+                       u8s[i++] = u8_toupper_final_tbl[uv][b3_base + start_id];
+       } else {
+               b3_tbl = u8_tolower_b3_tbl[uv][b2][b3].tbl_id;
+               if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
+                       return ((size_t)sz);
+
+               start_id = u8_tolower_b4_tbl[uv][b3_tbl][b4];
+               end_id = u8_tolower_b4_tbl[uv][b3_tbl][b4 + 1];
+
+               if (start_id >= end_id || (end_id - start_id) > U8_MB_CUR_MAX)
+                       return ((size_t)sz);
+
+               b3_base = u8_tolower_b3_tbl[uv][b2][b3].base;
+
+               for (i = 0; start_id < end_id; start_id++)
+                       u8s[i++] = u8_tolower_final_tbl[uv][b3_base + start_id];
+       }
+
+       /*
+        * If i is still zero, that means there is no corresponding character.
+        */
+       if (i == 0)
+               return ((size_t)sz);
+
+       u8s[i] = '\0';
+
+       return (i);
+}
+
+/*
+ * The do_case_compare() function compares the two input strings, s1 and s2,
+ * one character at a time doing case conversions if applicable and return
+ * the comparison result as like strcmp().
+ *
+ * Since, in empirical sense, most of text data are 7-bit ASCII characters,
+ * we treat the 7-bit ASCII characters as a special case trying to yield
+ * faster processing time.
+ */
+static int
+do_case_compare(size_t uv, uchar_t *s1, uchar_t *s2, size_t n1,
+       size_t n2, boolean_t is_it_toupper, int *errnum)
+{
+       int f;
+       int sz1;
+       int sz2;
+       size_t j;
+       size_t i1;
+       size_t i2;
+       uchar_t u8s1[U8_MB_CUR_MAX + 1];
+       uchar_t u8s2[U8_MB_CUR_MAX + 1];
+
+       i1 = i2 = 0;
+       while (i1 < n1 && i2 < n2) {
+               /*
+                * Find out what would be the byte length for this UTF-8
+                * character at string s1 and also find out if this is
+                * an illegal start byte or not and if so, issue a proper
+                * error number and yet treat this byte as a character.
+                */
+               sz1 = u8_number_of_bytes[*s1];
+               if (sz1 < 0) {
+                       *errnum = EILSEQ;
+                       sz1 = 1;
+               }
+
+               /*
+                * For 7-bit ASCII characters mainly, we do a quick case
+                * conversion right at here.
+                *
+                * If we don't have enough bytes for this character, issue
+                * an EINVAL error and use what are available.
+                *
+                * If we have enough bytes, find out if there is
+                * a corresponding uppercase character and if so, copy over
+                * the bytes for a comparison later. If there is no
+                * corresponding uppercase character, then, use what we have
+                * for the comparison.
+                */
+               if (sz1 == 1) {
+                       if (is_it_toupper)
+                               u8s1[0] = U8_ASCII_TOUPPER(*s1);
+                       else
+                               u8s1[0] = U8_ASCII_TOLOWER(*s1);
+                       s1++;
+                       u8s1[1] = '\0';
+               } else if ((i1 + sz1) > n1) {
+                       *errnum = EINVAL;
+                       for (j = 0; (i1 + j) < n1; )
+                               u8s1[j++] = *s1++;
+                       u8s1[j] = '\0';
+               } else {
+                       (void) do_case_conv(uv, u8s1, s1, sz1, is_it_toupper);
+                       s1 += sz1;
+               }
+
+               /* Do the same for the string s2. */
+               sz2 = u8_number_of_bytes[*s2];
+               if (sz2 < 0) {
+                       *errnum = EILSEQ;
+                       sz2 = 1;
+               }
+
+               if (sz2 == 1) {
+                       if (is_it_toupper)
+                               u8s2[0] = U8_ASCII_TOUPPER(*s2);
+                       else
+                               u8s2[0] = U8_ASCII_TOLOWER(*s2);
+                       s2++;
+                       u8s2[1] = '\0';
+               } else if ((i2 + sz2) > n2) {
+                       *errnum = EINVAL;
+                       for (j = 0; (i2 + j) < n2; )
+                               u8s2[j++] = *s2++;
+                       u8s2[j] = '\0';
+               } else {
+                       (void) do_case_conv(uv, u8s2, s2, sz2, is_it_toupper);
+                       s2 += sz2;
+               }
+
+               /* Now compare the two characters. */
+               if (sz1 == 1 && sz2 == 1) {
+                       if (*u8s1 > *u8s2)
+                               return (1);
+                       if (*u8s1 < *u8s2)
+                               return (-1);
+               } else {
+                       f = strcmp((const char *)u8s1, (const char *)u8s2);
+                       if (f != 0)
+                               return (f);
+               }
+
+               /*
+                * They were the same. Let's move on to the next
+                * characters then.
+                */
+               i1 += sz1;
+               i2 += sz2;
+       }
+
+       /*
+        * We compared until the end of either or both strings.
+        *
+        * If we reached to or went over the ends for the both, that means
+        * they are the same.
+        *
+        * If we reached only one of the two ends, that means the other string
+        * has something which then the fact can be used to determine
+        * the return value.
+        */
+       if (i1 >= n1) {
+               if (i2 >= n2)
+                       return (0);
+               return (-1);
+       }
+       return (1);
+}
+
+/*
+ * The combining_class() function checks on the given bytes and find out
+ * the corresponding Unicode combining class value. The return value 0 means
+ * it is a Starter. Any illegal UTF-8 character will also be treated as
+ * a Starter.
+ */
+static uchar_t
+combining_class(size_t uv, uchar_t *s, size_t sz)
+{
+       uint16_t b1 = 0;
+       uint16_t b2 = 0;
+       uint16_t b3 = 0;
+       uint16_t b4 = 0;
+
+       if (sz == 1 || sz > 4)
+               return (0);
+
+       if (sz == 2) {
+               b3 = s[0];
+               b4 = s[1];
+       } else if (sz == 3) {
+               b2 = s[0];
+               b3 = s[1];
+               b4 = s[2];
+       } else if (sz == 4) {
+               b1 = s[0];
+               b2 = s[1];
+               b3 = s[2];
+               b4 = s[3];
+       }
+
+       b1 = u8_common_b1_tbl[uv][b1];
+       if (b1 == U8_TBL_ELEMENT_NOT_DEF)
+               return (0);
+
+       b2 = u8_combining_class_b2_tbl[uv][b1][b2];
+       if (b2 == U8_TBL_ELEMENT_NOT_DEF)
+               return (0);
+
+       b3 = u8_combining_class_b3_tbl[uv][b2][b3];
+       if (b3 == U8_TBL_ELEMENT_NOT_DEF)
+               return (0);
+
+       return (u8_combining_class_b4_tbl[uv][b3][b4]);
+}
+
+/*
+ * The do_decomp() function finds out a matching decomposition if any
+ * and return. If there is no match, the input bytes are copied and returned.
+ * The function also checks if there is a Hangul, decomposes it if necessary
+ * and returns.
+ *
+ * To save time, a single byte 7-bit ASCII character should be handled by
+ * the caller.
+ *
+ * The function returns the number of bytes returned sans always terminating
+ * the null byte. It will also return a state that will tell if there was
+ * a Hangul character decomposed which then will be used by the caller.
+ */
+static size_t
+do_decomp(size_t uv, uchar_t *u8s, uchar_t *s, int sz,
+       boolean_t canonical_decomposition, u8_normalization_states_t *state)
+{
+       uint16_t b1 = 0;
+       uint16_t b2 = 0;
+       uint16_t b3 = 0;
+       uint16_t b3_tbl;
+       uint16_t b3_base;
+       uint16_t b4 = 0;
+       size_t start_id;
+       size_t end_id;
+       size_t i;
+       uint32_t u1;
+
+       if (sz == 2) {
+               b3 = u8s[0] = s[0];
+               b4 = u8s[1] = s[1];
+               u8s[2] = '\0';
+       } else if (sz == 3) {
+               /* Convert it to a Unicode scalar value. */
+               U8_PUT_3BYTES_INTO_UTF32(u1, s[0], s[1], s[2]);
+
+               /*
+                * If this is a Hangul syllable, we decompose it into
+                * a leading consonant, a vowel, and an optional trailing
+                * consonant and then return.
+                */
+               if (U8_HANGUL_SYLLABLE(u1)) {
+                       u1 -= U8_HANGUL_SYL_FIRST;
+
+                       b1 = U8_HANGUL_JAMO_L_FIRST + u1 / U8_HANGUL_VT_COUNT;
+                       b2 = U8_HANGUL_JAMO_V_FIRST + (u1 % U8_HANGUL_VT_COUNT)
+                           / U8_HANGUL_T_COUNT;
+                       b3 = u1 % U8_HANGUL_T_COUNT;
+
+                       U8_SAVE_HANGUL_AS_UTF8(u8s, 0, 1, 2, b1);
+                       U8_SAVE_HANGUL_AS_UTF8(u8s, 3, 4, 5, b2);
+                       if (b3) {
+                               b3 += U8_HANGUL_JAMO_T_FIRST;
+                               U8_SAVE_HANGUL_AS_UTF8(u8s, 6, 7, 8, b3);
+
+                               u8s[9] = '\0';
+                               *state = U8_STATE_HANGUL_LVT;
+                               return (9);
+                       }
+
+                       u8s[6] = '\0';
+                       *state = U8_STATE_HANGUL_LV;
+                       return (6);
+               }
+
+               b2 = u8s[0] = s[0];
+               b3 = u8s[1] = s[1];
+               b4 = u8s[2] = s[2];
+               u8s[3] = '\0';
+
+               /*
+                * If this is a Hangul Jamo, we know there is nothing
+                * further that we can decompose.
+                */
+               if (U8_HANGUL_JAMO_L(u1)) {
+                       *state = U8_STATE_HANGUL_L;
+                       return (3);
+               }
+
+               if (U8_HANGUL_JAMO_V(u1)) {
+                       if (*state == U8_STATE_HANGUL_L)
+                               *state = U8_STATE_HANGUL_LV;
+                       else
+                               *state = U8_STATE_HANGUL_V;
+                       return (3);
+               }
+
+               if (U8_HANGUL_JAMO_T(u1)) {
+                       if (*state == U8_STATE_HANGUL_LV)
+                               *state = U8_STATE_HANGUL_LVT;
+                       else
+                               *state = U8_STATE_HANGUL_T;
+                       return (3);
+               }
+       } else if (sz == 4) {
+               b1 = u8s[0] = s[0];
+               b2 = u8s[1] = s[1];
+               b3 = u8s[2] = s[2];
+               b4 = u8s[3] = s[3];
+               u8s[4] = '\0';
+       } else {
+               /*
+                * This is a fallback and should not happen if the function
+                * was called properly.
+                */
+               u8s[0] = s[0];
+               u8s[1] = '\0';
+               *state = U8_STATE_START;
+               return (1);
+       }
+
+       /*
+        * At this point, this rountine does not know what it would get.
+        * The caller should sort it out if the state isn't a Hangul one.
+        */
+       *state = U8_STATE_START;
+
+       /* Try to find matching decomposition mapping byte sequence. */
+       b1 = u8_common_b1_tbl[uv][b1];
+       if (b1 == U8_TBL_ELEMENT_NOT_DEF)
+               return ((size_t)sz);
+
+       b2 = u8_decomp_b2_tbl[uv][b1][b2];
+       if (b2 == U8_TBL_ELEMENT_NOT_DEF)
+               return ((size_t)sz);
+
+       b3_tbl = u8_decomp_b3_tbl[uv][b2][b3].tbl_id;
+       if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
+               return ((size_t)sz);
+
+       /*
+        * If b3_tbl is bigger than or equal to U8_16BIT_TABLE_INDICATOR
+        * which is 0x8000, this means we couldn't fit the mappings into
+        * the cardinality of a unsigned byte.
+        */
+       if (b3_tbl >= U8_16BIT_TABLE_INDICATOR) {
+               b3_tbl -= U8_16BIT_TABLE_INDICATOR;
+               start_id = u8_decomp_b4_16bit_tbl[uv][b3_tbl][b4];
+               end_id = u8_decomp_b4_16bit_tbl[uv][b3_tbl][b4 + 1];
+       } else {
+               start_id = u8_decomp_b4_tbl[uv][b3_tbl][b4];
+               end_id = u8_decomp_b4_tbl[uv][b3_tbl][b4 + 1];
+       }
+
+       /* This also means there wasn't any matching decomposition. */
+       if (start_id >= end_id)
+               return ((size_t)sz);
+
+       /*
+        * The final table for decomposition mappings has three types of
+        * byte sequences depending on whether a mapping is for compatibility
+        * decomposition, canonical decomposition, or both like the following:
+        *
+        * (1) Compatibility decomposition mappings:
+        *
+        *      +---+---+-...-+---+
+        *      | B0| B1| ... | Bm|
+        *      +---+---+-...-+---+
+        *
+        *      The first byte, B0, is always less then 0xF5 (U8_DECOMP_BOTH).
+        *
+        * (2) Canonical decomposition mappings:
+        *
+        *      +---+---+---+-...-+---+
+        *      | T | b0| b1| ... | bn|
+        *      +---+---+---+-...-+---+
+        *
+        *      where the first byte, T, is 0xF6 (U8_DECOMP_CANONICAL).
+        *
+        * (3) Both mappings:
+        *
+        *      +---+---+---+---+-...-+---+---+---+-...-+---+
+        *      | T | D | b0| b1| ... | bn| B0| B1| ... | Bm|
+        *      +---+---+---+---+-...-+---+---+---+-...-+---+
+        *
+        *      where T is 0xF5 (U8_DECOMP_BOTH) and D is a displacement
+        *      byte, b0 to bn are canonical mapping bytes and B0 to Bm are
+        *      compatibility mapping bytes.
+        *
+        * Note that compatibility decomposition means doing recursive
+        * decompositions using both compatibility decomposition mappings and
+        * canonical decomposition mappings. On the other hand, canonical
+        * decomposition means doing recursive decompositions using only
+        * canonical decomposition mappings. Since the table we have has gone
+        * through the recursions already, we do not need to do so during
+        * runtime, i.e., the table has been completely flattened out
+        * already.
+        */
+
+       b3_base = u8_decomp_b3_tbl[uv][b2][b3].base;
+
+       /* Get the type, T, of the byte sequence. */
+       b1 = u8_decomp_final_tbl[uv][b3_base + start_id];
+
+       /*
+        * If necessary, adjust start_id, end_id, or both. Note that if
+        * this is compatibility decomposition mapping, there is no
+        * adjustment.
+        */
+       if (canonical_decomposition) {
+               /* Is the mapping only for compatibility decomposition? */
+               if (b1 < U8_DECOMP_BOTH)
+                       return ((size_t)sz);
+
+               start_id++;
+
+               if (b1 == U8_DECOMP_BOTH) {
+                       end_id = start_id +
+                           u8_decomp_final_tbl[uv][b3_base + start_id];
+                       start_id++;
+               }
+       } else {
+               /*
+                * Unless this is a compatibility decomposition mapping,
+                * we adjust the start_id.
+                */
+               if (b1 == U8_DECOMP_BOTH) {
+                       start_id++;
+                       start_id += u8_decomp_final_tbl[uv][b3_base + start_id];
+               } else if (b1 == U8_DECOMP_CANONICAL) {
+                       start_id++;
+               }
+       }
+
+       for (i = 0; start_id < end_id; start_id++)
+               u8s[i++] = u8_decomp_final_tbl[uv][b3_base + start_id];
+       u8s[i] = '\0';
+
+       return (i);
+}
+
+/*
+ * The find_composition_start() function uses the character bytes given and
+ * find out the matching composition mappings if any and return the address
+ * to the composition mappings as explained in the do_composition().
+ */
+static uchar_t *
+find_composition_start(size_t uv, uchar_t *s, size_t sz)
+{
+       uint16_t b1 = 0;
+       uint16_t b2 = 0;
+       uint16_t b3 = 0;
+       uint16_t b3_tbl;
+       uint16_t b3_base;
+       uint16_t b4 = 0;
+       size_t start_id;
+       size_t end_id;
+
+       if (sz == 1) {
+               b4 = s[0];
+       } else if (sz == 2) {
+               b3 = s[0];
+               b4 = s[1];
+       } else if (sz == 3) {
+               b2 = s[0];
+               b3 = s[1];
+               b4 = s[2];
+       } else if (sz == 4) {
+               b1 = s[0];
+               b2 = s[1];
+               b3 = s[2];
+               b4 = s[3];
+       } else {
+               /*
+                * This is a fallback and should not happen if the function
+                * was called properly.
+                */
+               return (NULL);
+       }
+
+       b1 = u8_composition_b1_tbl[uv][b1];
+       if (b1 == U8_TBL_ELEMENT_NOT_DEF)
+               return (NULL);
+
+       b2 = u8_composition_b2_tbl[uv][b1][b2];
+       if (b2 == U8_TBL_ELEMENT_NOT_DEF)
+               return (NULL);
+
+       b3_tbl = u8_composition_b3_tbl[uv][b2][b3].tbl_id;
+       if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
+               return (NULL);
+
+       if (b3_tbl >= U8_16BIT_TABLE_INDICATOR) {
+               b3_tbl -= U8_16BIT_TABLE_INDICATOR;
+               start_id = u8_composition_b4_16bit_tbl[uv][b3_tbl][b4];
+               end_id = u8_composition_b4_16bit_tbl[uv][b3_tbl][b4 + 1];
+       } else {
+               start_id = u8_composition_b4_tbl[uv][b3_tbl][b4];
+               end_id = u8_composition_b4_tbl[uv][b3_tbl][b4 + 1];
+       }
+
+       if (start_id >= end_id)
+               return (NULL);
+
+       b3_base = u8_composition_b3_tbl[uv][b2][b3].base;
+
+       return ((uchar_t *)&(u8_composition_final_tbl[uv][b3_base + start_id]));
+}
+
+/*
+ * The blocked() function checks on the combining class values of previous
+ * characters in this sequence and return whether it is blocked or not.
+ */
+static boolean_t
+blocked(uchar_t *comb_class, size_t last)
+{
+       uchar_t my_comb_class;
+       size_t i;
+
+       my_comb_class = comb_class[last];
+       for (i = 1; i < last; i++)
+               if (comb_class[i] >= my_comb_class ||
+                   comb_class[i] == U8_COMBINING_CLASS_STARTER)
+                       return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+/*
+ * The do_composition() reads the character string pointed by 's' and
+ * do necessary canonical composition and then copy over the result back to
+ * the 's'.
+ *
+ * The input argument 's' cannot contain more than 32 characters.
+ */
+static size_t
+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];
+       uint8_t saved_marks[U8_MAX_CHARS_A_SEQ];
+       size_t saved_marks_count;
+       uchar_t *p;
+       uchar_t *saved_p;
+       uchar_t *q;
+       size_t i;
+       size_t saved_i;
+       size_t j;
+       size_t k;
+       size_t l;
+       size_t C;
+       size_t saved_l;
+       size_t size;
+       uint32_t u1;
+       uint32_t u2;
+       boolean_t match_not_found = B_TRUE;
+
+       /*
+        * This should never happen unless the callers are doing some strange
+        * and unexpected things.
+        *
+        * The "last" is the index pointing to the last character not last + 1.
+        */
+       if (last >= U8_MAX_CHARS_A_SEQ)
+               last = U8_UPPER_LIMIT_IN_A_SEQ;
+
+       for (i = l = 0; i <= last; i++) {
+               /*
+                * The last or any non-Starters at the beginning, we don't
+                * have any chance to do composition and so we just copy them
+                * to the temporary buffer.
+                */
+               if (i >= last || comb_class[i] != U8_COMBINING_CLASS_STARTER) {
+SAVE_THE_CHAR:
+                       p = s + start[i];
+                       size = disp[i];
+                       for (k = 0; k < size; k++)
+                               t[l++] = *p++;
+                       continue;
+               }
+
+               /*
+                * If this could be a start of Hangul Jamos, then, we try to
+                * conjoin them.
+                */
+               if (s[start[i]] == U8_HANGUL_JAMO_1ST_BYTE) {
+                       U8_PUT_3BYTES_INTO_UTF32(u1, s[start[i]],
+                           s[start[i] + 1], s[start[i] + 2]);
+                       U8_PUT_3BYTES_INTO_UTF32(u2, s[start[i] + 3],
+                           s[start[i] + 4], s[start[i] + 5]);
+
+                       if (U8_HANGUL_JAMO_L(u1) && U8_HANGUL_JAMO_V(u2)) {
+                               u1 -= U8_HANGUL_JAMO_L_FIRST;
+                               u2 -= U8_HANGUL_JAMO_V_FIRST;
+                               u1 = U8_HANGUL_SYL_FIRST +
+                                   (u1 * U8_HANGUL_V_COUNT + u2) *
+                                   U8_HANGUL_T_COUNT;
+
+                               i += 2;
+                               if (i <= last) {
+                                       U8_PUT_3BYTES_INTO_UTF32(u2,
+                                           s[start[i]], s[start[i] + 1],
+                                           s[start[i] + 2]);
+
+                                       if (U8_HANGUL_JAMO_T(u2)) {
+                                               u1 += u2 -
+                                                   U8_HANGUL_JAMO_T_FIRST;
+                                               i++;
+                                       }
+                               }
+
+                               U8_SAVE_HANGUL_AS_UTF8(t + l, 0, 1, 2, u1);
+                               i--;
+                               l += 3;
+                               continue;
+                       }
+               }
+
+               /*
+                * Let's then find out if this Starter has composition
+                * mapping.
+                */
+               p = find_composition_start(uv, s + start[i], disp[i]);
+               if (p == NULL)
+                       goto SAVE_THE_CHAR;
+
+               /*
+                * We have a Starter with composition mapping and the next
+                * character is a non-Starter. Let's try to find out if
+                * we can do composition.
+                */
+
+               saved_p = p;
+               saved_i = i;
+               saved_l = l;
+               saved_marks_count = 0;
+
+TRY_THE_NEXT_MARK:
+               q = s + start[++i];
+               size = disp[i];
+
+               /*
+                * The next for() loop compares the non-Starter pointed by
+                * 'q' with the possible (joinable) characters pointed by 'p'.
+                *
+                * The composition final table entry pointed by the 'p'
+                * looks like the following:
+                *
+                * +---+---+---+-...-+---+---+---+---+-...-+---+---+
+                * | C | b0| b2| ... | bn| F | B0| B1| ... | Bm| F |
+                * +---+---+---+-...-+---+---+---+---+-...-+---+---+
+                *
+                * where C is the count byte indicating the number of
+                * mapping pairs where each pair would be look like
+                * (b0-bn F, B0-Bm F). The b0-bn are the bytes of the second
+                * character of a canonical decomposition and the B0-Bm are
+                * the bytes of a matching composite character. The F is
+                * a filler byte after each character as the separator.
+                */
+
+               match_not_found = B_TRUE;
+
+               for (C = *p++; C > 0; C--) {
+                       for (k = 0; k < size; p++, k++)
+                               if (*p != q[k])
+                                       break;
+
+                       /* Have we found it? */
+                       if (k >= size && *p == U8_TBL_ELEMENT_FILLER) {
+                               match_not_found = B_FALSE;
+
+                               l = saved_l;
+
+                               while (*++p != U8_TBL_ELEMENT_FILLER)
+                                       t[l++] = *p;
+
+                               break;
+                       }
+
+                       /* We didn't find; skip to the next pair. */
+                       if (*p != U8_TBL_ELEMENT_FILLER)
+                               while (*++p != U8_TBL_ELEMENT_FILLER)
+                                       ;
+                       while (*++p != U8_TBL_ELEMENT_FILLER)
+                               ;
+                       p++;
+               }
+
+               /*
+                * If there was no match, we will need to save the combining
+                * mark for later appending. After that, if the next one
+                * is a non-Starter and not blocked, then, we try once
+                * again to do composition with the next non-Starter.
+                *
+                * If there was no match and this was a Starter, then,
+                * this is a new start.
+                *
+                * If there was a match and a composition done and we have
+                * more to check on, then, we retrieve a new composition final
+                * table entry for the composite and then try to do the
+                * composition again.
+                */
+
+               if (match_not_found) {
+                       if (comb_class[i] == U8_COMBINING_CLASS_STARTER) {
+                               i--;
+                               goto SAVE_THE_CHAR;
+                       }
+
+                       saved_marks[saved_marks_count++] = i;
+               }
+
+               if (saved_l == l) {
+                       while (i < last) {
+                               if (blocked(comb_class, i + 1))
+                                       saved_marks[saved_marks_count++] = ++i;
+                               else
+                                       break;
+                       }
+                       if (i < last) {
+                               p = saved_p;
+                               goto TRY_THE_NEXT_MARK;
+                       }
+               } else if (i < last) {
+                       p = find_composition_start(uv, t + saved_l,
+                           l - saved_l);
+                       if (p != NULL) {
+                               saved_p = p;
+                               goto TRY_THE_NEXT_MARK;
+                       }
+               }
+
+               /*
+                * There is no more composition possible.
+                *
+                * If there was no composition what so ever then we copy
+                * over the original Starter and then append any non-Starters
+                * remaining at the target string sequentially after that.
+                */
+
+               if (saved_l == l) {
+                       p = s + start[saved_i];
+                       size = disp[saved_i];
+                       for (j = 0; j < size; j++)
+                               t[l++] = *p++;
+               }
+
+               for (k = 0; k < saved_marks_count; k++) {
+                       p = s + start[saved_marks[k]];
+                       size = disp[saved_marks[k]];
+                       for (j = 0; j < size; j++)
+                               t[l++] = *p++;
+               }
+       }
+
+       /*
+        * If the last character is a Starter and if we have a character
+        * (possibly another Starter) that can be turned into a composite,
+        * we do so and we do so until there is no more of composition
+        * possible.
+        */
+       if (comb_class[last] == U8_COMBINING_CLASS_STARTER) {
+               p = *os;
+               saved_l = l - disp[last];
+
+               while (p < oslast) {
+                       size = u8_number_of_bytes[*p];
+                       if (size <= 1 || (p + size) > oslast)
+                               break;
+
+                       saved_p = p;
+
+                       for (i = 0; i < size; i++)
+                               tc[i] = *p++;
+
+                       q = find_composition_start(uv, t + saved_l,
+                           l - saved_l);
+                       if (q == NULL) {
+                               p = saved_p;
+                               break;
+                       }
+
+                       match_not_found = B_TRUE;
+
+                       for (C = *q++; C > 0; C--) {
+                               for (k = 0; k < size; q++, k++)
+                                       if (*q != tc[k])
+                                               break;
+
+                               if (k >= size && *q == U8_TBL_ELEMENT_FILLER) {
+                                       match_not_found = B_FALSE;
+
+                                       l = saved_l;
+
+                                       while (*++q != U8_TBL_ELEMENT_FILLER) {
+                                               /*
+                                                * This is practically
+                                                * impossible but we don't
+                                                * want to take any chances.
+                                                */
+                                               if (l >=
+                                                   U8_STREAM_SAFE_TEXT_MAX) {
+                                                       p = saved_p;
+                                                       goto SAFE_RETURN;
+                                               }
+                                               t[l++] = *q;
+                                       }
+
+                                       break;
+                               }
+
+                               if (*q != U8_TBL_ELEMENT_FILLER)
+                                       while (*++q != U8_TBL_ELEMENT_FILLER)
+                                               ;
+                               while (*++q != U8_TBL_ELEMENT_FILLER)
+                                       ;
+                               q++;
+                       }
+
+                       if (match_not_found) {
+                               p = saved_p;
+                               break;
+                       }
+               }
+SAFE_RETURN:
+               *os = p;
+       }
+
+       /*
+        * Now we copy over the temporary string to the target string.
+        * Since composition always reduces the number of characters or
+        * the number of characters stay, we don't need to worry about
+        * the buffer overflow here.
+        */
+       for (i = 0; i < l; i++)
+               s[i] = t[i];
+       s[l] = '\0';
+
+       return (l);
+}
+
+/*
+ * The collect_a_seq() function checks on the given string s, collect
+ * a sequence of characters at u8s, and return the sequence. While it collects
+ * a sequence, it also applies case conversion, canonical or compatibility
+ * decomposition, canonical decomposition, or some or all of them and
+ * in that order.
+ *
+ * The collected sequence cannot be bigger than 32 characters since if
+ * it is having more than 31 characters, the sequence will be terminated
+ * with a U+034F COMBINING GRAPHEME JOINER (CGJ) character and turned into
+ * a Stream-Safe Text. The collected sequence is always terminated with
+ * a null byte and the return value is the byte length of the sequence
+ * including 0. The return value does not include the terminating
+ * null byte.
+ */
+static size_t
+collect_a_seq(size_t uv, uchar_t *u8s, uchar_t **source, uchar_t *slast,
+       boolean_t is_it_toupper,
+       boolean_t is_it_tolower,
+       boolean_t canonical_decomposition,
+       boolean_t compatibility_decomposition,
+       boolean_t canonical_composition,
+       int *errnum, u8_normalization_states_t *state)
+{
+       uchar_t *s;
+       int sz;
+       int saved_sz;
+       size_t i;
+       size_t j;
+       size_t k;
+       size_t l;
+       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 uts[U8_STREAM_SAFE_TEXT_MAX + 1];
+       uchar_t tc;
+       size_t last;
+       size_t saved_last;
+       uint32_t u1;
+
+       /*
+        * Save the source string pointer which we will return a changed
+        * pointer if we do processing.
+        */
+       s = *source;
+
+       /*
+        * The following is a fallback for just in case callers are not
+        * checking the string boundaries before the calling.
+        */
+       if (s >= slast) {
+               u8s[0] = '\0';
+
+               return (0);
+       }
+
+       /*
+        * As the first thing, let's collect a character and do case
+        * conversion if necessary.
+        */
+
+       sz = u8_number_of_bytes[*s];
+
+       if (sz < 0) {
+               *errnum = EILSEQ;
+
+               u8s[0] = *s++;
+               u8s[1] = '\0';
+
+               *source = s;
+
+               return (1);
+       }
+
+       if (sz == 1) {
+               if (is_it_toupper)
+                       u8s[0] = U8_ASCII_TOUPPER(*s);
+               else if (is_it_tolower)
+                       u8s[0] = U8_ASCII_TOLOWER(*s);
+               else
+                       u8s[0] = *s;
+               s++;
+               u8s[1] = '\0';
+       } else if ((s + sz) > slast) {
+               *errnum = EINVAL;
+
+               for (i = 0; s < slast; )
+                       u8s[i++] = *s++;
+               u8s[i] = '\0';
+
+               *source = s;
+
+               return (i);
+       } else {
+               if (is_it_toupper || is_it_tolower) {
+                       i = do_case_conv(uv, u8s, s, sz, is_it_toupper);
+                       s += sz;
+                       sz = i;
+               } else {
+                       for (i = 0; i < sz; )
+                               u8s[i++] = *s++;
+                       u8s[i] = '\0';
+               }
+       }
+
+       /*
+        * And then canonical/compatibility decomposition followed by
+        * an optional canonical composition. Please be noted that
+        * canonical composition is done only when a decomposition is
+        * done.
+        */
+       if (canonical_decomposition || compatibility_decomposition) {
+               if (sz == 1) {
+                       *state = U8_STATE_START;
+
+                       saved_sz = 1;
+
+                       comb_class[0] = 0;
+                       start[0] = 0;
+                       disp[0] = 1;
+
+                       last = 1;
+               } else {
+                       saved_sz = do_decomp(uv, u8s, u8s, sz,
+                           canonical_decomposition, state);
+
+                       last = 0;
+
+                       for (i = 0; i < saved_sz; ) {
+                               sz = u8_number_of_bytes[u8s[i]];
+
+                               comb_class[last] = combining_class(uv,
+                                   u8s + i, sz);
+                               start[last] = i;
+                               disp[last] = sz;
+
+                               last++;
+                               i += sz;
+                       }
+
+                       /*
+                        * Decomposition yields various Hangul related
+                        * states but not on combining marks. We need to
+                        * find out at here by checking on the last
+                        * character.
+                        */
+                       if (*state == U8_STATE_START) {
+                               if (comb_class[last - 1])
+                                       *state = U8_STATE_COMBINING_MARK;
+                       }
+               }
+
+               saved_last = last;
+
+               while (s < slast) {
+                       sz = u8_number_of_bytes[*s];
+
+                       /*
+                        * If this is an illegal character, an incomplete
+                        * character, or an 7-bit ASCII Starter character,
+                        * then we have collected a sequence; break and let
+                        * the next call deal with the two cases.
+                        *
+                        * Note that this is okay only if you are using this
+                        * function with a fixed length string, not on
+                        * a buffer with multiple calls of one chunk at a time.
+                        */
+                       if (sz <= 1) {
+                               break;
+                       } else if ((s + sz) > slast) {
+                               break;
+                       } else {
+                               /*
+                                * If the previous character was a Hangul Jamo
+                                * and this character is a Hangul Jamo that
+                                * can be conjoined, we collect the Jamo.
+                                */
+                               if (*s == U8_HANGUL_JAMO_1ST_BYTE) {
+                                       U8_PUT_3BYTES_INTO_UTF32(u1,
+                                           *s, *(s + 1), *(s + 2));
+
+                                       if (U8_HANGUL_COMPOSABLE_L_V(*state,
+                                           u1)) {
+                                               i = 0;
+                                               *state = U8_STATE_HANGUL_LV;
+                                               goto COLLECT_A_HANGUL;
+                                       }
+
+                                       if (U8_HANGUL_COMPOSABLE_LV_T(*state,
+                                           u1)) {
+                                               i = 0;
+                                               *state = U8_STATE_HANGUL_LVT;
+                                               goto COLLECT_A_HANGUL;
+                                       }
+                               }
+
+                               /*
+                                * Regardless of whatever it was, if this is
+                                * a Starter, we don't collect the character
+                                * since that's a new start and we will deal
+                                * with it at the next time.
+                                */
+                               i = combining_class(uv, s, sz);
+                               if (i == U8_COMBINING_CLASS_STARTER)
+                                       break;
+
+                               /*
+                                * We know the current character is a combining
+                                * mark. If the previous character wasn't
+                                * a Starter (not Hangul) or a combining mark,
+                                * then, we don't collect this combining mark.
+                                */
+                               if (*state != U8_STATE_START &&
+                                   *state != U8_STATE_COMBINING_MARK)
+                                       break;
+
+                               *state = U8_STATE_COMBINING_MARK;
+COLLECT_A_HANGUL:
+                               /*
+                                * If we collected a Starter and combining
+                                * marks up to 30, i.e., total 31 characters,
+                                * then, we terminate this degenerately long
+                                * combining sequence with a U+034F COMBINING
+                                * GRAPHEME JOINER (CGJ) which is 0xCD 0x8F in
+                                * UTF-8 and turn this into a Stream-Safe
+                                * Text. This will be extremely rare but
+                                * possible.
+                                *
+                                * The following will also guarantee that
+                                * we are not writing more than 32 characters
+                                * plus a NULL at u8s[].
+                                */
+                               if (last >= U8_UPPER_LIMIT_IN_A_SEQ) {
+TURN_STREAM_SAFE:
+                                       *state = U8_STATE_START;
+                                       comb_class[last] = 0;
+                                       start[last] = saved_sz;
+                                       disp[last] = 2;
+                                       last++;
+
+                                       u8s[saved_sz++] = 0xCD;
+                                       u8s[saved_sz++] = 0x8F;
+
+                                       break;
+                               }
+
+                               /*
+                                * Some combining marks also do decompose into
+                                * another combining mark or marks.
+                                */
+                               if (*state == U8_STATE_COMBINING_MARK) {
+                                       k = last;
+                                       l = sz;
+                                       i = do_decomp(uv, uts, s, sz,
+                                           canonical_decomposition, state);
+                                       for (j = 0; j < i; ) {
+                                               sz = u8_number_of_bytes[uts[j]];
+
+                                               comb_class[last] =
+                                                   combining_class(uv,
+                                                   uts + j, sz);
+                                               start[last] = saved_sz + j;
+                                               disp[last] = sz;
+
+                                               last++;
+                                               if (last >=
+                                                   U8_UPPER_LIMIT_IN_A_SEQ) {
+                                                       last = k;
+                                                       goto TURN_STREAM_SAFE;
+                                               }
+                                               j += sz;
+                                       }
+
+                                       *state = U8_STATE_COMBINING_MARK;
+                                       sz = i;
+                                       s += l;
+
+                                       for (i = 0; i < sz; i++)
+                                               u8s[saved_sz++] = uts[i];
+                               } else {
+                                       comb_class[last] = i;
+                                       start[last] = saved_sz;
+                                       disp[last] = sz;
+                                       last++;
+
+                                       for (i = 0; i < sz; i++)
+                                               u8s[saved_sz++] = *s++;
+                               }
+
+                               /*
+                                * If this is U+0345 COMBINING GREEK
+                                * YPOGEGRAMMENI (0xCD 0x85 in UTF-8), a.k.a.,
+                                * iota subscript, and need to be converted to
+                                * uppercase letter, convert it to U+0399 GREEK
+                                * CAPITAL LETTER IOTA (0xCE 0x99 in UTF-8),
+                                * i.e., convert to capital adscript form as
+                                * specified in the Unicode standard.
+                                *
+                                * This is the only special case of (ambiguous)
+                                * case conversion at combining marks and
+                                * probably the standard will never have
+                                * anything similar like this in future.
+                                */
+                               if (is_it_toupper && sz >= 2 &&
+                                   u8s[saved_sz - 2] == 0xCD &&
+                                   u8s[saved_sz - 1] == 0x85) {
+                                       u8s[saved_sz - 2] = 0xCE;
+                                       u8s[saved_sz - 1] = 0x99;
+                               }
+                       }
+               }
+
+               /*
+                * Let's try to ensure a canonical ordering for the collected
+                * combining marks. We do this only if we have collected
+                * at least one more non-Starter. (The decomposition mapping
+                * data tables have fully (and recursively) expanded and
+                * canonically ordered decompositions.)
+                *
+                * The U8_SWAP_COMB_MARKS() convenience macro has some
+                * assumptions and we are meeting the assumptions.
+                */
+               last--;
+               if (last >= saved_last) {
+                       for (i = 0; i < last; i++)
+                               for (j = last; j > i; j--)
+                                       if (comb_class[j] &&
+                                           comb_class[j - 1] > comb_class[j]) {
+                                               U8_SWAP_COMB_MARKS(j - 1, j);
+                                       }
+               }
+
+               *source = s;
+
+               if (! canonical_composition) {
+                       u8s[saved_sz] = '\0';
+                       return (saved_sz);
+               }
+
+               /*
+                * Now do the canonical composition. Note that we do this
+                * only after a canonical or compatibility decomposition to
+                * finish up NFC or NFKC.
+                */
+               sz = do_composition(uv, u8s, comb_class, start, disp, last,
+                   &s, slast);
+       }
+
+       *source = s;
+
+       return ((size_t)sz);
+}
+
+/*
+ * The do_norm_compare() function does string comparion based on Unicode
+ * simple case mappings and Unicode Normalization definitions.
+ *
+ * It does so by collecting a sequence of character at a time and comparing
+ * the collected sequences from the strings.
+ *
+ * The meanings on the return values are the same as the usual strcmp().
+ */
+static int
+do_norm_compare(size_t uv, uchar_t *s1, uchar_t *s2, size_t n1, size_t n2,
+       int flag, int *errnum)
+{
+       int result;
+       size_t sz1;
+       size_t sz2;
+       uchar_t u8s1[U8_STREAM_SAFE_TEXT_MAX + 1];
+       uchar_t u8s2[U8_STREAM_SAFE_TEXT_MAX + 1];
+       uchar_t *s1last;
+       uchar_t *s2last;
+       boolean_t is_it_toupper;
+       boolean_t is_it_tolower;
+       boolean_t canonical_decomposition;
+       boolean_t compatibility_decomposition;
+       boolean_t canonical_composition;
+       u8_normalization_states_t state;
+
+       s1last = s1 + n1;
+       s2last = s2 + n2;
+
+       is_it_toupper = flag & U8_TEXTPREP_TOUPPER;
+       is_it_tolower = flag & U8_TEXTPREP_TOLOWER;
+       canonical_decomposition = flag & U8_CANON_DECOMP;
+       compatibility_decomposition = flag & U8_COMPAT_DECOMP;
+       canonical_composition = flag & U8_CANON_COMP;
+
+       while (s1 < s1last && s2 < s2last) {
+               /*
+                * If the current character is a 7-bit ASCII and the last
+                * character, or, if the current character and the next
+                * character are both some 7-bit ASCII characters then
+                * we treat the current character as a sequence.
+                *
+                * In any other cases, we need to call collect_a_seq().
+                */
+
+               if (U8_ISASCII(*s1) && ((s1 + 1) >= s1last ||
+                   ((s1 + 1) < s1last && U8_ISASCII(*(s1 + 1))))) {
+                       if (is_it_toupper)
+                               u8s1[0] = U8_ASCII_TOUPPER(*s1);
+                       else if (is_it_tolower)
+                               u8s1[0] = U8_ASCII_TOLOWER(*s1);
+                       else
+                               u8s1[0] = *s1;
+                       u8s1[1] = '\0';
+                       sz1 = 1;
+                       s1++;
+               } else {
+                       state = U8_STATE_START;
+                       sz1 = collect_a_seq(uv, u8s1, &s1, s1last,
+                           is_it_toupper, is_it_tolower,
+                           canonical_decomposition,
+                           compatibility_decomposition,
+                           canonical_composition, errnum, &state);
+               }
+
+               if (U8_ISASCII(*s2) && ((s2 + 1) >= s2last ||
+                   ((s2 + 1) < s2last && U8_ISASCII(*(s2 + 1))))) {
+                       if (is_it_toupper)
+                               u8s2[0] = U8_ASCII_TOUPPER(*s2);
+                       else if (is_it_tolower)
+                               u8s2[0] = U8_ASCII_TOLOWER(*s2);
+                       else
+                               u8s2[0] = *s2;
+                       u8s2[1] = '\0';
+                       sz2 = 1;
+                       s2++;
+               } else {
+                       state = U8_STATE_START;
+                       sz2 = collect_a_seq(uv, u8s2, &s2, s2last,
+                           is_it_toupper, is_it_tolower,
+                           canonical_decomposition,
+                           compatibility_decomposition,
+                           canonical_composition, errnum, &state);
+               }
+
+               /*
+                * Now compare the two characters. If they are the same,
+                * we move on to the next character sequences.
+                */
+               if (sz1 == 1 && sz2 == 1) {
+                       if (*u8s1 > *u8s2)
+                               return (1);
+                       if (*u8s1 < *u8s2)
+                               return (-1);
+               } else {
+                       result = strcmp((const char *)u8s1, (const char *)u8s2);
+                       if (result != 0)
+                               return (result);
+               }
+       }
+
+       /*
+        * We compared until the end of either or both strings.
+        *
+        * If we reached to or went over the ends for the both, that means
+        * they are the same.
+        *
+        * If we reached only one end, that means the other string has
+        * something which then can be used to determine the return value.
+        */
+       if (s1 >= s1last) {
+               if (s2 >= s2last)
+                       return (0);
+               return (-1);
+       }
+       return (1);
+}
+
+/*
+ * The u8_strcmp() function compares two UTF-8 strings quite similar to
+ * the strcmp(). For the comparison, however, Unicode Normalization specific
+ * equivalency and Unicode simple case conversion mappings based equivalency
+ * can be requested and checked against.
+ */
+int
+u8_strcmp(const char *s1, const char *s2, size_t n, int flag, size_t uv,
+               int *errnum)
+{
+       int f;
+       size_t n1;
+       size_t n2;
+
+       *errnum = 0;
+
+       /*
+        * Check on the requested Unicode version, case conversion, and
+        * normalization flag values.
+        */
+
+       if (uv > U8_UNICODE_LATEST) {
+               *errnum = ERANGE;
+               uv = U8_UNICODE_LATEST;
+       }
+
+       if (flag == 0) {
+               flag = U8_STRCMP_CS;
+       } else {
+               f = flag & (U8_STRCMP_CS | U8_STRCMP_CI_UPPER |
+                   U8_STRCMP_CI_LOWER);
+               if (f == 0) {
+                       flag |= U8_STRCMP_CS;
+               } else if (f != U8_STRCMP_CS && f != U8_STRCMP_CI_UPPER &&
+                   f != U8_STRCMP_CI_LOWER) {
+                       *errnum = EBADF;
+                       flag = U8_STRCMP_CS;
+               }
+
+               f = flag & (U8_CANON_DECOMP | U8_COMPAT_DECOMP | U8_CANON_COMP);
+               if (f && f != U8_STRCMP_NFD && f != U8_STRCMP_NFC &&
+                   f != U8_STRCMP_NFKD && f != U8_STRCMP_NFKC) {
+                       *errnum = EBADF;
+                       flag = U8_STRCMP_CS;
+               }
+       }
+
+       if (flag == U8_STRCMP_CS) {
+               return (n == 0 ? strcmp(s1, s2) : strncmp(s1, s2, n));
+       }
+
+       n1 = strlen(s1);
+       n2 = strlen(s2);
+       if (n != 0) {
+               if (n < n1)
+                       n1 = n;
+               if (n < n2)
+                       n2 = n;
+       }
+
+       /*
+        * Simple case conversion can be done much faster and so we do
+        * them separately here.
+        */
+       if (flag == U8_STRCMP_CI_UPPER) {
+               return (do_case_compare(uv, (uchar_t *)s1, (uchar_t *)s2,
+                   n1, n2, B_TRUE, errnum));
+       } else if (flag == U8_STRCMP_CI_LOWER) {
+               return (do_case_compare(uv, (uchar_t *)s1, (uchar_t *)s2,
+                   n1, n2, B_FALSE, errnum));
+       }
+
+       return (do_norm_compare(uv, (uchar_t *)s1, (uchar_t *)s2, n1, n2,
+           flag, errnum));
+}
+
+size_t
+u8_textprep_str(char *inarray, size_t *inlen, char *outarray, size_t *outlen,
+       int flag, size_t unicode_version, int *errnum)
+{
+       int f;
+       int sz;
+       uchar_t *ib;
+       uchar_t *ibtail;
+       uchar_t *ob;
+       uchar_t *obtail;
+       boolean_t do_not_ignore_null;
+       boolean_t do_not_ignore_invalid;
+       boolean_t is_it_toupper;
+       boolean_t is_it_tolower;
+       boolean_t canonical_decomposition;
+       boolean_t compatibility_decomposition;
+       boolean_t canonical_composition;
+       size_t ret_val;
+       size_t i;
+       size_t j;
+       uchar_t u8s[U8_STREAM_SAFE_TEXT_MAX + 1];
+       u8_normalization_states_t state;
+
+       if (unicode_version > U8_UNICODE_LATEST) {
+               *errnum = ERANGE;
+               return ((size_t)-1);
+       }
+
+       f = flag & (U8_TEXTPREP_TOUPPER | U8_TEXTPREP_TOLOWER);
+       if (f == (U8_TEXTPREP_TOUPPER | U8_TEXTPREP_TOLOWER)) {
+               *errnum = EBADF;
+               return ((size_t)-1);
+       }
+
+       f = flag & (U8_CANON_DECOMP | U8_COMPAT_DECOMP | U8_CANON_COMP);
+       if (f && f != U8_TEXTPREP_NFD && f != U8_TEXTPREP_NFC &&
+           f != U8_TEXTPREP_NFKD && f != U8_TEXTPREP_NFKC) {
+               *errnum = EBADF;
+               return ((size_t)-1);
+       }
+
+       if (inarray == NULL || *inlen == 0)
+               return (0);
+
+       if (outarray == NULL) {
+               *errnum = E2BIG;
+               return ((size_t)-1);
+       }
+
+       ib = (uchar_t *)inarray;
+       ob = (uchar_t *)outarray;
+       ibtail = ib + *inlen;
+       obtail = ob + *outlen;
+
+       do_not_ignore_null = !(flag & U8_TEXTPREP_IGNORE_NULL);
+       do_not_ignore_invalid = !(flag & U8_TEXTPREP_IGNORE_INVALID);
+       is_it_toupper = flag & U8_TEXTPREP_TOUPPER;
+       is_it_tolower = flag & U8_TEXTPREP_TOLOWER;
+
+       ret_val = 0;
+
+       /*
+        * If we don't have a normalization flag set, we do the simple case
+        * conversion based text preparation separately below. Text
+        * preparation involving Normalization will be done in the false task
+        * block, again, separately since it will take much more time and
+        * resource than doing simple case conversions.
+        */
+       if (f == 0) {
+               while (ib < ibtail) {
+                       if (*ib == '\0' && do_not_ignore_null)
+                               break;
+
+                       sz = u8_number_of_bytes[*ib];
+
+                       if (sz < 0) {
+                               if (do_not_ignore_invalid) {
+                                       *errnum = EILSEQ;
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               sz = 1;
+                               ret_val++;
+                       }
+
+                       if (sz == 1) {
+                               if (ob >= obtail) {
+                                       *errnum = E2BIG;
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               if (is_it_toupper)
+                                       *ob = U8_ASCII_TOUPPER(*ib);
+                               else if (is_it_tolower)
+                                       *ob = U8_ASCII_TOLOWER(*ib);
+                               else
+                                       *ob = *ib;
+                               ib++;
+                               ob++;
+                       } else if ((ib + sz) > ibtail) {
+                               if (do_not_ignore_invalid) {
+                                       *errnum = EINVAL;
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               if ((obtail - ob) < (ibtail - ib)) {
+                                       *errnum = E2BIG;
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               /*
+                                * We treat the remaining incomplete character
+                                * bytes as a character.
+                                */
+                               ret_val++;
+
+                               while (ib < ibtail)
+                                       *ob++ = *ib++;
+                       } else {
+                               if (is_it_toupper || is_it_tolower) {
+                                       i = do_case_conv(unicode_version, u8s,
+                                           ib, sz, is_it_toupper);
+
+                                       if ((obtail - ob) < i) {
+                                               *errnum = E2BIG;
+                                               ret_val = (size_t)-1;
+                                               break;
+                                       }
+
+                                       ib += sz;
+
+                                       for (sz = 0; sz < i; sz++)
+                                               *ob++ = u8s[sz];
+                               } else {
+                                       if ((obtail - ob) < sz) {
+                                               *errnum = E2BIG;
+                                               ret_val = (size_t)-1;
+                                               break;
+                                       }
+
+                                       for (i = 0; i < sz; i++)
+                                               *ob++ = *ib++;
+                               }
+                       }
+               }
+       } else {
+               canonical_decomposition = flag & U8_CANON_DECOMP;
+               compatibility_decomposition = flag & U8_COMPAT_DECOMP;
+               canonical_composition = flag & U8_CANON_COMP;
+
+               while (ib < ibtail) {
+                       if (*ib == '\0' && do_not_ignore_null)
+                               break;
+
+                       /*
+                        * If the current character is a 7-bit ASCII
+                        * character and it is the last character, or,
+                        * if the current character is a 7-bit ASCII
+                        * character and the next character is also a 7-bit
+                        * ASCII character, then, we copy over this
+                        * character without going through collect_a_seq().
+                        *
+                        * In any other cases, we need to look further with
+                        * the collect_a_seq() function.
+                        */
+                       if (U8_ISASCII(*ib) && ((ib + 1) >= ibtail ||
+                           ((ib + 1) < ibtail && U8_ISASCII(*(ib + 1))))) {
+                               if (ob >= obtail) {
+                                       *errnum = E2BIG;
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               if (is_it_toupper)
+                                       *ob = U8_ASCII_TOUPPER(*ib);
+                               else if (is_it_tolower)
+                                       *ob = U8_ASCII_TOLOWER(*ib);
+                               else
+                                       *ob = *ib;
+                               ib++;
+                               ob++;
+                       } else {
+                               *errnum = 0;
+                               state = U8_STATE_START;
+
+                               j = collect_a_seq(unicode_version, u8s,
+                                   &ib, ibtail,
+                                   is_it_toupper,
+                                   is_it_tolower,
+                                   canonical_decomposition,
+                                   compatibility_decomposition,
+                                   canonical_composition,
+                                   errnum, &state);
+
+                               if (*errnum && do_not_ignore_invalid) {
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               if ((obtail - ob) < j) {
+                                       *errnum = E2BIG;
+                                       ret_val = (size_t)-1;
+                                       break;
+                               }
+
+                               for (i = 0; i < j; i++)
+                                       *ob++ = u8s[i];
+                       }
+               }
+       }
+
+       *inlen = ibtail - ib;
+       *outlen = obtail - ob;
+
+       return (ret_val);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+static int __init
+unicode_init(void) {
+       return (0);
+}
+
+static void __exit
+unicode_fini(void)
+{
+}
+
+module_init(unicode_init);
+module_exit(unicode_fini);
+
+MODULE_DESCRIPTION("Unicode implementation");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
+
+EXPORT_SYMBOL(u8_validate);
+EXPORT_SYMBOL(u8_strcmp);
+EXPORT_SYMBOL(u8_textprep_str);
+#endif
diff --git a/zfs/module/unicode/uconv.c b/zfs/module/unicode/uconv.c
new file mode 100644 (file)
index 0000000..7a82783
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+
+
+/*
+ * Unicode encoding conversion functions among UTF-8, UTF-16, and UTF-32.
+ * (PSARC/2005/446, PSARC/2007/038, PSARC/2007/517)
+ * Man pages: uconv_u16tou32(9F), uconv_u16tou8(9F), uconv_u32tou16(9F),
+ * uconv_u32tou8(9F), uconv_u8tou16(9F), and uconv_u8tou32(9F). See also
+ * the section 3C man pages.
+ * Interface stability: Committed
+ */
+
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#else
+#include <sys/u8_textprep.h>
+#endif /* _KERNEL */
+#include <sys/byteorder.h>
+#include <sys/errno.h>
+
+
+/*
+ * The max and min values of high and low surrogate pairs of UTF-16,
+ * UTF-16 bit shift value, bit mask, and starting value outside of BMP.
+ */
+#define        UCONV_U16_HI_MIN        (0xd800U)
+#define        UCONV_U16_HI_MAX        (0xdbffU)
+#define        UCONV_U16_LO_MIN        (0xdc00U)
+#define        UCONV_U16_LO_MAX        (0xdfffU)
+#define        UCONV_U16_BIT_SHIFT     (0x0400U)
+#define        UCONV_U16_BIT_MASK      (0x0fffffU)
+#define        UCONV_U16_START         (0x010000U)
+
+/* The maximum value of Unicode coding space and ASCII coding space. */
+#define        UCONV_UNICODE_MAX       (0x10ffffU)
+#define        UCONV_ASCII_MAX         (0x7fU)
+
+/* The mask values for input and output endians. */
+#define        UCONV_IN_ENDIAN_MASKS   (UCONV_IN_BIG_ENDIAN | UCONV_IN_LITTLE_ENDIAN)
+#define        UCONV_OUT_ENDIAN_MASKS  (UCONV_OUT_BIG_ENDIAN | UCONV_OUT_LITTLE_ENDIAN)
+
+/* Native and reversed endian macros. */
+#ifdef _BIG_ENDIAN
+#define        UCONV_IN_NAT_ENDIAN     UCONV_IN_BIG_ENDIAN
+#define        UCONV_IN_REV_ENDIAN     UCONV_IN_LITTLE_ENDIAN
+#define        UCONV_OUT_NAT_ENDIAN    UCONV_OUT_BIG_ENDIAN
+#define        UCONV_OUT_REV_ENDIAN    UCONV_OUT_LITTLE_ENDIAN
+#else
+#define        UCONV_IN_NAT_ENDIAN     UCONV_IN_LITTLE_ENDIAN
+#define        UCONV_IN_REV_ENDIAN     UCONV_IN_BIG_ENDIAN
+#define        UCONV_OUT_NAT_ENDIAN    UCONV_OUT_LITTLE_ENDIAN
+#define        UCONV_OUT_REV_ENDIAN    UCONV_OUT_BIG_ENDIAN
+#endif /* _BIG_ENDIAN */
+
+/* The Byte Order Mark (BOM) character in normal and reversed byte orderings. */
+#define        UCONV_BOM_NORMAL        (0xfeffU)
+#define        UCONV_BOM_SWAPPED       (0xfffeU)
+#define        UCONV_BOM_SWAPPED_32    (0xfffe0000U)
+
+/* UTF-32 boundaries based on UTF-8 character byte lengths. */
+#define        UCONV_U8_ONE_BYTE       (0x7fU)
+#define        UCONV_U8_TWO_BYTES      (0x7ffU)
+#define        UCONV_U8_THREE_BYTES    (0xffffU)
+#define        UCONV_U8_FOUR_BYTES     (0x10ffffU)
+
+/* The common minimum and maximum values at the UTF-8 character bytes. */
+#define        UCONV_U8_BYTE_MIN       (0x80U)
+#define        UCONV_U8_BYTE_MAX       (0xbfU)
+
+/*
+ * The following "6" and "0x3f" came from "10xx xxxx" bit representation of
+ * UTF-8 character bytes.
+ */
+#define        UCONV_U8_BIT_SHIFT      6
+#define        UCONV_U8_BIT_MASK       0x3f
+
+/*
+ * The following vector shows remaining bytes in a UTF-8 character.
+ * Index will be the first byte of the character.
+ */
+static const uchar_t remaining_bytes_tbl[0x100] = {
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+
+/*     C0  C1  C2  C3  C4  C5  C6  C7  C8  C9  CA  CB  CC  CD  CE  CF */
+       0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+
+/*     D0  D1  D2  D3  D4  D5  D6  D7  D8  D9  DA  DB  DC  DD  DE  DF */
+       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+
+/*     E0  E1  E2  E3  E4  E5  E6  E7  E8  E9  EA  EB  EC  ED  EE  EF */
+       2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+
+/*     F0  F1  F2  F3  F4  F5  F6  F7  F8  F9  FA  FB  FC  FD  FE  FF */
+       3,  3,  3,  3,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
+};
+
+/*
+ * The following is a vector of bit-masks to get used bits in
+ * the first byte of a UTF-8 character.  Index is remaining bytes at above of
+ * the character.
+ */
+#ifdef _KERNEL
+const uchar_t u8_masks_tbl[6] = { 0x00, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+#else
+static const uchar_t u8_masks_tbl[6] = { 0x00, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+#endif /* _KERNEL */
+
+/*
+ * The following two vectors are to provide valid minimum and
+ * maximum values for the 2'nd byte of a multibyte UTF-8 character for
+ * better illegal sequence checking. The index value must be the value of
+ * the first byte of the UTF-8 character.
+ */
+static const uchar_t valid_min_2nd_byte[0x100] = {
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+
+/*     C0    C1    C2    C3    C4    C5    C6    C7 */
+       0,    0,    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+/*     C8    C9    CA    CB    CC    CD    CE    CF */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+/*     D0    D1    D2    D3    D4    D5    D6    D7 */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+/*     D8    D9    DA    DB    DC    DD    DE    DF */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+/*     E0    E1    E2    E3    E4    E5    E6    E7 */
+       0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+/*     E8    E9    EA    EB    EC    ED    EE    EF */
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+
+/*     F0    F1    F2    F3    F4    F5    F6    F7 */
+       0x90, 0x80, 0x80, 0x80, 0x80, 0,    0,    0,
+
+       0,    0,    0,    0,    0,    0,    0,    0
+};
+
+static const uchar_t valid_max_2nd_byte[0x100] = {
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+       0,    0,    0,    0,    0,    0,    0,    0,
+
+/*     C0    C1    C2    C3    C4    C5    C6    C7 */
+       0,    0,    0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+
+/*     C8    C9    CA    CB    CC    CD    CE    CF */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+
+/*     D0    D1    D2    D3    D4    D5    D6    D7 */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+
+/*     D8    D9    DA    DB    DC    DD    DE    DF */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+
+/*     E0    E1    E2    E3    E4    E5    E6    E7 */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+
+/*     E8    E9    EA    EB    EC    ED    EE    EF */
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x9f, 0xbf, 0xbf,
+
+/*     F0    F1    F2    F3    F4    F5    F6    F7 */
+       0xbf, 0xbf, 0xbf, 0xbf, 0x8f, 0,    0,    0,
+
+       0,    0,    0,    0,    0,    0,    0,    0
+};
+
+
+static int
+check_endian(int flag, int *in, int *out)
+{
+       *in = flag & UCONV_IN_ENDIAN_MASKS;
+
+       /* You cannot have both. */
+       if (*in == UCONV_IN_ENDIAN_MASKS)
+               return (EBADF);
+
+       if (*in == 0)
+               *in = UCONV_IN_NAT_ENDIAN;
+
+       *out = flag & UCONV_OUT_ENDIAN_MASKS;
+
+       /* You cannot have both. */
+       if (*out == UCONV_OUT_ENDIAN_MASKS)
+               return (EBADF);
+
+       if (*out == 0)
+               *out = UCONV_OUT_NAT_ENDIAN;
+
+       return (0);
+}
+
+static boolean_t
+check_bom16(const uint16_t *u16s, size_t u16l, int *in)
+{
+       if (u16l > 0) {
+               if (*u16s == UCONV_BOM_NORMAL) {
+                       *in = UCONV_IN_NAT_ENDIAN;
+                       return (B_TRUE);
+               }
+               if (*u16s == UCONV_BOM_SWAPPED) {
+                       *in = UCONV_IN_REV_ENDIAN;
+                       return (B_TRUE);
+               }
+       }
+
+       return (B_FALSE);
+}
+
+static boolean_t
+check_bom32(const uint32_t *u32s, size_t u32l, int *in)
+{
+       if (u32l > 0) {
+               if (*u32s == UCONV_BOM_NORMAL) {
+                       *in = UCONV_IN_NAT_ENDIAN;
+                       return (B_TRUE);
+               }
+               if (*u32s == UCONV_BOM_SWAPPED_32) {
+                       *in = UCONV_IN_REV_ENDIAN;
+                       return (B_TRUE);
+               }
+       }
+
+       return (B_FALSE);
+}
+
+int
+uconv_u16tou32(const uint16_t *u16s, size_t *utf16len,
+    uint32_t *u32s, size_t *utf32len, int flag)
+{
+       int inendian;
+       int outendian;
+       size_t u16l;
+       size_t u32l;
+       uint32_t hi;
+       uint32_t lo;
+       boolean_t do_not_ignore_null;
+
+       /*
+        * Do preliminary validity checks on parameters and collect info on
+        * endians.
+        */
+       if (u16s == NULL || utf16len == NULL)
+               return (EILSEQ);
+
+       if (u32s == NULL || utf32len == NULL)
+               return (E2BIG);
+
+       if (check_endian(flag, &inendian, &outendian) != 0)
+               return (EBADF);
+
+       /*
+        * Initialize input and output parameter buffer indices and
+        * temporary variables.
+        */
+       u16l = u32l = 0;
+       hi = 0;
+       do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
+
+       /*
+        * Check on the BOM at the beginning of the input buffer if required
+        * and if there is indeed one, process it.
+        */
+       if ((flag & UCONV_IN_ACCEPT_BOM) &&
+           check_bom16(u16s, *utf16len, &inendian))
+               u16l++;
+
+       /*
+        * Reset inendian and outendian so that after this point, those can be
+        * used as condition values.
+        */
+       inendian &= UCONV_IN_NAT_ENDIAN;
+       outendian &= UCONV_OUT_NAT_ENDIAN;
+
+       /*
+        * If there is something in the input buffer and if necessary and
+        * requested, save the BOM at the output buffer.
+        */
+       if (*utf16len > 0 && *utf32len > 0 && (flag & UCONV_OUT_EMIT_BOM))
+               u32s[u32l++] = (outendian) ? UCONV_BOM_NORMAL :
+                   UCONV_BOM_SWAPPED_32;
+
+       /*
+        * Do conversion; if encounter a surrogate pair, assemble high and
+        * low pair values to form a UTF-32 character. If a half of a pair
+        * exists alone, then, either it is an illegal (EILSEQ) or
+        * invalid (EINVAL) value.
+        */
+       for (; u16l < *utf16len; u16l++) {
+               if (u16s[u16l] == 0 && do_not_ignore_null)
+                       break;
+
+               lo = (uint32_t)((inendian) ? u16s[u16l] : BSWAP_16(u16s[u16l]));
+
+               if (lo >= UCONV_U16_HI_MIN && lo <= UCONV_U16_HI_MAX) {
+                       if (hi)
+                               return (EILSEQ);
+                       hi = lo;
+                       continue;
+               } else if (lo >= UCONV_U16_LO_MIN && lo <= UCONV_U16_LO_MAX) {
+                       if (! hi)
+                               return (EILSEQ);
+                       lo = (((hi - UCONV_U16_HI_MIN) * UCONV_U16_BIT_SHIFT +
+                           lo - UCONV_U16_LO_MIN) & UCONV_U16_BIT_MASK)
+                           + UCONV_U16_START;
+                       hi = 0;
+               } else if (hi) {
+                       return (EILSEQ);
+               }
+
+               if (u32l >= *utf32len)
+                       return (E2BIG);
+
+               u32s[u32l++] = (outendian) ? lo : BSWAP_32(lo);
+       }
+
+       /*
+        * If high half didn't see low half, then, it's most likely the input
+        * parameter is incomplete.
+        */
+       if (hi)
+               return (EINVAL);
+
+       /*
+        * Save the number of consumed and saved characters. They do not
+        * include terminating NULL character (U+0000) at the end of
+        * the input buffer (even when UCONV_IGNORE_NULL isn't specified and
+        * the input buffer length is big enough to include the terminating
+        * NULL character).
+        */
+       *utf16len = u16l;
+       *utf32len = u32l;
+
+       return (0);
+}
+
+int
+uconv_u16tou8(const uint16_t *u16s, size_t *utf16len,
+    uchar_t *u8s, size_t *utf8len, int flag)
+{
+       int inendian;
+       int outendian;
+       size_t u16l;
+       size_t u8l;
+       uint32_t hi;
+       uint32_t lo;
+       boolean_t do_not_ignore_null;
+
+       if (u16s == NULL || utf16len == NULL)
+               return (EILSEQ);
+
+       if (u8s == NULL || utf8len == NULL)
+               return (E2BIG);
+
+       if (check_endian(flag, &inendian, &outendian) != 0)
+               return (EBADF);
+
+       u16l = u8l = 0;
+       hi = 0;
+       do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
+
+       if ((flag & UCONV_IN_ACCEPT_BOM) &&
+           check_bom16(u16s, *utf16len, &inendian))
+               u16l++;
+
+       inendian &= UCONV_IN_NAT_ENDIAN;
+
+       for (; u16l < *utf16len; u16l++) {
+               if (u16s[u16l] == 0 && do_not_ignore_null)
+                       break;
+
+               lo = (uint32_t)((inendian) ? u16s[u16l] : BSWAP_16(u16s[u16l]));
+
+               if (lo >= UCONV_U16_HI_MIN && lo <= UCONV_U16_HI_MAX) {
+                       if (hi)
+                               return (EILSEQ);
+                       hi = lo;
+                       continue;
+               } else if (lo >= UCONV_U16_LO_MIN && lo <= UCONV_U16_LO_MAX) {
+                       if (! hi)
+                               return (EILSEQ);
+                       lo = (((hi - UCONV_U16_HI_MIN) * UCONV_U16_BIT_SHIFT +
+                           lo - UCONV_U16_LO_MIN) & UCONV_U16_BIT_MASK)
+                           + UCONV_U16_START;
+                       hi = 0;
+               } else if (hi) {
+                       return (EILSEQ);
+               }
+
+               /*
+                * Now we convert a UTF-32 character into a UTF-8 character.
+                * Unicode coding space is between U+0000 and U+10FFFF;
+                * anything bigger is an illegal character.
+                */
+               if (lo <= UCONV_U8_ONE_BYTE) {
+                       if (u8l >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)lo;
+               } else if (lo <= UCONV_U8_TWO_BYTES) {
+                       if ((u8l + 1) >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)(0xc0 | ((lo & 0x07c0) >> 6));
+                       u8s[u8l++] = (uchar_t)(0x80 |  (lo & 0x003f));
+               } else if (lo <= UCONV_U8_THREE_BYTES) {
+                       if ((u8l + 2) >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)(0xe0 | ((lo & 0x0f000) >> 12));
+                       u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x00fc0) >> 6));
+                       u8s[u8l++] = (uchar_t)(0x80 |  (lo & 0x0003f));
+               } else if (lo <= UCONV_U8_FOUR_BYTES) {
+                       if ((u8l + 3) >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)(0xf0 | ((lo & 0x01c0000) >> 18));
+                       u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x003f000) >> 12));
+                       u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x0000fc0) >> 6));
+                       u8s[u8l++] = (uchar_t)(0x80 |  (lo & 0x000003f));
+               } else {
+                       return (EILSEQ);
+               }
+       }
+
+       if (hi)
+               return (EINVAL);
+
+       *utf16len = u16l;
+       *utf8len = u8l;
+
+       return (0);
+}
+
+int
+uconv_u32tou16(const uint32_t *u32s, size_t *utf32len,
+    uint16_t *u16s, size_t *utf16len, int flag)
+{
+       int inendian;
+       int outendian;
+       size_t u16l;
+       size_t u32l;
+       uint32_t hi;
+       uint32_t lo;
+       boolean_t do_not_ignore_null;
+
+       if (u32s == NULL || utf32len == NULL)
+               return (EILSEQ);
+
+       if (u16s == NULL || utf16len == NULL)
+               return (E2BIG);
+
+       if (check_endian(flag, &inendian, &outendian) != 0)
+               return (EBADF);
+
+       u16l = u32l = 0;
+       do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
+
+       if ((flag & UCONV_IN_ACCEPT_BOM) &&
+           check_bom32(u32s, *utf32len, &inendian))
+               u32l++;
+
+       inendian &= UCONV_IN_NAT_ENDIAN;
+       outendian &= UCONV_OUT_NAT_ENDIAN;
+
+       if (*utf32len > 0 && *utf16len > 0 && (flag & UCONV_OUT_EMIT_BOM))
+               u16s[u16l++] = (outendian) ? UCONV_BOM_NORMAL :
+                   UCONV_BOM_SWAPPED;
+
+       for (; u32l < *utf32len; u32l++) {
+               if (u32s[u32l] == 0 && do_not_ignore_null)
+                       break;
+
+               hi = (inendian) ? u32s[u32l] : BSWAP_32(u32s[u32l]);
+
+               /*
+                * Anything bigger than the Unicode coding space, i.e.,
+                * Unicode scalar value bigger than U+10FFFF, is an illegal
+                * character.
+                */
+               if (hi > UCONV_UNICODE_MAX)
+                       return (EILSEQ);
+
+               /*
+                * Anything bigger than U+FFFF must be converted into
+                * a surrogate pair in UTF-16.
+                */
+               if (hi >= UCONV_U16_START) {
+                       lo = ((hi - UCONV_U16_START) % UCONV_U16_BIT_SHIFT) +
+                           UCONV_U16_LO_MIN;
+                       hi = ((hi - UCONV_U16_START) / UCONV_U16_BIT_SHIFT) +
+                           UCONV_U16_HI_MIN;
+
+                       if ((u16l + 1) >= *utf16len)
+                               return (E2BIG);
+
+                       if (outendian) {
+                               u16s[u16l++] = (uint16_t)hi;
+                               u16s[u16l++] = (uint16_t)lo;
+                       } else {
+                               u16s[u16l++] = BSWAP_16(((uint16_t)hi));
+                               u16s[u16l++] = BSWAP_16(((uint16_t)lo));
+                       }
+               } else {
+                       if (u16l >= *utf16len)
+                               return (E2BIG);
+                       u16s[u16l++] = (outendian) ? (uint16_t)hi :
+                           BSWAP_16(((uint16_t)hi));
+               }
+       }
+
+       *utf16len = u16l;
+       *utf32len = u32l;
+
+       return (0);
+}
+
+int
+uconv_u32tou8(const uint32_t *u32s, size_t *utf32len,
+    uchar_t *u8s, size_t *utf8len, int flag)
+{
+       int inendian;
+       int outendian;
+       size_t u32l;
+       size_t u8l;
+       uint32_t lo;
+       boolean_t do_not_ignore_null;
+
+       if (u32s == NULL || utf32len == NULL)
+               return (EILSEQ);
+
+       if (u8s == NULL || utf8len == NULL)
+               return (E2BIG);
+
+       if (check_endian(flag, &inendian, &outendian) != 0)
+               return (EBADF);
+
+       u32l = u8l = 0;
+       do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
+
+       if ((flag & UCONV_IN_ACCEPT_BOM) &&
+           check_bom32(u32s, *utf32len, &inendian))
+               u32l++;
+
+       inendian &= UCONV_IN_NAT_ENDIAN;
+
+       for (; u32l < *utf32len; u32l++) {
+               if (u32s[u32l] == 0 && do_not_ignore_null)
+                       break;
+
+               lo = (inendian) ? u32s[u32l] : BSWAP_32(u32s[u32l]);
+
+               if (lo <= UCONV_U8_ONE_BYTE) {
+                       if (u8l >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)lo;
+               } else if (lo <= UCONV_U8_TWO_BYTES) {
+                       if ((u8l + 1) >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)(0xc0 | ((lo & 0x07c0) >> 6));
+                       u8s[u8l++] = (uchar_t)(0x80 |  (lo & 0x003f));
+               } else if (lo <= UCONV_U8_THREE_BYTES) {
+                       if ((u8l + 2) >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)(0xe0 | ((lo & 0x0f000) >> 12));
+                       u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x00fc0) >> 6));
+                       u8s[u8l++] = (uchar_t)(0x80 |  (lo & 0x0003f));
+               } else if (lo <= UCONV_U8_FOUR_BYTES) {
+                       if ((u8l + 3) >= *utf8len)
+                               return (E2BIG);
+                       u8s[u8l++] = (uchar_t)(0xf0 | ((lo & 0x01c0000) >> 18));
+                       u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x003f000) >> 12));
+                       u8s[u8l++] = (uchar_t)(0x80 | ((lo & 0x0000fc0) >> 6));
+                       u8s[u8l++] = (uchar_t)(0x80 |  (lo & 0x000003f));
+               } else {
+                       return (EILSEQ);
+               }
+       }
+
+       *utf32len = u32l;
+       *utf8len = u8l;
+
+       return (0);
+}
+
+int
+uconv_u8tou16(const uchar_t *u8s, size_t *utf8len,
+    uint16_t *u16s, size_t *utf16len, int flag)
+{
+       int inendian;
+       int outendian;
+       size_t u16l;
+       size_t u8l;
+       uint32_t hi;
+       uint32_t lo;
+       int remaining_bytes;
+       int first_b;
+       boolean_t do_not_ignore_null;
+
+       if (u8s == NULL || utf8len == NULL)
+               return (EILSEQ);
+
+       if (u16s == NULL || utf16len == NULL)
+               return (E2BIG);
+
+       if (check_endian(flag, &inendian, &outendian) != 0)
+               return (EBADF);
+
+       u16l = u8l = 0;
+       do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
+
+       outendian &= UCONV_OUT_NAT_ENDIAN;
+
+       if (*utf8len > 0 && *utf16len > 0 && (flag & UCONV_OUT_EMIT_BOM))
+               u16s[u16l++] = (outendian) ? UCONV_BOM_NORMAL :
+                   UCONV_BOM_SWAPPED;
+
+       for (; u8l < *utf8len; ) {
+               if (u8s[u8l] == 0 && do_not_ignore_null)
+                       break;
+
+               /*
+                * Collect a UTF-8 character and convert it to a UTF-32
+                * character. In doing so, we screen out illegally formed
+                * UTF-8 characters and treat such as illegal characters.
+                * The algorithm at below also screens out anything bigger
+                * than the U+10FFFF.
+                *
+                * See Unicode 3.1 UTF-8 Corrigendum and Unicode 3.2 for
+                * more details on the illegal values of UTF-8 character
+                * bytes.
+                */
+               hi = (uint32_t)u8s[u8l++];
+
+               if (hi > UCONV_ASCII_MAX) {
+                       if ((remaining_bytes = remaining_bytes_tbl[hi]) == 0)
+                               return (EILSEQ);
+
+                       first_b = hi;
+                       hi = hi & u8_masks_tbl[remaining_bytes];
+
+                       for (; remaining_bytes > 0; remaining_bytes--) {
+                               /*
+                                * If we have no more bytes, the current
+                                * UTF-8 character is incomplete.
+                                */
+                               if (u8l >= *utf8len)
+                                       return (EINVAL);
+
+                               lo = (uint32_t)u8s[u8l++];
+
+                               if (first_b) {
+                                       if (lo < valid_min_2nd_byte[first_b] ||
+                                           lo > valid_max_2nd_byte[first_b])
+                                               return (EILSEQ);
+                                       first_b = 0;
+                               } else if (lo < UCONV_U8_BYTE_MIN ||
+                                   lo > UCONV_U8_BYTE_MAX) {
+                                       return (EILSEQ);
+                               }
+                               hi = (hi << UCONV_U8_BIT_SHIFT) |
+                                   (lo & UCONV_U8_BIT_MASK);
+                       }
+               }
+
+               if (hi >= UCONV_U16_START) {
+                       lo = ((hi - UCONV_U16_START) % UCONV_U16_BIT_SHIFT) +
+                           UCONV_U16_LO_MIN;
+                       hi = ((hi - UCONV_U16_START) / UCONV_U16_BIT_SHIFT) +
+                           UCONV_U16_HI_MIN;
+
+                       if ((u16l + 1) >= *utf16len)
+                               return (E2BIG);
+
+                       if (outendian) {
+                               u16s[u16l++] = (uint16_t)hi;
+                               u16s[u16l++] = (uint16_t)lo;
+                       } else {
+                               u16s[u16l++] = BSWAP_16(((uint16_t)hi));
+                               u16s[u16l++] = BSWAP_16(((uint16_t)lo));
+                       }
+               } else {
+                       if (u16l >= *utf16len)
+                               return (E2BIG);
+
+                       u16s[u16l++] = (outendian) ? (uint16_t)hi :
+                           BSWAP_16(((uint16_t)hi));
+               }
+       }
+
+       *utf16len = u16l;
+       *utf8len = u8l;
+
+       return (0);
+}
+
+int
+uconv_u8tou32(const uchar_t *u8s, size_t *utf8len,
+    uint32_t *u32s, size_t *utf32len, int flag)
+{
+       int inendian;
+       int outendian;
+       size_t u32l;
+       size_t u8l;
+       uint32_t hi;
+       uint32_t c;
+       int remaining_bytes;
+       int first_b;
+       boolean_t do_not_ignore_null;
+
+       if (u8s == NULL || utf8len == NULL)
+               return (EILSEQ);
+
+       if (u32s == NULL || utf32len == NULL)
+               return (E2BIG);
+
+       if (check_endian(flag, &inendian, &outendian) != 0)
+               return (EBADF);
+
+       u32l = u8l = 0;
+       do_not_ignore_null = ((flag & UCONV_IGNORE_NULL) == 0);
+
+       outendian &= UCONV_OUT_NAT_ENDIAN;
+
+       if (*utf8len > 0 && *utf32len > 0 && (flag & UCONV_OUT_EMIT_BOM))
+               u32s[u32l++] = (outendian) ? UCONV_BOM_NORMAL :
+                   UCONV_BOM_SWAPPED_32;
+
+       for (; u8l < *utf8len; ) {
+               if (u8s[u8l] == 0 && do_not_ignore_null)
+                       break;
+
+               hi = (uint32_t)u8s[u8l++];
+
+               if (hi > UCONV_ASCII_MAX) {
+                       if ((remaining_bytes = remaining_bytes_tbl[hi]) == 0)
+                               return (EILSEQ);
+
+                       first_b = hi;
+                       hi = hi & u8_masks_tbl[remaining_bytes];
+
+                       for (; remaining_bytes > 0; remaining_bytes--) {
+                               if (u8l >= *utf8len)
+                                       return (EINVAL);
+
+                               c = (uint32_t)u8s[u8l++];
+
+                               if (first_b) {
+                                       if (c < valid_min_2nd_byte[first_b] ||
+                                           c > valid_max_2nd_byte[first_b])
+                                               return (EILSEQ);
+                                       first_b = 0;
+                               } else if (c < UCONV_U8_BYTE_MIN ||
+                                   c > UCONV_U8_BYTE_MAX) {
+                                       return (EILSEQ);
+                               }
+                               hi = (hi << UCONV_U8_BIT_SHIFT) |
+                                   (c & UCONV_U8_BIT_MASK);
+                       }
+               }
+
+               if (u32l >= *utf32len)
+                       return (E2BIG);
+
+               u32s[u32l++] = (outendian) ? hi : BSWAP_32(hi);
+       }
+
+       *utf32len = u32l;
+       *utf8len = u8l;
+
+       return (0);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(uconv_u16tou32);
+EXPORT_SYMBOL(uconv_u16tou8);
+EXPORT_SYMBOL(uconv_u32tou16);
+EXPORT_SYMBOL(uconv_u32tou8);
+EXPORT_SYMBOL(uconv_u8tou16);
+EXPORT_SYMBOL(uconv_u8tou32);
+#endif
diff --git a/zfs/module/zcommon/Makefile.in b/zfs/module/zcommon/Makefile.in
new file mode 100644 (file)
index 0000000..67e474e
--- /dev/null
@@ -0,0 +1,17 @@
+src = @abs_top_srcdir@/module/zcommon
+obj = @abs_builddir@
+
+MODULE := zcommon
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+$(MODULE)-objs += zfs_deleg.o
+$(MODULE)-objs += zfs_prop.o
+$(MODULE)-objs += zprop_common.o
+$(MODULE)-objs += zfs_namecheck.o
+$(MODULE)-objs += zfs_comutil.o
+$(MODULE)-objs += zfs_fletcher.o
+$(MODULE)-objs += zfs_uio.o
+$(MODULE)-objs += zpool_prop.o
diff --git a/zfs/module/zcommon/zfs_comutil.c b/zfs/module/zcommon/zfs_comutil.c
new file mode 100644 (file)
index 0000000..6d0314f
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * This file is intended for functions that ought to be common between user
+ * land (libzfs) and the kernel. When many common routines need to be shared
+ * then a separate file should to be created.
+ */
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/fs/zfs.h>
+#include <sys/int_limits.h>
+#include <sys/nvpair.h>
+#include "zfs_comutil.h"
+
+/*
+ * Are there allocatable vdevs?
+ */
+boolean_t
+zfs_allocatable_devs(nvlist_t *nv)
+{
+       uint64_t is_log;
+       uint_t c;
+       nvlist_t **child;
+       uint_t children;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0) {
+               return (B_FALSE);
+       }
+       for (c = 0; c < children; c++) {
+               is_log = 0;
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if (!is_log)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+void
+zpool_get_rewind_policy(nvlist_t *nvl, zpool_rewind_policy_t *zrpp)
+{
+       nvlist_t *policy;
+       nvpair_t *elem;
+       char *nm;
+
+       /* Defaults */
+       zrpp->zrp_request = ZPOOL_NO_REWIND;
+       zrpp->zrp_maxmeta = 0;
+       zrpp->zrp_maxdata = UINT64_MAX;
+       zrpp->zrp_txg = UINT64_MAX;
+
+       if (nvl == NULL)
+               return;
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+               nm = nvpair_name(elem);
+               if (strcmp(nm, ZPOOL_REWIND_POLICY) == 0) {
+                       if (nvpair_value_nvlist(elem, &policy) == 0)
+                               zpool_get_rewind_policy(policy, zrpp);
+                       return;
+               } else if (strcmp(nm, ZPOOL_REWIND_REQUEST) == 0) {
+                       if (nvpair_value_uint32(elem, &zrpp->zrp_request) == 0)
+                               if (zrpp->zrp_request & ~ZPOOL_REWIND_POLICIES)
+                                       zrpp->zrp_request = ZPOOL_NO_REWIND;
+               } else if (strcmp(nm, ZPOOL_REWIND_REQUEST_TXG) == 0) {
+                       (void) nvpair_value_uint64(elem, &zrpp->zrp_txg);
+               } else if (strcmp(nm, ZPOOL_REWIND_META_THRESH) == 0) {
+                       (void) nvpair_value_uint64(elem, &zrpp->zrp_maxmeta);
+               } else if (strcmp(nm, ZPOOL_REWIND_DATA_THRESH) == 0) {
+                       (void) nvpair_value_uint64(elem, &zrpp->zrp_maxdata);
+               }
+       }
+       if (zrpp->zrp_request == 0)
+               zrpp->zrp_request = ZPOOL_NO_REWIND;
+}
+
+typedef struct zfs_version_spa_map {
+       int     version_zpl;
+       int     version_spa;
+} zfs_version_spa_map_t;
+
+/*
+ * Keep this table in monotonically increasing version number order.
+ */
+static zfs_version_spa_map_t zfs_version_table[] = {
+       {ZPL_VERSION_INITIAL, SPA_VERSION_INITIAL},
+       {ZPL_VERSION_DIRENT_TYPE, SPA_VERSION_INITIAL},
+       {ZPL_VERSION_FUID, SPA_VERSION_FUID},
+       {ZPL_VERSION_USERSPACE, SPA_VERSION_USERSPACE},
+       {ZPL_VERSION_SA, SPA_VERSION_SA},
+       {0, 0}
+};
+
+/*
+ * Return the max zpl version for a corresponding spa version
+ * -1 is returned if no mapping exists.
+ */
+int
+zfs_zpl_version_map(int spa_version)
+{
+       int i;
+       int version = -1;
+
+       for (i = 0; zfs_version_table[i].version_spa; i++) {
+               if (spa_version >= zfs_version_table[i].version_spa)
+                       version = zfs_version_table[i].version_zpl;
+       }
+
+       return (version);
+}
+
+/*
+ * Return the min spa version for a corresponding spa version
+ * -1 is returned if no mapping exists.
+ */
+int
+zfs_spa_version_map(int zpl_version)
+{
+       int i;
+       int version = -1;
+
+       for (i = 0; zfs_version_table[i].version_zpl; i++) {
+               if (zfs_version_table[i].version_zpl >= zpl_version)
+                       return (zfs_version_table[i].version_spa);
+       }
+
+       return (version);
+}
+
+/*
+ * This is the table of legacy internal event names; it should not be modified.
+ * The internal events are now stored in the history log as strings.
+ */
+const char *zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS] = {
+       "invalid event",
+       "pool create",
+       "vdev add",
+       "pool remove",
+       "pool destroy",
+       "pool export",
+       "pool import",
+       "vdev attach",
+       "vdev replace",
+       "vdev detach",
+       "vdev online",
+       "vdev offline",
+       "vdev upgrade",
+       "pool clear",
+       "pool scrub",
+       "pool property set",
+       "create",
+       "clone",
+       "destroy",
+       "destroy_begin_sync",
+       "inherit",
+       "property set",
+       "quota set",
+       "permission update",
+       "permission remove",
+       "permission who remove",
+       "promote",
+       "receive",
+       "rename",
+       "reservation set",
+       "replay_inc_sync",
+       "replay_full_sync",
+       "rollback",
+       "snapshot",
+       "filesystem version upgrade",
+       "refquota set",
+       "refreservation set",
+       "pool scrub done",
+       "user hold",
+       "user release",
+       "pool split",
+};
+
+#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);
+#endif
diff --git a/zfs/module/zcommon/zfs_deleg.c b/zfs/module/zcommon/zfs_deleg.c
new file mode 100644 (file)
index 0000000..f6e41da
--- /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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#include <sys/sunddi.h>
+#include <sys/ctype.h>
+#else
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <libnvpair.h>
+#include <ctype.h>
+#endif
+#include <sys/dsl_deleg.h>
+#include "zfs_prop.h"
+#include "zfs_deleg.h"
+#include "zfs_namecheck.h"
+
+zfs_deleg_perm_tab_t zfs_deleg_perm_tab[] = {
+       {ZFS_DELEG_PERM_ALLOW},
+       {ZFS_DELEG_PERM_BOOKMARK},
+       {ZFS_DELEG_PERM_CLONE},
+       {ZFS_DELEG_PERM_CREATE},
+       {ZFS_DELEG_PERM_DESTROY},
+       {ZFS_DELEG_PERM_DIFF},
+       {ZFS_DELEG_PERM_MOUNT},
+       {ZFS_DELEG_PERM_PROMOTE},
+       {ZFS_DELEG_PERM_RECEIVE},
+       {ZFS_DELEG_PERM_RENAME},
+       {ZFS_DELEG_PERM_ROLLBACK},
+       {ZFS_DELEG_PERM_SNAPSHOT},
+       {ZFS_DELEG_PERM_SHARE},
+       {ZFS_DELEG_PERM_SEND},
+       {ZFS_DELEG_PERM_USERPROP},
+       {ZFS_DELEG_PERM_USERQUOTA},
+       {ZFS_DELEG_PERM_GROUPQUOTA},
+       {ZFS_DELEG_PERM_USERUSED},
+       {ZFS_DELEG_PERM_GROUPUSED},
+       {ZFS_DELEG_PERM_HOLD},
+       {ZFS_DELEG_PERM_RELEASE},
+       {NULL}
+};
+
+static int
+zfs_valid_permission_name(const char *perm)
+{
+       if (zfs_deleg_canonicalize_perm(perm))
+               return (0);
+
+       return (permset_namecheck(perm, NULL, NULL));
+}
+
+const char *
+zfs_deleg_canonicalize_perm(const char *perm)
+{
+       int i;
+       zfs_prop_t prop;
+
+       for (i = 0; zfs_deleg_perm_tab[i].z_perm != NULL; i++) {
+               if (strcmp(perm, zfs_deleg_perm_tab[i].z_perm) == 0)
+                       return (perm);
+       }
+
+       prop = zfs_name_to_prop(perm);
+       if (prop != ZPROP_INVAL && zfs_prop_delegatable(prop))
+               return (zfs_prop_to_name(prop));
+       return (NULL);
+
+}
+
+static int
+zfs_validate_who(char *who)
+{
+       char *p;
+
+       if (who[2] != ZFS_DELEG_FIELD_SEP_CHR)
+               return (-1);
+
+       switch (who[0]) {
+       case ZFS_DELEG_USER:
+       case ZFS_DELEG_GROUP:
+       case ZFS_DELEG_USER_SETS:
+       case ZFS_DELEG_GROUP_SETS:
+               if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT)
+                       return (-1);
+               for (p = &who[3]; *p; p++)
+                       if (!isdigit(*p))
+                               return (-1);
+               break;
+
+       case ZFS_DELEG_NAMED_SET:
+       case ZFS_DELEG_NAMED_SET_SETS:
+               if (who[1] != ZFS_DELEG_NA)
+                       return (-1);
+               return (permset_namecheck(&who[3], NULL, NULL));
+
+       case ZFS_DELEG_CREATE:
+       case ZFS_DELEG_CREATE_SETS:
+               if (who[1] != ZFS_DELEG_NA)
+                       return (-1);
+               if (who[3] != '\0')
+                       return (-1);
+               break;
+
+       case ZFS_DELEG_EVERYONE:
+       case ZFS_DELEG_EVERYONE_SETS:
+               if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT)
+                       return (-1);
+               if (who[3] != '\0')
+                       return (-1);
+               break;
+
+       default:
+               return (-1);
+       }
+
+       return (0);
+}
+
+int
+zfs_deleg_verify_nvlist(nvlist_t *nvp)
+{
+       nvpair_t *who, *perm_name;
+       nvlist_t *perms;
+       int error;
+
+       if (nvp == NULL)
+               return (-1);
+
+       who = nvlist_next_nvpair(nvp, NULL);
+       if (who == NULL)
+               return (-1);
+
+       do {
+               if (zfs_validate_who(nvpair_name(who)))
+                       return (-1);
+
+               error = nvlist_lookup_nvlist(nvp, nvpair_name(who), &perms);
+
+               if (error && error != ENOENT)
+                       return (-1);
+               if (error == ENOENT)
+                       continue;
+
+               perm_name = nvlist_next_nvpair(perms, NULL);
+               if (perm_name == NULL) {
+                       return (-1);
+               }
+               do {
+                       error = zfs_valid_permission_name(
+                           nvpair_name(perm_name));
+                       if (error)
+                               return (-1);
+               } while ((perm_name = nvlist_next_nvpair(perms, perm_name)));
+       } while ((who = nvlist_next_nvpair(nvp, who)));
+       return (0);
+}
+
+/*
+ * Construct the base attribute name.  The base attribute names
+ * are the "key" to locate the jump objects which contain the actual
+ * permissions.  The base attribute names are encoded based on
+ * type of entry and whether it is a local or descendent permission.
+ *
+ * Arguments:
+ * attr - attribute name return string, attribute is assumed to be
+ *        ZFS_MAX_DELEG_NAME long.
+ * type - type of entry to construct
+ * inheritchr - inheritance type (local,descendent, or NA for create and
+ *                               permission set definitions
+ * data - is either a permission set name or a 64 bit uid/gid.
+ */
+void
+zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
+    char inheritchr, void *data)
+{
+       int len = ZFS_MAX_DELEG_NAME;
+       uint64_t *id = data;
+
+       switch (type) {
+       case ZFS_DELEG_USER:
+       case ZFS_DELEG_GROUP:
+       case ZFS_DELEG_USER_SETS:
+       case ZFS_DELEG_GROUP_SETS:
+               (void) snprintf(attr, len, "%c%c%c%lld", type, inheritchr,
+                   ZFS_DELEG_FIELD_SEP_CHR, (longlong_t)*id);
+               break;
+       case ZFS_DELEG_NAMED_SET_SETS:
+       case ZFS_DELEG_NAMED_SET:
+               (void) snprintf(attr, len, "%c-%c%s", type,
+                   ZFS_DELEG_FIELD_SEP_CHR, (char *)data);
+               break;
+       case ZFS_DELEG_CREATE:
+       case ZFS_DELEG_CREATE_SETS:
+               (void) snprintf(attr, len, "%c-%c", type,
+                   ZFS_DELEG_FIELD_SEP_CHR);
+               break;
+       case ZFS_DELEG_EVERYONE:
+       case ZFS_DELEG_EVERYONE_SETS:
+               (void) snprintf(attr, len, "%c%c%c", type, inheritchr,
+                   ZFS_DELEG_FIELD_SEP_CHR);
+               break;
+       default:
+               cmn_err(CE_PANIC, "bad zfs_deleg_who_type_t %d", type);
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zfs_deleg_verify_nvlist);
+EXPORT_SYMBOL(zfs_deleg_whokey);
+EXPORT_SYMBOL(zfs_deleg_canonicalize_perm);
+#endif
diff --git a/zfs/module/zcommon/zfs_fletcher.c b/zfs/module/zcommon/zfs_fletcher.c
new file mode 100644 (file)
index 0000000..edd0cbe
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Fletcher Checksums
+ * ------------------
+ *
+ * ZFS's 2nd and 4th order Fletcher checksums are defined by the following
+ * recurrence relations:
+ *
+ *     a  = a    + f
+ *      i    i-1    i-1
+ *
+ *     b  = b    + a
+ *      i    i-1    i
+ *
+ *     c  = c    + b           (fletcher-4 only)
+ *      i    i-1    i
+ *
+ *     d  = d    + c           (fletcher-4 only)
+ *      i    i-1    i
+ *
+ * Where
+ *     a_0 = b_0 = c_0 = d_0 = 0
+ * and
+ *     f_0 .. f_(n-1) are the input data.
+ *
+ * Using standard techniques, these translate into the following series:
+ *
+ *          __n_                            __n_
+ *          \   |                           \   |
+ *     a  =  >     f                   b  =  >     i * f
+ *      n   /___|   n - i               n   /___|       n - i
+ *          i = 1                           i = 1
+ *
+ *
+ *          __n_                            __n_
+ *          \   |  i*(i+1)                  \   |  i*(i+1)*(i+2)
+ *     c  =  >     ------- f           d  =  >     ------------- f
+ *      n   /___|     2     n - i       n   /___|        6        n - i
+ *          i = 1                           i = 1
+ *
+ * For fletcher-2, the f_is are 64-bit, and [ab]_i are 64-bit accumulators.
+ * Since the additions are done mod (2^64), errors in the high bits may not
+ * be noticed.  For this reason, fletcher-2 is deprecated.
+ *
+ * For fletcher-4, the f_is are 32-bit, and [abcd]_i are 64-bit accumulators.
+ * A conservative estimate of how big the buffer can get before we overflow
+ * can be estimated using f_i = 0xffffffff for all i:
+ *
+ * % bc
+ *  f=2^32-1;d=0; for (i = 1; d<2^64; i++) { d += f*i*(i+1)*(i+2)/6 }; (i-1)*4
+ * 2264
+ *  quit
+ * %
+ *
+ * So blocks of up to 2k will not overflow.  Our largest block size is
+ * 128k, which has 32k 4-byte words, so we can compute the largest possible
+ * accumulators, then divide by 2^64 to figure the max amount of overflow:
+ *
+ * % bc
+ *  a=b=c=d=0; f=2^32-1; for (i=1; i<=32*1024; i++) { a+=f; b+=a; c+=b; d+=c }
+ *  a/2^64;b/2^64;c/2^64;d/2^64
+ * 0
+ * 0
+ * 1365
+ * 11186858
+ *  quit
+ * %
+ *
+ * So a and b cannot overflow.  To make sure each bit of input has some
+ * effect on the contents of c and d, we can look at what the factors of
+ * the coefficients in the equations for c_n and d_n are.  The number of 2s
+ * in the factors determines the lowest set bit in the multiplier.  Running
+ * through the cases for n*(n+1)/2 reveals that the highest power of 2 is
+ * 2^14, and for n*(n+1)*(n+2)/6 it is 2^15.  So while some data may overflow
+ * the 64-bit accumulators, every bit of every f_i effects every accumulator,
+ * even for 128k blocks.
+ *
+ * If we wanted to make a stronger version of fletcher4 (fletcher4c?),
+ * we could do our calculations mod (2^32 - 1) by adding in the carries
+ * periodically, and store the number of carries in the top 32-bits.
+ *
+ * --------------------
+ * Checksum Performance
+ * --------------------
+ *
+ * There are two interesting components to checksum performance: cached and
+ * uncached performance.  With cached data, fletcher-2 is about four times
+ * faster than fletcher-4.  With uncached data, the performance difference is
+ * negligible, since the cost of a cache fill dominates the processing time.
+ * Even though fletcher-4 is slower than fletcher-2, it is still a pretty
+ * efficient pass over the data.
+ *
+ * In normal operation, the data which is being checksummed is in a buffer
+ * which has been filled either by:
+ *
+ *     1. a compression step, which will be mostly cached, or
+ *     2. a bcopy() or copyin(), which will be uncached (because the
+ *        copy is cache-bypassing).
+ *
+ * For both cached and uncached data, both fletcher checksums are much faster
+ * than sha-256, and slower than 'off', which doesn't touch the data at all.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/byteorder.h>
+#include <sys/zio.h>
+#include <sys/spa.h>
+
+void
+fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = ip + (size / sizeof (uint64_t));
+       uint64_t a0, b0, a1, b1;
+
+       for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) {
+               a0 += ip[0];
+               a1 += ip[1];
+               b0 += a0;
+               b1 += a1;
+       }
+
+       ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
+}
+
+void
+fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = ip + (size / sizeof (uint64_t));
+       uint64_t a0, b0, a1, b1;
+
+       for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) {
+               a0 += BSWAP_64(ip[0]);
+               a1 += BSWAP_64(ip[1]);
+               b0 += a0;
+               b1 += a1;
+       }
+
+       ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
+}
+
+void
+fletcher_4_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;
+
+       for (a = b = c = d = 0; ip < ipend; ip++) {
+               a += ip[0];
+               b += a;
+               c += b;
+               d += c;
+       }
+
+       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+}
+
+void
+fletcher_4_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;
+
+       for (a = b = c = d = 0; ip < ipend; ip++) {
+               a += BSWAP_32(ip[0]);
+               b += a;
+               c += b;
+               d += c;
+       }
+
+       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+}
+
+void
+fletcher_4_incremental_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;
+
+       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 += ip[0];
+               b += a;
+               c += b;
+               d += c;
+       }
+
+       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+}
+
+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;
+
+       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;
+       }
+
+       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(fletcher_2_native);
+EXPORT_SYMBOL(fletcher_2_byteswap);
+EXPORT_SYMBOL(fletcher_4_native);
+EXPORT_SYMBOL(fletcher_4_byteswap);
+EXPORT_SYMBOL(fletcher_4_incremental_native);
+EXPORT_SYMBOL(fletcher_4_incremental_byteswap);
+#endif
diff --git a/zfs/module/zcommon/zfs_namecheck.c b/zfs/module/zcommon/zfs_namecheck.c
new file mode 100644 (file)
index 0000000..ff724be
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+/*
+ * Common name validation routines for ZFS.  These routines are shared by the
+ * userland code as well as the ioctl() layer to ensure that we don't
+ * inadvertently expose a hole through direct ioctl()s that never gets tested.
+ * In userland, however, we want significantly more information about _why_ the
+ * name is invalid.  In the kernel, we only care whether it's valid or not.
+ * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
+ * the name failed to validate.
+ *
+ * Each function returns 0 on success, -1 on error.
+ */
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <string.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/nvpair.h>
+#include "zfs_namecheck.h"
+#include "zfs_deleg.h"
+
+static int
+valid_char(char c)
+{
+       return ((c >= 'a' && c <= 'z') ||
+           (c >= 'A' && c <= 'Z') ||
+           (c >= '0' && c <= '9') ||
+           c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
+}
+
+/*
+ * Snapshot names must be made up of alphanumeric characters plus the following
+ * characters:
+ *
+ *     [-_.: ]
+ */
+int
+zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
+{
+       const char *loc;
+
+       if (strlen(path) >= MAXNAMELEN) {
+               if (why)
+                       *why = NAME_ERR_TOOLONG;
+               return (-1);
+       }
+
+       if (path[0] == '\0') {
+               if (why)
+                       *why = NAME_ERR_EMPTY_COMPONENT;
+               return (-1);
+       }
+
+       for (loc = path; *loc; loc++) {
+               if (!valid_char(*loc)) {
+                       if (why) {
+                               *why = NAME_ERR_INVALCHAR;
+                               *what = *loc;
+                       }
+                       return (-1);
+               }
+       }
+       return (0);
+}
+
+
+/*
+ * Permissions set name must start with the letter '@' followed by the
+ * same character restrictions as snapshot names, except that the name
+ * cannot exceed 64 characters.
+ */
+int
+permset_namecheck(const char *path, namecheck_err_t *why, char *what)
+{
+       if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
+               if (why)
+                       *why = NAME_ERR_TOOLONG;
+               return (-1);
+       }
+
+       if (path[0] != '@') {
+               if (why) {
+                       *why = NAME_ERR_NO_AT;
+                       *what = path[0];
+               }
+               return (-1);
+       }
+
+       return (zfs_component_namecheck(&path[1], why, what));
+}
+
+/*
+ * Dataset names must be of the following form:
+ *
+ *     [component][/]*[component][@component]
+ *
+ * Where each component is made up of alphanumeric characters plus the following
+ * characters:
+ *
+ *     [-_.:%]
+ *
+ * We allow '%' here as we use that character internally to create unique
+ * names for temporary clones (for online recv).
+ */
+int
+dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
+{
+       const char *loc, *end;
+       int found_snapshot;
+
+       /*
+        * 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 (why)
+                       *why = NAME_ERR_TOOLONG;
+               return (-1);
+       }
+
+       /* Explicitly check for a leading slash.  */
+       if (path[0] == '/') {
+               if (why)
+                       *why = NAME_ERR_LEADING_SLASH;
+               return (-1);
+       }
+
+       if (path[0] == '\0') {
+               if (why)
+                       *why = NAME_ERR_EMPTY_COMPONENT;
+               return (-1);
+       }
+
+       loc = path;
+       found_snapshot = 0;
+       for (;;) {
+               /* Find the end of this component */
+               end = loc;
+               while (*end != '/' && *end != '@' && *end != '\0')
+                       end++;
+
+               if (*end == '\0' && end[-1] == '/') {
+                       /* trailing slashes are not allowed */
+                       if (why)
+                               *why = NAME_ERR_TRAILING_SLASH;
+                       return (-1);
+               }
+
+               /* Zero-length components are not allowed */
+               if (loc == end) {
+                       if (why) {
+                               /*
+                                * Make sure this is really a zero-length
+                                * component and not a '@@'.
+                                */
+                               if (*end == '@' && found_snapshot) {
+                                       *why = NAME_ERR_MULTIPLE_AT;
+                               } else {
+                                       *why = NAME_ERR_EMPTY_COMPONENT;
+                               }
+                       }
+
+                       return (-1);
+               }
+
+               /* Validate the contents of this component */
+               while (loc != end) {
+                       if (!valid_char(*loc) && *loc != '%') {
+                               if (why) {
+                                       *why = NAME_ERR_INVALCHAR;
+                                       *what = *loc;
+                               }
+                               return (-1);
+                       }
+                       loc++;
+               }
+
+               /* If we've reached the end of the string, we're OK */
+               if (*end == '\0')
+                       return (0);
+
+               if (*end == '@') {
+                       /*
+                        * If we've found an @ symbol, indicate that we're in
+                        * the snapshot component, and report a second '@'
+                        * character as an error.
+                        */
+                       if (found_snapshot) {
+                               if (why)
+                                       *why = NAME_ERR_MULTIPLE_AT;
+                               return (-1);
+                       }
+
+                       found_snapshot = 1;
+               }
+
+               /*
+                * If there is a '/' in a snapshot name
+                * then report an error
+                */
+               if (*end == '/' && found_snapshot) {
+                       if (why)
+                               *why = NAME_ERR_TRAILING_SLASH;
+                       return (-1);
+               }
+
+               /* Update to the next component */
+               loc = end + 1;
+       }
+}
+
+
+/*
+ * mountpoint names must be of the following form:
+ *
+ *     /[component][/]*[component][/]
+ */
+int
+mountpoint_namecheck(const char *path, namecheck_err_t *why)
+{
+       const char *start, *end;
+
+       /*
+        * Make sure none of the mountpoint component names are too long.
+        * If a component name is too long then the mkdir of the mountpoint
+        * will fail but then the mountpoint property will be set to a value
+        * that can never be mounted.  Better to fail before setting the prop.
+        * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
+        */
+
+       if (path == NULL || *path != '/') {
+               if (why)
+                       *why = NAME_ERR_LEADING_SLASH;
+               return (-1);
+       }
+
+       /* Skip leading slash  */
+       start = &path[1];
+       do {
+               end = start;
+               while (*end != '/' && *end != '\0')
+                       end++;
+
+               if (end - start >= MAXNAMELEN) {
+                       if (why)
+                               *why = NAME_ERR_TOOLONG;
+                       return (-1);
+               }
+               start = end + 1;
+
+       } while (*end != '\0');
+
+       return (0);
+}
+
+/*
+ * For pool names, we have the same set of valid characters as described in
+ * dataset names, with the additional restriction that the pool name must begin
+ * with a letter.  The pool names 'raidz' and 'mirror' are also reserved names
+ * that cannot be used.
+ */
+int
+pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
+{
+       const char *c;
+
+       /*
+        * 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 (why)
+                       *why = NAME_ERR_TOOLONG;
+               return (-1);
+       }
+
+       c = pool;
+       while (*c != '\0') {
+               if (!valid_char(*c)) {
+                       if (why) {
+                               *why = NAME_ERR_INVALCHAR;
+                               *what = *c;
+                       }
+                       return (-1);
+               }
+               c++;
+       }
+
+       if (!(*pool >= 'a' && *pool <= 'z') &&
+           !(*pool >= 'A' && *pool <= 'Z')) {
+               if (why)
+                       *why = NAME_ERR_NOLETTER;
+               return (-1);
+       }
+
+       if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
+               if (why)
+                       *why = NAME_ERR_RESERVED;
+               return (-1);
+       }
+
+       if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
+               if (why)
+                       *why = NAME_ERR_DISKLIKE;
+               return (-1);
+       }
+
+       return (0);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(pool_namecheck);
+EXPORT_SYMBOL(dataset_namecheck);
+EXPORT_SYMBOL(zfs_component_namecheck);
+#endif
diff --git a/zfs/module/zcommon/zfs_prop.c b/zfs/module/zcommon/zfs_prop.c
new file mode 100644 (file)
index 0000000..aaebab4
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/u8_textprep.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_znode.h>
+
+#include "zfs_prop.h"
+#include "zfs_deleg.h"
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#endif
+
+static zprop_desc_t zfs_prop_table[ZFS_NUM_PROPS];
+
+/* Note this is indexed by zfs_userquota_prop_t, keep the order the same */
+const char *zfs_userquota_prop_prefixes[] = {
+       "userused@",
+       "userquota@",
+       "groupused@",
+       "groupquota@"
+};
+
+zprop_desc_t *
+zfs_prop_get_table(void)
+{
+       return (zfs_prop_table);
+}
+
+void
+zfs_prop_init(void)
+{
+       static zprop_index_t checksum_table[] = {
+               { "on",         ZIO_CHECKSUM_ON },
+               { "off",        ZIO_CHECKSUM_OFF },
+               { "fletcher2",  ZIO_CHECKSUM_FLETCHER_2 },
+               { "fletcher4",  ZIO_CHECKSUM_FLETCHER_4 },
+               { "sha256",     ZIO_CHECKSUM_SHA256 },
+               { NULL }
+       };
+
+       static zprop_index_t dedup_table[] = {
+               { "on",         ZIO_CHECKSUM_ON },
+               { "off",        ZIO_CHECKSUM_OFF },
+               { "verify",     ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY },
+               { "sha256",     ZIO_CHECKSUM_SHA256 },
+               { "sha256,verify",
+                               ZIO_CHECKSUM_SHA256 | ZIO_CHECKSUM_VERIFY },
+               { NULL }
+       };
+
+       static zprop_index_t compress_table[] = {
+               { "on",         ZIO_COMPRESS_ON },
+               { "off",        ZIO_COMPRESS_OFF },
+               { "lzjb",       ZIO_COMPRESS_LZJB },
+               { "gzip",       ZIO_COMPRESS_GZIP_6 },  /* gzip default */
+               { "gzip-1",     ZIO_COMPRESS_GZIP_1 },
+               { "gzip-2",     ZIO_COMPRESS_GZIP_2 },
+               { "gzip-3",     ZIO_COMPRESS_GZIP_3 },
+               { "gzip-4",     ZIO_COMPRESS_GZIP_4 },
+               { "gzip-5",     ZIO_COMPRESS_GZIP_5 },
+               { "gzip-6",     ZIO_COMPRESS_GZIP_6 },
+               { "gzip-7",     ZIO_COMPRESS_GZIP_7 },
+               { "gzip-8",     ZIO_COMPRESS_GZIP_8 },
+               { "gzip-9",     ZIO_COMPRESS_GZIP_9 },
+               { "zle",        ZIO_COMPRESS_ZLE },
+               { "lz4",        ZIO_COMPRESS_LZ4 },
+               { NULL }
+       };
+
+       static zprop_index_t snapdir_table[] = {
+               { "hidden",     ZFS_SNAPDIR_HIDDEN },
+               { "visible",    ZFS_SNAPDIR_VISIBLE },
+               { NULL }
+       };
+
+       static zprop_index_t snapdev_table[] = {
+               { "hidden",     ZFS_SNAPDEV_HIDDEN },
+               { "visible",    ZFS_SNAPDEV_VISIBLE },
+               { NULL }
+       };
+
+       static zprop_index_t acltype_table[] = {
+               { "off",        ZFS_ACLTYPE_OFF },
+               { "disabled",   ZFS_ACLTYPE_OFF },
+               { "noacl",      ZFS_ACLTYPE_OFF },
+               { "posixacl",   ZFS_ACLTYPE_POSIXACL },
+               { NULL }
+       };
+
+       static zprop_index_t acl_inherit_table[] = {
+               { "discard",    ZFS_ACL_DISCARD },
+               { "noallow",    ZFS_ACL_NOALLOW },
+               { "restricted", ZFS_ACL_RESTRICTED },
+               { "passthrough", ZFS_ACL_PASSTHROUGH },
+               { "secure",     ZFS_ACL_RESTRICTED }, /* bkwrd compatability */
+               { "passthrough-x", ZFS_ACL_PASSTHROUGH_X },
+               { NULL }
+       };
+
+       static zprop_index_t case_table[] = {
+               { "sensitive",          ZFS_CASE_SENSITIVE },
+               { "insensitive",        ZFS_CASE_INSENSITIVE },
+               { "mixed",              ZFS_CASE_MIXED },
+               { NULL }
+       };
+
+       static zprop_index_t copies_table[] = {
+               { "1",          1 },
+               { "2",          2 },
+               { "3",          3 },
+               { NULL }
+       };
+
+       /*
+        * Use the unique flags we have to send to u8_strcmp() and/or
+        * u8_textprep() to represent the various normalization property
+        * values.
+        */
+       static zprop_index_t normalize_table[] = {
+               { "none",       0 },
+               { "formD",      U8_TEXTPREP_NFD },
+               { "formKC",     U8_TEXTPREP_NFKC },
+               { "formC",      U8_TEXTPREP_NFC },
+               { "formKD",     U8_TEXTPREP_NFKD },
+               { NULL }
+       };
+
+       static zprop_index_t version_table[] = {
+               { "1",          1 },
+               { "2",          2 },
+               { "3",          3 },
+               { "4",          4 },
+               { "5",          5 },
+               { "current",    ZPL_VERSION },
+               { NULL }
+       };
+
+       static zprop_index_t boolean_table[] = {
+               { "off",        0 },
+               { "on",         1 },
+               { NULL }
+       };
+
+       static zprop_index_t logbias_table[] = {
+               { "latency",    ZFS_LOGBIAS_LATENCY },
+               { "throughput", ZFS_LOGBIAS_THROUGHPUT },
+               { NULL }
+       };
+
+       static zprop_index_t canmount_table[] = {
+               { "off",        ZFS_CANMOUNT_OFF },
+               { "on",         ZFS_CANMOUNT_ON },
+               { "noauto",     ZFS_CANMOUNT_NOAUTO },
+               { NULL }
+       };
+
+       static zprop_index_t cache_table[] = {
+               { "none",       ZFS_CACHE_NONE },
+               { "metadata",   ZFS_CACHE_METADATA },
+               { "all",        ZFS_CACHE_ALL },
+               { NULL }
+       };
+
+       static zprop_index_t sync_table[] = {
+               { "standard",   ZFS_SYNC_STANDARD },
+               { "always",     ZFS_SYNC_ALWAYS },
+               { "disabled",   ZFS_SYNC_DISABLED },
+               { NULL }
+       };
+
+       static zprop_index_t xattr_table[] = {
+               { "off",        ZFS_XATTR_OFF },
+               { "on",         ZFS_XATTR_DIR },
+               { "sa",         ZFS_XATTR_SA },
+               { "dir",        ZFS_XATTR_DIR },
+               { NULL }
+       };
+
+       static zprop_index_t redundant_metadata_table[] = {
+               { "all",        ZFS_REDUNDANT_METADATA_ALL },
+               { "most",       ZFS_REDUNDANT_METADATA_MOST },
+               { NULL }
+       };
+
+       /* inherit index properties */
+       zprop_register_index(ZFS_PROP_REDUNDANT_METADATA, "redundant_metadata",
+           ZFS_REDUNDANT_METADATA_ALL,
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "all | most", "REDUND_MD",
+           redundant_metadata_table);
+       zprop_register_index(ZFS_PROP_SYNC, "sync", ZFS_SYNC_STANDARD,
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "standard | always | disabled", "SYNC",
+           sync_table);
+       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);
+       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);
+       zprop_register_index(ZFS_PROP_COMPRESSION, "compression",
+           ZIO_COMPRESS_DEFAULT, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "on | off | lzjb | gzip | gzip-[1-9] | zle | lz4", "COMPRESS",
+           compress_table);
+       zprop_register_index(ZFS_PROP_SNAPDIR, "snapdir", ZFS_SNAPDIR_HIDDEN,
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
+           "hidden | visible", "SNAPDIR", snapdir_table);
+       zprop_register_index(ZFS_PROP_SNAPDEV, "snapdev", ZFS_SNAPDEV_HIDDEN,
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "hidden | visible", "SNAPDEV", snapdev_table);
+       zprop_register_index(ZFS_PROP_ACLTYPE, "acltype", ZFS_ACLTYPE_OFF,
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+           "noacl | posixacl", "ACLTYPE", acltype_table);
+       zprop_register_index(ZFS_PROP_ACLINHERIT, "aclinherit",
+           ZFS_ACL_RESTRICTED, PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
+           "discard | noallow | restricted | passthrough | passthrough-x",
+           "ACLINHERIT", acl_inherit_table);
+       zprop_register_index(ZFS_PROP_COPIES, "copies", 1, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "1 | 2 | 3", "COPIES", copies_table);
+       zprop_register_index(ZFS_PROP_PRIMARYCACHE, "primarycache",
+           ZFS_CACHE_ALL, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT | ZFS_TYPE_VOLUME,
+           "all | none | metadata", "PRIMARYCACHE", cache_table);
+       zprop_register_index(ZFS_PROP_SECONDARYCACHE, "secondarycache",
+           ZFS_CACHE_ALL, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT | ZFS_TYPE_VOLUME,
+           "all | none | metadata", "SECONDARYCACHE", cache_table);
+       zprop_register_index(ZFS_PROP_LOGBIAS, "logbias", ZFS_LOGBIAS_LATENCY,
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "latency | throughput", "LOGBIAS", logbias_table);
+       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);
+
+       /* inherit index (boolean) properties */
+       zprop_register_index(ZFS_PROP_ATIME, "atime", 1, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "on | off", "ATIME", boolean_table);
+       zprop_register_index(ZFS_PROP_RELATIME, "relatime", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "on | off", "RELATIME", boolean_table);
+       zprop_register_index(ZFS_PROP_DEVICES, "devices", 1, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "DEVICES",
+           boolean_table);
+       zprop_register_index(ZFS_PROP_EXEC, "exec", 1, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "EXEC",
+           boolean_table);
+       zprop_register_index(ZFS_PROP_SETUID, "setuid", 1, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID",
+           boolean_table);
+       zprop_register_index(ZFS_PROP_READONLY, "readonly", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "on | off", "RDONLY",
+           boolean_table);
+       zprop_register_index(ZFS_PROP_ZONED, "zoned", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "on | off", "ZONED", boolean_table);
+       zprop_register_index(ZFS_PROP_VSCAN, "vscan", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "on | off", "VSCAN", boolean_table);
+       zprop_register_index(ZFS_PROP_NBMAND, "nbmand", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "NBMAND",
+           boolean_table);
+       zprop_register_index(ZFS_PROP_OVERLAY, "overlay", 0, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "on | off", "OVERLAY", boolean_table);
+
+       /* default index properties */
+       zprop_register_index(ZFS_PROP_VERSION, "version", 0, PROP_DEFAULT,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+           "1 | 2 | 3 | 4 | 5 | current", "VERSION", version_table);
+       zprop_register_index(ZFS_PROP_CANMOUNT, "canmount", ZFS_CANMOUNT_ON,
+           PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, "on | off | noauto",
+           "CANMOUNT", canmount_table);
+
+       /* readonly index (boolean) properties */
+       zprop_register_index(ZFS_PROP_MOUNTED, "mounted", 0, PROP_READONLY,
+           ZFS_TYPE_FILESYSTEM, "yes | no", "MOUNTED", boolean_table);
+       zprop_register_index(ZFS_PROP_DEFER_DESTROY, "defer_destroy", 0,
+           PROP_READONLY, ZFS_TYPE_SNAPSHOT, "yes | no", "DEFER_DESTROY",
+           boolean_table);
+
+       /* set once index properties */
+       zprop_register_index(ZFS_PROP_NORMALIZE, "normalization", 0,
+           PROP_ONETIME, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+           "none | formC | formD | formKC | formKD", "NORMALIZATION",
+           normalize_table);
+       zprop_register_index(ZFS_PROP_CASE, "casesensitivity",
+           ZFS_CASE_SENSITIVE, PROP_ONETIME, ZFS_TYPE_FILESYSTEM |
+           ZFS_TYPE_SNAPSHOT,
+           "sensitive | insensitive | mixed", "CASE", case_table);
+
+       /* set once index (boolean) properties */
+       zprop_register_index(ZFS_PROP_UTF8ONLY, "utf8only", 0, PROP_ONETIME,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+           "on | off", "UTF8ONLY", boolean_table);
+
+       /* string properties */
+       zprop_register_string(ZFS_PROP_ORIGIN, "origin", NULL, PROP_READONLY,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN");
+       zprop_register_string(ZFS_PROP_CLONES, "clones", NULL, PROP_READONLY,
+           ZFS_TYPE_SNAPSHOT, "<dataset>[,...]", "CLONES");
+       zprop_register_string(ZFS_PROP_MOUNTPOINT, "mountpoint", "/",
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "<path> | legacy | none",
+           "MOUNTPOINT");
+       zprop_register_string(ZFS_PROP_SHARENFS, "sharenfs", "off",
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "on | off | share(1M) options",
+           "SHARENFS");
+       zprop_register_string(ZFS_PROP_TYPE, "type", NULL, PROP_READONLY,
+           ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
+           "filesystem | volume | snapshot | bookmark", "TYPE");
+       zprop_register_string(ZFS_PROP_SHARESMB, "sharesmb", "off",
+           PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
+           "on | off | sharemgr(1M) options", "SHARESMB");
+       zprop_register_string(ZFS_PROP_MLSLABEL, "mlslabel",
+           ZFS_MLSLABEL_DEFAULT, PROP_INHERIT, ZFS_TYPE_DATASET,
+           "<sensitivity label>", "MLSLABEL");
+       zprop_register_string(ZFS_PROP_SELINUX_CONTEXT, "context",
+           "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux context>",
+           "CONTEXT");
+       zprop_register_string(ZFS_PROP_SELINUX_FSCONTEXT, "fscontext",
+           "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux fscontext>",
+           "FSCONTEXT");
+       zprop_register_string(ZFS_PROP_SELINUX_DEFCONTEXT, "defcontext",
+           "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux defcontext>",
+           "DEFCONTEXT");
+       zprop_register_string(ZFS_PROP_SELINUX_ROOTCONTEXT, "rootcontext",
+           "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux rootcontext>",
+           "ROOTCONTEXT");
+
+       /* readonly number properties */
+       zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
+           ZFS_TYPE_DATASET, "<size>", "USED");
+       zprop_register_number(ZFS_PROP_AVAILABLE, "available", 0, PROP_READONLY,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL");
+       zprop_register_number(ZFS_PROP_REFERENCED, "referenced", 0,
+           PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "REFER");
+       zprop_register_number(ZFS_PROP_COMPRESSRATIO, "compressratio", 0,
+           PROP_READONLY, ZFS_TYPE_DATASET,
+           "<1.00x or higher if compressed>", "RATIO");
+       zprop_register_number(ZFS_PROP_REFRATIO, "refcompressratio", 0,
+           PROP_READONLY, ZFS_TYPE_DATASET,
+           "<1.00x or higher if compressed>", "REFRATIO");
+       zprop_register_number(ZFS_PROP_VOLBLOCKSIZE, "volblocksize",
+           ZVOL_DEFAULT_BLOCKSIZE, PROP_ONETIME,
+           ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK");
+       zprop_register_number(ZFS_PROP_USEDSNAP, "usedbysnapshots", 0,
+           PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
+           "USEDSNAP");
+       zprop_register_number(ZFS_PROP_USEDDS, "usedbydataset", 0,
+           PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
+           "USEDDS");
+       zprop_register_number(ZFS_PROP_USEDCHILD, "usedbychildren", 0,
+           PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
+           "USEDCHILD");
+       zprop_register_number(ZFS_PROP_USEDREFRESERV, "usedbyrefreservation", 0,
+           PROP_READONLY,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "USEDREFRESERV");
+       zprop_register_number(ZFS_PROP_USERREFS, "userrefs", 0, PROP_READONLY,
+           ZFS_TYPE_SNAPSHOT, "<count>", "USERREFS");
+       zprop_register_number(ZFS_PROP_WRITTEN, "written", 0, PROP_READONLY,
+           ZFS_TYPE_DATASET, "<size>", "WRITTEN");
+       zprop_register_number(ZFS_PROP_LOGICALUSED, "logicalused", 0,
+           PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LUSED");
+       zprop_register_number(ZFS_PROP_LOGICALREFERENCED, "logicalreferenced",
+           0, PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LREFER");
+
+       /* default number properties */
+       zprop_register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
+           ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA");
+       zprop_register_number(ZFS_PROP_RESERVATION, "reservation", 0,
+           PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "<size> | none", "RESERV");
+       zprop_register_number(ZFS_PROP_VOLSIZE, "volsize", 0, PROP_DEFAULT,
+           ZFS_TYPE_SNAPSHOT | ZFS_TYPE_VOLUME, "<size>", "VOLSIZE");
+       zprop_register_number(ZFS_PROP_REFQUOTA, "refquota", 0, PROP_DEFAULT,
+           ZFS_TYPE_FILESYSTEM, "<size> | none", "REFQUOTA");
+       zprop_register_number(ZFS_PROP_REFRESERVATION, "refreservation", 0,
+           PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "<size> | none", "REFRESERV");
+       zprop_register_number(ZFS_PROP_FILESYSTEM_LIMIT, "filesystem_limit",
+           UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM,
+           "<count> | none", "FSLIMIT");
+       zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit",
+           UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "<count> | none", "SSLIMIT");
+       zprop_register_number(ZFS_PROP_FILESYSTEM_COUNT, "filesystem_count",
+           UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM,
+           "<count>", "FSCOUNT");
+       zprop_register_number(ZFS_PROP_SNAPSHOT_COUNT, "snapshot_count",
+           UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "<count>", "SSCOUNT");
+
+       /* inherit number properties */
+       zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize",
+           SPA_OLD_MAXBLOCKSIZE, PROP_INHERIT,
+           ZFS_TYPE_FILESYSTEM, "512 to 1M, power of 2", "RECSIZE");
+
+       /* hidden properties */
+       zprop_register_hidden(ZFS_PROP_CREATETXG, "createtxg", PROP_TYPE_NUMBER,
+           PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "CREATETXG");
+       zprop_register_hidden(ZFS_PROP_NUMCLONES, "numclones", PROP_TYPE_NUMBER,
+           PROP_READONLY, ZFS_TYPE_SNAPSHOT, "NUMCLONES");
+       zprop_register_hidden(ZFS_PROP_NAME, "name", PROP_TYPE_STRING,
+           PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "NAME");
+       zprop_register_hidden(ZFS_PROP_ISCSIOPTIONS, "iscsioptions",
+           PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME, "ISCSIOPTIONS");
+       zprop_register_hidden(ZFS_PROP_STMF_SHAREINFO, "stmf_sbd_lu",
+           PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME,
+           "STMF_SBD_LU");
+       zprop_register_hidden(ZFS_PROP_GUID, "guid", PROP_TYPE_NUMBER,
+           PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "GUID");
+       zprop_register_hidden(ZFS_PROP_USERACCOUNTING, "useraccounting",
+           PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET,
+           "USERACCOUNTING");
+       zprop_register_hidden(ZFS_PROP_UNIQUE, "unique", PROP_TYPE_NUMBER,
+           PROP_READONLY, ZFS_TYPE_DATASET, "UNIQUE");
+       zprop_register_hidden(ZFS_PROP_OBJSETID, "objsetid", PROP_TYPE_NUMBER,
+           PROP_READONLY, ZFS_TYPE_DATASET, "OBJSETID");
+       zprop_register_hidden(ZFS_PROP_INCONSISTENT, "inconsistent",
+           PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "INCONSISTENT");
+
+       /*
+        * Property to be removed once libbe is integrated
+        */
+       zprop_register_hidden(ZFS_PROP_PRIVATE, "priv_prop",
+           PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_FILESYSTEM,
+           "PRIV_PROP");
+
+       /* oddball properties */
+       zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0,
+           NULL, PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
+           "<date>", "CREATION", B_FALSE, B_TRUE, NULL);
+}
+
+boolean_t
+zfs_prop_delegatable(zfs_prop_t prop)
+{
+       zprop_desc_t *pd = &zfs_prop_table[prop];
+
+       /* The mlslabel property is never delegatable. */
+       if (prop == ZFS_PROP_MLSLABEL)
+               return (B_FALSE);
+
+       return (pd->pd_attr != PROP_READONLY);
+}
+
+/*
+ * Given a zfs dataset property name, returns the corresponding property ID.
+ */
+zfs_prop_t
+zfs_name_to_prop(const char *propname)
+{
+       return (zprop_name_to_prop(propname, ZFS_TYPE_DATASET));
+}
+
+/*
+ * For user property names, we allow all lowercase alphanumeric characters, plus
+ * a few useful punctuation characters.
+ */
+static int
+valid_char(char c)
+{
+       return ((c >= 'a' && c <= 'z') ||
+           (c >= '0' && c <= '9') ||
+           c == '-' || c == '_' || c == '.' || c == ':');
+}
+
+/*
+ * Returns true if this is a valid user-defined property (one with a ':').
+ */
+boolean_t
+zfs_prop_user(const char *name)
+{
+       int i;
+       char c;
+       boolean_t foundsep = B_FALSE;
+
+       for (i = 0; i < strlen(name); i++) {
+               c = name[i];
+               if (!valid_char(c))
+                       return (B_FALSE);
+               if (c == ':')
+                       foundsep = B_TRUE;
+       }
+
+       if (!foundsep)
+               return (B_FALSE);
+
+       return (B_TRUE);
+}
+
+/*
+ * Returns true if this is a valid userspace-type property (one with a '@').
+ * Note that after the @, any character is valid (eg, another @, for SID
+ * user@domain).
+ */
+boolean_t
+zfs_prop_userquota(const char *name)
+{
+       zfs_userquota_prop_t prop;
+
+       for (prop = 0; prop < ZFS_NUM_USERQUOTA_PROPS; prop++) {
+               if (strncmp(name, zfs_userquota_prop_prefixes[prop],
+                   strlen(zfs_userquota_prop_prefixes[prop])) == 0) {
+                       return (B_TRUE);
+               }
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Returns true if this is a valid written@ property.
+ * Note that after the @, any character is valid (eg, another @, for
+ * written@pool/fs@origin).
+ */
+boolean_t
+zfs_prop_written(const char *name)
+{
+       static const char *prefix = "written@";
+       return (strncmp(name, prefix, strlen(prefix)) == 0);
+}
+
+/*
+ * Tables of index types, plus functions to convert between the user view
+ * (strings) and internal representation (uint64_t).
+ */
+int
+zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index)
+{
+       return (zprop_string_to_index(prop, string, index, ZFS_TYPE_DATASET));
+}
+
+int
+zfs_prop_index_to_string(zfs_prop_t prop, uint64_t index, const char **string)
+{
+       return (zprop_index_to_string(prop, index, string, ZFS_TYPE_DATASET));
+}
+
+uint64_t
+zfs_prop_random_value(zfs_prop_t prop, uint64_t seed)
+{
+       return (zprop_random_value(prop, seed, ZFS_TYPE_DATASET));
+}
+
+/*
+ * Returns TRUE if the property applies to any of the given dataset types.
+ */
+boolean_t
+zfs_prop_valid_for_type(int prop, zfs_type_t types, boolean_t headcheck)
+{
+       return (zprop_valid_for_type(prop, types, headcheck));
+}
+
+zprop_type_t
+zfs_prop_get_type(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_proptype);
+}
+
+/*
+ * Returns TRUE if the property is readonly.
+ */
+boolean_t
+zfs_prop_readonly(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_attr == PROP_READONLY ||
+           zfs_prop_table[prop].pd_attr == PROP_ONETIME);
+}
+
+/*
+ * Returns TRUE if the property is only allowed to be set once.
+ */
+boolean_t
+zfs_prop_setonce(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_attr == PROP_ONETIME);
+}
+
+const char *
+zfs_prop_default_string(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_strdefault);
+}
+
+uint64_t
+zfs_prop_default_numeric(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_numdefault);
+}
+
+/*
+ * Given a dataset property ID, returns the corresponding name.
+ * Assuming the zfs dataset property ID is valid.
+ */
+const char *
+zfs_prop_to_name(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_name);
+}
+
+/*
+ * Returns TRUE if the property is inheritable.
+ */
+boolean_t
+zfs_prop_inheritable(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_attr == PROP_INHERIT ||
+           zfs_prop_table[prop].pd_attr == PROP_ONETIME);
+}
+
+#ifndef _KERNEL
+
+/*
+ * Returns a string describing the set of acceptable values for the given
+ * zfs property, or NULL if it cannot be set.
+ */
+const char *
+zfs_prop_values(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_values);
+}
+
+/*
+ * Returns TRUE if this property is a string type.  Note that index types
+ * (compression, checksum) are treated as strings in userland, even though they
+ * are stored numerically on disk.
+ */
+int
+zfs_prop_is_string(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_proptype == PROP_TYPE_STRING ||
+           zfs_prop_table[prop].pd_proptype == PROP_TYPE_INDEX);
+}
+
+/*
+ * Returns the column header for the given property.  Used only in
+ * 'zfs list -o', but centralized here with the other property information.
+ */
+const char *
+zfs_prop_column_name(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_colname);
+}
+
+/*
+ * Returns whether the given property should be displayed right-justified for
+ * 'zfs list'.
+ */
+boolean_t
+zfs_prop_align_right(zfs_prop_t prop)
+{
+       return (zfs_prop_table[prop].pd_rightalign);
+}
+
+#endif
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+static int __init
+zcommon_init(void)
+{
+       return (0);
+}
+
+static void __exit
+zcommon_fini(void)
+{
+}
+
+module_init(zcommon_init);
+module_exit(zcommon_fini);
+
+MODULE_DESCRIPTION("Generic ZFS support");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
+
+/* zfs dataset property functions */
+EXPORT_SYMBOL(zfs_userquota_prop_prefixes);
+EXPORT_SYMBOL(zfs_prop_init);
+EXPORT_SYMBOL(zfs_prop_get_type);
+EXPORT_SYMBOL(zfs_prop_get_table);
+EXPORT_SYMBOL(zfs_prop_delegatable);
+
+/* Dataset property functions shared between libzfs and kernel. */
+EXPORT_SYMBOL(zfs_prop_default_string);
+EXPORT_SYMBOL(zfs_prop_default_numeric);
+EXPORT_SYMBOL(zfs_prop_readonly);
+EXPORT_SYMBOL(zfs_prop_inheritable);
+EXPORT_SYMBOL(zfs_prop_setonce);
+EXPORT_SYMBOL(zfs_prop_to_name);
+EXPORT_SYMBOL(zfs_name_to_prop);
+EXPORT_SYMBOL(zfs_prop_user);
+EXPORT_SYMBOL(zfs_prop_userquota);
+EXPORT_SYMBOL(zfs_prop_index_to_string);
+EXPORT_SYMBOL(zfs_prop_string_to_index);
+EXPORT_SYMBOL(zfs_prop_valid_for_type);
+
+#endif
diff --git a/zfs/module/zcommon/zfs_uio.c b/zfs/module/zcommon/zfs_uio.c
new file mode 100644 (file)
index 0000000..f78db68
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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   */
+
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+/*
+ * The uio support from OpenSolaris has been added as a short term
+ * work around.  The hope is to adopt native Linux type and drop the
+ * use of uio's entirely.  Under Linux they only add overhead and
+ * when possible we want to use native APIs for the ZPL layer.
+ */
+#ifdef _KERNEL
+
+#include <sys/types.h>
+#include <sys/uio_impl.h>
+#include <linux/kmap_compat.h>
+
+/*
+ * Move "n" bytes at byte address "p"; "rw" indicates the direction
+ * of the move, and the I/O parameters are provided in "uio", which is
+ * update to reflect the data which was moved.  Returns 0 on success or
+ * a non-zero errno on failure.
+ */
+static int
+uiomove_iov(void *p, size_t n, enum uio_rw rw, struct uio *uio)
+{
+       const struct iovec *iov = uio->uio_iov;
+       size_t skip = uio->uio_skip;
+       ulong_t cnt;
+
+       while (n && uio->uio_resid) {
+               cnt = MIN(iov->iov_len - skip, n);
+               switch (uio->uio_segflg) {
+               case UIO_USERSPACE:
+               case UIO_USERISPACE:
+                       /*
+                        * p = kernel data pointer
+                        * iov->iov_base = user data pointer
+                        */
+                       if (rw == UIO_READ) {
+                               if (copy_to_user(iov->iov_base+skip, p, cnt))
+                                       return (EFAULT);
+                       } else {
+                               if (copy_from_user(p, iov->iov_base+skip, cnt))
+                                       return (EFAULT);
+                       }
+                       break;
+               case UIO_SYSSPACE:
+                       if (rw == UIO_READ)
+                               bcopy(p, iov->iov_base + skip, cnt);
+                       else
+                               bcopy(iov->iov_base + skip, p, cnt);
+                       break;
+               default:
+                       ASSERT(0);
+               }
+               skip += cnt;
+               if (skip == iov->iov_len) {
+                       skip = 0;
+                       uio->uio_iov = (++iov);
+                       uio->uio_iovcnt--;
+               }
+               uio->uio_skip = skip;
+               uio->uio_resid -= cnt;
+               uio->uio_loffset += cnt;
+               p = (caddr_t)p + cnt;
+               n -= cnt;
+       }
+       return (0);
+}
+
+static int
+uiomove_bvec(void *p, size_t n, enum uio_rw rw, struct uio *uio)
+{
+       const struct bio_vec *bv = uio->uio_bvec;
+       size_t skip = uio->uio_skip;
+       ulong_t cnt;
+
+       while (n && uio->uio_resid) {
+               void *paddr;
+               cnt = MIN(bv->bv_len - skip, n);
+
+               paddr = zfs_kmap_atomic(bv->bv_page, KM_USER1);
+               if (rw == UIO_READ)
+                       bcopy(p, paddr + bv->bv_offset + skip, cnt);
+               else
+                       bcopy(paddr + bv->bv_offset + skip, p, cnt);
+               zfs_kunmap_atomic(paddr, KM_USER1);
+
+               skip += cnt;
+               if (skip == bv->bv_len) {
+                       skip = 0;
+                       uio->uio_bvec = (++bv);
+                       uio->uio_iovcnt--;
+               }
+               uio->uio_skip = skip;
+               uio->uio_resid -= cnt;
+               uio->uio_loffset += cnt;
+               p = (caddr_t)p + cnt;
+               n -= cnt;
+       }
+       return (0);
+}
+
+int
+uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio)
+{
+       if (uio->uio_segflg != UIO_BVEC)
+               return (uiomove_iov(p, n, rw, uio));
+       else
+               return (uiomove_bvec(p, n, rw, uio));
+}
+EXPORT_SYMBOL(uiomove);
+
+#define        fuword8(uptr, vptr)     get_user((*vptr), (uptr))
+
+/*
+ * Fault in the pages of the first n bytes specified by the uio structure.
+ * 1 byte in each page is touched and the uio struct is unmodified. Any
+ * error will terminate the process as this is only a best attempt to get
+ * the pages resident.
+ */
+void
+uio_prefaultpages(ssize_t n, struct uio *uio)
+{
+       const struct iovec *iov;
+       ulong_t cnt, incr;
+       caddr_t p;
+       uint8_t tmp;
+       int iovcnt;
+       size_t skip = uio->uio_skip;
+
+       /* no need to fault in kernel pages */
+       switch (uio->uio_segflg) {
+               case UIO_SYSSPACE:
+               case UIO_BVEC:
+                       return;
+               case UIO_USERSPACE:
+               case UIO_USERISPACE:
+                       break;
+               default:
+                       ASSERT(0);
+       }
+
+       iov = uio->uio_iov;
+       iovcnt = uio->uio_iovcnt;
+
+       while ((n > 0) && (iovcnt > 0)) {
+               cnt = MIN(iov->iov_len - skip, n);
+               n -= cnt;
+               /*
+                * touch each page in this segment.
+                */
+               p = iov->iov_base + skip;
+               while (cnt) {
+                       if (fuword8((uint8_t *) p, &tmp))
+                               return;
+                       incr = MIN(cnt, PAGESIZE);
+                       p += incr;
+                       cnt -= incr;
+               }
+               /*
+                * touch the last byte in case it straddles a page.
+                */
+               p--;
+               if (fuword8((uint8_t *) p, &tmp))
+                       return;
+               iov++;
+               iovcnt--;
+               skip = 0;
+       }
+}
+EXPORT_SYMBOL(uio_prefaultpages);
+
+/*
+ * same as uiomove() but doesn't modify uio structure.
+ * return in cbytes how many bytes were copied.
+ */
+int
+uiocopy(void *p, size_t n, enum uio_rw rw, struct uio *uio, size_t *cbytes)
+{
+       struct uio uio_copy;
+       int ret;
+
+       bcopy(uio, &uio_copy, sizeof (struct uio));
+       ret = uiomove(p, n, rw, &uio_copy);
+       *cbytes = uio->uio_resid - uio_copy.uio_resid;
+       return (ret);
+}
+EXPORT_SYMBOL(uiocopy);
+
+/*
+ * Drop the next n chars out of *uiop.
+ */
+void
+uioskip(uio_t *uiop, size_t n)
+{
+       if (n > uiop->uio_resid)
+               return;
+
+       uiop->uio_skip += n;
+       if (uiop->uio_segflg != UIO_BVEC) {
+               while (uiop->uio_iovcnt &&
+                   uiop->uio_skip >= uiop->uio_iov->iov_len) {
+                       uiop->uio_skip -= uiop->uio_iov->iov_len;
+                       uiop->uio_iov++;
+                       uiop->uio_iovcnt--;
+               }
+       } else {
+               while (uiop->uio_iovcnt &&
+                   uiop->uio_skip >= uiop->uio_bvec->bv_len) {
+                       uiop->uio_skip -= uiop->uio_bvec->bv_len;
+                       uiop->uio_bvec++;
+                       uiop->uio_iovcnt--;
+               }
+       }
+       uiop->uio_loffset += n;
+       uiop->uio_resid -= n;
+}
+EXPORT_SYMBOL(uioskip);
+#endif /* _KERNEL */
diff --git a/zfs/module/zcommon/zpool_prop.c b/zfs/module/zcommon/zpool_prop.c
new file mode 100644 (file)
index 0000000..910c56d
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/fs/zfs.h>
+
+#include "zfs_prop.h"
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#endif
+
+static zprop_desc_t zpool_prop_table[ZPOOL_NUM_PROPS];
+
+zprop_desc_t *
+zpool_prop_get_table(void)
+{
+       return (zpool_prop_table);
+}
+
+void
+zpool_prop_init(void)
+{
+       static zprop_index_t boolean_table[] = {
+               { "off",        0},
+               { "on",         1},
+               { NULL }
+       };
+
+       static zprop_index_t failuremode_table[] = {
+               { "wait",       ZIO_FAILURE_MODE_WAIT },
+               { "continue",   ZIO_FAILURE_MODE_CONTINUE },
+               { "panic",      ZIO_FAILURE_MODE_PANIC },
+               { NULL }
+       };
+
+       /* string properties */
+       zprop_register_string(ZPOOL_PROP_ALTROOT, "altroot", NULL, PROP_DEFAULT,
+           ZFS_TYPE_POOL, "<path>", "ALTROOT");
+       zprop_register_string(ZPOOL_PROP_BOOTFS, "bootfs", NULL, PROP_DEFAULT,
+           ZFS_TYPE_POOL, "<filesystem>", "BOOTFS");
+       zprop_register_string(ZPOOL_PROP_CACHEFILE, "cachefile", NULL,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "<file> | none", "CACHEFILE");
+       zprop_register_string(ZPOOL_PROP_COMMENT, "comment", NULL,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "<comment-string>", "COMMENT");
+
+       /* readonly number properties */
+       zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<size>", "SIZE");
+       zprop_register_number(ZPOOL_PROP_FREE, "free", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<size>", "FREE");
+       zprop_register_number(ZPOOL_PROP_FREEING, "freeing", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<size>", "FREEING");
+       zprop_register_number(ZPOOL_PROP_LEAKED, "leaked", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<size>", "LEAKED");
+       zprop_register_number(ZPOOL_PROP_ALLOCATED, "allocated", 0,
+           PROP_READONLY, ZFS_TYPE_POOL, "<size>", "ALLOC");
+       zprop_register_number(ZPOOL_PROP_EXPANDSZ, "expandsize", 0,
+           PROP_READONLY, ZFS_TYPE_POOL, "<size>", "EXPANDSZ");
+       zprop_register_number(ZPOOL_PROP_FRAGMENTATION, "fragmentation", 0,
+           PROP_READONLY, ZFS_TYPE_POOL, "<percent>", "FRAG");
+       zprop_register_number(ZPOOL_PROP_CAPACITY, "capacity", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<size>", "CAP");
+       zprop_register_number(ZPOOL_PROP_GUID, "guid", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<guid>", "GUID");
+       zprop_register_number(ZPOOL_PROP_HEALTH, "health", 0, PROP_READONLY,
+           ZFS_TYPE_POOL, "<state>", "HEALTH");
+       zprop_register_number(ZPOOL_PROP_DEDUPRATIO, "dedupratio", 0,
+           PROP_READONLY, ZFS_TYPE_POOL, "<1.00x or higher if deduped>",
+           "DEDUP");
+
+       /* readonly onetime number properties */
+       zprop_register_number(ZPOOL_PROP_ASHIFT, "ashift", 0, PROP_ONETIME,
+           ZFS_TYPE_POOL, "<ashift, 9-13, or 0=default>", "ASHIFT");
+
+       /* default number properties */
+       zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION");
+       zprop_register_number(ZPOOL_PROP_DEDUPDITTO, "dedupditto", 0,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "<threshold (min 100)>", "DEDUPDITTO");
+
+       /* default index (boolean) properties */
+       zprop_register_index(ZPOOL_PROP_DELEGATION, "delegation", 1,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "on | off", "DELEGATION",
+           boolean_table);
+       zprop_register_index(ZPOOL_PROP_AUTOREPLACE, "autoreplace", 0,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "on | off", "REPLACE", boolean_table);
+       zprop_register_index(ZPOOL_PROP_LISTSNAPS, "listsnapshots", 0,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "on | off", "LISTSNAPS",
+           boolean_table);
+       zprop_register_index(ZPOOL_PROP_AUTOEXPAND, "autoexpand", 0,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "on | off", "EXPAND", boolean_table);
+       zprop_register_index(ZPOOL_PROP_READONLY, "readonly", 0,
+           PROP_DEFAULT, ZFS_TYPE_POOL, "on | off", "RDONLY", boolean_table);
+
+       /* default index properties */
+       zprop_register_index(ZPOOL_PROP_FAILUREMODE, "failmode",
+           ZIO_FAILURE_MODE_WAIT, PROP_DEFAULT, ZFS_TYPE_POOL,
+           "wait | continue | panic", "FAILMODE", failuremode_table);
+
+       /* hidden properties */
+       zprop_register_hidden(ZPOOL_PROP_NAME, "name", PROP_TYPE_STRING,
+           PROP_READONLY, ZFS_TYPE_POOL, "NAME");
+       zprop_register_hidden(ZPOOL_PROP_MAXBLOCKSIZE, "maxblocksize",
+           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");
+}
+
+/*
+ * Given a property name and its type, returns the corresponding property ID.
+ */
+zpool_prop_t
+zpool_name_to_prop(const char *propname)
+{
+       return (zprop_name_to_prop(propname, ZFS_TYPE_POOL));
+}
+
+/*
+ * Given a pool property ID, returns the corresponding name.
+ * Assuming the pool propety ID is valid.
+ */
+const char *
+zpool_prop_to_name(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_name);
+}
+
+zprop_type_t
+zpool_prop_get_type(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_proptype);
+}
+
+boolean_t
+zpool_prop_readonly(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_attr == PROP_READONLY);
+}
+
+const char *
+zpool_prop_default_string(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_strdefault);
+}
+
+uint64_t
+zpool_prop_default_numeric(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_numdefault);
+}
+
+/*
+ * Returns true if this is a valid feature@ property.
+ */
+boolean_t
+zpool_prop_feature(const char *name)
+{
+       static const char *prefix = "feature@";
+       return (strncmp(name, prefix, strlen(prefix)) == 0);
+}
+
+/*
+ * Returns true if this is a valid unsupported@ property.
+ */
+boolean_t
+zpool_prop_unsupported(const char *name)
+{
+       static const char *prefix = "unsupported@";
+       return (strncmp(name, prefix, strlen(prefix)) == 0);
+}
+
+int
+zpool_prop_string_to_index(zpool_prop_t prop, const char *string,
+    uint64_t *index)
+{
+       return (zprop_string_to_index(prop, string, index, ZFS_TYPE_POOL));
+}
+
+int
+zpool_prop_index_to_string(zpool_prop_t prop, uint64_t index,
+    const char **string)
+{
+       return (zprop_index_to_string(prop, index, string, ZFS_TYPE_POOL));
+}
+
+uint64_t
+zpool_prop_random_value(zpool_prop_t prop, uint64_t seed)
+{
+       return (zprop_random_value(prop, seed, ZFS_TYPE_POOL));
+}
+
+#ifndef _KERNEL
+
+const char *
+zpool_prop_values(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_values);
+}
+
+const char *
+zpool_prop_column_name(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_colname);
+}
+
+boolean_t
+zpool_prop_align_right(zpool_prop_t prop)
+{
+       return (zpool_prop_table[prop].pd_rightalign);
+}
+#endif
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+/* zpool property functions */
+EXPORT_SYMBOL(zpool_prop_init);
+EXPORT_SYMBOL(zpool_prop_get_type);
+EXPORT_SYMBOL(zpool_prop_get_table);
+
+/* Pool property functions shared between libzfs and kernel. */
+EXPORT_SYMBOL(zpool_name_to_prop);
+EXPORT_SYMBOL(zpool_prop_to_name);
+EXPORT_SYMBOL(zpool_prop_default_string);
+EXPORT_SYMBOL(zpool_prop_default_numeric);
+EXPORT_SYMBOL(zpool_prop_readonly);
+EXPORT_SYMBOL(zpool_prop_feature);
+EXPORT_SYMBOL(zpool_prop_unsupported);
+EXPORT_SYMBOL(zpool_prop_index_to_string);
+EXPORT_SYMBOL(zpool_prop_string_to_index);
+#endif
diff --git a/zfs/module/zcommon/zprop_common.c b/zfs/module/zcommon/zprop_common.c
new file mode 100644 (file)
index 0000000..b32c226
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * Common routines used by zfs and zpool property management.
+ */
+
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_znode.h>
+#include <sys/fs/zfs.h>
+
+#include "zfs_prop.h"
+#include "zfs_deleg.h"
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#include <util/qsort.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#endif
+
+static zprop_desc_t *
+zprop_get_proptable(zfs_type_t type)
+{
+       if (type == ZFS_TYPE_POOL)
+               return (zpool_prop_get_table());
+       else
+               return (zfs_prop_get_table());
+}
+
+static int
+zprop_get_numprops(zfs_type_t type)
+{
+       if (type == ZFS_TYPE_POOL)
+               return (ZPOOL_NUM_PROPS);
+       else
+               return (ZFS_NUM_PROPS);
+}
+
+void
+zprop_register_impl(int prop, const char *name, zprop_type_t type,
+    uint64_t numdefault, const char *strdefault, zprop_attr_t attr,
+    int objset_types, const char *values, const char *colname,
+    boolean_t rightalign, boolean_t visible, const zprop_index_t *idx_tbl)
+{
+       zprop_desc_t *prop_tbl = zprop_get_proptable(objset_types);
+       zprop_desc_t *pd;
+
+       pd = &prop_tbl[prop];
+
+       ASSERT(pd->pd_name == NULL || pd->pd_name == name);
+       ASSERT(name != NULL);
+       ASSERT(colname != NULL);
+
+       pd->pd_name = name;
+       pd->pd_propnum = prop;
+       pd->pd_proptype = type;
+       pd->pd_numdefault = numdefault;
+       pd->pd_strdefault = strdefault;
+       pd->pd_attr = attr;
+       pd->pd_types = objset_types;
+       pd->pd_values = values;
+       pd->pd_colname = colname;
+       pd->pd_rightalign = rightalign;
+       pd->pd_visible = visible;
+       pd->pd_table = idx_tbl;
+       pd->pd_table_size = 0;
+       while (idx_tbl && (idx_tbl++)->pi_name != NULL)
+               pd->pd_table_size++;
+}
+
+void
+zprop_register_string(int prop, const char *name, const char *def,
+    zprop_attr_t attr, int objset_types, const char *values,
+    const char *colname)
+{
+       zprop_register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
+           objset_types, values, colname, B_FALSE, B_TRUE, NULL);
+
+}
+
+void
+zprop_register_number(int prop, const char *name, uint64_t def,
+    zprop_attr_t attr, int objset_types, const char *values,
+    const char *colname)
+{
+       zprop_register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
+           objset_types, values, colname, B_TRUE, B_TRUE, NULL);
+}
+
+void
+zprop_register_index(int prop, const char *name, uint64_t def,
+    zprop_attr_t attr, int objset_types, const char *values,
+    const char *colname, const zprop_index_t *idx_tbl)
+{
+       zprop_register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, attr,
+           objset_types, values, colname, B_TRUE, B_TRUE, idx_tbl);
+}
+
+void
+zprop_register_hidden(int prop, const char *name, zprop_type_t type,
+    zprop_attr_t attr, int objset_types, const char *colname)
+{
+       zprop_register_impl(prop, name, type, 0, NULL, attr,
+           objset_types, NULL, colname,
+           type == PROP_TYPE_NUMBER, B_FALSE, NULL);
+}
+
+
+/*
+ * A comparison function we can use to order indexes into property tables.
+ */
+static int
+zprop_compare(const void *arg1, const void *arg2)
+{
+       const zprop_desc_t *p1 = *((zprop_desc_t **)arg1);
+       const zprop_desc_t *p2 = *((zprop_desc_t **)arg2);
+       boolean_t p1ro, p2ro;
+
+       p1ro = (p1->pd_attr == PROP_READONLY);
+       p2ro = (p2->pd_attr == PROP_READONLY);
+
+       if (p1ro == p2ro)
+               return (strcmp(p1->pd_name, p2->pd_name));
+
+       return (p1ro ? -1 : 1);
+}
+
+/*
+ * Iterate over all properties in the given property table, calling back
+ * into the specified function for each property. We will continue to
+ * iterate until we either reach the end or the callback function returns
+ * something other than ZPROP_CONT.
+ */
+int
+zprop_iter_common(zprop_func func, void *cb, boolean_t show_all,
+    boolean_t ordered, zfs_type_t type)
+{
+       int i, j, num_props, size, prop;
+       zprop_desc_t *prop_tbl;
+       zprop_desc_t **order;
+
+       prop_tbl = zprop_get_proptable(type);
+       num_props = zprop_get_numprops(type);
+       size = num_props * sizeof (zprop_desc_t *);
+
+#if defined(_KERNEL)
+       order = kmem_alloc(size, KM_SLEEP);
+#else
+       if ((order = malloc(size)) == NULL)
+               return (ZPROP_CONT);
+#endif
+
+       for (j = 0; j < num_props; j++)
+               order[j] = &prop_tbl[j];
+
+       if (ordered) {
+               qsort((void *)order, num_props, sizeof (zprop_desc_t *),
+                   zprop_compare);
+       }
+
+       prop = ZPROP_CONT;
+       for (i = 0; i < num_props; i++) {
+               if ((order[i]->pd_visible || show_all) &&
+                   (func(order[i]->pd_propnum, cb) != ZPROP_CONT)) {
+                       prop = order[i]->pd_propnum;
+                       break;
+               }
+       }
+
+#if defined(_KERNEL)
+       kmem_free(order, size);
+#else
+       free(order);
+#endif
+       return (prop);
+}
+
+static boolean_t
+propname_match(const char *p, size_t len, zprop_desc_t *prop_entry)
+{
+       const char *propname = prop_entry->pd_name;
+#ifndef _KERNEL
+       const char *colname = prop_entry->pd_colname;
+       int c;
+#endif
+
+       if (len == strlen(propname) &&
+           strncmp(p, propname, len) == 0)
+               return (B_TRUE);
+
+#ifndef _KERNEL
+       if (colname == NULL || len != strlen(colname))
+               return (B_FALSE);
+
+       for (c = 0; c < len; c++)
+               if (p[c] != tolower(colname[c]))
+                       break;
+
+       return (colname[c] == '\0');
+#else
+       return (B_FALSE);
+#endif
+}
+
+typedef struct name_to_prop_cb {
+       const char *propname;
+       zprop_desc_t *prop_tbl;
+} name_to_prop_cb_t;
+
+static int
+zprop_name_to_prop_cb(int prop, void *cb_data)
+{
+       name_to_prop_cb_t *data = cb_data;
+
+       if (propname_match(data->propname, strlen(data->propname),
+           &data->prop_tbl[prop]))
+               return (prop);
+
+       return (ZPROP_CONT);
+}
+
+int
+zprop_name_to_prop(const char *propname, zfs_type_t type)
+{
+       int prop;
+       name_to_prop_cb_t cb_data;
+
+       cb_data.propname = propname;
+       cb_data.prop_tbl = zprop_get_proptable(type);
+
+       prop = zprop_iter_common(zprop_name_to_prop_cb, &cb_data,
+           B_TRUE, B_FALSE, type);
+
+       return (prop == ZPROP_CONT ? ZPROP_INVAL : prop);
+}
+
+int
+zprop_string_to_index(int prop, const char *string, uint64_t *index,
+    zfs_type_t type)
+{
+       zprop_desc_t *prop_tbl;
+       const zprop_index_t *idx_tbl;
+       int i;
+
+       if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
+               return (-1);
+
+       ASSERT(prop < zprop_get_numprops(type));
+       prop_tbl = zprop_get_proptable(type);
+       if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
+               return (-1);
+
+       for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
+               if (strcmp(string, idx_tbl[i].pi_name) == 0) {
+                       *index = idx_tbl[i].pi_value;
+                       return (0);
+               }
+       }
+
+       return (-1);
+}
+
+int
+zprop_index_to_string(int prop, uint64_t index, const char **string,
+    zfs_type_t type)
+{
+       zprop_desc_t *prop_tbl;
+       const zprop_index_t *idx_tbl;
+       int i;
+
+       if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
+               return (-1);
+
+       ASSERT(prop < zprop_get_numprops(type));
+       prop_tbl = zprop_get_proptable(type);
+       if ((idx_tbl = prop_tbl[prop].pd_table) == NULL)
+               return (-1);
+
+       for (i = 0; idx_tbl[i].pi_name != NULL; i++) {
+               if (idx_tbl[i].pi_value == index) {
+                       *string = idx_tbl[i].pi_name;
+                       return (0);
+               }
+       }
+
+       return (-1);
+}
+
+/*
+ * Return a random valid property value.  Used by ztest.
+ */
+uint64_t
+zprop_random_value(int prop, uint64_t seed, zfs_type_t type)
+{
+       zprop_desc_t *prop_tbl;
+       const zprop_index_t *idx_tbl;
+
+       ASSERT((uint_t)prop < zprop_get_numprops(type));
+       prop_tbl = zprop_get_proptable(type);
+       idx_tbl = prop_tbl[prop].pd_table;
+
+       if (idx_tbl == NULL)
+               return (seed);
+
+       return (idx_tbl[seed % prop_tbl[prop].pd_table_size].pi_value);
+}
+
+const char *
+zprop_values(int prop, zfs_type_t type)
+{
+       zprop_desc_t *prop_tbl;
+
+       ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
+       ASSERT(prop < zprop_get_numprops(type));
+
+       prop_tbl = zprop_get_proptable(type);
+
+       return (prop_tbl[prop].pd_values);
+}
+
+/*
+ * Returns TRUE if the property applies to any of the given dataset types.
+ *
+ * If headcheck is set, the check is being made against the head dataset
+ * type of a snapshot which requires to return B_TRUE when the property
+ * is only valid for snapshots.
+ */
+boolean_t
+zprop_valid_for_type(int prop, zfs_type_t type, boolean_t headcheck)
+{
+       zprop_desc_t *prop_tbl;
+
+       if (prop == ZPROP_INVAL || prop == ZPROP_CONT)
+               return (B_FALSE);
+
+       ASSERT(prop < zprop_get_numprops(type));
+       prop_tbl = zprop_get_proptable(type);
+       if (headcheck && prop_tbl[prop].pd_types == ZFS_TYPE_SNAPSHOT)
+               return (B_TRUE);
+       return ((prop_tbl[prop].pd_types & type) != 0);
+}
+
+#ifndef _KERNEL
+
+/*
+ * Determines the minimum width for the column, and indicates whether it's fixed
+ * or not.  Only string columns are non-fixed.
+ */
+size_t
+zprop_width(int prop, boolean_t *fixed, zfs_type_t type)
+{
+       zprop_desc_t *prop_tbl, *pd;
+       const zprop_index_t *idx;
+       size_t ret;
+       int i;
+
+       ASSERT(prop != ZPROP_INVAL && prop != ZPROP_CONT);
+       ASSERT(prop < zprop_get_numprops(type));
+
+       prop_tbl = zprop_get_proptable(type);
+       pd = &prop_tbl[prop];
+
+       *fixed = B_TRUE;
+
+       /*
+        * Start with the width of the column name.
+        */
+       ret = strlen(pd->pd_colname);
+
+       /*
+        * For fixed-width values, make sure the width is large enough to hold
+        * any possible value.
+        */
+       switch (pd->pd_proptype) {
+       case PROP_TYPE_NUMBER:
+               /*
+                * The maximum length of a human-readable number is 5 characters
+                * ("20.4M", for example).
+                */
+               if (ret < 5)
+                       ret = 5;
+               /*
+                * 'creation' is handled specially because it's a number
+                * internally, but displayed as a date string.
+                */
+               if (prop == ZFS_PROP_CREATION)
+                       *fixed = B_FALSE;
+               break;
+       case PROP_TYPE_INDEX:
+               idx = prop_tbl[prop].pd_table;
+               for (i = 0; idx[i].pi_name != NULL; i++) {
+                       if (strlen(idx[i].pi_name) > ret)
+                               ret = strlen(idx[i].pi_name);
+               }
+               break;
+
+       case PROP_TYPE_STRING:
+               *fixed = B_FALSE;
+               break;
+       }
+
+       return (ret);
+}
+
+#endif
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+/* Common routines to initialize property tables */
+EXPORT_SYMBOL(zprop_register_impl);
+EXPORT_SYMBOL(zprop_register_string);
+EXPORT_SYMBOL(zprop_register_number);
+EXPORT_SYMBOL(zprop_register_index);
+EXPORT_SYMBOL(zprop_register_hidden);
+
+/* Common routines for zfs and zpool property management */
+EXPORT_SYMBOL(zprop_iter_common);
+EXPORT_SYMBOL(zprop_name_to_prop);
+EXPORT_SYMBOL(zprop_string_to_index);
+EXPORT_SYMBOL(zprop_index_to_string);
+EXPORT_SYMBOL(zprop_random_value);
+EXPORT_SYMBOL(zprop_values);
+EXPORT_SYMBOL(zprop_valid_for_type);
+#endif
diff --git a/zfs/module/zfs/Makefile.in b/zfs/module/zfs/Makefile.in
new file mode 100644 (file)
index 0000000..55f8cef
--- /dev/null
@@ -0,0 +1,108 @@
+src = @abs_top_srcdir@/module/zfs
+obj = @abs_builddir@
+
+MODULE := zfs
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+$(MODULE)-objs += arc.o
+$(MODULE)-objs += blkptr.o
+$(MODULE)-objs += bplist.o
+$(MODULE)-objs += bpobj.o
+$(MODULE)-objs += dbuf.o
+$(MODULE)-objs += dbuf_stats.o
+$(MODULE)-objs += bptree.o
+$(MODULE)-objs += ddt.o
+$(MODULE)-objs += ddt_zap.o
+$(MODULE)-objs += dmu.o
+$(MODULE)-objs += dmu_diff.o
+$(MODULE)-objs += dmu_object.o
+$(MODULE)-objs += dmu_objset.o
+$(MODULE)-objs += dmu_send.o
+$(MODULE)-objs += dmu_traverse.o
+$(MODULE)-objs += dmu_tx.o
+$(MODULE)-objs += dmu_zfetch.o
+$(MODULE)-objs += dnode.o
+$(MODULE)-objs += dnode_sync.o
+$(MODULE)-objs += dsl_dataset.o
+$(MODULE)-objs += dsl_deadlist.o
+$(MODULE)-objs += dsl_deleg.o
+$(MODULE)-objs += dsl_bookmark.o
+$(MODULE)-objs += dsl_dir.o
+$(MODULE)-objs += dsl_pool.o
+$(MODULE)-objs += dsl_prop.o
+$(MODULE)-objs += dsl_scan.o
+$(MODULE)-objs += dsl_synctask.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 += range_tree.o
+$(MODULE)-objs += refcount.o
+$(MODULE)-objs += rrwlock.o
+$(MODULE)-objs += sa.o
+$(MODULE)-objs += sha256.o
+$(MODULE)-objs += spa.o
+$(MODULE)-objs += spa_boot.o
+$(MODULE)-objs += spa_config.o
+$(MODULE)-objs += spa_errlog.o
+$(MODULE)-objs += spa_history.o
+$(MODULE)-objs += spa_misc.o
+$(MODULE)-objs += spa_stats.o
+$(MODULE)-objs += space_map.o
+$(MODULE)-objs += space_reftree.o
+$(MODULE)-objs += txg.o
+$(MODULE)-objs += trace.o
+$(MODULE)-objs += uberblock.o
+$(MODULE)-objs += unique.o
+$(MODULE)-objs += vdev.o
+$(MODULE)-objs += vdev_cache.o
+$(MODULE)-objs += vdev_disk.o
+$(MODULE)-objs += vdev_file.o
+$(MODULE)-objs += vdev_label.o
+$(MODULE)-objs += vdev_mirror.o
+$(MODULE)-objs += vdev_missing.o
+$(MODULE)-objs += vdev_queue.o
+$(MODULE)-objs += vdev_raidz.o
+$(MODULE)-objs += vdev_root.o
+$(MODULE)-objs += zap.o
+$(MODULE)-objs += zap_leaf.o
+$(MODULE)-objs += zap_micro.o
+$(MODULE)-objs += zfeature.o
+$(MODULE)-objs += zfeature_common.o
+$(MODULE)-objs += zfs_acl.o
+$(MODULE)-objs += zfs_byteswap.o
+$(MODULE)-objs += zfs_ctldir.o
+$(MODULE)-objs += zfs_debug.o
+$(MODULE)-objs += zfs_dir.o
+$(MODULE)-objs += zfs_fm.o
+$(MODULE)-objs += zfs_fuid.o
+$(MODULE)-objs += zfs_ioctl.o
+$(MODULE)-objs += zfs_log.o
+$(MODULE)-objs += zfs_onexit.o
+$(MODULE)-objs += zfs_replay.o
+$(MODULE)-objs += zfs_rlock.o
+$(MODULE)-objs += zfs_sa.o
+$(MODULE)-objs += zfs_vfsops.o
+$(MODULE)-objs += zfs_vnops.o
+$(MODULE)-objs += zfs_znode.o
+$(MODULE)-objs += zil.o
+$(MODULE)-objs += zio.o
+$(MODULE)-objs += zio_checksum.o
+$(MODULE)-objs += zio_compress.o
+$(MODULE)-objs += zio_inject.o
+$(MODULE)-objs += zle.o
+$(MODULE)-objs += zpl_ctldir.o
+$(MODULE)-objs += zpl_export.o
+$(MODULE)-objs += zpl_file.o
+$(MODULE)-objs += zpl_inode.o
+$(MODULE)-objs += zpl_super.o
+$(MODULE)-objs += zpl_xattr.o
+$(MODULE)-objs += zrlock.o
+$(MODULE)-objs += zvol.o
+$(MODULE)-objs += dsl_destroy.o
+$(MODULE)-objs += dsl_userhold.o
diff --git a/zfs/module/zfs/arc.c b/zfs/module/zfs/arc.c
new file mode 100644 (file)
index 0000000..04fde6c
--- /dev/null
@@ -0,0 +1,7092 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2014 by Saso Kiselkov. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+/*
+ * DVA-based Adjustable Replacement Cache
+ *
+ * While much of the theory of operation used here is
+ * based on the self-tuning, low overhead replacement cache
+ * presented by Megiddo and Modha at FAST 2003, there are some
+ * significant differences:
+ *
+ * 1. The Megiddo and Modha model assumes any page is evictable.
+ * Pages in its cache cannot be "locked" into memory.  This makes
+ * the eviction algorithm simple: evict the last page in the list.
+ * This also make the performance characteristics easy to reason
+ * about.  Our cache is not so simple.  At any given moment, some
+ * subset of the blocks in the cache are un-evictable because we
+ * have handed out a reference to them.  Blocks are only evictable
+ * when there are no external references active.  This makes
+ * eviction far more problematic:  we choose to evict the evictable
+ * blocks that are the "lowest" in the list.
+ *
+ * There are times when it is not possible to evict the requested
+ * space.  In these circumstances we are unable to adjust the cache
+ * size.  To prevent the cache growing unbounded at these times we
+ * implement a "cache throttle" that slows the flow of new data
+ * into the cache until we can make space available.
+ *
+ * 2. The Megiddo and Modha model assumes a fixed cache size.
+ * Pages are evicted when the cache is full and there is a cache
+ * miss.  Our model has a variable sized cache.  It grows with
+ * high use, but also tries to react to memory pressure from the
+ * operating system: decreasing its size when system memory is
+ * tight.
+ *
+ * 3. The Megiddo and Modha model assumes a fixed page size. All
+ * elements of the cache are therefore exactly the same size.  So
+ * when adjusting the cache size following a cache miss, its simply
+ * a matter of choosing a single page to evict.  In our model, we
+ * have variable sized cache blocks (rangeing from 512 bytes to
+ * 128K bytes).  We therefore choose a set of blocks to evict to make
+ * space for a cache miss that approximates as closely as possible
+ * the space used by the new block.
+ *
+ * See also:  "ARC: A Self-Tuning, Low Overhead Replacement Cache"
+ * by N. Megiddo & D. Modha, FAST 2003
+ */
+
+/*
+ * The locking model:
+ *
+ * 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
+ * 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.
+ *
+ * Buffers do not have their own mutexes, rather they rely on the
+ * hash table mutexes for the bulk of their protection (i.e. most
+ * fields in the arc_buf_hdr_t are protected by these mutexes).
+ *
+ * buf_hash_find() returns the appropriate mutex (held) when it
+ * locates the requested buffer in the hash table.  It returns
+ * NULL for the mutex if the buffer was not in the table.
+ *
+ * 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
+ * buffer list associated with the state.  When attempting to
+ * 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
+ * they can be reclaimed and the arc_meta_limit honored.  For example,
+ * when using the ZPL each dentry holds a references on a znode.  These
+ * dentries must be pruned before the arc buffer holding the znode can
+ * be safely evicted.
+ *
+ * Note that the majority of the performance stats are manipulated
+ * with atomic operations.
+ *
+ * The L2ARC uses the l2ad_mtx on each vdev for the following:
+ *
+ *     - L2ARC buflist creation
+ *     - L2ARC buflist eviction
+ *     - L2ARC write completion, which walks L2ARC buflists
+ *     - ARC header destruction, as it removes from L2ARC buflists
+ *     - ARC header release, as it removes from L2ARC buflists
+ */
+
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/zio_compress.h>
+#include <sys/zfs_context.h>
+#include <sys/arc.h>
+#include <sys/refcount.h>
+#include <sys/vdev.h>
+#include <sys/vdev_impl.h>
+#include <sys/dsl_pool.h>
+#include <sys/multilist.h>
+#ifdef _KERNEL
+#include <sys/vmsystm.h>
+#include <vm/anon.h>
+#include <sys/fs/swapnode.h>
+#include <sys/zpl.h>
+#include <linux/mm_compat.h>
+#endif
+#include <sys/callb.h>
+#include <sys/kstat.h>
+#include <sys/dmu_tx.h>
+#include <zfs_fletcher.h>
+#include <sys/arc_impl.h>
+#include <sys/trace_arc.h>
+
+#ifndef _KERNEL
+/* set with ZFS_DEBUG=watch, to enable watchpoints on frozen buffers */
+boolean_t arc_watch = B_FALSE;
+#endif
+
+static kmutex_t                arc_reclaim_lock;
+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
+ * value means we're more likely to evict the "correct" header (i.e. the
+ * oldest header in the arc state), but comes with higher overhead
+ * (i.e. more invocations of arc_evict_state_impl()).
+ */
+int zfs_arc_evict_batch_limit = 10;
+
+/*
+ * The number of sublists used for each of the arc state lists. If this
+ * is not set to a suitable value by the user, it will be configured to
+ * the number of CPUs on the system in arc_init().
+ */
+int zfs_arc_num_sublists_per_state = 0;
+
+/* number of seconds before growing cache again */
+static int             arc_grow_retry = 5;
+
+/* shift of arc_c for calculating overflow limit in arc_get_data_buf */
+int            zfs_arc_overflow_shift = 8;
+
+/* shift of arc_c for calculating both min and max arc_p */
+static int             arc_p_min_shift = 4;
+
+/* log2(fraction of arc to reclaim) */
+static int             arc_shrink_shift = 7;
+
+/*
+ * log2(fraction of ARC which must be free to allow growing).
+ * I.e. If there is less than arc_c >> arc_no_grow_shift free memory,
+ * when reading a new block into the ARC, we will evict an equal-sized block
+ * from the ARC.
+ *
+ * This must be less than arc_shrink_shift, so that when we shrink the ARC,
+ * we will still not allow it to grow.
+ */
+int                    arc_no_grow_shift = 5;
+
+
+/*
+ * minimum lifespan of a prefetch block in clock ticks
+ * (initialized in arc_init())
+ */
+static int             arc_min_prefetch_lifespan;
+
+/*
+ * If this percent of memory is free, don't throttle.
+ */
+int arc_lotsfree_percent = 10;
+
+static int arc_dead;
+
+/*
+ * The arc has filled available memory and has now warmed up.
+ */
+static boolean_t arc_warm;
+
+/*
+ * These tunables are for performance analysis.
+ */
+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;
+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 */
+
+/*
+ * These tunables are Linux specific
+ */
+unsigned long zfs_arc_sys_free = 0;
+int zfs_arc_min_prefetch_lifespan = 0;
+int zfs_arc_p_aggressive_disable = 1;
+int zfs_arc_p_dampener_disable = 1;
+int zfs_arc_meta_prune = 10000;
+int zfs_arc_meta_strategy = ARC_STRATEGY_META_BALANCED;
+int zfs_arc_meta_adjust_restarts = 4096;
+int zfs_arc_lotsfree_percent = 10;
+
+/* The 6 states: */
+static arc_state_t ARC_anon;
+static arc_state_t ARC_mru;
+static arc_state_t ARC_mru_ghost;
+static arc_state_t ARC_mfu;
+static arc_state_t ARC_mfu_ghost;
+static arc_state_t ARC_l2c_only;
+
+typedef struct arc_stats {
+       kstat_named_t arcstat_hits;
+       kstat_named_t arcstat_misses;
+       kstat_named_t arcstat_demand_data_hits;
+       kstat_named_t arcstat_demand_data_misses;
+       kstat_named_t arcstat_demand_metadata_hits;
+       kstat_named_t arcstat_demand_metadata_misses;
+       kstat_named_t arcstat_prefetch_data_hits;
+       kstat_named_t arcstat_prefetch_data_misses;
+       kstat_named_t arcstat_prefetch_metadata_hits;
+       kstat_named_t arcstat_prefetch_metadata_misses;
+       kstat_named_t arcstat_mru_hits;
+       kstat_named_t arcstat_mru_ghost_hits;
+       kstat_named_t arcstat_mfu_hits;
+       kstat_named_t arcstat_mfu_ghost_hits;
+       kstat_named_t arcstat_deleted;
+       /*
+        * Number of buffers that could not be evicted because the hash lock
+        * was held by another thread.  The lock may not necessarily be held
+        * by something using the same buffer, since hash locks are shared
+        * by multiple buffers.
+        */
+       kstat_named_t arcstat_mutex_miss;
+       /*
+        * Number of buffers skipped because they have I/O in progress, are
+        * indrect prefetch buffers that have not lived long enough, or are
+        * not from the spa we're trying to evict from.
+        */
+       kstat_named_t arcstat_evict_skip;
+       /*
+        * Number of times arc_evict_state() was unable to evict enough
+        * buffers to reach its target amount.
+        */
+       kstat_named_t arcstat_evict_not_enough;
+       kstat_named_t arcstat_evict_l2_cached;
+       kstat_named_t arcstat_evict_l2_eligible;
+       kstat_named_t arcstat_evict_l2_ineligible;
+       kstat_named_t arcstat_evict_l2_skip;
+       kstat_named_t arcstat_hash_elements;
+       kstat_named_t arcstat_hash_elements_max;
+       kstat_named_t arcstat_hash_collisions;
+       kstat_named_t arcstat_hash_chains;
+       kstat_named_t arcstat_hash_chain_max;
+       kstat_named_t arcstat_p;
+       kstat_named_t arcstat_c;
+       kstat_named_t arcstat_c_min;
+       kstat_named_t arcstat_c_max;
+       kstat_named_t arcstat_size;
+       /*
+        * Number of bytes consumed by internal ARC structures necessary
+        * for tracking purposes; these structures are not actually
+        * backed by ARC buffers. This includes arc_buf_hdr_t structures
+        * (allocated via arc_buf_hdr_t_full and arc_buf_hdr_t_l2only
+        * caches), and arc_buf_t structures (allocated via arc_buf_t
+        * cache).
+        */
+       kstat_named_t arcstat_hdr_size;
+       /*
+        * Number of bytes consumed by ARC buffers of type equal to
+        * ARC_BUFC_DATA. This is generally consumed by buffers backing
+        * on disk user data (e.g. plain file contents).
+        */
+       kstat_named_t arcstat_data_size;
+       /*
+        * Number of bytes consumed by ARC buffers of type equal to
+        * ARC_BUFC_METADATA. This is generally consumed by buffers
+        * backing on disk data that is used for internal ZFS
+        * structures (e.g. ZAP, dnode, indirect blocks, etc).
+        */
+       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).
+        */
+       kstat_named_t arcstat_other_size;
+       /*
+        * Total number of bytes consumed by ARC buffers residing in the
+        * arc_anon state. This includes *all* buffers in the arc_anon
+        * state; e.g. data, metadata, evictable, and unevictable buffers
+        * are all included in this value.
+        */
+       kstat_named_t arcstat_anon_size;
+       /*
+        * Number of bytes consumed by ARC buffers that meet the
+        * following criteria: backing buffers of type ARC_BUFC_DATA,
+        * residing in the arc_anon state, and are eligible for eviction
+        * (e.g. have no outstanding holds on the buffer).
+        */
+       kstat_named_t arcstat_anon_evictable_data;
+       /*
+        * Number of bytes consumed by ARC buffers that meet the
+        * following criteria: backing buffers of type ARC_BUFC_METADATA,
+        * residing in the arc_anon state, and are eligible for eviction
+        * (e.g. have no outstanding holds on the buffer).
+        */
+       kstat_named_t arcstat_anon_evictable_metadata;
+       /*
+        * Total number of bytes consumed by ARC buffers residing in the
+        * arc_mru state. This includes *all* buffers in the arc_mru
+        * state; e.g. data, metadata, evictable, and unevictable buffers
+        * are all included in this value.
+        */
+       kstat_named_t arcstat_mru_size;
+       /*
+        * Number of bytes consumed by ARC buffers that meet the
+        * following criteria: backing buffers of type ARC_BUFC_DATA,
+        * residing in the arc_mru state, and are eligible for eviction
+        * (e.g. have no outstanding holds on the buffer).
+        */
+       kstat_named_t arcstat_mru_evictable_data;
+       /*
+        * Number of bytes consumed by ARC buffers that meet the
+        * following criteria: backing buffers of type ARC_BUFC_METADATA,
+        * residing in the arc_mru state, and are eligible for eviction
+        * (e.g. have no outstanding holds on the buffer).
+        */
+       kstat_named_t arcstat_mru_evictable_metadata;
+       /*
+        * Total number of bytes that *would have been* consumed by ARC
+        * buffers in the arc_mru_ghost state. The key thing to note
+        * here, is the fact that this size doesn't actually indicate
+        * RAM consumption. The ghost lists only consist of headers and
+        * don't actually have ARC buffers linked off of these headers.
+        * Thus, *if* the headers had associated ARC buffers, these
+        * buffers *would have* consumed this number of bytes.
+        */
+       kstat_named_t arcstat_mru_ghost_size;
+       /*
+        * Number of bytes that *would have been* consumed by ARC
+        * buffers that are eligible for eviction, of type
+        * ARC_BUFC_DATA, and linked off the arc_mru_ghost state.
+        */
+       kstat_named_t arcstat_mru_ghost_evictable_data;
+       /*
+        * Number of bytes that *would have been* consumed by ARC
+        * buffers that are eligible for eviction, of type
+        * ARC_BUFC_METADATA, and linked off the arc_mru_ghost state.
+        */
+       kstat_named_t arcstat_mru_ghost_evictable_metadata;
+       /*
+        * Total number of bytes consumed by ARC buffers residing in the
+        * arc_mfu state. This includes *all* buffers in the arc_mfu
+        * state; e.g. data, metadata, evictable, and unevictable buffers
+        * are all included in this value.
+        */
+       kstat_named_t arcstat_mfu_size;
+       /*
+        * Number of bytes consumed by ARC buffers that are eligible for
+        * eviction, of type ARC_BUFC_DATA, and reside in the arc_mfu
+        * state.
+        */
+       kstat_named_t arcstat_mfu_evictable_data;
+       /*
+        * Number of bytes consumed by ARC buffers that are eligible for
+        * eviction, of type ARC_BUFC_METADATA, and reside in the
+        * arc_mfu state.
+        */
+       kstat_named_t arcstat_mfu_evictable_metadata;
+       /*
+        * Total number of bytes that *would have been* consumed by ARC
+        * buffers in the arc_mfu_ghost state. See the comment above
+        * arcstat_mru_ghost_size for more details.
+        */
+       kstat_named_t arcstat_mfu_ghost_size;
+       /*
+        * Number of bytes that *would have been* consumed by ARC
+        * buffers that are eligible for eviction, of type
+        * ARC_BUFC_DATA, and linked off the arc_mfu_ghost state.
+        */
+       kstat_named_t arcstat_mfu_ghost_evictable_data;
+       /*
+        * Number of bytes that *would have been* consumed by ARC
+        * buffers that are eligible for eviction, of type
+        * ARC_BUFC_METADATA, and linked off the arc_mru_ghost state.
+        */
+       kstat_named_t arcstat_mfu_ghost_evictable_metadata;
+       kstat_named_t arcstat_l2_hits;
+       kstat_named_t arcstat_l2_misses;
+       kstat_named_t arcstat_l2_feeds;
+       kstat_named_t arcstat_l2_rw_clash;
+       kstat_named_t arcstat_l2_read_bytes;
+       kstat_named_t arcstat_l2_write_bytes;
+       kstat_named_t arcstat_l2_writes_sent;
+       kstat_named_t arcstat_l2_writes_done;
+       kstat_named_t arcstat_l2_writes_error;
+       kstat_named_t arcstat_l2_writes_lock_retry;
+       kstat_named_t arcstat_l2_evict_lock_retry;
+       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;
+       kstat_named_t arcstat_tempreserve;
+       kstat_named_t arcstat_loaned_bytes;
+       kstat_named_t arcstat_prune;
+       kstat_named_t arcstat_meta_used;
+       kstat_named_t arcstat_meta_limit;
+       kstat_named_t arcstat_meta_max;
+       kstat_named_t arcstat_meta_min;
+       kstat_named_t arcstat_need_free;
+       kstat_named_t arcstat_sys_free;
+} arc_stats_t;
+
+static arc_stats_t arc_stats = {
+       { "hits",                       KSTAT_DATA_UINT64 },
+       { "misses",                     KSTAT_DATA_UINT64 },
+       { "demand_data_hits",           KSTAT_DATA_UINT64 },
+       { "demand_data_misses",         KSTAT_DATA_UINT64 },
+       { "demand_metadata_hits",       KSTAT_DATA_UINT64 },
+       { "demand_metadata_misses",     KSTAT_DATA_UINT64 },
+       { "prefetch_data_hits",         KSTAT_DATA_UINT64 },
+       { "prefetch_data_misses",       KSTAT_DATA_UINT64 },
+       { "prefetch_metadata_hits",     KSTAT_DATA_UINT64 },
+       { "prefetch_metadata_misses",   KSTAT_DATA_UINT64 },
+       { "mru_hits",                   KSTAT_DATA_UINT64 },
+       { "mru_ghost_hits",             KSTAT_DATA_UINT64 },
+       { "mfu_hits",                   KSTAT_DATA_UINT64 },
+       { "mfu_ghost_hits",             KSTAT_DATA_UINT64 },
+       { "deleted",                    KSTAT_DATA_UINT64 },
+       { "mutex_miss",                 KSTAT_DATA_UINT64 },
+       { "evict_skip",                 KSTAT_DATA_UINT64 },
+       { "evict_not_enough",           KSTAT_DATA_UINT64 },
+       { "evict_l2_cached",            KSTAT_DATA_UINT64 },
+       { "evict_l2_eligible",          KSTAT_DATA_UINT64 },
+       { "evict_l2_ineligible",        KSTAT_DATA_UINT64 },
+       { "evict_l2_skip",              KSTAT_DATA_UINT64 },
+       { "hash_elements",              KSTAT_DATA_UINT64 },
+       { "hash_elements_max",          KSTAT_DATA_UINT64 },
+       { "hash_collisions",            KSTAT_DATA_UINT64 },
+       { "hash_chains",                KSTAT_DATA_UINT64 },
+       { "hash_chain_max",             KSTAT_DATA_UINT64 },
+       { "p",                          KSTAT_DATA_UINT64 },
+       { "c",                          KSTAT_DATA_UINT64 },
+       { "c_min",                      KSTAT_DATA_UINT64 },
+       { "c_max",                      KSTAT_DATA_UINT64 },
+       { "size",                       KSTAT_DATA_UINT64 },
+       { "hdr_size",                   KSTAT_DATA_UINT64 },
+       { "data_size",                  KSTAT_DATA_UINT64 },
+       { "metadata_size",              KSTAT_DATA_UINT64 },
+       { "other_size",                 KSTAT_DATA_UINT64 },
+       { "anon_size",                  KSTAT_DATA_UINT64 },
+       { "anon_evictable_data",        KSTAT_DATA_UINT64 },
+       { "anon_evictable_metadata",    KSTAT_DATA_UINT64 },
+       { "mru_size",                   KSTAT_DATA_UINT64 },
+       { "mru_evictable_data",         KSTAT_DATA_UINT64 },
+       { "mru_evictable_metadata",     KSTAT_DATA_UINT64 },
+       { "mru_ghost_size",             KSTAT_DATA_UINT64 },
+       { "mru_ghost_evictable_data",   KSTAT_DATA_UINT64 },
+       { "mru_ghost_evictable_metadata", KSTAT_DATA_UINT64 },
+       { "mfu_size",                   KSTAT_DATA_UINT64 },
+       { "mfu_evictable_data",         KSTAT_DATA_UINT64 },
+       { "mfu_evictable_metadata",     KSTAT_DATA_UINT64 },
+       { "mfu_ghost_size",             KSTAT_DATA_UINT64 },
+       { "mfu_ghost_evictable_data",   KSTAT_DATA_UINT64 },
+       { "mfu_ghost_evictable_metadata", KSTAT_DATA_UINT64 },
+       { "l2_hits",                    KSTAT_DATA_UINT64 },
+       { "l2_misses",                  KSTAT_DATA_UINT64 },
+       { "l2_feeds",                   KSTAT_DATA_UINT64 },
+       { "l2_rw_clash",                KSTAT_DATA_UINT64 },
+       { "l2_read_bytes",              KSTAT_DATA_UINT64 },
+       { "l2_write_bytes",             KSTAT_DATA_UINT64 },
+       { "l2_writes_sent",             KSTAT_DATA_UINT64 },
+       { "l2_writes_done",             KSTAT_DATA_UINT64 },
+       { "l2_writes_error",            KSTAT_DATA_UINT64 },
+       { "l2_writes_lock_retry",       KSTAT_DATA_UINT64 },
+       { "l2_evict_lock_retry",        KSTAT_DATA_UINT64 },
+       { "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 },
+       { "arc_tempreserve",            KSTAT_DATA_UINT64 },
+       { "arc_loaned_bytes",           KSTAT_DATA_UINT64 },
+       { "arc_prune",                  KSTAT_DATA_UINT64 },
+       { "arc_meta_used",              KSTAT_DATA_UINT64 },
+       { "arc_meta_limit",             KSTAT_DATA_UINT64 },
+       { "arc_meta_max",               KSTAT_DATA_UINT64 },
+       { "arc_meta_min",               KSTAT_DATA_UINT64 },
+       { "arc_need_free",              KSTAT_DATA_UINT64 },
+       { "arc_sys_free",               KSTAT_DATA_UINT64 }
+};
+
+#define        ARCSTAT(stat)   (arc_stats.stat.value.ui64)
+
+#define        ARCSTAT_INCR(stat, val) \
+       atomic_add_64(&arc_stats.stat.value.ui64, (val))
+
+#define        ARCSTAT_BUMP(stat)      ARCSTAT_INCR(stat, 1)
+#define        ARCSTAT_BUMPDOWN(stat)  ARCSTAT_INCR(stat, -1)
+
+#define        ARCSTAT_MAX(stat, val) {                                        \
+       uint64_t m;                                                     \
+       while ((val) > (m = arc_stats.stat.value.ui64) &&               \
+           (m != atomic_cas_64(&arc_stats.stat.value.ui64, m, (val)))) \
+               continue;                                               \
+}
+
+#define        ARCSTAT_MAXSTAT(stat) \
+       ARCSTAT_MAX(stat##_max, arc_stats.stat.value.ui64)
+
+/*
+ * We define a macro to allow ARC hits/misses to be easily broken down by
+ * two separate conditions, giving a total of four different subtypes for
+ * each of hits and misses (so eight statistics total).
+ */
+#define        ARCSTAT_CONDSTAT(cond1, stat1, notstat1, cond2, stat2, notstat2, stat) \
+       if (cond1) {                                                    \
+               if (cond2) {                                            \
+                       ARCSTAT_BUMP(arcstat_##stat1##_##stat2##_##stat); \
+               } else {                                                \
+                       ARCSTAT_BUMP(arcstat_##stat1##_##notstat2##_##stat); \
+               }                                                       \
+       } else {                                                        \
+               if (cond2) {                                            \
+                       ARCSTAT_BUMP(arcstat_##notstat1##_##stat2##_##stat); \
+               } else {                                                \
+                       ARCSTAT_BUMP(arcstat_##notstat1##_##notstat2##_##stat);\
+               }                                                       \
+       }
+
+kstat_t                        *arc_ksp;
+static arc_state_t     *arc_anon;
+static arc_state_t     *arc_mru;
+static arc_state_t     *arc_mru_ghost;
+static arc_state_t     *arc_mfu;
+static arc_state_t     *arc_mfu_ghost;
+static arc_state_t     *arc_l2c_only;
+
+/*
+ * There are several ARC variables that are critical to export as kstats --
+ * but we don't want to have to grovel around in the kstat whenever we wish to
+ * manipulate them.  For these variables, we therefore define them to be in
+ * terms of the statistic variable.  This assures that we are not introducing
+ * the possibility of inconsistency by having shadow copies of the variables,
+ * while still allowing the code to be readable.
+ */
+#define        arc_size        ARCSTAT(arcstat_size)   /* actual total arc size */
+#define        arc_p           ARCSTAT(arcstat_p)      /* target size of MRU */
+#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_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_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_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)
+
+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 ||        \
+       (state) == arc_l2c_only)
+
+#define        HDR_IN_HASH_TABLE(hdr)  ((hdr)->b_flags & ARC_FLAG_IN_HASH_TABLE)
+#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_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))
+#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_ISTYPE_METADATA(hdr)        \
+           ((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)
+
+/*
+ * Other sizes
+ */
+
+#define        HDR_FULL_SIZE ((int64_t)sizeof (arc_buf_hdr_t))
+#define        HDR_L2ONLY_SIZE ((int64_t)offsetof(arc_buf_hdr_t, b_l1hdr))
+
+/*
+ * Hash table routines
+ */
+
+#define        HT_LOCK_ALIGN   64
+#define        HT_LOCK_PAD     (P2NPHASE(sizeof (kmutex_t), (HT_LOCK_ALIGN)))
+
+struct ht_lock {
+       kmutex_t        ht_lock;
+#ifdef _KERNEL
+       unsigned char   pad[HT_LOCK_PAD];
+#endif
+};
+
+#define        BUF_LOCKS 8192
+typedef struct buf_hash_table {
+       uint64_t ht_mask;
+       arc_buf_hdr_t **ht_table;
+       struct ht_lock ht_locks[BUF_LOCKS];
+} buf_hash_table_t;
+
+static buf_hash_table_t buf_hash_table;
+
+#define        BUF_HASH_INDEX(spa, dva, birth) \
+       (buf_hash(spa, dva, birth) & buf_hash_table.ht_mask)
+#define        BUF_HASH_LOCK_NTRY(idx) (buf_hash_table.ht_locks[idx & (BUF_LOCKS-1)])
+#define        BUF_HASH_LOCK(idx)      (&(BUF_HASH_LOCK_NTRY(idx).ht_lock))
+#define        HDR_LOCK(hdr) \
+       (BUF_HASH_LOCK(BUF_HASH_INDEX(hdr->b_spa, &hdr->b_dva, hdr->b_birth)))
+
+uint64_t zfs_crc64_table[256];
+
+/*
+ * Level 2 ARC
+ */
+
+#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.
+ */
+#define        L2ARC_HEADROOM_BOOST    200
+#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)
+
+/* L2ARC Performance Tunables */
+unsigned long l2arc_write_max = L2ARC_WRITE_SIZE;      /* def max write size */
+unsigned long l2arc_write_boost = L2ARC_WRITE_SIZE;    /* extra warmup write */
+unsigned long l2arc_headroom = L2ARC_HEADROOM;         /* # of dev writes */
+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 */
+
+/*
+ * L2ARC Internals
+ */
+static list_t L2ARC_dev_list;                  /* device list */
+static list_t *l2arc_dev_list;                 /* device list pointer */
+static kmutex_t l2arc_dev_mtx;                 /* device list mutex */
+static l2arc_dev_t *l2arc_dev_last;            /* last device used */
+static list_t L2ARC_free_on_write;             /* free after write buf list */
+static list_t *l2arc_free_on_write;            /* free after write list ptr */
+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 */
+       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);
+       list_node_t     l2df_list_node;
+} l2arc_data_free_t;
+
+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_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 arc_buf_contents_t arc_buf_type(arc_buf_hdr_t *);
+static uint32_t arc_bufc_to_flags(arc_buf_contents_t);
+
+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)
+{
+       uint8_t *vdva = (uint8_t *)dva;
+       uint64_t crc = -1ULL;
+       int i;
+
+       ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
+
+       for (i = 0; i < sizeof (dva_t); i++)
+               crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ vdva[i]) & 0xFF];
+
+       crc ^= (spa>>8) ^ birth;
+
+       return (crc);
+}
+
+#define        BUF_EMPTY(buf)                                          \
+       ((buf)->b_dva.dva_word[0] == 0 &&                       \
+       (buf)->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)
+
+static void
+buf_discard_identity(arc_buf_hdr_t *hdr)
+{
+       hdr->b_dva.dva_word[0] = 0;
+       hdr->b_dva.dva_word[1] = 0;
+       hdr->b_birth = 0;
+}
+
+static arc_buf_hdr_t *
+buf_hash_find(uint64_t spa, const blkptr_t *bp, kmutex_t **lockp)
+{
+       const dva_t *dva = BP_IDENTITY(bp);
+       uint64_t birth = BP_PHYSICAL_BIRTH(bp);
+       uint64_t idx = BUF_HASH_INDEX(spa, dva, birth);
+       kmutex_t *hash_lock = BUF_HASH_LOCK(idx);
+       arc_buf_hdr_t *hdr;
+
+       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)) {
+                       *lockp = hash_lock;
+                       return (hdr);
+               }
+       }
+       mutex_exit(hash_lock);
+       *lockp = NULL;
+       return (NULL);
+}
+
+/*
+ * Insert an entry into the hash table.  If there is already an element
+ * equal to elem in the hash table, then the already existing element
+ * will be returned and the new element will not be inserted.
+ * Otherwise returns NULL.
+ * If lockp == NULL, the caller is assumed to already hold the hash lock.
+ */
+static arc_buf_hdr_t *
+buf_hash_insert(arc_buf_hdr_t *hdr, kmutex_t **lockp)
+{
+       uint64_t idx = BUF_HASH_INDEX(hdr->b_spa, &hdr->b_dva, hdr->b_birth);
+       kmutex_t *hash_lock = BUF_HASH_LOCK(idx);
+       arc_buf_hdr_t *fhdr;
+       uint32_t i;
+
+       ASSERT(!DVA_IS_EMPTY(&hdr->b_dva));
+       ASSERT(hdr->b_birth != 0);
+       ASSERT(!HDR_IN_HASH_TABLE(hdr));
+
+       if (lockp != NULL) {
+               *lockp = hash_lock;
+               mutex_enter(hash_lock);
+       } else {
+               ASSERT(MUTEX_HELD(hash_lock));
+       }
+
+       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))
+                       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;
+
+       /* collect some hash table performance data */
+       if (i > 0) {
+               ARCSTAT_BUMP(arcstat_hash_collisions);
+               if (i == 1)
+                       ARCSTAT_BUMP(arcstat_hash_chains);
+
+               ARCSTAT_MAX(arcstat_hash_chain_max, i);
+       }
+
+       ARCSTAT_BUMP(arcstat_hash_elements);
+       ARCSTAT_MAXSTAT(arcstat_hash_elements);
+
+       return (NULL);
+}
+
+static void
+buf_hash_remove(arc_buf_hdr_t *hdr)
+{
+       arc_buf_hdr_t *fhdr, **hdrp;
+       uint64_t idx = BUF_HASH_INDEX(hdr->b_spa, &hdr->b_dva, hdr->b_birth);
+
+       ASSERT(MUTEX_HELD(BUF_HASH_LOCK(idx)));
+       ASSERT(HDR_IN_HASH_TABLE(hdr));
+
+       hdrp = &buf_hash_table.ht_table[idx];
+       while ((fhdr = *hdrp) != hdr) {
+               ASSERT(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;
+
+       /* collect some hash table performance data */
+       ARCSTAT_BUMPDOWN(arcstat_hash_elements);
+
+       if (buf_hash_table.ht_table[idx] &&
+           buf_hash_table.ht_table[idx]->b_hash_next == NULL)
+               ARCSTAT_BUMPDOWN(arcstat_hash_chains);
+}
+
+/*
+ * Global data structures and functions for the buf kmem cache.
+ */
+static kmem_cache_t *hdr_full_cache;
+static kmem_cache_t *hdr_l2only_cache;
+static kmem_cache_t *buf_cache;
+
+static void
+buf_fini(void)
+{
+       int i;
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+       /*
+        * Large allocations which do not require contiguous pages
+        * should be using vmem_free() in the linux kernel\
+        */
+       vmem_free(buf_hash_table.ht_table,
+           (buf_hash_table.ht_mask + 1) * sizeof (void *));
+#else
+       kmem_free(buf_hash_table.ht_table,
+           (buf_hash_table.ht_mask + 1) * sizeof (void *));
+#endif
+       for (i = 0; i < BUF_LOCKS; i++)
+               mutex_destroy(&buf_hash_table.ht_locks[i].ht_lock);
+       kmem_cache_destroy(hdr_full_cache);
+       kmem_cache_destroy(hdr_l2only_cache);
+       kmem_cache_destroy(buf_cache);
+}
+
+/*
+ * Constructor callback - called when the cache is empty
+ * and a new buf is requested.
+ */
+/* ARGSUSED */
+static int
+hdr_full_cons(void *vbuf, void *unused, int kmflag)
+{
+       arc_buf_hdr_t *hdr = vbuf;
+
+       bzero(hdr, HDR_FULL_SIZE);
+       cv_init(&hdr->b_l1hdr.b_cv, NULL, CV_DEFAULT, NULL);
+       refcount_create(&hdr->b_l1hdr.b_refcnt);
+       mutex_init(&hdr->b_l1hdr.b_freeze_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_link_init(&hdr->b_l1hdr.b_arc_node);
+       list_link_init(&hdr->b_l2hdr.b_l2node);
+       multilist_link_init(&hdr->b_l1hdr.b_arc_node);
+       arc_space_consume(HDR_FULL_SIZE, ARC_SPACE_HDRS);
+
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+hdr_l2only_cons(void *vbuf, void *unused, int kmflag)
+{
+       arc_buf_hdr_t *hdr = vbuf;
+
+       bzero(hdr, HDR_L2ONLY_SIZE);
+       arc_space_consume(HDR_L2ONLY_SIZE, ARC_SPACE_L2HDRS);
+
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+buf_cons(void *vbuf, void *unused, int kmflag)
+{
+       arc_buf_t *buf = vbuf;
+
+       bzero(buf, sizeof (arc_buf_t));
+       mutex_init(&buf->b_evict_lock, NULL, MUTEX_DEFAULT, NULL);
+       arc_space_consume(sizeof (arc_buf_t), ARC_SPACE_HDRS);
+
+       return (0);
+}
+
+/*
+ * Destructor callback - called when a cached buf is
+ * no longer required.
+ */
+/* ARGSUSED */
+static void
+hdr_full_dest(void *vbuf, void *unused)
+{
+       arc_buf_hdr_t *hdr = vbuf;
+
+       ASSERT(BUF_EMPTY(hdr));
+       cv_destroy(&hdr->b_l1hdr.b_cv);
+       refcount_destroy(&hdr->b_l1hdr.b_refcnt);
+       mutex_destroy(&hdr->b_l1hdr.b_freeze_lock);
+       ASSERT(!multilist_link_active(&hdr->b_l1hdr.b_arc_node));
+       arc_space_return(HDR_FULL_SIZE, ARC_SPACE_HDRS);
+}
+
+/* ARGSUSED */
+static void
+hdr_l2only_dest(void *vbuf, void *unused)
+{
+       ASSERTV(arc_buf_hdr_t *hdr = vbuf);
+
+       ASSERT(BUF_EMPTY(hdr));
+       arc_space_return(HDR_L2ONLY_SIZE, ARC_SPACE_L2HDRS);
+}
+
+/* ARGSUSED */
+static void
+buf_dest(void *vbuf, void *unused)
+{
+       arc_buf_t *buf = vbuf;
+
+       mutex_destroy(&buf->b_evict_lock);
+       arc_space_return(sizeof (arc_buf_t), ARC_SPACE_HDRS);
+}
+
+/*
+ * Reclaim callback -- invoked when memory is low.
+ */
+/* ARGSUSED */
+static void
+hdr_recl(void *unused)
+{
+       dprintf("hdr_recl called\n");
+       /*
+        * umem calls the reclaim func when we destroy the buf cache,
+        * which is after we do arc_fini().
+        */
+       if (!arc_dead)
+               cv_signal(&arc_reclaim_thread_cv);
+}
+
+static void
+buf_init(void)
+{
+       uint64_t *ct;
+       uint64_t hsize = 1ULL << 12;
+       int i, j;
+
+       /*
+        * The hash table is big enough to fill all of physical memory
+        * with an average block size of zfs_arc_average_blocksize (default 8K).
+        * By default, the table will take up
+        * totalmem * sizeof(void*) / 8K (1MB per GB with 8-byte pointers).
+        */
+       while (hsize * zfs_arc_average_blocksize < physmem * PAGESIZE)
+               hsize <<= 1;
+retry:
+       buf_hash_table.ht_mask = hsize - 1;
+#if defined(_KERNEL) && defined(HAVE_SPL)
+       /*
+        * Large allocations which do not require contiguous pages
+        * should be using vmem_alloc() in the linux kernel
+        */
+       buf_hash_table.ht_table =
+           vmem_zalloc(hsize * sizeof (void*), KM_SLEEP);
+#else
+       buf_hash_table.ht_table =
+           kmem_zalloc(hsize * sizeof (void*), KM_NOSLEEP);
+#endif
+       if (buf_hash_table.ht_table == NULL) {
+               ASSERT(hsize > (1ULL << 8));
+               hsize >>= 1;
+               goto retry;
+       }
+
+       hdr_full_cache = kmem_cache_create("arc_buf_hdr_t_full", HDR_FULL_SIZE,
+           0, hdr_full_cons, hdr_full_dest, hdr_recl, NULL, NULL, 0);
+       hdr_l2only_cache = kmem_cache_create("arc_buf_hdr_t_l2only",
+           HDR_L2ONLY_SIZE, 0, hdr_l2only_cons, hdr_l2only_dest, hdr_recl,
+           NULL, NULL, 0);
+       buf_cache = kmem_cache_create("arc_buf_t", sizeof (arc_buf_t),
+           0, buf_cons, buf_dest, NULL, NULL, NULL, 0);
+
+       for (i = 0; i < 256; i++)
+               for (ct = zfs_crc64_table + i, *ct = i, j = 8; j > 0; j--)
+                       *ct = (*ct >> 1) ^ (-(*ct & 1) & ZFS_CRC64_POLY);
+
+       for (i = 0; i < BUF_LOCKS; i++) {
+               mutex_init(&buf_hash_table.ht_locks[i].ht_lock,
+                   NULL, MUTEX_DEFAULT, NULL);
+       }
+}
+
+/*
+ * 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;
+
+       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));
+
+       mutex_enter(&dev->l2ad_mtx);
+
+       /*
+        * 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);
+
+       mutex_exit(&dev->l2ad_mtx);
+
+       /*
+        * 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.
+        */
+
+       (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);
+}
+
+
+#define        ARC_MINTIME     (hz>>4) /* 62 ms */
+
+static void
+arc_cksum_verify(arc_buf_t *buf)
+{
+       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);
+               return;
+       }
+       fletcher_2_native(buf->b_data, buf->b_hdr->b_size, &zc);
+       if (!ZIO_CHECKSUM_EQUAL(*buf->b_hdr->b_freeze_cksum, zc))
+               panic("buffer modified while frozen!");
+       mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+}
+
+static int
+arc_cksum_equal(arc_buf_t *buf)
+{
+       zio_cksum_t zc;
+       int equal;
+
+       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);
+
+       return (equal);
+}
+
+static void
+arc_cksum_compute(arc_buf_t *buf, boolean_t force)
+{
+       if (!force && !(zfs_flags & ZFS_DEBUG_MODIFY))
+               return;
+
+       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);
+               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);
+       arc_buf_watch(buf);
+}
+
+#ifndef _KERNEL
+void
+arc_buf_sigsegv(int sig, siginfo_t *si, void *unused)
+{
+       panic("Got SIGSEGV at address: 0x%lx\n", (long) si->si_addr);
+}
+#endif
+
+/* ARGSUSED */
+static void
+arc_buf_unwatch(arc_buf_t *buf)
+{
+#ifndef _KERNEL
+       if (arc_watch) {
+               ASSERT0(mprotect(buf->b_data, buf->b_hdr->b_size,
+                   PROT_READ | PROT_WRITE));
+       }
+#endif
+}
+
+/* ARGSUSED */
+static void
+arc_buf_watch(arc_buf_t *buf)
+{
+#ifndef _KERNEL
+       if (arc_watch)
+               ASSERT0(mprotect(buf->b_data, buf->b_hdr->b_size, PROT_READ));
+#endif
+}
+
+static arc_buf_contents_t
+arc_buf_type(arc_buf_hdr_t *hdr)
+{
+       if (HDR_ISTYPE_METADATA(hdr)) {
+               return (ARC_BUFC_METADATA);
+       } else {
+               return (ARC_BUFC_DATA);
+       }
+}
+
+static uint32_t
+arc_bufc_to_flags(arc_buf_contents_t type)
+{
+       switch (type) {
+       case ARC_BUFC_DATA:
+               /* metadata field is 0 if buffer contains normal data */
+               return (0);
+       case ARC_BUFC_METADATA:
+               return (ARC_FLAG_BUFC_METADATA);
+       default:
+               break;
+       }
+       panic("undefined ARC buffer type!");
+       return ((uint32_t)-1);
+}
+
+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);
+       }
+
+       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;
+       }
+
+       mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+
+       arc_buf_unwatch(buf);
+}
+
+void
+arc_buf_freeze(arc_buf_t *buf)
+{
+       kmutex_t *hash_lock;
+
+       if (!(zfs_flags & ZFS_DEBUG_MODIFY))
+               return;
+
+       hash_lock = HDR_LOCK(buf->b_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);
+       mutex_exit(hash_lock);
+
+}
+
+static void
+add_reference(arc_buf_hdr_t *hdr, kmutex_t *hash_lock, void *tag)
+{
+       arc_state_t *state;
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       ASSERT(MUTEX_HELD(hash_lock));
+
+       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) {
+                       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];
+
+                       multilist_remove(list, 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;
+       }
+}
+
+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)) {
+               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);
+
+               ASSERT(hdr->b_l1hdr.b_datacnt > 0);
+               atomic_add_64(size, hdr->b_size *
+                   hdr->b_l1hdr.b_datacnt);
+       }
+       return (cnt);
+}
+
+/*
+ * Returns detailed information about a specific arc buffer.  When the
+ * state_index argument is set the function will calculate the arc header
+ * list position for its arc state.  Since this requires a linear traversal
+ * callers are strongly encourage not to do this.  However, it can be helpful
+ * for targeted analysis so the functionality is provided.
+ */
+void
+arc_buf_info(arc_buf_t *ab, arc_buf_info_t *abi, int state_index)
+{
+       arc_buf_hdr_t *hdr = ab->b_hdr;
+       l1arc_buf_hdr_t *l1hdr = NULL;
+       l2arc_buf_hdr_t *l2hdr = NULL;
+       arc_state_t *state = NULL;
+
+       memset(abi, 0, sizeof (arc_buf_info_t));
+
+       if (hdr == NULL)
+               return;
+
+       abi->abi_flags = hdr->b_flags;
+
+       if (HDR_HAS_L1HDR(hdr)) {
+               l1hdr = &hdr->b_l1hdr;
+               state = l1hdr->b_state;
+       }
+       if (HDR_HAS_L2HDR(hdr))
+               l2hdr = &hdr->b_l2hdr;
+
+       if (l1hdr) {
+               abi->abi_datacnt = l1hdr->b_datacnt;
+               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;
+               abi->abi_mfu_hits = l1hdr->b_mfu_hits;
+               abi->abi_mfu_ghost_hits = l1hdr->b_mfu_ghost_hits;
+               abi->abi_holds = refcount_count(&l1hdr->b_refcnt);
+       }
+
+       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;
+}
+
+/*
+ * Move the supplied buffer to the indicated state. The hash lock
+ * for the buffer must be held by the caller.
+ */
+static void
+arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
+    kmutex_t *hash_lock)
+{
+       arc_state_t *old_state;
+       int64_t refcnt;
+       uint32_t datacnt;
+       uint64_t from_delta, to_delta;
+       arc_buf_contents_t buftype = arc_buf_type(hdr);
+
+       /*
+        * We almost always have an L1 hdr here, since we call arc_hdr_realloc()
+        * in arc_read() when bringing a buffer out of the L2ARC.  However, the
+        * L1 hdr doesn't always exist when we change state to arc_anon before
+        * destroying a header, in which case reallocating to add the L1 hdr is
+        * pointless.
+        */
+       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;
+       } else {
+               old_state = arc_l2c_only;
+               refcnt = 0;
+               datacnt = 0;
+       }
+
+       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;
+
+       /*
+        * If this buffer is evictable, transfer it from the
+        * old state list to the new state list.
+        */
+       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;
+                       }
+                       ASSERT3U(*size, >=, from_delta);
+                       atomic_add_64(size, -from_delta);
+               }
+               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
+                        * anonymous), we realloc the header to add an L1hdr
+                        * beforehand.
+                        */
+                       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;
+                       }
+                       atomic_add_64(size, to_delta);
+               }
+       }
+
+       ASSERT(!BUF_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) {
+               ASSERT(HDR_HAS_L1HDR(hdr));
+               if (GHOST_STATE(new_state)) {
+                       ASSERT0(datacnt);
+
+                       /*
+                        * We 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
+                        * 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);
+               } else {
+                       arc_buf_t *buf;
+                       ASSERT3U(datacnt, !=, 0);
+
+                       /*
+                        * Each individual buffer holds a unique reference,
+                        * thus we must remove each of these references one
+                        * at a time.
+                        */
+                       for (buf = hdr->b_l1hdr.b_buf; buf != NULL;
+                           buf = buf->b_next) {
+                               (void) refcount_add_many(&new_state->arcs_size,
+                                   hdr->b_size, buf);
+                       }
+               }
+       }
+
+       if (from_delta && old_state != arc_l2c_only) {
+               ASSERT(HDR_HAS_L1HDR(hdr));
+               if (GHOST_STATE(old_state)) {
+                       /*
+                        * 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).
+                        */
+
+                       IMPLY(datacnt == 0, new_state == arc_anon ||
+                           new_state == arc_l2c_only);
+
+                       (void) refcount_remove_many(&old_state->arcs_size,
+                           hdr->b_size, hdr);
+               } else {
+                       arc_buf_t *buf;
+                       ASSERT3U(datacnt, !=, 0);
+
+                       /*
+                        * Each individual buffer holds a unique reference,
+                        * thus we must remove each of these references one
+                        * at a time.
+                        */
+                       for (buf = hdr->b_l1hdr.b_buf; buf != NULL;
+                           buf = buf->b_next) {
+                               (void) refcount_remove_many(
+                                   &old_state->arcs_size, hdr->b_size, buf);
+                       }
+               }
+       }
+
+       if (HDR_HAS_L1HDR(hdr))
+               hdr->b_l1hdr.b_state = new_state;
+
+       /*
+        * L2 headers should never be on the L2 state list since they don't
+        * have L1 headers allocated.
+        */
+       ASSERT(multilist_is_empty(&arc_l2c_only->arcs_list[ARC_BUFC_DATA]) &&
+           multilist_is_empty(&arc_l2c_only->arcs_list[ARC_BUFC_METADATA]));
+}
+
+void
+arc_space_consume(uint64_t space, arc_space_type_t type)
+{
+       ASSERT(type >= 0 && type < ARC_SPACE_NUMTYPES);
+
+       switch (type) {
+       default:
+               break;
+       case ARC_SPACE_DATA:
+               ARCSTAT_INCR(arcstat_data_size, space);
+               break;
+       case ARC_SPACE_META:
+               ARCSTAT_INCR(arcstat_metadata_size, space);
+               break;
+       case ARC_SPACE_OTHER:
+               ARCSTAT_INCR(arcstat_other_size, space);
+               break;
+       case ARC_SPACE_HDRS:
+               ARCSTAT_INCR(arcstat_hdr_size, space);
+               break;
+       case ARC_SPACE_L2HDRS:
+               ARCSTAT_INCR(arcstat_l2_hdr_size, space);
+               break;
+       }
+
+       if (type != ARC_SPACE_DATA)
+               ARCSTAT_INCR(arcstat_meta_used, space);
+
+       atomic_add_64(&arc_size, space);
+}
+
+void
+arc_space_return(uint64_t space, arc_space_type_t type)
+{
+       ASSERT(type >= 0 && type < ARC_SPACE_NUMTYPES);
+
+       switch (type) {
+       default:
+               break;
+       case ARC_SPACE_DATA:
+               ARCSTAT_INCR(arcstat_data_size, -space);
+               break;
+       case ARC_SPACE_META:
+               ARCSTAT_INCR(arcstat_metadata_size, -space);
+               break;
+       case ARC_SPACE_OTHER:
+               ARCSTAT_INCR(arcstat_other_size, -space);
+               break;
+       case ARC_SPACE_HDRS:
+               ARCSTAT_INCR(arcstat_hdr_size, -space);
+               break;
+       case ARC_SPACE_L2HDRS:
+               ARCSTAT_INCR(arcstat_l2_hdr_size, -space);
+               break;
+       }
+
+       if (type != ARC_SPACE_DATA) {
+               ASSERT(arc_meta_used >= space);
+               if (arc_meta_max < arc_meta_used)
+                       arc_meta_max = arc_meta_used;
+               ARCSTAT_INCR(arcstat_meta_used, -space);
+       }
+
+       ASSERT(arc_size >= space);
+       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)
+{
+       arc_buf_hdr_t *hdr;
+       arc_buf_t *buf;
+
+       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->b_hdr = hdr;
+       buf->b_data = NULL;
+       buf->b_efunc = NULL;
+       buf->b_private = NULL;
+       buf->b_next = NULL;
+
+       hdr->b_flags = arc_bufc_to_flags(type);
+       hdr->b_flags |= ARC_FLAG_HAS_L1HDR;
+
+       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;
+
+       arc_get_data_buf(buf);
+       ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+       (void) refcount_add(&hdr->b_l1hdr.b_refcnt, tag);
+
+       return (buf);
+}
+
+static char *arc_onloan_tag = "onloan";
+
+/*
+ * Loan out an anonymous arc buffer. Loaned buffers are not counted as in
+ * flight data by arc_tempreserve_space() until they are "returned". Loaned
+ * buffers must be returned to the arc before they can be used by the DMU or
+ * freed.
+ */
+arc_buf_t *
+arc_loan_buf(spa_t *spa, uint64_t size)
+{
+       arc_buf_t *buf;
+
+       buf = arc_buf_alloc(spa, size, arc_onloan_tag, ARC_BUFC_DATA);
+
+       atomic_add_64(&arc_loaned_bytes, size);
+       return (buf);
+}
+
+/*
+ * Return a loaned arc buffer to the arc.
+ */
+void
+arc_return_buf(arc_buf_t *buf, void *tag)
+{
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+
+       ASSERT(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);
+}
+
+/* Detach an arc_buf from a dbuf (tag) */
+void
+arc_loan_inuse_buf(arc_buf_t *buf, void *tag)
+{
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+
+       ASSERT(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);
+}
+
+static arc_buf_t *
+arc_buf_clone(arc_buf_t *from)
+{
+       arc_buf_t *buf;
+       arc_buf_hdr_t *hdr = from->b_hdr;
+       uint64_t size = hdr->b_size;
+
+       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);
+
+       /*
+        * 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.
+        */
+       if (HDR_ISTYPE_DATA(hdr)) {
+               ARCSTAT_BUMP(arcstat_duplicate_buffers);
+               ARCSTAT_INCR(arcstat_duplicate_buffers_size, size);
+       }
+       hdr->b_l1hdr.b_datacnt += 1;
+       return (buf);
+}
+
+void
+arc_buf_add_ref(arc_buf_t *buf, void* tag)
+{
+       arc_buf_hdr_t *hdr;
+       kmutex_t *hash_lock;
+
+       /*
+        * Check to see if this buffer is evicted.  Callers
+        * must verify b_data != NULL to know if the add_ref
+        * was successful.
+        */
+       mutex_enter(&buf->b_evict_lock);
+       if (buf->b_data == NULL) {
+               mutex_exit(&buf->b_evict_lock);
+               return;
+       }
+       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);
+
+       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);
+}
+
+static void
+arc_buf_free_on_write(void *data, size_t size,
+    void (*free_func)(void *, size_t))
+{
+       l2arc_data_free_t *df;
+
+       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);
+}
+
+/*
+ * 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_buf_hdr_t *hdr = buf->b_hdr;
+
+       if (HDR_L2_WRITING(hdr)) {
+               arc_buf_free_on_write(buf->b_data, hdr->b_size, free_func);
+               ARCSTAT_BUMP(arcstat_l2_free_on_write);
+       } else {
+               free_func(buf->b_data, hdr->b_size);
+       }
+}
+
+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));
+
+       /*
+        * 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).
+        */
+       if (!HDR_HAS_L1HDR(hdr))
+               return;
+
+       /*
+        * 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;
+       }
+
+       /*
+        * 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).
+        */
+       if (hdr->b_l2hdr.b_compress == ZIO_COMPRESS_OFF) {
+               hdr->b_l1hdr.b_tmp_cdata = NULL;
+               return;
+       }
+
+       /*
+        * There's nothing to free since the buffer was all zero's and
+        * compressed to a zero length buffer.
+        */
+       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));
+
+       arc_buf_free_on_write(hdr->b_l1hdr.b_tmp_cdata,
+           hdr->b_size, zio_data_buf_free);
+
+       ARCSTAT_BUMP(arcstat_l2_cdata_free_on_write);
+       hdr->b_l1hdr.b_tmp_cdata = NULL;
+}
+
+/*
+ * 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.
+ */
+static void
+arc_buf_destroy(arc_buf_t *buf, boolean_t remove)
+{
+       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);
+               }
+
+               (void) refcount_remove_many(&state->arcs_size, size, buf);
+               buf->b_data = NULL;
+
+               /*
+                * 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;
+       }
+
+       /* only remove the buf if requested */
+       if (!remove)
+               return;
+
+       /* 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;
+
+       ASSERT(buf->b_efunc == NULL);
+
+       /* clean up the buf */
+       buf->b_hdr = NULL;
+       kmem_cache_free(buf_cache, buf);
+}
+
+static void
+arc_hdr_l2hdr_destroy(arc_buf_hdr_t *hdr)
+{
+       l2arc_buf_hdr_t *l2hdr = &hdr->b_l2hdr;
+       l2arc_dev_t *dev = l2hdr->b_dev;
+
+       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);
+
+               (void) refcount_remove_many(&dev->l2ad_alloc,
+                   l2hdr->b_asize, hdr);
+       }
+
+       hdr->b_flags &= ~ARC_FLAG_HAS_L2HDR;
+}
+
+static void
+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);
+               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_HAS_L2HDR(hdr)) {
+               l2arc_dev_t *dev = hdr->b_l2hdr.b_dev;
+               boolean_t buflist_held = MUTEX_HELD(&dev->l2ad_mtx);
+
+               if (!buflist_held)
+                       mutex_enter(&dev->l2ad_mtx);
+
+               /*
+                * Even though we checked this conditional above, we
+                * need to check this again now that we have the
+                * l2ad_mtx. This is because we could be racing with
+                * another thread calling l2arc_evict() which might have
+                * destroyed this header's L2 portion as we were waiting
+                * to acquire the l2ad_mtx. If that happens, we don't
+                * want to re-destroy the header's L2 portion.
+                */
+               if (HDR_HAS_L2HDR(hdr))
+                       arc_hdr_l2hdr_destroy(hdr);
+
+               if (!buflist_held)
+                       mutex_exit(&dev->l2ad_mtx);
+       }
+
+       if (!BUF_EMPTY(hdr))
+               buf_discard_identity(hdr);
+
+       if (hdr->b_freeze_cksum != NULL) {
+               kmem_free(hdr->b_freeze_cksum, sizeof (zio_cksum_t));
+               hdr->b_freeze_cksum = NULL;
+       }
+
+       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);
+                       }
+               }
+       }
+
+       ASSERT3P(hdr->b_hash_next, ==, NULL);
+       if (HDR_HAS_L1HDR(hdr)) {
+               ASSERT(!multilist_link_active(&hdr->b_l1hdr.b_arc_node));
+               ASSERT3P(hdr->b_l1hdr.b_acb, ==, NULL);
+               kmem_cache_free(hdr_full_cache, hdr);
+       } else {
+               kmem_cache_free(hdr_l2only_cache, 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_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);
+       }
+
+       mutex_enter(hash_lock);
+       hdr = buf->b_hdr;
+       ASSERT(hdr->b_l1hdr.b_datacnt > 0);
+       ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
+       ASSERT(hdr->b_l1hdr.b_state != arc_anon);
+       ASSERT(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));
+       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);
+}
+
+/*
+ * Evict the arc_buf_hdr that is provided as a parameter. The resultant
+ * state of the header is dependent on its state prior to entering this
+ * function. The following transitions are possible:
+ *
+ *    - arc_mru -> arc_mru_ghost
+ *    - arc_mfu -> arc_mfu_ghost
+ *    - arc_mru_ghost -> arc_l2c_only
+ *    - arc_mru_ghost -> deleted
+ *    - arc_mfu_ghost -> arc_l2c_only
+ *    - arc_mfu_ghost -> deleted
+ */
+static int64_t
+arc_evict_hdr(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
+{
+       arc_state_t *evicted_state, *state;
+       int64_t bytes_evicted = 0;
+
+       ASSERT(MUTEX_HELD(hash_lock));
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
+       state = hdr->b_l1hdr.b_state;
+       if (GHOST_STATE(state)) {
+               ASSERT(!HDR_IO_IN_PROGRESS(hdr));
+               ASSERT(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.
+                * 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.
+                */
+               if (HDR_HAS_L2HDR(hdr) && HDR_L2_WRITING(hdr)) {
+                       ARCSTAT_BUMP(arcstat_evict_l2_skip);
+                       return (bytes_evicted);
+               }
+
+               ARCSTAT_BUMP(arcstat_deleted);
+               bytes_evicted += hdr->b_size;
+
+               DTRACE_PROBE1(arc__delete, arc_buf_hdr_t *, hdr);
+
+               if (HDR_HAS_L2HDR(hdr)) {
+                       /*
+                        * This buffer is cached on the 2nd Level ARC;
+                        * don't destroy the header.
+                        */
+                       arc_change_state(arc_l2c_only, hdr, hash_lock);
+                       /*
+                        * dropping from L1+L2 cached to L2-only,
+                        * realloc to remove the L1 header.
+                        */
+                       hdr = arc_hdr_realloc(hdr, hdr_full_cache,
+                           hdr_l2only_cache);
+               } else {
+                       arc_change_state(arc_anon, hdr, hash_lock);
+                       arc_hdr_destroy(hdr);
+               }
+               return (bytes_evicted);
+       }
+
+       ASSERT(state == arc_mru || state == arc_mfu);
+       evicted_state = (state == arc_mru) ? arc_mru_ghost : arc_mfu_ghost;
+
+       /* prefetch buffers have a minimum lifespan */
+       if (HDR_IO_IN_PROGRESS(hdr) ||
+           ((hdr->b_flags & (ARC_FLAG_PREFETCH | ARC_FLAG_INDIRECT)) &&
+           ddi_get_lbolt() - hdr->b_l1hdr.b_arc_access <
+           arc_min_prefetch_lifespan)) {
+               ARCSTAT_BUMP(arcstat_evict_skip);
+               return (bytes_evicted);
+       }
+
+       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)) {
+                       ARCSTAT_BUMP(arcstat_mutex_miss);
+                       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);
+               }
+       }
+
+       if (HDR_HAS_L2HDR(hdr)) {
+               ARCSTAT_INCR(arcstat_evict_l2_cached, hdr->b_size);
+       } 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 (hdr->b_l1hdr.b_datacnt == 0) {
+               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;
+               DTRACE_PROBE1(arc__evict, arc_buf_hdr_t *, hdr);
+       }
+
+       return (bytes_evicted);
+}
+
+static uint64_t
+arc_evict_state_impl(multilist_t *ml, int idx, arc_buf_hdr_t *marker,
+    uint64_t spa, int64_t bytes)
+{
+       multilist_sublist_t *mls;
+       uint64_t bytes_evicted = 0;
+       arc_buf_hdr_t *hdr;
+       kmutex_t *hash_lock;
+       int evict_count = 0;
+
+       ASSERT3P(marker, !=, NULL);
+       IMPLY(bytes < 0, bytes == ARC_EVICT_ALL);
+
+       mls = multilist_sublist_lock(ml, idx);
+
+       for (hdr = multilist_sublist_prev(mls, marker); hdr != NULL;
+           hdr = multilist_sublist_prev(mls, marker)) {
+               if ((bytes != ARC_EVICT_ALL && bytes_evicted >= bytes) ||
+                   (evict_count >= zfs_arc_evict_batch_limit))
+                       break;
+
+               /*
+                * To keep our iteration location, move the marker
+                * forward. Since we're not holding hdr's hash lock, we
+                * must be very careful and not remove 'hdr' from the
+                * sublist. Otherwise, other consumers might mistake the
+                * 'hdr' as not being on a sublist when they call the
+                * multilist_link_active() function (they all rely on
+                * the hash lock protecting concurrent insertions and
+                * removals). multilist_sublist_move_forward() was
+                * specifically implemented to ensure this is the case
+                * (only 'marker' will be removed and re-inserted).
+                */
+               multilist_sublist_move_forward(mls, marker);
+
+               /*
+                * The only case where the b_spa field should ever be
+                * zero, is the marker headers inserted by
+                * arc_evict_state(). It's possible for multiple threads
+                * to be calling arc_evict_state() concurrently (e.g.
+                * dsl_pool_close() and zio_inject_fault()), so we must
+                * skip any markers we see from these other threads.
+                */
+               if (hdr->b_spa == 0)
+                       continue;
+
+               /* we're only interested in evicting buffers of a certain spa */
+               if (spa != 0 && hdr->b_spa != spa) {
+                       ARCSTAT_BUMP(arcstat_evict_skip);
+                       continue;
+               }
+
+               hash_lock = HDR_LOCK(hdr);
+
+               /*
+                * We aren't calling this function from any code path
+                * that would already be holding a hash lock, so we're
+                * asserting on this assumption to be defensive in case
+                * this ever changes. Without this check, it would be
+                * possible to incorrectly increment arcstat_mutex_miss
+                * below (e.g. if the code changed such that we called
+                * this function with a hash lock held).
+                */
+               ASSERT(!MUTEX_HELD(hash_lock));
+
+               if (mutex_tryenter(hash_lock)) {
+                       uint64_t evicted = arc_evict_hdr(hdr, hash_lock);
+                       mutex_exit(hash_lock);
+
+                       bytes_evicted += evicted;
+
+                       /*
+                        * If evicted is zero, arc_evict_hdr() must have
+                        * decided to skip this header, don't increment
+                        * evict_count in this case.
+                        */
+                       if (evicted != 0)
+                               evict_count++;
+
+                       /*
+                        * If arc_size isn't overflowing, signal any
+                        * threads that might happen to be waiting.
+                        *
+                        * For each header evicted, we wake up a single
+                        * thread. If we used cv_broadcast, we could
+                        * wake up "too many" threads causing arc_size
+                        * to significantly overflow arc_c; since
+                        * arc_get_data_buf() doesn't check for overflow
+                        * when it's woken up (it doesn't because it's
+                        * possible for the ARC to be overflowing while
+                        * full of un-evictable buffers, and the
+                        * function should proceed in this case).
+                        *
+                        * If threads are left sleeping, due to not
+                        * using cv_broadcast, they will be woken up
+                        * just before arc_reclaim_thread() sleeps.
+                        */
+                       mutex_enter(&arc_reclaim_lock);
+                       if (!arc_is_overflowing())
+                               cv_signal(&arc_reclaim_waiters_cv);
+                       mutex_exit(&arc_reclaim_lock);
+               } else {
+                       ARCSTAT_BUMP(arcstat_mutex_miss);
+               }
+       }
+
+       multilist_sublist_unlock(mls);
+
+       return (bytes_evicted);
+}
+
+/*
+ * Evict buffers from the given arc state, until we've removed the
+ * specified number of bytes. Move the removed buffers to the
+ * appropriate evict state.
+ *
+ * This function makes a "best effort". It skips over any buffers
+ * it can't get a hash_lock on, and so, may not catch all candidates.
+ * It may also return without evicting as much space as requested.
+ *
+ * If bytes is specified using the special value ARC_EVICT_ALL, this
+ * will evict all available (i.e. unlocked and evictable) buffers from
+ * the given arc state; which is used by arc_flush().
+ */
+static uint64_t
+arc_evict_state(arc_state_t *state, uint64_t spa, int64_t bytes,
+    arc_buf_contents_t type)
+{
+       uint64_t total_evicted = 0;
+       multilist_t *ml = &state->arcs_list[type];
+       int num_sublists;
+       arc_buf_hdr_t **markers;
+       int i;
+
+       IMPLY(bytes < 0, bytes == ARC_EVICT_ALL);
+
+       num_sublists = multilist_get_num_sublists(ml);
+
+       /*
+        * If we've tried to evict from each sublist, made some
+        * progress, but still have not hit the target number of bytes
+        * to evict, we want to keep trying. The markers allow us to
+        * pick up where we left off for each individual sublist, rather
+        * than starting from the tail each time.
+        */
+       markers = kmem_zalloc(sizeof (*markers) * num_sublists, KM_SLEEP);
+       for (i = 0; i < num_sublists; i++) {
+               multilist_sublist_t *mls;
+
+               markers[i] = kmem_cache_alloc(hdr_full_cache, KM_SLEEP);
+
+               /*
+                * A b_spa of 0 is used to indicate that this header is
+                * a marker. This fact is used in arc_adjust_type() and
+                * arc_evict_state_impl().
+                */
+               markers[i]->b_spa = 0;
+
+               mls = multilist_sublist_lock(ml, i);
+               multilist_sublist_insert_tail(mls, markers[i]);
+               multilist_sublist_unlock(mls);
+       }
+
+       /*
+        * While we haven't hit our target number of bytes to evict, or
+        * we're evicting all available buffers.
+        */
+       while (total_evicted < bytes || bytes == ARC_EVICT_ALL) {
+               /*
+                * Start eviction using a randomly selected sublist,
+                * this is to try and evenly balance eviction across all
+                * sublists. Always starting at the same sublist
+                * (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;
+
+                       if (bytes == ARC_EVICT_ALL)
+                               bytes_remaining = ARC_EVICT_ALL;
+                       else if (total_evicted < bytes)
+                               bytes_remaining = bytes - total_evicted;
+                       else
+                               break;
+
+                       bytes_evicted = arc_evict_state_impl(ml, sublist_idx,
+                           markers[sublist_idx], spa, bytes_remaining);
+
+                       scan_evicted += bytes_evicted;
+                       total_evicted += bytes_evicted;
+
+                       /* we've reached the end, wrap to the beginning */
+                       if (++sublist_idx >= num_sublists)
+                               sublist_idx = 0;
+               }
+
+               /*
+                * If we didn't evict anything during this scan, we have
+                * no reason to believe we'll evict more during another
+                * scan, so break the loop.
+                */
+               if (scan_evicted == 0) {
+                       /* This isn't possible, let's make that obvious */
+                       ASSERT3S(bytes, !=, 0);
+
+                       /*
+                        * When bytes is ARC_EVICT_ALL, the only way to
+                        * break the loop is when scan_evicted is zero.
+                        * In that case, we actually have evicted enough,
+                        * so we don't want to increment the kstat.
+                        */
+                       if (bytes != ARC_EVICT_ALL) {
+                               ASSERT3S(total_evicted, <, bytes);
+                               ARCSTAT_BUMP(arcstat_evict_not_enough);
+                       }
+
+                       break;
+               }
+       }
+
+       for (i = 0; i < num_sublists; i++) {
+               multilist_sublist_t *mls = multilist_sublist_lock(ml, i);
+               multilist_sublist_remove(mls, markers[i]);
+               multilist_sublist_unlock(mls);
+
+               kmem_cache_free(hdr_full_cache, markers[i]);
+       }
+       kmem_free(markers, sizeof (*markers) * num_sublists);
+
+       return (total_evicted);
+}
+
+/*
+ * 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
+ * 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
+ * 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
+ * wind up in an infinite loop, continually trying to evict buffers.
+ */
+static uint64_t
+arc_flush_state(arc_state_t *state, uint64_t spa, arc_buf_contents_t type,
+    boolean_t retry)
+{
+       uint64_t evicted = 0;
+
+       while (state->arcs_lsize[type] != 0) {
+               evicted += arc_evict_state(state, spa, ARC_EVICT_ALL, type);
+
+               if (!retry)
+                       break;
+       }
+
+       return (evicted);
+}
+
+/*
+ * Helper function for arc_prune_async() it is responsible for safely
+ * handling the execution of a registered arc_prune_func_t.
+ */
+static void
+arc_prune_task(void *ptr)
+{
+       arc_prune_t *ap = (arc_prune_t *)ptr;
+       arc_prune_func_t *func = ap->p_pfunc;
+
+       if (func != NULL)
+               func(ap->p_adjust, ap->p_private);
+
+       refcount_remove(&ap->p_refcnt, func);
+}
+
+/*
+ * Notify registered consumers they must drop holds on a portion of the ARC
+ * buffered they reference.  This provides a mechanism to ensure the ARC can
+ * honor the arc_meta_limit and reclaim otherwise pinned ARC buffers.  This
+ * is analogous to dnlc_reduce_cache() but more generic.
+ *
+ * This operation is performed asynchronously so it may be safely called
+ * in the context of the arc_reclaim_thread().  A reference is taken here
+ * for each registered arc_prune_t and the arc_prune_task() is responsible
+ * for releasing it once the registered arc_prune_func_t has completed.
+ */
+static void
+arc_prune_async(int64_t adjust)
+{
+       arc_prune_t *ap;
+
+       mutex_enter(&arc_prune_mtx);
+       for (ap = list_head(&arc_prune_list); ap != NULL;
+           ap = list_next(&arc_prune_list, ap)) {
+
+               if (refcount_count(&ap->p_refcnt) >= 2)
+                       continue;
+
+               refcount_add(&ap->p_refcnt, ap->p_pfunc);
+               ap->p_adjust = adjust;
+               taskq_dispatch(arc_prune_taskq, arc_prune_task, ap, TQ_SLEEP);
+               ARCSTAT_BUMP(arcstat_prune);
+       }
+       mutex_exit(&arc_prune_mtx);
+}
+
+/*
+ * Evict the specified number of bytes from the state specified,
+ * restricting eviction to the spa and type given. This function
+ * prevents us from trying to evict more from a state's list than
+ * is "evictable", and to skip evicting altogether when passed a
+ * negative value for "bytes". In contrast, arc_evict_state() will
+ * evict everything it can, when passed a negative value for "bytes".
+ */
+static uint64_t
+arc_adjust_impl(arc_state_t *state, uint64_t spa, int64_t bytes,
+    arc_buf_contents_t type)
+{
+       int64_t delta;
+
+       if (bytes > 0 && state->arcs_lsize[type] > 0) {
+               delta = MIN(state->arcs_lsize[type], bytes);
+               return (arc_evict_state(state, spa, delta, type));
+       }
+
+       return (0);
+}
+
+/*
+ * The goal of this function is to evict enough meta data buffers from the
+ * ARC in order to enforce the arc_meta_limit.  Achieving this is slightly
+ * more complicated than it appears because it is common for data buffers
+ * to have holds on meta data buffers.  In addition, dnode meta data buffers
+ * will be held by the dnodes in the block preventing them from being freed.
+ * This means we can't simply traverse the ARC and expect to always find
+ * enough unheld meta data buffer to release.
+ *
+ * Therefore, this function has been updated to make alternating passes
+ * over the ARC releasing data buffers and then newly unheld meta data
+ * buffers.  This ensures forward progress is maintained and arc_meta_used
+ * will decrease.  Normally this is sufficient, but if required the ARC
+ * will call the registered prune callbacks causing dentry and inodes to
+ * be dropped from the VFS cache.  This will make dnode meta data buffers
+ * available for reclaim.
+ */
+static uint64_t
+arc_adjust_meta_balanced(void)
+{
+       int64_t adjustmnt, delta, prune = 0;
+       uint64_t total_evicted = 0;
+       arc_buf_contents_t type = ARC_BUFC_DATA;
+       int restarts = MAX(zfs_arc_meta_adjust_restarts, 0);
+
+restart:
+       /*
+        * This slightly differs than the way we evict from the mru in
+        * arc_adjust because we don't have a "target" value (i.e. no
+        * "meta" arc_p). As a result, I think we can completely
+        * cannibalize the metadata in the MRU before we evict the
+        * metadata from the MFU. I think we probably need to implement a
+        * "metadata arc_p" value to do this properly.
+        */
+       adjustmnt = arc_meta_used - arc_meta_limit;
+
+       if (adjustmnt > 0 && arc_mru->arcs_lsize[type] > 0) {
+               delta = MIN(arc_mru->arcs_lsize[type], adjustmnt);
+               total_evicted += arc_adjust_impl(arc_mru, 0, delta, type);
+               adjustmnt -= delta;
+       }
+
+       /*
+        * We can't afford to recalculate adjustmnt here. If we do,
+        * new metadata buffers can sneak into the MRU or ANON lists,
+        * thus penalize the MFU metadata. Although the fudge factor is
+        * small, it has been empirically shown to be significant for
+        * certain workloads (e.g. creating many empty directories). As
+        * such, we use the original calculation for adjustmnt, and
+        * 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);
+               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) {
+               delta = MIN(adjustmnt,
+                   arc_mru_ghost->arcs_lsize[type]);
+               total_evicted += arc_adjust_impl(arc_mru_ghost, 0, delta, type);
+               adjustmnt -= delta;
+       }
+
+       if (adjustmnt > 0 && arc_mfu_ghost->arcs_lsize[type] > 0) {
+               delta = MIN(adjustmnt,
+                   arc_mfu_ghost->arcs_lsize[type]);
+               total_evicted += arc_adjust_impl(arc_mfu_ghost, 0, delta, type);
+       }
+
+       /*
+        * If after attempting to make the requested adjustment to the ARC
+        * the meta limit is still being exceeded then request that the
+        * higher layers drop some cached objects which have holds on ARC
+        * meta buffers.  Requests to the upper layers will be made with
+        * increasingly large scan sizes until the ARC is below the limit.
+        */
+       if (arc_meta_used > arc_meta_limit) {
+               if (type == ARC_BUFC_DATA) {
+                       type = ARC_BUFC_METADATA;
+               } else {
+                       type = ARC_BUFC_DATA;
+
+                       if (zfs_arc_meta_prune) {
+                               prune += zfs_arc_meta_prune;
+                               arc_prune_async(prune);
+                       }
+               }
+
+               if (restarts > 0) {
+                       restarts--;
+                       goto restart;
+               }
+       }
+       return (total_evicted);
+}
+
+/*
+ * Evict metadata buffers from the cache, such that arc_meta_used is
+ * capped by the arc_meta_limit tunable.
+ */
+static uint64_t
+arc_adjust_meta_only(void)
+{
+       uint64_t total_evicted = 0;
+       int64_t target;
+
+       /*
+        * If we're over the meta limit, we want to evict enough
+        * metadata to get back under the meta limit. We don't want to
+        * evict so much that we drop the MRU below arc_p, though. If
+        * we're over the meta limit more than we're over arc_p, we
+        * evict some from the MRU here, and some from the MFU below.
+        */
+       target = MIN((int64_t)(arc_meta_used - arc_meta_limit),
+           (int64_t)(refcount_count(&arc_anon->arcs_size) +
+           refcount_count(&arc_mru->arcs_size) - arc_p));
+
+       total_evicted += arc_adjust_impl(arc_mru, 0, target, ARC_BUFC_METADATA);
+
+       /*
+        * 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).
+        */
+       target = MIN((int64_t)(arc_meta_used - arc_meta_limit),
+           (int64_t)(refcount_count(&arc_mfu->arcs_size) - (arc_c - arc_p)));
+
+       total_evicted += arc_adjust_impl(arc_mfu, 0, target, ARC_BUFC_METADATA);
+
+       return (total_evicted);
+}
+
+static uint64_t
+arc_adjust_meta(void)
+{
+       if (zfs_arc_meta_strategy == ARC_STRATEGY_META_ONLY)
+               return (arc_adjust_meta_only());
+       else
+               return (arc_adjust_meta_balanced());
+}
+
+/*
+ * Return the type of the oldest buffer in the given arc state
+ *
+ * This function will select a random sublist of type ARC_BUFC_DATA and
+ * a random sublist of type ARC_BUFC_METADATA. The tail of each sublist
+ * is compared, and the type which contains the "older" buffer will be
+ * returned.
+ */
+static arc_buf_contents_t
+arc_adjust_type(arc_state_t *state)
+{
+       multilist_t *data_ml = &state->arcs_list[ARC_BUFC_DATA];
+       multilist_t *meta_ml = &state->arcs_list[ARC_BUFC_METADATA];
+       int data_idx = multilist_get_random_index(data_ml);
+       int meta_idx = multilist_get_random_index(meta_ml);
+       multilist_sublist_t *data_mls;
+       multilist_sublist_t *meta_mls;
+       arc_buf_contents_t type;
+       arc_buf_hdr_t *data_hdr;
+       arc_buf_hdr_t *meta_hdr;
+
+       /*
+        * We keep the sublist lock until we're finished, to prevent
+        * the headers from being destroyed via arc_evict_state().
+        */
+       data_mls = multilist_sublist_lock(data_ml, data_idx);
+       meta_mls = multilist_sublist_lock(meta_ml, meta_idx);
+
+       /*
+        * These two loops are to ensure we skip any markers that
+        * might be at the tail of the lists due to arc_evict_state().
+        */
+
+       for (data_hdr = multilist_sublist_tail(data_mls); data_hdr != NULL;
+           data_hdr = multilist_sublist_prev(data_mls, data_hdr)) {
+               if (data_hdr->b_spa != 0)
+                       break;
+       }
+
+       for (meta_hdr = multilist_sublist_tail(meta_mls); meta_hdr != NULL;
+           meta_hdr = multilist_sublist_prev(meta_mls, meta_hdr)) {
+               if (meta_hdr->b_spa != 0)
+                       break;
+       }
+
+       if (data_hdr == NULL && meta_hdr == NULL) {
+               type = ARC_BUFC_DATA;
+       } else if (data_hdr == NULL) {
+               ASSERT3P(meta_hdr, !=, NULL);
+               type = ARC_BUFC_METADATA;
+       } else if (meta_hdr == NULL) {
+               ASSERT3P(data_hdr, !=, NULL);
+               type = ARC_BUFC_DATA;
+       } else {
+               ASSERT3P(data_hdr, !=, NULL);
+               ASSERT3P(meta_hdr, !=, NULL);
+
+               /* The headers can't be on the sublist without an L1 header */
+               ASSERT(HDR_HAS_L1HDR(data_hdr));
+               ASSERT(HDR_HAS_L1HDR(meta_hdr));
+
+               if (data_hdr->b_l1hdr.b_arc_access <
+                   meta_hdr->b_l1hdr.b_arc_access) {
+                       type = ARC_BUFC_DATA;
+               } else {
+                       type = ARC_BUFC_METADATA;
+               }
+       }
+
+       multilist_sublist_unlock(meta_mls);
+       multilist_sublist_unlock(data_mls);
+
+       return (type);
+}
+
+/*
+ * Evict buffers from the cache, such that arc_size is capped by arc_c.
+ */
+static uint64_t
+arc_adjust(void)
+{
+       uint64_t total_evicted = 0;
+       uint64_t bytes;
+       int64_t target;
+
+       /*
+        * If we're over arc_meta_limit, we want to correct that before
+        * potentially evicting data buffers below.
+        */
+       total_evicted += arc_adjust_meta();
+
+       /*
+        * Adjust MRU size
+        *
+        * If we're over the target cache size, we want to evict enough
+        * from the list to get back to our target size. We don't want
+        * to evict too much from the MRU, such that it drops below
+        * arc_p. So, if we're over our target cache size more than
+        * the MRU is over arc_p, we'll evict enough to get back to
+        * arc_p here, and then evict more from the MFU below.
+        */
+       target = MIN((int64_t)(arc_size - arc_c),
+           (int64_t)(refcount_count(&arc_anon->arcs_size) +
+           refcount_count(&arc_mru->arcs_size) + arc_meta_used - arc_p));
+
+       /*
+        * If we're below arc_meta_min, always prefer to evict data.
+        * Otherwise, try to satisfy the requested number of bytes to
+        * evict from the type which contains older buffers; in an
+        * effort to keep newer buffers in the cache regardless of their
+        * type. If we cannot satisfy the number of bytes from this
+        * type, spill over into the next type.
+        */
+       if (arc_adjust_type(arc_mru) == ARC_BUFC_METADATA &&
+           arc_meta_used > arc_meta_min) {
+               bytes = arc_adjust_impl(arc_mru, 0, target, ARC_BUFC_METADATA);
+               total_evicted += bytes;
+
+               /*
+                * If we couldn't evict our target number of bytes from
+                * metadata, we try to get the rest from data.
+                */
+               target -= bytes;
+
+               total_evicted +=
+                   arc_adjust_impl(arc_mru, 0, target, ARC_BUFC_DATA);
+       } else {
+               bytes = arc_adjust_impl(arc_mru, 0, target, ARC_BUFC_DATA);
+               total_evicted += bytes;
+
+               /*
+                * If we couldn't evict our target number of bytes from
+                * data, we try to get the rest from metadata.
+                */
+               target -= bytes;
+
+               total_evicted +=
+                   arc_adjust_impl(arc_mru, 0, target, ARC_BUFC_METADATA);
+       }
+
+       /*
+        * Adjust MFU size
+        *
+        * Now that we've tried to evict enough from the MRU to get its
+        * size back to arc_p, if we're still above the target cache
+        * size, we evict the rest from the MFU.
+        */
+       target = arc_size - arc_c;
+
+       if (arc_adjust_type(arc_mfu) == ARC_BUFC_METADATA &&
+           arc_meta_used > arc_meta_min) {
+               bytes = arc_adjust_impl(arc_mfu, 0, target, ARC_BUFC_METADATA);
+               total_evicted += bytes;
+
+               /*
+                * If we couldn't evict our target number of bytes from
+                * metadata, we try to get the rest from data.
+                */
+               target -= bytes;
+
+               total_evicted +=
+                   arc_adjust_impl(arc_mfu, 0, target, ARC_BUFC_DATA);
+       } else {
+               bytes = arc_adjust_impl(arc_mfu, 0, target, ARC_BUFC_DATA);
+               total_evicted += bytes;
+
+               /*
+                * If we couldn't evict our target number of bytes from
+                * data, we try to get the rest from data.
+                */
+               target -= bytes;
+
+               total_evicted +=
+                   arc_adjust_impl(arc_mfu, 0, target, ARC_BUFC_METADATA);
+       }
+
+       /*
+        * Adjust ghost lists
+        *
+        * In addition to the above, the ARC also defines target values
+        * for the ghost lists. The sum of the mru list and mru ghost
+        * list should never exceed the target size of the cache, and
+        * the sum of the mru list, mfu list, mru ghost list, and mfu
+        * ghost list should never exceed twice the target size of the
+        * cache. The following logic enforces these limits on the ghost
+        * caches, and evicts from them as needed.
+        */
+       target = refcount_count(&arc_mru->arcs_size) +
+           refcount_count(&arc_mru_ghost->arcs_size) - arc_c;
+
+       bytes = arc_adjust_impl(arc_mru_ghost, 0, target, ARC_BUFC_DATA);
+       total_evicted += bytes;
+
+       target -= bytes;
+
+       total_evicted +=
+           arc_adjust_impl(arc_mru_ghost, 0, target, ARC_BUFC_METADATA);
+
+       /*
+        * We assume the sum of the mru list and mfu list is less than
+        * or equal to arc_c (we enforced this above), which means we
+        * can use the simpler of the two equations below:
+        *
+        *      mru + mfu + mru ghost + mfu ghost <= 2 * arc_c
+        *                  mru ghost + mfu ghost <= arc_c
+        */
+       target = refcount_count(&arc_mru_ghost->arcs_size) +
+           refcount_count(&arc_mfu_ghost->arcs_size) - arc_c;
+
+       bytes = arc_adjust_impl(arc_mfu_ghost, 0, target, ARC_BUFC_DATA);
+       total_evicted += bytes;
+
+       target -= bytes;
+
+       total_evicted +=
+           arc_adjust_impl(arc_mfu_ghost, 0, target, ARC_BUFC_METADATA);
+
+       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
+        * no good way to determine if all of a spa's buffers have been
+        * evicted from an arc state.
+        */
+       ASSERT(!retry || spa == 0);
+
+       if (spa != NULL)
+               guid = spa_load_guid(spa);
+
+       (void) arc_flush_state(arc_mru, guid, ARC_BUFC_DATA, retry);
+       (void) arc_flush_state(arc_mru, guid, ARC_BUFC_METADATA, retry);
+
+       (void) arc_flush_state(arc_mfu, guid, ARC_BUFC_DATA, retry);
+       (void) arc_flush_state(arc_mfu, guid, ARC_BUFC_METADATA, retry);
+
+       (void) arc_flush_state(arc_mru_ghost, guid, ARC_BUFC_DATA, retry);
+       (void) arc_flush_state(arc_mru_ghost, guid, ARC_BUFC_METADATA, 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
+arc_shrink(int64_t to_free)
+{
+       uint64_t c = arc_c;
+
+       if (c > to_free && c - to_free > arc_c_min) {
+               arc_c = c - to_free;
+               atomic_add_64(&arc_p, -(arc_p >> arc_shrink_shift));
+               if (arc_c > arc_size)
+                       arc_c = MAX(arc_size, arc_c_min);
+               if (arc_p > arc_c)
+                       arc_p = (arc_c >> 1);
+               ASSERT(arc_c >= arc_c_min);
+               ASSERT((int64_t)arc_p >= 0);
+       } else {
+               arc_c = arc_c_min;
+       }
+
+       if (arc_size > arc_c)
+               (void) arc_adjust();
+}
+
+typedef enum free_memory_reason_t {
+       FMR_UNKNOWN,
+       FMR_NEEDFREE,
+       FMR_LOTSFREE,
+       FMR_SWAPFS_MINFREE,
+       FMR_PAGES_PP_MAXIMUM,
+       FMR_HEAP_ARENA,
+       FMR_ZIO_ARENA,
+} free_memory_reason_t;
+
+int64_t last_free_memory;
+free_memory_reason_t last_free_reason;
+
+#ifdef _KERNEL
+/*
+ * Additional reserve of pages for pp_reserve.
+ */
+int64_t arc_pages_pp_reserve = 64;
+
+/*
+ * Additional reserve of pages for swapfs.
+ */
+int64_t arc_swapfs_reserve = 64;
+#endif /* _KERNEL */
+
+/*
+ * Return the amount of memory that can be consumed before reclaim will be
+ * needed.  Positive if there is sufficient free memory, negative indicates
+ * the amount of memory that needs to be freed up.
+ */
+static int64_t
+arc_available_memory(void)
+{
+       int64_t lowest = INT64_MAX;
+       free_memory_reason_t r = FMR_UNKNOWN;
+#ifdef _KERNEL
+       int64_t n;
+#ifdef __linux__
+       pgcnt_t needfree = btop(arc_need_free);
+       pgcnt_t lotsfree = btop(arc_sys_free);
+       pgcnt_t desfree = 0;
+#endif
+
+       if (needfree > 0) {
+               n = PAGESIZE * (-needfree);
+               if (n < lowest) {
+                       lowest = n;
+                       r = FMR_NEEDFREE;
+               }
+       }
+
+       /*
+        * check that we're out of range of the pageout scanner.  It starts to
+        * schedule paging if freemem is less than lotsfree and needfree.
+        * lotsfree is the high-water mark for pageout, and needfree is the
+        * number of needed free pages.  We add extra pages here to make sure
+        * the scanner doesn't start up while we're freeing memory.
+        */
+       n = PAGESIZE * (freemem - lotsfree - needfree - desfree);
+       if (n < lowest) {
+               lowest = n;
+               r = FMR_LOTSFREE;
+       }
+
+#ifndef __linux__
+       /*
+        * check to make sure that swapfs has enough space so that anon
+        * reservations can still succeed. anon_resvmem() checks that the
+        * availrmem is greater than swapfs_minfree, and the number of reserved
+        * swap pages.  We also add a bit of extra here just to prevent
+        * circumstances from getting really dire.
+        */
+       n = PAGESIZE * (availrmem - swapfs_minfree - swapfs_reserve -
+           desfree - arc_swapfs_reserve);
+       if (n < lowest) {
+               lowest = n;
+               r = FMR_SWAPFS_MINFREE;
+       }
+
+
+       /*
+        * Check that we have enough availrmem that memory locking (e.g., via
+        * mlock(3C) or memcntl(2)) can still succeed.  (pages_pp_maximum
+        * stores the number of pages that cannot be locked; when availrmem
+        * drops below pages_pp_maximum, page locking mechanisms such as
+        * page_pp_lock() will fail.)
+        */
+       n = PAGESIZE * (availrmem - pages_pp_maximum -
+           arc_pages_pp_reserve);
+       if (n < lowest) {
+               lowest = n;
+               r = FMR_PAGES_PP_MAXIMUM;
+       }
+#endif
+
+#if defined(__i386)
+       /*
+        * If we're on an i386 platform, it's possible that we'll exhaust the
+        * kernel heap space before we ever run out of available physical
+        * memory.  Most checks of the size of the heap_area compare against
+        * tune.t_minarmem, which is the minimum available real memory that we
+        * can have in the system.  However, this is generally fixed at 25 pages
+        * which is so low that it's useless.  In this comparison, we seek to
+        * calculate the total heap-size, and reclaim if more than 3/4ths of the
+        * heap is allocated.  (Or, in the calculation, if less than 1/4th is
+        * free)
+        */
+       n = vmem_size(heap_arena, VMEM_FREE) -
+           (vmem_size(heap_arena, VMEM_FREE | VMEM_ALLOC) >> 2);
+       if (n < lowest) {
+               lowest = n;
+               r = FMR_HEAP_ARENA;
+       }
+#endif
+
+       /*
+        * 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.
+        *
+        * 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.
+        */
+       if (zio_arena != NULL) {
+               n = vmem_size(zio_arena, VMEM_FREE) -
+                   (vmem_size(zio_arena, VMEM_ALLOC) >> 4);
+               if (n < lowest) {
+                       lowest = n;
+                       r = FMR_ZIO_ARENA;
+               }
+       }
+#else /* _KERNEL */
+       /* Every 100 calls, free a small amount */
+       if (spa_get_random(100) == 0)
+               lowest = -1024;
+#endif /* _KERNEL */
+
+       last_free_memory = lowest;
+       last_free_reason = r;
+
+       return (lowest);
+}
+
+/*
+ * Determine if the system is under memory pressure and is asking
+ * to reclaim memory. A return value of TRUE indicates that the system
+ * is under memory pressure and that the arc should adjust accordingly.
+ */
+static boolean_t
+arc_reclaim_needed(void)
+{
+       return (arc_available_memory() < 0);
+}
+
+static void
+arc_kmem_reap_now(void)
+{
+       size_t                  i;
+       kmem_cache_t            *prev_cache = NULL;
+       kmem_cache_t            *prev_data_cache = NULL;
+       extern kmem_cache_t     *zio_buf_cache[];
+       extern kmem_cache_t     *zio_data_buf_cache[];
+       extern kmem_cache_t     *range_seg_cache;
+
+       if ((arc_meta_used >= arc_meta_limit) && zfs_arc_meta_prune) {
+               /*
+                * We are exceeding our meta-data cache limit.
+                * Prune some entries to release holds on meta-data.
+                */
+               arc_prune_async(zfs_arc_meta_prune);
+       }
+
+       for (i = 0; i < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; i++) {
+#ifdef _ILP32
+               /* reach upper limit of cache size on 32-bit */
+               if (zio_buf_cache[i] == NULL)
+                       break;
+#endif
+               if (zio_buf_cache[i] != prev_cache) {
+                       prev_cache = zio_buf_cache[i];
+                       kmem_cache_reap_now(zio_buf_cache[i]);
+               }
+               if (zio_data_buf_cache[i] != prev_data_cache) {
+                       prev_data_cache = zio_data_buf_cache[i];
+                       kmem_cache_reap_now(zio_data_buf_cache[i]);
+               }
+       }
+       kmem_cache_reap_now(buf_cache);
+       kmem_cache_reap_now(hdr_full_cache);
+       kmem_cache_reap_now(hdr_l2only_cache);
+       kmem_cache_reap_now(range_seg_cache);
+
+       if (zio_arena != NULL) {
+               /*
+                * Ask the vmem arena to reclaim unused memory from its
+                * quantum caches.
+                */
+               vmem_qcache_reap(zio_arena);
+       }
+}
+
+/*
+ * Threads can block in arc_get_data_buf() waiting for this thread to evict
+ * enough data and signal them to proceed. When this happens, the threads in
+ * arc_get_data_buf() are sleeping while holding the hash lock for their
+ * particular arc header. Thus, we must be careful to never sleep on a
+ * hash lock in this thread. This is to prevent the following deadlock:
+ *
+ *  - Thread A sleeps on CV in arc_get_data_buf() holding hash lock "L",
+ *    waiting for the reclaim thread to signal it.
+ *
+ *  - arc_reclaim_thread() tries to acquire hash lock "L" using mutex_enter,
+ *    fails, and goes to sleep forever.
+ *
+ * This possible deadlock is avoided by always acquiring a hash lock
+ * using mutex_tryenter() from arc_reclaim_thread().
+ */
+static void
+arc_reclaim_thread(void)
+{
+       fstrans_cookie_t        cookie = spl_fstrans_mark();
+       clock_t                 growtime = 0;
+       callb_cpr_t             cpr;
+
+       CALLB_CPR_INIT(&cpr, &arc_reclaim_lock, callb_generic_cpr, FTAG);
+
+       mutex_enter(&arc_reclaim_lock);
+       while (!arc_reclaim_thread_exit) {
+               int64_t to_free;
+               int64_t free_memory = arc_available_memory();
+               uint64_t evicted = 0;
+
+               arc_tuning_update();
+
+               mutex_exit(&arc_reclaim_lock);
+
+               if (free_memory < 0) {
+
+                       arc_no_grow = B_TRUE;
+                       arc_warm = B_TRUE;
+
+                       /*
+                        * Wait at least zfs_grow_retry (default 5) seconds
+                        * before considering growing.
+                        */
+                       growtime = ddi_get_lbolt() + (arc_grow_retry * hz);
+
+                       arc_kmem_reap_now();
+
+                       /*
+                        * If we are still low on memory, shrink the ARC
+                        * so that we have arc_shrink_min free space.
+                        */
+                       free_memory = arc_available_memory();
+
+                       to_free = (arc_c >> arc_shrink_shift) - free_memory;
+                       if (to_free > 0) {
+#ifdef _KERNEL
+                               to_free = MAX(to_free, arc_need_free);
+#endif
+                               arc_shrink(to_free);
+                       }
+               } else if (free_memory < arc_c >> arc_no_grow_shift) {
+                       arc_no_grow = B_TRUE;
+               } else if (ddi_get_lbolt() >= growtime) {
+                       arc_no_grow = B_FALSE;
+               }
+
+               evicted = arc_adjust();
+
+               mutex_enter(&arc_reclaim_lock);
+
+               /*
+                * If evicted is zero, we couldn't evict anything via
+                * arc_adjust(). This could be due to hash lock
+                * collisions, but more likely due to the majority of
+                * arc buffers being unevictable. Therefore, even if
+                * arc_size is above arc_c, another pass is unlikely to
+                * be helpful and could potentially cause us to enter an
+                * infinite loop.
+                */
+               if (arc_size <= arc_c || evicted == 0) {
+                       /*
+                        * We're either no longer overflowing, or we
+                        * can't evict anything more, so we should wake
+                        * up any threads before we go to sleep and clear
+                        * arc_need_free since nothing more can be done.
+                        */
+                       cv_broadcast(&arc_reclaim_waiters_cv);
+                       arc_need_free = 0;
+
+                       /*
+                        * Block until signaled, or after one second (we
+                        * might need to perform arc_kmem_reap_now()
+                        * 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);
+                       CALLB_CPR_SAFE_END(&cpr, &arc_reclaim_lock);
+               }
+       }
+
+       arc_reclaim_thread_exit = 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
+ * ARC. All clean data reported by the ghost lists can always be safely
+ * evicted. Due to arc_c_min, the same does not hold for all clean data
+ * contained by the regular mru and mfu lists.
+ *
+ * In the case of the regular mru and mfu lists, we need to report as
+ * much clean data as possible, such that evicting that same reported
+ * data will not bring arc_size below arc_c_min. Thus, in certain
+ * circumstances, the total amount of clean data in the mru and mfu
+ * lists might not actually be evictable.
+ *
+ * The following two distinct cases are accounted for:
+ *
+ * 1. The sum of the amount of dirty data contained by both the mru and
+ *    mfu lists, plus the ARC's other accounting (e.g. the anon list),
+ *    is greater than or equal to arc_c_min.
+ *    (i.e. amount of dirty data >= arc_c_min)
+ *
+ *    This is the easy case; all clean data contained by the mru and mfu
+ *    lists is evictable. Evicting all clean data can only drop arc_size
+ *    to the amount of dirty data, which is greater than arc_c_min.
+ *
+ * 2. The sum of the amount of dirty data contained by both the mru and
+ *    mfu lists, plus the ARC's other accounting (e.g. the anon list),
+ *    is less than arc_c_min.
+ *    (i.e. arc_c_min > amount of dirty data)
+ *
+ *    2.1. arc_size is greater than or equal arc_c_min.
+ *         (i.e. arc_size >= arc_c_min > amount of dirty data)
+ *
+ *         In this case, not all clean data from the regular mru and mfu
+ *         lists is actually evictable; we must leave enough clean data
+ *         to keep arc_size above arc_c_min. Thus, the maximum amount of
+ *         evictable data from the two lists combined, is exactly the
+ *         difference between arc_size and arc_c_min.
+ *
+ *    2.2. arc_size is less than arc_c_min
+ *         (i.e. arc_c_min > arc_size > amount of dirty data)
+ *
+ *         In this case, none of the data contained in the mru and mfu
+ *         lists is evictable, even if it's clean. Since arc_size is
+ *         already below arc_c_min, evicting any more would only
+ *         increase this negative difference.
+ */
+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];
+       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];
+       uint64_t arc_dirty = MAX((int64_t)arc_size - (int64_t)arc_clean, 0);
+
+       if (arc_dirty >= arc_c_min)
+               return (ghost_clean + arc_clean);
+
+       return (ghost_clean + MAX((int64_t)arc_size - (int64_t)arc_c_min, 0));
+}
+
+/*
+ * If sc->nr_to_scan is zero, the caller is requesting a query of the
+ * number of objects which can potentially be freed.  If it is nonzero,
+ * the request is to free that many objects.
+ *
+ * Linux kernels >= 3.12 have the count_objects and scan_objects callbacks
+ * in struct shrinker and also require the shrinker to return the number
+ * of objects freed.
+ *
+ * Older kernels require the shrinker to return the number of freeable
+ * objects following the freeing of nr_to_free.
+ */
+static spl_shrinker_t
+__arc_shrinker_func(struct shrinker *shrink, struct shrink_control *sc)
+{
+       int64_t pages;
+
+       /* The arc is considered warm once reclaim has occurred */
+       if (unlikely(arc_warm == B_FALSE))
+               arc_warm = B_TRUE;
+
+       /* Return the potential number of reclaimable pages */
+       pages = btop((int64_t)arc_evictable_memory());
+       if (sc->nr_to_scan == 0)
+               return (pages);
+
+       /* Not allowed to perform filesystem reclaim */
+       if (!(sc->gfp_mask & __GFP_FS))
+               return (SHRINK_STOP);
+
+       /* Reclaim in progress */
+       if (mutex_tryenter(&arc_reclaim_lock) == 0)
+               return (SHRINK_STOP);
+
+       mutex_exit(&arc_reclaim_lock);
+
+       /*
+        * Evict the requested number of pages by shrinking arc_c the
+        * requested amount.  If there is nothing left to evict just
+        * reap whatever we can from the various arc slabs.
+        */
+       if (pages > 0) {
+               arc_shrink(ptob(sc->nr_to_scan));
+               arc_kmem_reap_now();
+#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
+               pages = MAX(pages - btop(arc_evictable_memory()), 0);
+#else
+               pages = btop(arc_evictable_memory());
+#endif
+       } else {
+               arc_kmem_reap_now();
+               pages = SHRINK_STOP;
+       }
+
+       /*
+        * We've reaped what we can, wake up threads.
+        */
+       cv_broadcast(&arc_reclaim_waiters_cv);
+
+       /*
+        * When direct reclaim is observed it usually indicates a rapid
+        * increase in memory pressure.  This occurs because the kswapd
+        * threads were unable to asynchronously keep enough free memory
+        * available.  In this case set arc_no_grow to briefly pause arc
+        * growth to avoid compounding the memory pressure.
+        */
+       if (current_is_kswapd()) {
+               ARCSTAT_BUMP(arcstat_memory_indirect_count);
+       } else {
+               arc_no_grow = B_TRUE;
+               arc_need_free = ptob(sc->nr_to_scan);
+               ARCSTAT_BUMP(arcstat_memory_direct_count);
+       }
+
+       return (pages);
+}
+SPL_SHRINKER_CALLBACK_WRAPPER(arc_shrinker_func);
+
+SPL_SHRINKER_DECLARE(arc_shrinker, arc_shrinker_func, DEFAULT_SEEKS);
+#endif /* _KERNEL */
+
+/*
+ * Adapt arc info given the number of bytes we are trying to add and
+ * the state that we are comming from.  This function is only called
+ * when we are adding new content to the cache.
+ */
+static void
+arc_adapt(int bytes, arc_state_t *state)
+{
+       int mult;
+       uint64_t arc_p_min = (arc_c >> arc_p_min_shift);
+       int64_t mrug_size = refcount_count(&arc_mru_ghost->arcs_size);
+       int64_t mfug_size = refcount_count(&arc_mfu_ghost->arcs_size);
+
+       if (state == arc_l2c_only)
+               return;
+
+       ASSERT(bytes > 0);
+       /*
+        * Adapt the target size of the MRU list:
+        *      - if we just hit in the MRU ghost list, then increase
+        *        the target size of the MRU list.
+        *      - if we just hit in the MFU ghost list, then increase
+        *        the target size of the MFU list by decreasing the
+        *        target size of the MRU list.
+        */
+       if (state == arc_mru_ghost) {
+               mult = (mrug_size >= mfug_size) ? 1 : (mfug_size / mrug_size);
+               if (!zfs_arc_p_dampener_disable)
+                       mult = MIN(mult, 10); /* avoid wild arc_p adjustment */
+
+               arc_p = MIN(arc_c - arc_p_min, arc_p + bytes * mult);
+       } else if (state == arc_mfu_ghost) {
+               uint64_t delta;
+
+               mult = (mfug_size >= mrug_size) ? 1 : (mrug_size / mfug_size);
+               if (!zfs_arc_p_dampener_disable)
+                       mult = MIN(mult, 10);
+
+               delta = MIN(bytes * mult, arc_p);
+               arc_p = MAX(arc_p_min, arc_p - delta);
+       }
+       ASSERT((int64_t)arc_p >= 0);
+
+       if (arc_reclaim_needed()) {
+               cv_signal(&arc_reclaim_thread_cv);
+               return;
+       }
+
+       if (arc_no_grow)
+               return;
+
+       if (arc_c >= arc_c_max)
+               return;
+
+       /*
+        * If we're within (2 * maxblocksize) bytes of the target
+        * cache size, increment the target cache size
+        */
+       ASSERT3U(arc_c, >=, 2ULL << SPA_MAXBLOCKSHIFT);
+       if (arc_size >= arc_c - (2ULL << SPA_MAXBLOCKSHIFT)) {
+               atomic_add_64(&arc_c, (int64_t)bytes);
+               if (arc_c > arc_c_max)
+                       arc_c = arc_c_max;
+               else if (state == arc_anon)
+                       atomic_add_64(&arc_p, (int64_t)bytes);
+               if (arc_p > arc_c)
+                       arc_p = arc_c;
+       }
+       ASSERT((int64_t)arc_p >= 0);
+}
+
+/*
+ * Check if arc_size has grown past our upper threshold, determined by
+ * zfs_arc_overflow_shift.
+ */
+static boolean_t
+arc_is_overflowing(void)
+{
+       /* Always allow at least one block of overflow */
+       uint64_t overflow = MAX(SPA_MAXBLOCKSIZE,
+           arc_c >> zfs_arc_overflow_shift);
+
+       return (arc_size >= arc_c + overflow);
+}
+
+/*
+ * 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.
+ */
+static void
+arc_get_data_buf(arc_buf_t *buf)
+{
+       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_adapt(size, state);
+
+       /*
+        * If arc_size is currently overflowing, and has grown past our
+        * upper limit, we must be adding data faster than the evict
+        * thread can evict. Thus, to ensure we don't compound the
+        * problem by adding more data and forcing arc_size to grow even
+        * further past it's target size, we halt and wait for the
+        * eviction thread to catch up.
+        *
+        * It's also possible that the reclaim thread is unable to evict
+        * enough buffers to get arc_size below the overflow limit (e.g.
+        * due to buffers being un-evictable, or hash lock collisions).
+        * In this case, we want to proceed regardless if we're
+        * overflowing; thus we don't use a while loop here.
+        */
+       if (arc_is_overflowing()) {
+               mutex_enter(&arc_reclaim_lock);
+
+               /*
+                * Now that we've acquired the lock, we may no longer be
+                * over the overflow limit, lets check.
+                *
+                * We're ignoring the case of spurious wake ups. If that
+                * were to happen, it'd let this thread consume an ARC
+                * buffer before it should have (i.e. before we're under
+                * the overflow limit and were signalled by the reclaim
+                * thread). As long as that is a rare occurrence, it
+                * shouldn't cause any harm.
+                */
+               if (arc_is_overflowing()) {
+                       cv_signal(&arc_reclaim_thread_cv);
+                       cv_wait(&arc_reclaim_waiters_cv, &arc_reclaim_lock);
+               }
+
+               mutex_exit(&arc_reclaim_lock);
+       }
+
+       if (type == ARC_BUFC_METADATA) {
+               buf->b_data = 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);
+               arc_space_consume(size, ARC_SPACE_DATA);
+       }
+
+       /*
+        * 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;
+
+               (void) refcount_add_many(&state->arcs_size, size, buf);
+
+               /*
+                * If this is reached via arc_read, the link is
+                * protected by the hash lock. If reached via
+                * arc_buf_alloc, the header should not be accessed by
+                * any other thread. And, if reached via arc_read_done,
+                * the hash lock will protect it if it's found in the
+                * hash table; otherwise no other thread should be
+                * trying to [add|remove]_reference it.
+                */
+               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);
+               }
+               /*
+                * If we are growing the cache, and we are adding anonymous
+                * data, and we have outgrown arc_p, update arc_p
+                */
+               if (arc_size < arc_c && hdr->b_l1hdr.b_state == arc_anon &&
+                   (refcount_count(&arc_anon->arcs_size) +
+                   refcount_count(&arc_mru->arcs_size) > arc_p))
+                       arc_p = MIN(arc_c, arc_p + size);
+       }
+}
+
+/*
+ * This routine is called whenever a buffer is accessed.
+ * NOTE: the hash lock is dropped in this function.
+ */
+static void
+arc_access(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
+{
+       clock_t now;
+
+       ASSERT(MUTEX_HELD(hash_lock));
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
+       if (hdr->b_l1hdr.b_state == arc_anon) {
+               /*
+                * This buffer is not in the cache, and does not
+                * appear in our "ghost" list.  Add the new buffer
+                * to the MRU state.
+                */
+
+               ASSERT0(hdr->b_l1hdr.b_arc_access);
+               hdr->b_l1hdr.b_arc_access = ddi_get_lbolt();
+               DTRACE_PROBE1(new_state__mru, arc_buf_hdr_t *, hdr);
+               arc_change_state(arc_mru, hdr, hash_lock);
+
+       } else if (hdr->b_l1hdr.b_state == arc_mru) {
+               now = ddi_get_lbolt();
+
+               /*
+                * If this buffer is here because of a prefetch, then either:
+                * - clear the flag if this is a "referencing" read
+                *   (any subsequent access will bump this into the MFU state).
+                * or
+                * - move the buffer to the head of the list if this is
+                *   another prefetch (to make it less likely to be evicted).
+                */
+               if (HDR_PREFETCH(hdr)) {
+                       if (refcount_count(&hdr->b_l1hdr.b_refcnt) == 0) {
+                               /* link protected by hash lock */
+                               ASSERT(multilist_link_active(
+                                   &hdr->b_l1hdr.b_arc_node));
+                       } else {
+                               hdr->b_flags &= ~ARC_FLAG_PREFETCH;
+                               atomic_inc_32(&hdr->b_l1hdr.b_mru_hits);
+                               ARCSTAT_BUMP(arcstat_mru_hits);
+                       }
+                       hdr->b_l1hdr.b_arc_access = now;
+                       return;
+               }
+
+               /*
+                * This buffer has been "accessed" only once so far,
+                * but it is still in the cache. Move it to the MFU
+                * state.
+                */
+               if (ddi_time_after(now, hdr->b_l1hdr.b_arc_access +
+                   ARC_MINTIME)) {
+                       /*
+                        * More than 125ms have passed since we
+                        * instantiated this buffer.  Move it to the
+                        * most frequently used state.
+                        */
+                       hdr->b_l1hdr.b_arc_access = now;
+                       DTRACE_PROBE1(new_state__mfu, arc_buf_hdr_t *, hdr);
+                       arc_change_state(arc_mfu, hdr, hash_lock);
+               }
+               atomic_inc_32(&hdr->b_l1hdr.b_mru_hits);
+               ARCSTAT_BUMP(arcstat_mru_hits);
+       } else if (hdr->b_l1hdr.b_state == arc_mru_ghost) {
+               arc_state_t     *new_state;
+               /*
+                * This buffer has been "accessed" recently, but
+                * was evicted from the cache.  Move it to the
+                * MFU state.
+                */
+
+               if (HDR_PREFETCH(hdr)) {
+                       new_state = arc_mru;
+                       if (refcount_count(&hdr->b_l1hdr.b_refcnt) > 0)
+                               hdr->b_flags &= ~ARC_FLAG_PREFETCH;
+                       DTRACE_PROBE1(new_state__mru, arc_buf_hdr_t *, hdr);
+               } else {
+                       new_state = arc_mfu;
+                       DTRACE_PROBE1(new_state__mfu, arc_buf_hdr_t *, hdr);
+               }
+
+               hdr->b_l1hdr.b_arc_access = ddi_get_lbolt();
+               arc_change_state(new_state, hdr, hash_lock);
+
+               atomic_inc_32(&hdr->b_l1hdr.b_mru_ghost_hits);
+               ARCSTAT_BUMP(arcstat_mru_ghost_hits);
+       } else if (hdr->b_l1hdr.b_state == arc_mfu) {
+               /*
+                * This buffer has been accessed more than once and is
+                * still in the cache.  Keep it in the MFU state.
+                *
+                * NOTE: an add_reference() that occurred when we did
+                * the arc_read() will have kicked this off the list.
+                * If it was a prefetch, we will explicitly move it to
+                * the head of the list now.
+                */
+               if ((HDR_PREFETCH(hdr)) != 0) {
+                       ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+                       /* link protected by hash_lock */
+                       ASSERT(multilist_link_active(&hdr->b_l1hdr.b_arc_node));
+               }
+               atomic_inc_32(&hdr->b_l1hdr.b_mfu_hits);
+               ARCSTAT_BUMP(arcstat_mfu_hits);
+               hdr->b_l1hdr.b_arc_access = ddi_get_lbolt();
+       } else if (hdr->b_l1hdr.b_state == arc_mfu_ghost) {
+               arc_state_t     *new_state = arc_mfu;
+               /*
+                * This buffer has been accessed more than once but has
+                * been evicted from the cache.  Move it back to the
+                * MFU state.
+                */
+
+               if (HDR_PREFETCH(hdr)) {
+                       /*
+                        * This is a prefetch access...
+                        * move this block back to the MRU state.
+                        */
+                       ASSERT0(refcount_count(&hdr->b_l1hdr.b_refcnt));
+                       new_state = arc_mru;
+               }
+
+               hdr->b_l1hdr.b_arc_access = ddi_get_lbolt();
+               DTRACE_PROBE1(new_state__mfu, arc_buf_hdr_t *, hdr);
+               arc_change_state(new_state, hdr, hash_lock);
+
+               atomic_inc_32(&hdr->b_l1hdr.b_mfu_ghost_hits);
+               ARCSTAT_BUMP(arcstat_mfu_ghost_hits);
+       } else if (hdr->b_l1hdr.b_state == arc_l2c_only) {
+               /*
+                * This buffer is on the 2nd Level ARC.
+                */
+
+               hdr->b_l1hdr.b_arc_access = ddi_get_lbolt();
+               DTRACE_PROBE1(new_state__mfu, arc_buf_hdr_t *, hdr);
+               arc_change_state(arc_mfu, hdr, hash_lock);
+       } else {
+               cmn_err(CE_PANIC, "invalid arc state 0x%p",
+                   hdr->b_l1hdr.b_state);
+       }
+}
+
+/* a generic arc_done_func_t which you can use */
+/* ARGSUSED */
+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));
+}
+
+/* a generic arc_done_func_t */
+void
+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));
+               *bufp = NULL;
+       } else {
+               *bufp = buf;
+               ASSERT(buf->b_data);
+       }
+}
+
+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 */
+       kmutex_t        *hash_lock = NULL;
+       arc_callback_t  *callback_list, *acb;
+       int             freeable = FALSE;
+
+       buf = zio->io_private;
+       hdr = buf->b_hdr;
+
+       /*
+        * The hdr was inserted into hash-table and removed from lists
+        * prior to starting I/O.  We should find this header, since
+        * it's in the hash table, and it should be legit since it's
+        * not possible to evict it during the I/O.  The only possible
+        * reason for it not to be found is if we were freed during the
+        * read.
+        */
+       if (HDR_IN_HASH_TABLE(hdr)) {
+               arc_buf_hdr_t *found;
+
+               ASSERT3U(hdr->b_birth, ==, BP_PHYSICAL_BIRTH(zio->io_bp));
+               ASSERT3U(hdr->b_dva.dva_word[0], ==,
+                   BP_IDENTITY(zio->io_bp)->dva_word[0]);
+               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);
+
+               ASSERT((found == NULL && HDR_FREED_IN_READ(hdr) &&
+                   hash_lock == NULL) ||
+                   (found == hdr &&
+                   DVA_EQUAL(&hdr->b_dva, BP_IDENTITY(zio->io_bp))) ||
+                   (found == hdr && HDR_L2_READING(hdr)));
+       }
+
+       hdr->b_flags &= ~ARC_FLAG_L2_EVICTED;
+       if (l2arc_noprefetch && HDR_PREFETCH(hdr))
+               hdr->b_flags &= ~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);
+
+       if (hash_lock && zio->io_error == 0 &&
+           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
+                * called arc_access (to prevent any simultaneous readers from
+                * getting confused).
+                */
+               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;
+               }
+       }
+       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;
+       }
+
+       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 (hdr->b_l1hdr.b_state != arc_anon)
+                       arc_change_state(arc_anon, hdr, hash_lock);
+               if (HDR_IN_HASH_TABLE(hdr))
+                       buf_hash_remove(hdr);
+               freeable = refcount_is_zero(&hdr->b_l1hdr.b_refcnt);
+       }
+
+       /*
+        * Broadcast before we drop the hash_lock to avoid the possibility
+        * that the hdr (and hence the cv) might be freed before we get to
+        * the cv_broadcast().
+        */
+       cv_broadcast(&hdr->b_l1hdr.b_cv);
+
+       if (hash_lock != NULL) {
+               mutex_exit(hash_lock);
+       } else {
+               /*
+                * This block was freed while we waited for the read to
+                * complete.  It has been removed from the hash table and
+                * moved to the anonymous state (so that it won't show up
+                * in the cache).
+                */
+               ASSERT3P(hdr->b_l1hdr.b_state, ==, arc_anon);
+               freeable = refcount_is_zero(&hdr->b_l1hdr.b_refcnt);
+       }
+
+       /* execute each callback and free its structure */
+       while ((acb = callback_list) != NULL) {
+               if (acb->acb_done)
+                       acb->acb_done(zio, acb->acb_buf, acb->acb_private);
+
+               if (acb->acb_zio_dummy != NULL) {
+                       acb->acb_zio_dummy->io_error = zio->io_error;
+                       zio_nowait(acb->acb_zio_dummy);
+               }
+
+               callback_list = acb->acb_next;
+               kmem_free(acb, sizeof (arc_callback_t));
+       }
+
+       if (freeable)
+               arc_hdr_destroy(hdr);
+}
+
+/*
+ * "Read" the block at the specified DVA (in bp) via the
+ * cache.  If the block is found in the cache, invoke the provided
+ * callback immediately and return.  Note that the `zio' parameter
+ * in the callback will be NULL in this case, since no IO was
+ * required.  If the block is not in the cache pass the read request
+ * on to the spa with a substitute callback function, so that the
+ * requested block will be added to the cache.
+ *
+ * If a read request arrives for a block that has a read in-progress,
+ * either wait for the in-progress read to complete (and return the
+ * results); or, if this is a read with a "done" func, add a record
+ * to the read to invoke the "done" func when the read completes,
+ * and return; or just return.
+ *
+ * arc_read_done() will invoke all the requested "done" functions
+ * for readers of this block.
+ */
+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 zio_flags,
+    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);
+       int rc = 0;
+
+       ASSERT(!BP_IS_EMBEDDED(bp) ||
+           BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA);
+
+top:
+       if (!BP_IS_EMBEDDED(bp)) {
+               /*
+                * Embedded BP's have no DVA and require no I/O to "read".
+                * Create an anonymous arc buf to back it.
+                */
+               hdr = buf_hash_find(guid, bp, &hash_lock);
+       }
+
+       if (hdr != NULL && HDR_HAS_L1HDR(hdr) && hdr->b_l1hdr.b_datacnt > 0) {
+
+               *arc_flags |= ARC_FLAG_CACHED;
+
+               if (HDR_IO_IN_PROGRESS(hdr)) {
+
+                       if (*arc_flags & ARC_FLAG_WAIT) {
+                               cv_wait(&hdr->b_l1hdr.b_cv, hash_lock);
+                               mutex_exit(hash_lock);
+                               goto top;
+                       }
+                       ASSERT(*arc_flags & ARC_FLAG_NOWAIT);
+
+                       if (done) {
+                               arc_callback_t  *acb = NULL;
+
+                               acb = kmem_zalloc(sizeof (arc_callback_t),
+                                   KM_SLEEP);
+                               acb->acb_done = done;
+                               acb->acb_private = private;
+                               if (pio != NULL)
+                                       acb->acb_zio_dummy = zio_null(pio,
+                                           spa, NULL, NULL, NULL, zio_flags);
+
+                               ASSERT(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;
+                       }
+                       mutex_exit(hash_lock);
+                       goto out;
+               }
+
+               ASSERT(hdr->b_l1hdr.b_state == arc_mru ||
+                   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);
+                       }
+
+               } else if (*arc_flags & ARC_FLAG_PREFETCH &&
+                   refcount_count(&hdr->b_l1hdr.b_refcnt) == 0) {
+                       hdr->b_flags |= 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;
+               mutex_exit(hash_lock);
+               ARCSTAT_BUMP(arcstat_hits);
+               ARCSTAT_CONDSTAT(!HDR_PREFETCH(hdr),
+                   demand, prefetch, !HDR_ISTYPE_METADATA(hdr),
+                   data, metadata, hits);
+
+               if (done)
+                       done(NULL, buf, private);
+       } else {
+               uint64_t size = BP_GET_LSIZE(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;
+
+               /*
+                * Gracefully handle a damaged logical block size as a
+                * checksum error.
+                */
+               if (size > spa_maxblocksize(spa)) {
+                       ASSERT3P(buf, ==, NULL);
+                       rc = SET_ERROR(ECKSUM);
+                       goto out;
+               }
+
+               if (hdr == NULL) {
+                       /* 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;
+                       if (!BP_IS_EMBEDDED(bp)) {
+                               hdr->b_dva = *BP_IDENTITY(bp);
+                               hdr->b_birth = BP_PHYSICAL_BIRTH(bp);
+                               exists = buf_hash_insert(hdr, &hash_lock);
+                       }
+                       if (exists != NULL) {
+                               /* somebody beat us to the hash insert */
+                               mutex_exit(hash_lock);
+                               buf_discard_identity(hdr);
+                               (void) arc_buf_remove_ref(buf, private);
+                               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
+                        * (and thus didn't have an L1 hdr), we realloc the
+                        * header to add an L1 hdr.
+                        */
+                       if (!HDR_HAS_L1HDR(hdr)) {
+                               hdr = arc_hdr_realloc(hdr, hdr_l2only_cache,
+                                   hdr_full_cache);
+                       }
+
+                       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);
+
+                       /* 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);
+                       arc_access(hdr, hash_lock);
+               }
+
+               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;
+
+               ASSERT(hdr->b_l1hdr.b_acb == NULL);
+               hdr->b_l1hdr.b_acb = acb;
+               hdr->b_flags |= 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.
+                        */
+                       if (vdev_is_dead(vd) ||
+                           !spa_config_tryenter(spa, SCL_L2ARC, vd, RW_READER))
+                               vd = NULL;
+               }
+
+               if (hash_lock != NULL)
+                       mutex_exit(hash_lock);
+
+               /*
+                * At this point, we have a level 1 cache miss.  Try again in
+                * L2ARC if possible.
+                */
+               ASSERT3U(hdr->b_size, ==, size);
+               DTRACE_PROBE4(arc__miss, arc_buf_hdr_t *, hdr, blkptr_t *, bp,
+                   uint64_t, size, zbookmark_phys_t *, zb);
+               ARCSTAT_BUMP(arcstat_misses);
+               ARCSTAT_CONDSTAT(!HDR_PREFETCH(hdr),
+                   demand, prefetch, !HDR_ISTYPE_METADATA(hdr),
+                   data, metadata, misses);
+
+               if (vd != NULL && l2arc_ndev != 0 && !(l2arc_norw && devw)) {
+                       /*
+                        * Read from the L2ARC if the following are true:
+                        * 1. The L2ARC vdev was previously cached.
+                        * 2. This buffer still has L2ARC metadata.
+                        * 3. This buffer isn't currently writing to the L2ARC.
+                        * 4. The L2ARC entry wasn't evicted, which may
+                        *    also have invalidated the vdev.
+                        * 5. This isn't prefetch and l2arc_noprefetch is set.
+                        */
+                       if (HDR_HAS_L2HDR(hdr) &&
+                           !HDR_L2_WRITING(hdr) && !HDR_L2_EVICTED(hdr) &&
+                           !(l2arc_noprefetch && HDR_PREFETCH(hdr))) {
+                               l2arc_read_callback_t *cb;
+
+                               DTRACE_PROBE1(l2arc__hit, arc_buf_hdr_t *, hdr);
+                               ARCSTAT_BUMP(arcstat_l2_hits);
+                               atomic_inc_32(&hdr->b_l2hdr.b_hits);
+
+                               cb = kmem_zalloc(sizeof (l2arc_read_callback_t),
+                                   KM_SLEEP);
+                               cb->l2rcb_buf = buf;
+                               cb->l2rcb_spa = spa;
+                               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 -
+                                   VDEV_LABEL_END_SIZE);
+
+                               /*
+                                * l2arc read.  The SCL_L2ARC lock will be
+                                * released by l2arc_read_done().
+                                * 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);
+                               }
+                               DTRACE_PROBE2(l2arc__read, vdev_t *, vd,
+                                   zio_t *, rzio);
+                               ARCSTAT_INCR(arcstat_l2_read_bytes, b_asize);
+
+                               if (*arc_flags & ARC_FLAG_NOWAIT) {
+                                       zio_nowait(rzio);
+                                       goto out;
+                               }
+
+                               ASSERT(*arc_flags & ARC_FLAG_WAIT);
+                               if (zio_wait(rzio) == 0)
+                                       goto out;
+
+                               /* l2arc read error; goto zio_read() */
+                       } else {
+                               DTRACE_PROBE1(l2arc__miss,
+                                   arc_buf_hdr_t *, hdr);
+                               ARCSTAT_BUMP(arcstat_l2_misses);
+                               if (HDR_L2_WRITING(hdr))
+                                       ARCSTAT_BUMP(arcstat_l2_rw_clash);
+                               spa_config_exit(spa, SCL_L2ARC, vd);
+                       }
+               } else {
+                       if (vd != NULL)
+                               spa_config_exit(spa, SCL_L2ARC, vd);
+                       if (l2arc_ndev != 0) {
+                               DTRACE_PROBE1(l2arc__miss,
+                                   arc_buf_hdr_t *, hdr);
+                               ARCSTAT_BUMP(arcstat_l2_misses);
+                       }
+               }
+
+               rzio = zio_read(pio, spa, bp, buf->b_data, size,
+                   arc_read_done, buf, priority, zio_flags, zb);
+
+               if (*arc_flags & ARC_FLAG_WAIT) {
+                       rc = zio_wait(rzio);
+                       goto out;
+               }
+
+               ASSERT(*arc_flags & ARC_FLAG_NOWAIT);
+               zio_nowait(rzio);
+       }
+
+out:
+       spa_read_history_add(spa, zb, *arc_flags);
+       return (rc);
+}
+
+arc_prune_t *
+arc_add_prune_callback(arc_prune_func_t *func, void *private)
+{
+       arc_prune_t *p;
+
+       p = kmem_alloc(sizeof (*p), KM_SLEEP);
+       p->p_pfunc = func;
+       p->p_private = private;
+       list_link_init(&p->p_node);
+       refcount_create(&p->p_refcnt);
+
+       mutex_enter(&arc_prune_mtx);
+       refcount_add(&p->p_refcnt, &arc_prune_list);
+       list_insert_head(&arc_prune_list, p);
+       mutex_exit(&arc_prune_mtx);
+
+       return (p);
+}
+
+void
+arc_remove_prune_callback(arc_prune_t *p)
+{
+       boolean_t wait = B_FALSE;
+       mutex_enter(&arc_prune_mtx);
+       list_remove(&arc_prune_list, p);
+       if (refcount_remove(&p->p_refcnt, &arc_prune_list) > 0)
+               wait = B_TRUE;
+       mutex_exit(&arc_prune_mtx);
+
+       /* wait for arc_prune_task to finish */
+       if (wait)
+               taskq_wait_outstanding(arc_prune_taskq, 0);
+       ASSERT0(refcount_count(&p->p_refcnt));
+       refcount_destroy(&p->p_refcnt);
+       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.
+ */
+void
+arc_freed(spa_t *spa, const blkptr_t *bp)
+{
+       arc_buf_hdr_t *hdr;
+       kmutex_t *hash_lock;
+       uint64_t guid = spa_load_guid(spa);
+
+       ASSERT(!BP_IS_EMBEDDED(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 {
+               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);
+       VERIFY0(efunc(private));
+       return (B_TRUE);
+}
+
+/*
+ * Release this buffer from the cache, making it an anonymous buffer.  This
+ * must be done after a read and prior to modifying the buffer contents.
+ * If the buffer has more than one reference, we must make
+ * a new hdr for the buffer.
+ */
+void
+arc_release(arc_buf_t *buf, void *tag)
+{
+       kmutex_t *hash_lock;
+       arc_state_t *state;
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+
+       /*
+        * It would be nice to assert that if its DMU metadata (level >
+        * 0 || it's the dnode file), then it must be syncing context.
+        * But we don't know that information at this level.
+        */
+
+       mutex_enter(&buf->b_evict_lock);
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
+       /*
+        * We don't grab the hash lock prior to this check, because if
+        * the buffer's header is in the arc_anon state, it won't be
+        * linked into the hash table.
+        */
+       if (hdr->b_l1hdr.b_state == arc_anon) {
+               mutex_exit(&buf->b_evict_lock);
+               ASSERT(!HDR_IO_IN_PROGRESS(hdr));
+               ASSERT(!HDR_IN_HASH_TABLE(hdr));
+               ASSERT(!HDR_HAS_L2HDR(hdr));
+               ASSERT(BUF_EMPTY(hdr));
+
+               ASSERT3U(hdr->b_l1hdr.b_datacnt, ==, 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;
+               arc_buf_thaw(buf);
+
+               return;
+       }
+
+       hash_lock = HDR_LOCK(hdr);
+       mutex_enter(hash_lock);
+
+       /*
+        * This assignment is only valid as long as the hash_lock is
+        * held, we must be careful not to reference state or the
+        * b_state field after dropping the lock.
+        */
+       state = hdr->b_l1hdr.b_state;
+       ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
+       ASSERT3P(state, !=, arc_anon);
+
+       /* this buffer is not on any list */
+       ASSERT(refcount_count(&hdr->b_l1hdr.b_refcnt) > 0);
+
+       if (HDR_HAS_L2HDR(hdr)) {
+               mutex_enter(&hdr->b_l2hdr.b_dev->l2ad_mtx);
+
+               /*
+                * We have to recheck this conditional again now that
+                * we're holding the l2ad_mtx to prevent a race with
+                * another thread which might be concurrently calling
+                * l2arc_evict(). In that case, l2arc_evict() might have
+                * destroyed the header's L2 portion as we were waiting
+                * to acquire the l2ad_mtx.
+                */
+               if (HDR_HAS_L2HDR(hdr))
+                       arc_hdr_l2hdr_destroy(hdr);
+
+               mutex_exit(&hdr->b_l2hdr.b_dev->l2ad_mtx);
+       }
+
+       /*
+        * Do we have more than one buf?
+        */
+       if (hdr->b_l1hdr.b_datacnt > 1) {
+               arc_buf_hdr_t *nhdr;
+               arc_buf_t **bufp;
+               uint64_t blksz = hdr->b_size;
+               uint64_t spa = hdr->b_spa;
+               arc_buf_contents_t type = arc_buf_type(hdr);
+               uint32_t flags = hdr->b_flags;
+
+               ASSERT(hdr->b_l1hdr.b_buf != buf || buf->b_next != NULL);
+               /*
+                * Pull the data off of this hdr and attach it to
+                * a new anonymous hdr.
+                */
+               (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;
+
+               ASSERT3P(state, !=, arc_l2c_only);
+
+               (void) refcount_remove_many(
+                   &state->arcs_size, hdr->b_size, 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);
+               }
+
+               /*
+                * 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;
+               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;
+
+               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);
+       } else {
+               mutex_exit(&buf->b_evict_lock);
+               ASSERT(refcount_count(&hdr->b_l1hdr.b_refcnt) == 1);
+               /* protected by hash lock, or hdr is on arc_anon */
+               ASSERT(!multilist_link_active(&hdr->b_l1hdr.b_arc_node));
+               ASSERT(!HDR_IO_IN_PROGRESS(hdr));
+               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;
+               arc_change_state(arc_anon, hdr, hash_lock);
+               hdr->b_l1hdr.b_arc_access = 0;
+               mutex_exit(hash_lock);
+
+               buf_discard_identity(hdr);
+               arc_buf_thaw(buf);
+       }
+       buf->b_efunc = NULL;
+       buf->b_private = NULL;
+}
+
+int
+arc_released(arc_buf_t *buf)
+{
+       int released;
+
+       mutex_enter(&buf->b_evict_lock);
+       released = (buf->b_data != NULL &&
+           buf->b_hdr->b_l1hdr.b_state == arc_anon);
+       mutex_exit(&buf->b_evict_lock);
+       return (released);
+}
+
+#ifdef ZFS_DEBUG
+int
+arc_referenced(arc_buf_t *buf)
+{
+       int referenced;
+
+       mutex_enter(&buf->b_evict_lock);
+       referenced = (refcount_count(&buf->b_hdr->b_l1hdr.b_refcnt));
+       mutex_exit(&buf->b_evict_lock);
+       return (referenced);
+}
+#endif
+
+static void
+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;
+
+       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);
+
+       /*
+        * 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 (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;
+               }
+               mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
+       }
+       arc_cksum_compute(buf, B_FALSE);
+       hdr->b_flags |= ARC_FLAG_IO_IN_PROGRESS;
+}
+
+/*
+ * The SPA calls this callback for each physical write that happens on behalf
+ * of a logical write.  See the comment in dbuf_write_physdone() for details.
+ */
+static void
+arc_write_physdone(zio_t *zio)
+{
+       arc_write_callback_t *cb = zio->io_private;
+       if (cb->awcb_physdone != NULL)
+               cb->awcb_physdone(zio, cb->awcb_buf, cb->awcb_private);
+}
+
+static void
+arc_write_done(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;
+
+       ASSERT(hdr->b_l1hdr.b_acb == NULL);
+
+       if (zio->io_error == 0) {
+               if (BP_IS_HOLE(zio->io_bp) || BP_IS_EMBEDDED(zio->io_bp)) {
+                       buf_discard_identity(hdr);
+               } else {
+                       hdr->b_dva = *BP_IDENTITY(zio->io_bp);
+                       hdr->b_birth = BP_PHYSICAL_BIRTH(zio->io_bp);
+               }
+       } else {
+               ASSERT(BUF_EMPTY(hdr));
+       }
+
+       /*
+        * If the block to be written was all-zero or compressed enough to be
+        * embedded in the BP, no write was performed so there will be no
+        * dva/birth/checksum.  The buffer must therefore remain anonymous
+        * (and uncached).
+        */
+       if (!BUF_EMPTY(hdr)) {
+               arc_buf_hdr_t *exists;
+               kmutex_t *hash_lock;
+
+               ASSERT(zio->io_error == 0);
+
+               arc_cksum_verify(buf);
+
+               exists = buf_hash_insert(hdr, &hash_lock);
+               if (exists != NULL) {
+                       /*
+                        * This can only happen if we overwrite for
+                        * sync-to-convergence, because we remove
+                        * buffers from the hash table when we arc_free().
+                        */
+                       if (zio->io_flags & ZIO_FLAG_IO_REWRITE) {
+                               if (!BP_EQUAL(&zio->io_bp_orig, zio->io_bp))
+                                       panic("bad overwrite, hdr=%p exists=%p",
+                                           (void *)hdr, (void *)exists);
+                               ASSERT(refcount_is_zero(
+                                   &exists->b_l1hdr.b_refcnt));
+                               arc_change_state(arc_anon, exists, hash_lock);
+                               mutex_exit(hash_lock);
+                               arc_hdr_destroy(exists);
+                               exists = buf_hash_insert(hdr, &hash_lock);
+                               ASSERT3P(exists, ==, NULL);
+                       } else if (zio->io_flags & ZIO_FLAG_NOPWRITE) {
+                               /* nopwrite */
+                               ASSERT(zio->io_prop.zp_nopwrite);
+                               if (!BP_EQUAL(&zio->io_bp_orig, zio->io_bp))
+                                       panic("bad nopwrite, hdr=%p exists=%p",
+                                           (void *)hdr, (void *)exists);
+                       } else {
+                               /* Dedup */
+                               ASSERT(hdr->b_l1hdr.b_datacnt == 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;
+               /* 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;
+       }
+
+       ASSERT(!refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+       callback->awcb_done(zio, buf, callback->awcb_private);
+
+       kmem_free(callback, sizeof (arc_write_callback_t));
+}
+
+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)
+{
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+       arc_write_callback_t *callback;
+       zio_t *zio;
+
+       ASSERT(ready != NULL);
+       ASSERT(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);
+       if (l2arc)
+               hdr->b_flags |= ARC_FLAG_L2CACHE;
+       if (l2arc_compress)
+               hdr->b_flags |= ARC_FLAG_L2COMPRESS;
+       callback = kmem_zalloc(sizeof (arc_write_callback_t), KM_SLEEP);
+       callback->awcb_ready = 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,
+           priority, zio_flags, zb);
+
+       return (zio);
+}
+
+static int
+arc_memory_throttle(uint64_t reserve, uint64_t txg)
+{
+#ifdef _KERNEL
+       uint64_t available_memory = ptob(freemem);
+       static uint64_t page_load = 0;
+       static uint64_t last_txg = 0;
+#ifdef __linux__
+       pgcnt_t minfree = btop(arc_sys_free / 4);
+#endif
+
+       if (freemem > physmem * arc_lotsfree_percent / 100)
+               return (0);
+
+       if (txg > last_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
+        * continue to let page writes occur as quickly as possible.
+        */
+       if (current_is_kswapd()) {
+               if (page_load > MAX(ptob(minfree), available_memory) / 4) {
+                       DMU_TX_STAT_BUMP(dmu_tx_memory_reclaim);
+                       return (SET_ERROR(ERESTART));
+               }
+               /* Note: reserve is inflated, so we deflate */
+               page_load += reserve / 8;
+               return (0);
+       } else if (page_load > 0 && arc_reclaim_needed()) {
+               /* memory is low, delay before restarting */
+               ARCSTAT_INCR(arcstat_memory_throttle_count, 1);
+               DMU_TX_STAT_BUMP(dmu_tx_memory_reclaim);
+               return (SET_ERROR(EAGAIN));
+       }
+       page_load = 0;
+#endif
+       return (0);
+}
+
+void
+arc_tempreserve_clear(uint64_t reserve)
+{
+       atomic_add_64(&arc_tempreserve, -reserve);
+       ASSERT((int64_t)arc_tempreserve >= 0);
+}
+
+int
+arc_tempreserve_space(uint64_t reserve, uint64_t txg)
+{
+       int error;
+       uint64_t anon_size;
+
+       if (!arc_no_grow &&
+           reserve > arc_c/4 &&
+           reserve * 4 > (2ULL << SPA_MAXBLOCKSHIFT))
+               arc_c = MIN(arc_c_max, reserve * 4);
+
+       /*
+        * Throttle when the calculated memory footprint for the TXG
+        * exceeds the target ARC size.
+        */
+       if (reserve > arc_c) {
+               DMU_TX_STAT_BUMP(dmu_tx_memory_reserve);
+               return (SET_ERROR(ERESTART));
+       }
+
+       /*
+        * Don't count loaned bufs as in flight dirty data to prevent long
+        * network delays from blocking transactions that are ready to be
+        * assigned to a txg.
+        */
+       anon_size = MAX((int64_t)(refcount_count(&arc_anon->arcs_size) -
+           arc_loaned_bytes), 0);
+
+       /*
+        * Writes will, almost always, require additional memory allocations
+        * in order to compress/encrypt/etc the data.  We therefore need to
+        * make sure that there is sufficient available memory for this.
+        */
+       error = arc_memory_throttle(reserve, txg);
+       if (error != 0)
+               return (error);
+
+       /*
+        * Throttle writes when the amount of dirty data in the cache
+        * gets too large.  We try to keep the cache less than half full
+        * of dirty blocks so that our sync times don't grow too large.
+        * Note: if two requests come in concurrently, we might let them
+        * both succeed, when one of them should fail.  Not a huge deal.
+        */
+
+       if (reserve + arc_tempreserve + anon_size > arc_c / 2 &&
+           anon_size > arc_c / 4) {
+               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);
+               DMU_TX_STAT_BUMP(dmu_tx_dirty_throttle);
+               return (SET_ERROR(ERESTART));
+       }
+       atomic_add_64(&arc_tempreserve, reserve);
+       return (0);
+}
+
+static void
+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];
+}
+
+static int
+arc_kstat_update(kstat_t *ksp, int rw)
+{
+       arc_stats_t *as = ksp->ks_data;
+
+       if (rw == KSTAT_WRITE) {
+               return (EACCES);
+       } else {
+               arc_kstat_update_state(arc_anon,
+                   &as->arcstat_anon_size,
+                   &as->arcstat_anon_evictable_data,
+                   &as->arcstat_anon_evictable_metadata);
+               arc_kstat_update_state(arc_mru,
+                   &as->arcstat_mru_size,
+                   &as->arcstat_mru_evictable_data,
+                   &as->arcstat_mru_evictable_metadata);
+               arc_kstat_update_state(arc_mru_ghost,
+                   &as->arcstat_mru_ghost_size,
+                   &as->arcstat_mru_ghost_evictable_data,
+                   &as->arcstat_mru_ghost_evictable_metadata);
+               arc_kstat_update_state(arc_mfu,
+                   &as->arcstat_mfu_size,
+                   &as->arcstat_mfu_evictable_data,
+                   &as->arcstat_mfu_evictable_metadata);
+               arc_kstat_update_state(arc_mfu_ghost,
+                   &as->arcstat_mfu_ghost_size,
+                   &as->arcstat_mfu_ghost_evictable_data,
+                   &as->arcstat_mfu_ghost_evictable_metadata);
+       }
+
+       return (0);
+}
+
+/*
+ * This function *must* return indices evenly distributed between all
+ * sublists of the multilist. This is needed due to how the ARC eviction
+ * code is laid out; arc_evict_state() assumes ARC buffers 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
+arc_state_multilist_index_func(multilist_t *ml, void *obj)
+{
+       arc_buf_hdr_t *hdr = obj;
+
+       /*
+        * We rely on b_dva to generate evenly distributed index
+        * 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));
+
+       /*
+        * The assumption here, is the hash value for a given
+        * arc_buf_hdr_t will remain constant throughout its lifetime
+        * (i.e. its b_spa, b_dva, and b_birth fields don't change).
+        * Thus, we don't need to store the header'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 (buf_hash(hdr->b_spa, &hdr->b_dva, hdr->b_birth) %
+           multilist_get_num_sublists(ml));
+}
+
+/*
+ * Called during module initialization and periodically thereafter to
+ * apply reasonable changes to the exposed performance tunings.  Non-zero
+ * zfs_* values which differ from the currently set values will be applied.
+ */
+static void
+arc_tuning_update(void)
+{
+       /* 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)) &&
+           (zfs_arc_max > arc_c_min)) {
+               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: 32M - <arc_c_max> */
+       if ((zfs_arc_min) && (zfs_arc_min != arc_c_min) &&
+           (zfs_arc_min >= 2ULL << SPA_MAXBLOCKSHIFT) &&
+           (zfs_arc_min <= arc_c_max)) {
+               arc_c_min = zfs_arc_min;
+               arc_c = MAX(arc_c, arc_c_min);
+       }
+
+       /* Valid range: 16M - <arc_c_max> */
+       if ((zfs_arc_meta_min) && (zfs_arc_meta_min != arc_meta_min) &&
+           (zfs_arc_meta_min >= 1ULL << SPA_MAXBLOCKSHIFT) &&
+           (zfs_arc_meta_min <= arc_c_max)) {
+               arc_meta_min = zfs_arc_meta_min;
+               arc_meta_limit = MAX(arc_meta_limit, arc_meta_min);
+       }
+
+       /* Valid range: <arc_meta_min> - <arc_c_max> */
+       if ((zfs_arc_meta_limit) && (zfs_arc_meta_limit != arc_meta_limit) &&
+           (zfs_arc_meta_limit >= zfs_arc_meta_min) &&
+           (zfs_arc_meta_limit <= arc_c_max))
+               arc_meta_limit = zfs_arc_meta_limit;
+
+       /* Valid range: 1 - N */
+       if (zfs_arc_grow_retry)
+               arc_grow_retry = zfs_arc_grow_retry;
+
+       /* Valid range: 1 - N */
+       if (zfs_arc_shrink_shift) {
+               arc_shrink_shift = zfs_arc_shrink_shift;
+               arc_no_grow_shift = MIN(arc_no_grow_shift, arc_shrink_shift -1);
+       }
+
+       /* Valid range: 1 - N */
+       if (zfs_arc_p_min_shift)
+               arc_p_min_shift = zfs_arc_p_min_shift;
+
+       /* Valid range: 1 - N ticks */
+       if (zfs_arc_min_prefetch_lifespan)
+               arc_min_prefetch_lifespan = zfs_arc_min_prefetch_lifespan;
+
+       /* Valid range: 0 - 100 */
+       if ((zfs_arc_lotsfree_percent >= 0) &&
+           (zfs_arc_lotsfree_percent <= 100))
+               arc_lotsfree_percent = zfs_arc_lotsfree_percent;
+
+       /* Valid range: 0 - <all physical memory> */
+       if ((zfs_arc_sys_free) && (zfs_arc_sys_free != arc_sys_free))
+               arc_sys_free = MIN(MAX(zfs_arc_sys_free, 0), ptob(physmem));
+
+}
+
+void
+arc_init(void)
+{
+       /*
+        * allmem is "all memory that we could possibly use".
+        */
+#ifdef _KERNEL
+       uint64_t allmem = ptob(physmem);
+#else
+       uint64_t allmem = (physmem * PAGESIZE) / 2;
+#endif
+
+       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
+        * swapping out pages when it is preferable to shrink the arc.
+        */
+       spl_register_shrinker(&arc_shrinker);
+
+       /* Set to 1/64 of all memory or a minimum of 512K */
+       arc_sys_free = MAX(ptob(physmem / 64), (512 * 1024));
+       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;
+
+       arc_c = arc_c_max;
+       arc_p = (arc_c >> 1);
+
+       /* 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);
+
+       /* Apply user specified tunings */
+       arc_tuning_update();
+
+       if (zfs_arc_num_sublists_per_state < 1)
+               zfs_arc_num_sublists_per_state = MAX(boot_ncpus, 1);
+
+       /* if kmem_flags are set, lets try to use less memory */
+       if (kmem_debugging())
+               arc_c = arc_c / 2;
+       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);
+
+       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_ksp = kstat_create("zfs", 0, "arcstats", "misc", KSTAT_TYPE_NAMED,
+           sizeof (arc_stats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
+
+       if (arc_ksp != NULL) {
+               arc_ksp->ks_data = &arc_stats;
+               arc_ksp->ks_update = arc_kstat_update;
+               kstat_install(arc_ksp);
+       }
+
+       (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_warm = B_FALSE;
+
+       /*
+        * Calculate maximum amount of dirty data per pool.
+        *
+        * If it has been set by a module parameter, take that.
+        * Otherwise, use a percentage of physical memory defined by
+        * zfs_dirty_data_max_percent (default 10%) with a cap at
+        * zfs_dirty_data_max_max (default 25% of physical memory).
+        */
+       if (zfs_dirty_data_max_max == 0)
+               zfs_dirty_data_max_max = (uint64_t)physmem * PAGESIZE *
+                   zfs_dirty_data_max_max_percent / 100;
+
+       if (zfs_dirty_data_max == 0) {
+               zfs_dirty_data_max = (uint64_t)physmem * PAGESIZE *
+                   zfs_dirty_data_max_percent / 100;
+               zfs_dirty_data_max = MIN(zfs_dirty_data_max,
+                   zfs_dirty_data_max_max);
+       }
+}
+
+void
+arc_fini(void)
+{
+       arc_prune_t *p;
+
+#ifdef _KERNEL
+       spl_unregister_shrinker(&arc_shrinker);
+#endif /* _KERNEL */
+
+       mutex_enter(&arc_reclaim_lock);
+       arc_reclaim_thread_exit = TRUE;
+       /*
+        * The reclaim thread will set arc_reclaim_thread_exit back to
+        * FALSE when it is finished exiting; we're waiting for that.
+        */
+       while (arc_reclaim_thread_exit) {
+               cv_signal(&arc_reclaim_thread_cv);
+               cv_wait(&arc_reclaim_thread_cv, &arc_reclaim_lock);
+       }
+       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);
+
+       arc_dead = TRUE;
+
+       if (arc_ksp != NULL) {
+               kstat_delete(arc_ksp);
+               arc_ksp = NULL;
+       }
+
+       taskq_wait(arc_prune_taskq);
+       taskq_destroy(arc_prune_taskq);
+
+       mutex_enter(&arc_prune_mtx);
+       while ((p = list_head(&arc_prune_list)) != NULL) {
+               list_remove(&arc_prune_list, p);
+               refcount_remove(&p->p_refcnt, &arc_prune_list);
+               refcount_destroy(&p->p_refcnt);
+               kmem_free(p, sizeof (*p));
+       }
+       mutex_exit(&arc_prune_mtx);
+
+       list_destroy(&arc_prune_list);
+       mutex_destroy(&arc_prune_mtx);
+       mutex_destroy(&arc_reclaim_lock);
+       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]);
+
+       buf_fini();
+
+       ASSERT0(arc_loaned_bytes);
+}
+
+/*
+ * Level 2 ARC
+ *
+ * The level 2 ARC (L2ARC) is a cache layer in-between main memory and disk.
+ * It uses dedicated storage devices to hold cached data, which are populated
+ * using large infrequent writes.  The main role of this cache is to boost
+ * the performance of random read workloads.  The intended L2ARC devices
+ * include short-stroked disks, solid state disks, and other media with
+ * substantially faster read latency than disk.
+ *
+ *                 +-----------------------+
+ *                 |         ARC           |
+ *                 +-----------------------+
+ *                    |         ^     ^
+ *                    |         |     |
+ *      l2arc_feed_thread()    arc_read()
+ *                    |         |     |
+ *                    |  l2arc read   |
+ *                    V         |     |
+ *               +---------------+    |
+ *               |     L2ARC     |    |
+ *               +---------------+    |
+ *                   |    ^           |
+ *          l2arc_write() |           |
+ *                   |    |           |
+ *                   V    |           |
+ *                 +-------+      +-------+
+ *                 | vdev  |      | vdev  |
+ *                 | cache |      | cache |
+ *                 +-------+      +-------+
+ *                 +=========+     .-----.
+ *                 :  L2ARC  :    |-_____-|
+ *                 : devices :    | Disks |
+ *                 +=========+    `-_____-'
+ *
+ * Read requests are satisfied from the following sources, in order:
+ *
+ *     1) ARC
+ *     2) vdev cache of L2ARC devices
+ *     3) L2ARC devices
+ *     4) vdev cache of disks
+ *     5) disks
+ *
+ * Some L2ARC device types exhibit extremely slow write performance.
+ * To accommodate for this there are some significant differences between
+ * the L2ARC and traditional cache design:
+ *
+ * 1. There is no eviction path from the ARC to the L2ARC.  Evictions from
+ * the ARC behave as usual, freeing buffers and placing headers on ghost
+ * lists.  The ARC does not send buffers to the L2ARC during eviction as
+ * this would add inflated write latencies for all ARC memory pressure.
+ *
+ * 2. The L2ARC attempts to cache data from the ARC before it is evicted.
+ * It does this by periodically scanning buffers from the eviction-end of
+ * the MFU and MRU ARC lists, copying them to the L2ARC devices if they are
+ * not already there. It scans until a headroom of buffers is satisfied,
+ * which itself is a buffer for ARC eviction. If a compressible buffer is
+ * found during scanning and selected for writing to an L2ARC device, we
+ * temporarily boost scanning headroom during the next scan cycle to make
+ * sure we adapt to compression effects (which might significantly reduce
+ * the data volume we write to L2ARC). The thread that does this is
+ * l2arc_feed_thread(), illustrated below; example sizes are included to
+ * provide a better sense of ratio than this diagram:
+ *
+ *            head -->                        tail
+ *             +---------------------+----------+
+ *     ARC_mfu |:::::#:::::::::::::::|o#o###o###|-->.   # already on L2ARC
+ *             +---------------------+----------+   |   o L2ARC eligible
+ *     ARC_mru |:#:::::::::::::::::::|#o#ooo####|-->|   : ARC buffer
+ *             +---------------------+----------+   |
+ *                  15.9 Gbytes      ^ 32 Mbytes    |
+ *                                headroom          |
+ *                                           l2arc_feed_thread()
+ *                                                  |
+ *                      l2arc write hand <--[oooo]--'
+ *                              |           8 Mbyte
+ *                              |          write max
+ *                              V
+ *               +==============================+
+ *     L2ARC dev |####|#|###|###|    |####| ... |
+ *               +==============================+
+ *                          32 Gbytes
+ *
+ * 3. If an ARC buffer is copied to the L2ARC but then hit instead of
+ * evicted, then the L2ARC has cached a buffer much sooner than it probably
+ * needed to, potentially wasting L2ARC device bandwidth and storage.  It is
+ * safe to say that this is an uncommon case, since buffers at the end of
+ * the ARC lists have moved there due to inactivity.
+ *
+ * 4. If the ARC evicts faster than the L2ARC can maintain a headroom,
+ * then the L2ARC simply misses copying some buffers.  This serves as a
+ * pressure valve to prevent heavy read workloads from both stalling the ARC
+ * with waits and clogging the L2ARC with writes.  This also helps prevent
+ * the potential for the L2ARC to churn if it attempts to cache content too
+ * quickly, such as during backups of the entire pool.
+ *
+ * 5. After system boot and before the ARC has filled main memory, there are
+ * no evictions from the ARC and so the tails of the ARC_mfu and ARC_mru
+ * lists can remain mostly static.  Instead of searching from tail of these
+ * lists as pictured, the l2arc_feed_thread() will search from the list heads
+ * for eligible buffers, greatly increasing its chance of finding them.
+ *
+ * The L2ARC device write speed is also boosted during this time so that
+ * the L2ARC warms up faster.  Since there have been no ARC evictions yet,
+ * there are no L2ARC reads, and no fear of degrading read performance
+ * through increased writes.
+ *
+ * 6. Writes to the L2ARC devices are grouped and sent in-sequence, so that
+ * the vdev queue can aggregate them into larger and fewer writes.  Each
+ * device is written to in a rotor fashion, sweeping writes through
+ * available space then repeating.
+ *
+ * 7. The L2ARC does not store dirty content.  It never needs to flush
+ * write buffers back to disk based storage.
+ *
+ * 8. If an ARC buffer is written (and dirtied) which also exists in the
+ * L2ARC, the now stale L2ARC buffer is immediately dropped.
+ *
+ * The performance of the L2ARC can be tweaked by a number of tunables, which
+ * may be necessary for different workloads:
+ *
+ *     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
+ *                             percentage factor for the next scan cycle,
+ *                             since more compressed buffers are likely to
+ *                             be present
+ *     l2arc_feed_secs         seconds between L2ARC writing
+ *
+ * Tunables may be removed or added as future performance improvements are
+ * integrated, and also may become zpool properties.
+ *
+ * There are three key functions that control how the L2ARC warms up:
+ *
+ *     l2arc_write_eligible()  check if a buffer is eligible to cache
+ *     l2arc_write_size()      calculate how much to write
+ *     l2arc_write_interval()  calculate sleep delay between writes
+ *
+ * These three functions determine what to write, how much, and how quickly
+ * to send writes.
+ */
+
+static boolean_t
+l2arc_write_eligible(uint64_t spa_guid, arc_buf_hdr_t *hdr)
+{
+       /*
+        * A buffer is *not* eligible for the L2ARC if it:
+        * 1. belongs to a different spa.
+        * 2. is already cached on the L2ARC.
+        * 3. has an I/O in progress (it may be an incomplete read).
+        * 4. is flagged not eligible (zfs property).
+        */
+       if (hdr->b_spa != spa_guid || HDR_HAS_L2HDR(hdr) ||
+           HDR_IO_IN_PROGRESS(hdr) || !HDR_L2CACHE(hdr))
+               return (B_FALSE);
+
+       return (B_TRUE);
+}
+
+static uint64_t
+l2arc_write_size(void)
+{
+       uint64_t size;
+
+       /*
+        * Make sure our globals have meaningful values in case the user
+        * altered them.
+        */
+       size = l2arc_write_max;
+       if (size == 0) {
+               cmn_err(CE_NOTE, "Bad value for l2arc_write_max, value must "
+                   "be greater than zero, resetting it to the default (%d)",
+                   L2ARC_WRITE_SIZE);
+               size = l2arc_write_max = L2ARC_WRITE_SIZE;
+       }
+
+       if (arc_warm == B_FALSE)
+               size += l2arc_write_boost;
+
+       return (size);
+
+}
+
+static clock_t
+l2arc_write_interval(clock_t began, uint64_t wanted, uint64_t wrote)
+{
+       clock_t interval, next, now;
+
+       /*
+        * If the ARC lists are busy, increase our write rate; if the
+        * lists are stale, idle back.  This is achieved by checking
+        * how much we previously wrote - if it was more than half of
+        * what we wanted, schedule the next write much sooner.
+        */
+       if (l2arc_feed_again && wrote > (wanted / 2))
+               interval = (hz * l2arc_feed_min_ms) / 1000;
+       else
+               interval = hz * l2arc_feed_secs;
+
+       now = ddi_get_lbolt();
+       next = MAX(now, MIN(now + interval, began + interval));
+
+       return (next);
+}
+
+/*
+ * Cycle through L2ARC devices.  This is how L2ARC load balances.
+ * If a device is returned, this also returns holding the spa config lock.
+ */
+static l2arc_dev_t *
+l2arc_dev_get_next(void)
+{
+       l2arc_dev_t *first, *next = NULL;
+
+       /*
+        * Lock out the removal of spas (spa_namespace_lock), then removal
+        * of cache devices (l2arc_dev_mtx).  Once a device has been selected,
+        * both locks will be dropped and a spa config lock held instead.
+        */
+       mutex_enter(&spa_namespace_lock);
+       mutex_enter(&l2arc_dev_mtx);
+
+       /* if there are no vdevs, there is nothing to do */
+       if (l2arc_ndev == 0)
+               goto out;
+
+       first = NULL;
+       next = l2arc_dev_last;
+       do {
+               /* loop around the list looking for a non-faulted vdev */
+               if (next == NULL) {
+                       next = list_head(l2arc_dev_list);
+               } else {
+                       next = list_next(l2arc_dev_list, next);
+                       if (next == NULL)
+                               next = list_head(l2arc_dev_list);
+               }
+
+               /* if we have come back to the start, bail out */
+               if (first == NULL)
+                       first = next;
+               else if (next == first)
+                       break;
+
+       } while (vdev_is_dead(next->l2ad_vdev));
+
+       /* if we were unable to find any usable vdevs, return NULL */
+       if (vdev_is_dead(next->l2ad_vdev))
+               next = NULL;
+
+       l2arc_dev_last = next;
+
+out:
+       mutex_exit(&l2arc_dev_mtx);
+
+       /*
+        * Grab the config lock to prevent the 'next' device from being
+        * removed while we are writing to it.
+        */
+       if (next != NULL)
+               spa_config_enter(next->l2ad_spa, SCL_L2ARC, next, RW_READER);
+       mutex_exit(&spa_namespace_lock);
+
+       return (next);
+}
+
+/*
+ * Free buffers that were tagged for destruction.
+ */
+static void
+l2arc_do_free_on_write(void)
+{
+       list_t *buflist;
+       l2arc_data_free_t *df, *df_prev;
+
+       mutex_enter(&l2arc_free_on_write_mtx);
+       buflist = l2arc_free_on_write;
+
+       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);
+               list_remove(buflist, df);
+               kmem_free(df, sizeof (l2arc_data_free_t));
+       }
+
+       mutex_exit(&l2arc_free_on_write_mtx);
+}
+
+/*
+ * A write to a cache device has completed.  Update all headers to allow
+ * reads from these buffers to begin.
+ */
+static void
+l2arc_write_done(zio_t *zio)
+{
+       l2arc_write_callback_t *cb;
+       l2arc_dev_t *dev;
+       list_t *buflist;
+       arc_buf_hdr_t *head, *hdr, *hdr_prev;
+       kmutex_t *hash_lock;
+       int64_t bytes_dropped = 0;
+
+       cb = zio->io_private;
+       ASSERT(cb != NULL);
+       dev = cb->l2wcb_dev;
+       ASSERT(dev != NULL);
+       head = cb->l2wcb_head;
+       ASSERT(head != NULL);
+       buflist = &dev->l2ad_buflist;
+       ASSERT(buflist != NULL);
+       DTRACE_PROBE2(l2arc__iodone, zio_t *, zio,
+           l2arc_write_callback_t *, cb);
+
+       if (zio->io_error != 0)
+               ARCSTAT_BUMP(arcstat_l2_writes_error);
+
+       /*
+        * All writes completed, or an error was hit.
+        */
+top:
+       mutex_enter(&dev->l2ad_mtx);
+       for (hdr = list_prev(buflist, head); hdr; hdr = hdr_prev) {
+               hdr_prev = list_prev(buflist, hdr);
+
+               hash_lock = HDR_LOCK(hdr);
+
+               /*
+                * We cannot use mutex_enter or else we can deadlock
+                * with l2arc_write_buffers (due to swapping the order
+                * the hash lock and l2ad_mtx are taken).
+                */
+               if (!mutex_tryenter(hash_lock)) {
+                       /*
+                        * Missed the hash lock. We must retry so we
+                        * don't leave the ARC_FLAG_L2_WRITING bit set.
+                        */
+                       ARCSTAT_BUMP(arcstat_l2_writes_lock_retry);
+
+                       /*
+                        * We don't want to rescan the headers we've
+                        * already marked as having been written out, so
+                        * we reinsert the head node so we can pick up
+                        * where we left off.
+                        */
+                       list_remove(buflist, head);
+                       list_insert_after(buflist, hdr, head);
+
+                       mutex_exit(&dev->l2ad_mtx);
+
+                       /*
+                        * We wait for the hash lock to become available
+                        * to try and prevent busy waiting, and increase
+                        * the chance we'll be able to acquire the lock
+                        * the next time around.
+                        */
+                       mutex_enter(hash_lock);
+                       mutex_exit(hash_lock);
+                       goto top;
+               }
+
+               /*
+                * We could not have been moved into the arc_l2c_only
+                * state while in-flight due to our ARC_FLAG_L2_WRITING
+                * bit being set. Let's just ensure that's being enforced.
+                */
+               ASSERT(HDR_HAS_L1HDR(hdr));
+
+               /*
+                * We may have allocated a buffer for L2ARC compression,
+                * we must release it to avoid leaking this data.
+                */
+               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;
+
+                       ARCSTAT_INCR(arcstat_l2_asize, -hdr->b_l2hdr.b_asize);
+                       ARCSTAT_INCR(arcstat_l2_size, -hdr->b_size);
+
+                       bytes_dropped += hdr->b_l2hdr.b_asize;
+                       (void) refcount_remove_many(&dev->l2ad_alloc,
+                           hdr->b_l2hdr.b_asize, hdr);
+               }
+
+               /*
+                * Allow ARC to begin reads and ghost list evictions to
+                * this L2ARC entry.
+                */
+               hdr->b_flags &= ~ARC_FLAG_L2_WRITING;
+
+               mutex_exit(hash_lock);
+       }
+
+       atomic_inc_64(&l2arc_writes_done);
+       list_remove(buflist, head);
+       ASSERT(!HDR_HAS_L1HDR(head));
+       kmem_cache_free(hdr_l2only_cache, head);
+       mutex_exit(&dev->l2ad_mtx);
+
+       vdev_space_update(dev->l2ad_vdev, -bytes_dropped, 0, 0);
+
+       l2arc_do_free_on_write();
+
+       kmem_free(cb, sizeof (l2arc_write_callback_t));
+}
+
+/*
+ * A read to a cache device completed.  Validate buffer contents before
+ * handing over to the regular ARC routines.
+ */
+static void
+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;
+
+       ASSERT(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);
+
+       hash_lock = HDR_LOCK(buf->b_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);
+
+       /*
+        * Check this survived the L2ARC journey.
+        */
+       equal = arc_cksum_equal(buf);
+       if (equal && 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 */
+               arc_read_done(zio);
+       } else {
+               mutex_exit(hash_lock);
+               /*
+                * Buffer didn't survive caching.  Increment stats and
+                * reissue to the original storage device.
+                */
+               if (zio->io_error != 0) {
+                       ARCSTAT_BUMP(arcstat_l2_io_error);
+               } else {
+                       zio->io_error = SET_ERROR(EIO);
+               }
+               if (!equal)
+                       ARCSTAT_BUMP(arcstat_l2_cksum_bad);
+
+               /*
+                * If there's no waiter, issue an async i/o to the primary
+                * storage now.  If there *is* a waiter, the caller must
+                * issue the i/o in a context where it's OK to block.
+                */
+               if (zio->io_waiter == NULL) {
+                       zio_t *pio = zio_unique_parent(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));
+               }
+       }
+
+       kmem_free(cb, sizeof (l2arc_read_callback_t));
+}
+
+/*
+ * This is the list priority from which the L2ARC will search for pages to
+ * cache.  This is used within loops (0..3) to cycle through lists in the
+ * desired order.  This order can have a significant effect on cache
+ * performance.
+ *
+ * Currently the metadata lists are hit first, MFU then MRU, followed by
+ * the data lists.  This function returns a locked list, and also returns
+ * the lock pointer.
+ */
+static multilist_sublist_t *
+l2arc_sublist_lock(int list_num)
+{
+       multilist_t *ml = NULL;
+       unsigned int idx;
+
+       ASSERT(list_num >= 0 && list_num <= 3);
+
+       switch (list_num) {
+       case 0:
+               ml = &arc_mfu->arcs_list[ARC_BUFC_METADATA];
+               break;
+       case 1:
+               ml = &arc_mru->arcs_list[ARC_BUFC_METADATA];
+               break;
+       case 2:
+               ml = &arc_mfu->arcs_list[ARC_BUFC_DATA];
+               break;
+       case 3:
+               ml = &arc_mru->arcs_list[ARC_BUFC_DATA];
+               break;
+       }
+
+       /*
+        * Return a randomly-selected sublist. This is acceptable
+        * because the caller feeds only a little bit of data for each
+        * call (8MB). Subsequent calls will result in different
+        * sublists being selected.
+        */
+       idx = multilist_get_random_index(ml);
+       return (multilist_sublist_lock(ml, idx));
+}
+
+/*
+ * Evict buffers from the device write hand to the distance specified in
+ * bytes.  This distance may span populated buffers, it may span nothing.
+ * This is clearing a region on the L2ARC device ready for writing.
+ * If the 'all' boolean is set, every buffer is evicted.
+ */
+static void
+l2arc_evict(l2arc_dev_t *dev, uint64_t distance, boolean_t all)
+{
+       list_t *buflist;
+       arc_buf_hdr_t *hdr, *hdr_prev;
+       kmutex_t *hash_lock;
+       uint64_t taddr;
+
+       buflist = &dev->l2ad_buflist;
+
+       if (!all && dev->l2ad_first) {
+               /*
+                * This is the first sweep through the device.  There is
+                * nothing to evict.
+                */
+               return;
+       }
+
+       if (dev->l2ad_hand >= (dev->l2ad_end - (2 * distance))) {
+               /*
+                * When nearing the end of the device, evict to the end
+                * before the device write hand jumps to the start.
+                */
+               taddr = dev->l2ad_end;
+       } else {
+               taddr = dev->l2ad_hand + distance;
+       }
+       DTRACE_PROBE4(l2arc__evict, l2arc_dev_t *, dev, list_t *, buflist,
+           uint64_t, taddr, boolean_t, all);
+
+top:
+       mutex_enter(&dev->l2ad_mtx);
+       for (hdr = list_tail(buflist); hdr; hdr = hdr_prev) {
+               hdr_prev = list_prev(buflist, hdr);
+
+               hash_lock = HDR_LOCK(hdr);
+
+               /*
+                * We cannot use mutex_enter or else we can deadlock
+                * with l2arc_write_buffers (due to swapping the order
+                * the hash lock and l2ad_mtx are taken).
+                */
+               if (!mutex_tryenter(hash_lock)) {
+                       /*
+                        * Missed the hash lock.  Retry.
+                        */
+                       ARCSTAT_BUMP(arcstat_l2_evict_lock_retry);
+                       mutex_exit(&dev->l2ad_mtx);
+                       mutex_enter(hash_lock);
+                       mutex_exit(hash_lock);
+                       goto top;
+               }
+
+               if (HDR_L2_WRITE_HEAD(hdr)) {
+                       /*
+                        * We hit a write head node.  Leave it for
+                        * l2arc_write_done().
+                        */
+                       list_remove(buflist, hdr);
+                       mutex_exit(hash_lock);
+                       continue;
+               }
+
+               if (!all && HDR_HAS_L2HDR(hdr) &&
+                   (hdr->b_l2hdr.b_daddr > taddr ||
+                   hdr->b_l2hdr.b_daddr < dev->l2ad_hand)) {
+                       /*
+                        * We've evicted to the target address,
+                        * or the end of the device.
+                        */
+                       mutex_exit(hash_lock);
+                       break;
+               }
+
+               ASSERT(HDR_HAS_L2HDR(hdr));
+               if (!HDR_HAS_L1HDR(hdr)) {
+                       ASSERT(!HDR_L2_READING(hdr));
+                       /*
+                        * This doesn't exist in the ARC.  Destroy.
+                        * arc_hdr_destroy() will call list_remove()
+                        * and decrement arcstat_l2_size.
+                        */
+                       arc_change_state(arc_anon, hdr, hash_lock);
+                       arc_hdr_destroy(hdr);
+               } else {
+                       ASSERT(hdr->b_l1hdr.b_state != arc_l2c_only);
+                       ARCSTAT_BUMP(arcstat_l2_evict_l1cached);
+                       /*
+                        * Invalidate issued or about to be issued
+                        * reads, since we may be about to write
+                        * over this location.
+                        */
+                       if (HDR_L2_READING(hdr)) {
+                               ARCSTAT_BUMP(arcstat_l2_evict_reading);
+                               hdr->b_flags |= 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);
+               }
+               mutex_exit(hash_lock);
+       }
+       mutex_exit(&dev->l2ad_mtx);
+}
+
+/*
+ * Find and write ARC buffers to the L2ARC device.
+ *
+ * An ARC_FLAG_L2_WRITING flag is set so that the L2ARC buffers are not valid
+ * for reading until they have completed writing.
+ * The headroom_boost is an in-out parameter used to maintain headroom boost
+ * state between calls to this function.
+ *
+ * Returns the number of bytes actually written (which may be smaller than
+ * 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)
+{
+       arc_buf_hdr_t *hdr, *hdr_prev, *head;
+       uint64_t write_asize, write_sz, headroom, buf_compress_minsz,
+           stats_size;
+       void *buf_data;
+       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;
+
+       pio = NULL;
+       write_sz = write_asize = 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;
+
+       /*
+        * Copy buffers for L2ARC writing.
+        */
+       for (try = 0; try <= 3; try++) {
+               multilist_sublist_t *mls = l2arc_sublist_lock(try);
+               uint64_t passed_sz = 0;
+
+               /*
+                * L2ARC fast warmup.
+                *
+                * Until the ARC is warm and starts to evict, read from the
+                * head of the ARC lists rather than the tail.
+                */
+               if (arc_warm == B_FALSE)
+                       hdr = multilist_sublist_head(mls);
+               else
+                       hdr = multilist_sublist_tail(mls);
+
+               headroom = target_sz * l2arc_headroom;
+               if (do_headroom_boost)
+                       headroom = (headroom * l2arc_headroom_boost) / 100;
+
+               for (; hdr; hdr = hdr_prev) {
+                       kmutex_t *hash_lock;
+                       uint64_t buf_sz;
+                       uint64_t buf_a_sz;
+
+                       if (arc_warm == B_FALSE)
+                               hdr_prev = multilist_sublist_next(mls, hdr);
+                       else
+                               hdr_prev = multilist_sublist_prev(mls, hdr);
+
+                       hash_lock = HDR_LOCK(hdr);
+                       if (!mutex_tryenter(hash_lock)) {
+                               /*
+                                * Skip this buffer rather than waiting.
+                                */
+                               continue;
+                       }
+
+                       passed_sz += hdr->b_size;
+                       if (passed_sz > headroom) {
+                               /*
+                                * Searched too far.
+                                */
+                               mutex_exit(hash_lock);
+                               break;
+                       }
+
+                       if (!l2arc_write_eligible(guid, hdr)) {
+                               mutex_exit(hash_lock);
+                               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) {
+                               full = B_TRUE;
+                               mutex_exit(hash_lock);
+                               break;
+                       }
+
+                       if (pio == NULL) {
+                               /*
+                                * Insert a dummy header on the buflist so
+                                * l2arc_write_done() can find where the
+                                * write buffers begin without searching.
+                                */
+                               mutex_enter(&dev->l2ad_mtx);
+                               list_insert_head(&dev->l2ad_buflist, head);
+                               mutex_exit(&dev->l2ad_mtx);
+
+                               cb = kmem_alloc(
+                                   sizeof (l2arc_write_callback_t), KM_SLEEP);
+                               cb->l2wcb_dev = dev;
+                               cb->l2wcb_head = head;
+                               pio = zio_root(spa, l2arc_write_done, cb,
+                                   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;
+
+                       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.
+                        */
+                       arc_cksum_verify(hdr->b_l1hdr.b_buf);
+                       arc_cksum_compute(hdr->b_l1hdr.b_buf, B_TRUE);
+
+                       mutex_exit(hash_lock);
+
+                       write_sz += buf_sz;
+                       write_asize += buf_a_sz;
+               }
+
+               multilist_sublist_unlock(mls);
+
+               if (full == B_TRUE)
+                       break;
+       }
+
+       /* No buffers selected for writing? */
+       if (pio == NULL) {
+               ASSERT0(write_sz);
+               ASSERT(!HDR_HAS_L1HDR(head));
+               kmem_cache_free(hdr_l2only_cache, head);
+               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);
+
+       /*
+        * Bump device hand to the device start if it is approaching the end.
+        * l2arc_evict() will already have evicted ahead for this case.
+        */
+       if (dev->l2ad_hand >= (dev->l2ad_end - target_sz)) {
+               dev->l2ad_hand = dev->l2ad_start;
+               dev->l2ad_first = B_FALSE;
+       }
+
+       dev->l2ad_writing = B_TRUE;
+       (void) zio_wait(pio);
+       dev->l2ad_writing = B_FALSE;
+
+       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.
+ */
+static void
+l2arc_feed_thread(void)
+{
+       callb_cpr_t cpr;
+       l2arc_dev_t *dev;
+       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);
+
+       mutex_enter(&l2arc_feed_thr_lock);
+
+       cookie = spl_fstrans_mark();
+       while (l2arc_thread_exit == 0) {
+               CALLB_CPR_SAFE_BEGIN(&cpr);
+               (void) cv_timedwait_sig(&l2arc_feed_thr_cv,
+                   &l2arc_feed_thr_lock, next);
+               CALLB_CPR_SAFE_END(&cpr, &l2arc_feed_thr_lock);
+               next = ddi_get_lbolt() + hz;
+
+               /*
+                * Quick check for L2ARC devices.
+                */
+               mutex_enter(&l2arc_dev_mtx);
+               if (l2arc_ndev == 0) {
+                       mutex_exit(&l2arc_dev_mtx);
+                       continue;
+               }
+               mutex_exit(&l2arc_dev_mtx);
+               begin = ddi_get_lbolt();
+
+               /*
+                * This selects the next l2arc device to write to, and in
+                * doing so the next spa to feed from: dev->l2ad_spa.   This
+                * will return NULL if there are now no l2arc devices or if
+                * they are all faulted.
+                *
+                * If a device is returned, its spa's config lock is also
+                * held to prevent device removal.  l2arc_dev_get_next()
+                * will grab and release l2arc_dev_mtx.
+                */
+               if ((dev = l2arc_dev_get_next()) == NULL)
+                       continue;
+
+               spa = dev->l2ad_spa;
+               ASSERT(spa != NULL);
+
+               /*
+                * If the pool is read-only then force the feed thread to
+                * sleep a little longer.
+                */
+               if (!spa_writeable(spa)) {
+                       next = ddi_get_lbolt() + 5 * l2arc_feed_secs * hz;
+                       spa_config_exit(spa, SCL_L2ARC, dev);
+                       continue;
+               }
+
+               /*
+                * Avoid contributing to memory pressure.
+                */
+               if (arc_reclaim_needed()) {
+                       ARCSTAT_BUMP(arcstat_l2_abort_lowmem);
+                       spa_config_exit(spa, SCL_L2ARC, dev);
+                       continue;
+               }
+
+               ARCSTAT_BUMP(arcstat_l2_feeds);
+
+               size = l2arc_write_size();
+
+               /*
+                * Evict L2ARC buffers that will be overwritten.
+                */
+               l2arc_evict(dev, size, B_FALSE);
+
+               /*
+                * Write ARC buffers.
+                */
+               wrote = l2arc_write_buffers(spa, dev, size, &headroom_boost);
+
+               /*
+                * Calculate interval between writes.
+                */
+               next = l2arc_write_interval(begin, size, wrote);
+               spa_config_exit(spa, SCL_L2ARC, dev);
+       }
+       spl_fstrans_unmark(cookie);
+
+       l2arc_thread_exit = 0;
+       cv_broadcast(&l2arc_feed_thr_cv);
+       CALLB_CPR_EXIT(&cpr);           /* drops l2arc_feed_thr_lock */
+       thread_exit();
+}
+
+boolean_t
+l2arc_vdev_present(vdev_t *vd)
+{
+       l2arc_dev_t *dev;
+
+       mutex_enter(&l2arc_dev_mtx);
+       for (dev = list_head(l2arc_dev_list); dev != NULL;
+           dev = list_next(l2arc_dev_list, dev)) {
+               if (dev->l2ad_vdev == vd)
+                       break;
+       }
+       mutex_exit(&l2arc_dev_mtx);
+
+       return (dev != NULL);
+}
+
+/*
+ * Add a vdev for use by the L2ARC.  By this point the spa has already
+ * validated the vdev and opened it.
+ */
+void
+l2arc_add_vdev(spa_t *spa, vdev_t *vd)
+{
+       l2arc_dev_t *adddev;
+
+       ASSERT(!l2arc_vdev_present(vd));
+
+       /*
+        * Create a new l2arc device entry.
+        */
+       adddev = kmem_zalloc(sizeof (l2arc_dev_t), KM_SLEEP);
+       adddev->l2ad_spa = spa;
+       adddev->l2ad_vdev = vd;
+       adddev->l2ad_start = VDEV_LABEL_START_SIZE;
+       adddev->l2ad_end = VDEV_LABEL_START_SIZE + vdev_get_min_asize(vd);
+       adddev->l2ad_hand = adddev->l2ad_start;
+       adddev->l2ad_first = B_TRUE;
+       adddev->l2ad_writing = B_FALSE;
+       list_link_init(&adddev->l2ad_node);
+
+       mutex_init(&adddev->l2ad_mtx, NULL, MUTEX_DEFAULT, NULL);
+       /*
+        * This is a list of all ARC buffers that are still valid on the
+        * device.
+        */
+       list_create(&adddev->l2ad_buflist, sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l2hdr.b_l2node));
+
+       vdev_space_update(vd, 0, 0, adddev->l2ad_end - adddev->l2ad_hand);
+       refcount_create(&adddev->l2ad_alloc);
+
+       /*
+        * Add device to global list
+        */
+       mutex_enter(&l2arc_dev_mtx);
+       list_insert_head(l2arc_dev_list, adddev);
+       atomic_inc_64(&l2arc_ndev);
+       mutex_exit(&l2arc_dev_mtx);
+}
+
+/*
+ * Remove a vdev from the L2ARC.
+ */
+void
+l2arc_remove_vdev(vdev_t *vd)
+{
+       l2arc_dev_t *dev, *nextdev, *remdev = NULL;
+
+       /*
+        * Find the device by vdev
+        */
+       mutex_enter(&l2arc_dev_mtx);
+       for (dev = list_head(l2arc_dev_list); dev; dev = nextdev) {
+               nextdev = list_next(l2arc_dev_list, dev);
+               if (vd == dev->l2ad_vdev) {
+                       remdev = dev;
+                       break;
+               }
+       }
+       ASSERT(remdev != NULL);
+
+       /*
+        * Remove device from global list
+        */
+       list_remove(l2arc_dev_list, remdev);
+       l2arc_dev_last = NULL;          /* may have been invalidated */
+       atomic_dec_64(&l2arc_ndev);
+       mutex_exit(&l2arc_dev_mtx);
+
+       /*
+        * Clear all buflists and ARC references.  L2ARC device flush.
+        */
+       l2arc_evict(remdev, 0, B_TRUE);
+       list_destroy(&remdev->l2ad_buflist);
+       mutex_destroy(&remdev->l2ad_mtx);
+       refcount_destroy(&remdev->l2ad_alloc);
+       kmem_free(remdev, sizeof (l2arc_dev_t));
+}
+
+void
+l2arc_init(void)
+{
+       l2arc_thread_exit = 0;
+       l2arc_ndev = 0;
+       l2arc_writes_sent = 0;
+       l2arc_writes_done = 0;
+
+       mutex_init(&l2arc_feed_thr_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&l2arc_feed_thr_cv, NULL, CV_DEFAULT, NULL);
+       mutex_init(&l2arc_dev_mtx, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&l2arc_free_on_write_mtx, NULL, MUTEX_DEFAULT, NULL);
+
+       l2arc_dev_list = &L2ARC_dev_list;
+       l2arc_free_on_write = &L2ARC_free_on_write;
+       list_create(l2arc_dev_list, sizeof (l2arc_dev_t),
+           offsetof(l2arc_dev_t, l2ad_node));
+       list_create(l2arc_free_on_write, sizeof (l2arc_data_free_t),
+           offsetof(l2arc_data_free_t, l2df_list_node));
+}
+
+void
+l2arc_fini(void)
+{
+       /*
+        * This is called from dmu_fini(), which is called from spa_fini();
+        * Because of this, we can assume that all l2arc devices have
+        * already been removed when the pools themselves were removed.
+        */
+
+       l2arc_do_free_on_write();
+
+       mutex_destroy(&l2arc_feed_thr_lock);
+       cv_destroy(&l2arc_feed_thr_cv);
+       mutex_destroy(&l2arc_dev_mtx);
+       mutex_destroy(&l2arc_free_on_write_mtx);
+
+       list_destroy(l2arc_dev_list);
+       list_destroy(l2arc_free_on_write);
+}
+
+void
+l2arc_start(void)
+{
+       if (!(spa_mode_global & FWRITE))
+               return;
+
+       (void) thread_create(NULL, 0, l2arc_feed_thread, NULL, 0, &p0,
+           TS_RUN, defclsyspri);
+}
+
+void
+l2arc_stop(void)
+{
+       if (!(spa_mode_global & FWRITE))
+               return;
+
+       mutex_enter(&l2arc_feed_thr_lock);
+       cv_signal(&l2arc_feed_thr_cv);  /* kick thread out of startup */
+       l2arc_thread_exit = 1;
+       while (l2arc_thread_exit != 0)
+               cv_wait(&l2arc_feed_thr_cv, &l2arc_feed_thr_lock);
+       mutex_exit(&l2arc_feed_thr_lock);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+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);
+EXPORT_SYMBOL(arc_remove_prune_callback);
+
+module_param(zfs_arc_min, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_min, "Min arc size");
+
+module_param(zfs_arc_max, ulong, 0644);
+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_min, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_meta_min, "Min arc metadata");
+
+module_param(zfs_arc_meta_prune, int, 0644);
+MODULE_PARM_DESC(zfs_arc_meta_prune, "Meta objects to scan for prune");
+
+module_param(zfs_arc_meta_adjust_restarts, int, 0644);
+MODULE_PARM_DESC(zfs_arc_meta_adjust_restarts,
+       "Limit number of restarts in arc_adjust_meta");
+
+module_param(zfs_arc_meta_strategy, int, 0644);
+MODULE_PARM_DESC(zfs_arc_meta_strategy, "Meta reclaim strategy");
+
+module_param(zfs_arc_grow_retry, int, 0644);
+MODULE_PARM_DESC(zfs_arc_grow_retry, "Seconds before growing arc size");
+
+module_param(zfs_arc_p_aggressive_disable, int, 0644);
+MODULE_PARM_DESC(zfs_arc_p_aggressive_disable, "disable aggressive arc_p grow");
+
+module_param(zfs_arc_p_dampener_disable, int, 0644);
+MODULE_PARM_DESC(zfs_arc_p_dampener_disable, "disable arc_p adapt dampener");
+
+module_param(zfs_arc_shrink_shift, int, 0644);
+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_arc_min_prefetch_lifespan, int, 0644);
+MODULE_PARM_DESC(zfs_arc_min_prefetch_lifespan, "Min life of prefetch block");
+
+module_param(zfs_arc_num_sublists_per_state, int, 0644);
+MODULE_PARM_DESC(zfs_arc_num_sublists_per_state,
+       "Number of sublists used in each of the ARC state lists");
+
+module_param(l2arc_write_max, ulong, 0644);
+MODULE_PARM_DESC(l2arc_write_max, "Max write bytes per interval");
+
+module_param(l2arc_write_boost, ulong, 0644);
+MODULE_PARM_DESC(l2arc_write_boost, "Extra write bytes during device warmup");
+
+module_param(l2arc_headroom, ulong, 0644);
+MODULE_PARM_DESC(l2arc_headroom, "Number of max device writes to precache");
+
+module_param(l2arc_headroom_boost, ulong, 0644);
+MODULE_PARM_DESC(l2arc_headroom_boost, "Compressed l2arc_headroom multiplier");
+
+module_param(l2arc_feed_secs, ulong, 0644);
+MODULE_PARM_DESC(l2arc_feed_secs, "Seconds between L2ARC writing");
+
+module_param(l2arc_feed_min_ms, ulong, 0644);
+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");
+
+module_param(l2arc_norw, int, 0644);
+MODULE_PARM_DESC(l2arc_norw, "No reads during writes");
+
+module_param(zfs_arc_lotsfree_percent, int, 0644);
+MODULE_PARM_DESC(zfs_arc_lotsfree_percent,
+       "System free memory I/O throttle in bytes");
+
+module_param(zfs_arc_sys_free, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_sys_free, "System free memory target size in bytes");
+
+#endif
diff --git a/zfs/module/zfs/blkptr.c b/zfs/module/zfs/blkptr.c
new file mode 100644 (file)
index 0000000..d56e199
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+#include <sys/zio_compress.h>
+
+/*
+ * Embedded-data Block Pointers
+ *
+ * Normally, block pointers point (via their DVAs) to a block which holds data.
+ * If the data that we need to store is very small, this is an inefficient
+ * use of space, because a block must be at minimum 1 sector (typically 512
+ * bytes or 4KB).  Additionally, reading these small blocks tends to generate
+ * more random reads.
+ *
+ * Embedded-data Block Pointers allow small pieces of data (the "payload",
+ * up to 112 bytes) to be stored in the block pointer itself, instead of
+ * being pointed to.  The "Pointer" part of this name is a bit of a
+ * misnomer, as nothing is pointed to.
+ *
+ * BP_EMBEDDED_TYPE_DATA block pointers allow highly-compressible data to
+ * be embedded in the block pointer.  The logic for this is handled in
+ * the SPA, by the zio pipeline.  Therefore most code outside the zio
+ * pipeline doesn't need special-cases to handle these block pointers.
+ *
+ * See spa.h for details on the exact layout of embedded block pointers.
+ */
+
+void
+encode_embedded_bp_compressed(blkptr_t *bp, void *data,
+    enum zio_compress comp, int uncompressed_size, int compressed_size)
+{
+       uint64_t *bp64 = (uint64_t *)bp;
+       uint64_t w = 0;
+       uint8_t *data8 = data;
+       int i;
+
+       ASSERT3U(compressed_size, <=, BPE_PAYLOAD_SIZE);
+       ASSERT(uncompressed_size == compressed_size ||
+           comp != ZIO_COMPRESS_OFF);
+       ASSERT3U(comp, >=, ZIO_COMPRESS_OFF);
+       ASSERT3U(comp, <, ZIO_COMPRESS_FUNCTIONS);
+
+       bzero(bp, sizeof (*bp));
+       BP_SET_EMBEDDED(bp, B_TRUE);
+       BP_SET_COMPRESS(bp, comp);
+       BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
+       BPE_SET_LSIZE(bp, uncompressed_size);
+       BPE_SET_PSIZE(bp, compressed_size);
+
+       /*
+        * Encode the byte array into the words of the block pointer.
+        * First byte goes into low bits of first word (little endian).
+        */
+       for (i = 0; i < compressed_size; i++) {
+               BF64_SET(w, (i % sizeof (w)) * NBBY, NBBY, data8[i]);
+               if (i % sizeof (w) == sizeof (w) - 1) {
+                       /* we've reached the end of a word */
+                       ASSERT3P(bp64, <, bp + 1);
+                       *bp64 = w;
+                       bp64++;
+                       if (!BPE_IS_PAYLOADWORD(bp, bp64))
+                               bp64++;
+                       w = 0;
+               }
+       }
+       /* write last partial word */
+       if (bp64 < (uint64_t *)(bp + 1))
+               *bp64 = w;
+}
+
+/*
+ * buf must be at least BPE_GET_PSIZE(bp) bytes long (which will never be
+ * more than BPE_PAYLOAD_SIZE bytes).
+ */
+void
+decode_embedded_bp_compressed(const blkptr_t *bp, void *buf)
+{
+       int psize;
+       uint8_t *buf8 = buf;
+       uint64_t w = 0;
+       const uint64_t *bp64 = (const uint64_t *)bp;
+       int i;
+
+       ASSERT(BP_IS_EMBEDDED(bp));
+
+       psize = BPE_GET_PSIZE(bp);
+
+       /*
+        * Decode the words of the block pointer into the byte array.
+        * Low bits of first word are the first byte (little endian).
+        */
+       for (i = 0; i < psize; i++) {
+               if (i % sizeof (w) == 0) {
+                       /* beginning of a word */
+                       ASSERT3P(bp64, <, bp + 1);
+                       w = *bp64;
+                       bp64++;
+                       if (!BPE_IS_PAYLOADWORD(bp, bp64))
+                               bp64++;
+               }
+               buf8[i] = BF64_GET(w, (i % sizeof (w)) * NBBY, NBBY);
+       }
+}
diff --git a/zfs/module/zfs/bplist.c b/zfs/module/zfs/bplist.c
new file mode 100644 (file)
index 0000000..c81151e
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <sys/bplist.h>
+#include <sys/zfs_context.h>
+
+
+void
+bplist_create(bplist_t *bpl)
+{
+       mutex_init(&bpl->bpl_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&bpl->bpl_list, sizeof (bplist_entry_t),
+           offsetof(bplist_entry_t, bpe_node));
+}
+
+void
+bplist_destroy(bplist_t *bpl)
+{
+       list_destroy(&bpl->bpl_list);
+       mutex_destroy(&bpl->bpl_lock);
+}
+
+void
+bplist_append(bplist_t *bpl, const blkptr_t *bp)
+{
+       bplist_entry_t *bpe = kmem_alloc(sizeof (*bpe), KM_SLEEP);
+
+       mutex_enter(&bpl->bpl_lock);
+       bpe->bpe_blk = *bp;
+       list_insert_tail(&bpl->bpl_list, bpe);
+       mutex_exit(&bpl->bpl_lock);
+}
+
+/*
+ * To aid debugging, we keep the most recently removed entry.  This way if
+ * we are in the callback, we can easily locate the entry.
+ */
+static bplist_entry_t *bplist_iterate_last_removed;
+
+void
+bplist_iterate(bplist_t *bpl, bplist_itor_t *func, void *arg, dmu_tx_t *tx)
+{
+       bplist_entry_t *bpe;
+
+       mutex_enter(&bpl->bpl_lock);
+       while ((bpe = list_head(&bpl->bpl_list))) {
+               bplist_iterate_last_removed = bpe;
+               list_remove(&bpl->bpl_list, bpe);
+               mutex_exit(&bpl->bpl_lock);
+               func(arg, &bpe->bpe_blk, tx);
+               kmem_free(bpe, sizeof (*bpe));
+               mutex_enter(&bpl->bpl_lock);
+       }
+       mutex_exit(&bpl->bpl_lock);
+}
diff --git a/zfs/module/zfs/bpobj.c b/zfs/module/zfs/bpobj.c
new file mode 100644 (file)
index 0000000..17d98c3
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/bpobj.h>
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+#include <sys/dsl_pool.h>
+#include <sys/zfeature.h>
+#include <sys/zap.h>
+
+/*
+ * Return an empty bpobj, preferably the empty dummy one (dp_empty_bpobj).
+ */
+uint64_t
+bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_objset_spa(os);
+       dsl_pool_t *dp = dmu_objset_pool(os);
+
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_EMPTY_BPOBJ)) {
+               if (!spa_feature_is_active(spa, SPA_FEATURE_EMPTY_BPOBJ)) {
+                       ASSERT0(dp->dp_empty_bpobj);
+                       dp->dp_empty_bpobj =
+                           bpobj_alloc(os, SPA_OLD_MAXBLOCKSIZE, tx);
+                       VERIFY(zap_add(os,
+                           DMU_POOL_DIRECTORY_OBJECT,
+                           DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
+                           &dp->dp_empty_bpobj, tx) == 0);
+               }
+               spa_feature_incr(spa, SPA_FEATURE_EMPTY_BPOBJ, tx);
+               ASSERT(dp->dp_empty_bpobj != 0);
+               return (dp->dp_empty_bpobj);
+       } else {
+               return (bpobj_alloc(os, blocksize, tx));
+       }
+}
+
+void
+bpobj_decr_empty(objset_t *os, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dmu_objset_pool(os);
+
+       spa_feature_decr(dmu_objset_spa(os), SPA_FEATURE_EMPTY_BPOBJ, tx);
+       if (!spa_feature_is_active(dmu_objset_spa(os),
+           SPA_FEATURE_EMPTY_BPOBJ)) {
+               VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_EMPTY_BPOBJ, tx));
+               VERIFY3U(0, ==, dmu_object_free(os, dp->dp_empty_bpobj, tx));
+               dp->dp_empty_bpobj = 0;
+       }
+}
+
+uint64_t
+bpobj_alloc(objset_t *os, int blocksize, dmu_tx_t *tx)
+{
+       int size;
+
+       if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_BPOBJ_ACCOUNT)
+               size = BPOBJ_SIZE_V0;
+       else if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_DEADLISTS)
+               size = BPOBJ_SIZE_V1;
+       else
+               size = sizeof (bpobj_phys_t);
+
+       return (dmu_object_alloc(os, DMU_OT_BPOBJ, blocksize,
+           DMU_OT_BPOBJ_HDR, size, tx));
+}
+
+void
+bpobj_free(objset_t *os, uint64_t obj, dmu_tx_t *tx)
+{
+       int64_t i;
+       bpobj_t bpo;
+       dmu_object_info_t doi;
+       int epb;
+       dmu_buf_t *dbuf = NULL;
+
+       ASSERT(obj != dmu_objset_pool(os)->dp_empty_bpobj);
+       VERIFY3U(0, ==, bpobj_open(&bpo, os, obj));
+
+       mutex_enter(&bpo.bpo_lock);
+
+       if (!bpo.bpo_havesubobj || bpo.bpo_phys->bpo_subobjs == 0)
+               goto out;
+
+       VERIFY3U(0, ==, dmu_object_info(os, bpo.bpo_phys->bpo_subobjs, &doi));
+       epb = doi.doi_data_block_size / sizeof (uint64_t);
+
+       for (i = bpo.bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) {
+               uint64_t *objarray;
+               uint64_t offset, blkoff;
+
+               offset = i * sizeof (uint64_t);
+               blkoff = P2PHASE(i, epb);
+
+               if (dbuf == NULL || dbuf->db_offset > offset) {
+                       if (dbuf)
+                               dmu_buf_rele(dbuf, FTAG);
+                       VERIFY3U(0, ==, dmu_buf_hold(os,
+                           bpo.bpo_phys->bpo_subobjs, offset, FTAG, &dbuf, 0));
+               }
+
+               ASSERT3U(offset, >=, dbuf->db_offset);
+               ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size);
+
+               objarray = dbuf->db_data;
+               bpobj_free(os, objarray[blkoff], tx);
+       }
+       if (dbuf) {
+               dmu_buf_rele(dbuf, FTAG);
+               dbuf = NULL;
+       }
+       VERIFY3U(0, ==, dmu_object_free(os, bpo.bpo_phys->bpo_subobjs, tx));
+
+out:
+       mutex_exit(&bpo.bpo_lock);
+       bpobj_close(&bpo);
+
+       VERIFY3U(0, ==, dmu_object_free(os, obj, tx));
+}
+
+int
+bpobj_open(bpobj_t *bpo, objset_t *os, uint64_t object)
+{
+       dmu_object_info_t doi;
+       int err;
+
+       err = dmu_object_info(os, object, &doi);
+       if (err)
+               return (err);
+
+       bzero(bpo, sizeof (*bpo));
+       mutex_init(&bpo->bpo_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       ASSERT(bpo->bpo_dbuf == NULL);
+       ASSERT(bpo->bpo_phys == NULL);
+       ASSERT(object != 0);
+       ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ);
+       ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_BPOBJ_HDR);
+
+       err = dmu_bonus_hold(os, object, bpo, &bpo->bpo_dbuf);
+       if (err)
+               return (err);
+
+       bpo->bpo_os = os;
+       bpo->bpo_object = object;
+       bpo->bpo_epb = doi.doi_data_block_size >> SPA_BLKPTRSHIFT;
+       bpo->bpo_havecomp = (doi.doi_bonus_size > BPOBJ_SIZE_V0);
+       bpo->bpo_havesubobj = (doi.doi_bonus_size > BPOBJ_SIZE_V1);
+       bpo->bpo_phys = bpo->bpo_dbuf->db_data;
+       return (0);
+}
+
+void
+bpobj_close(bpobj_t *bpo)
+{
+       /* Lame workaround for closing a bpobj that was never opened. */
+       if (bpo->bpo_object == 0)
+               return;
+
+       dmu_buf_rele(bpo->bpo_dbuf, bpo);
+       if (bpo->bpo_cached_dbuf != NULL)
+               dmu_buf_rele(bpo->bpo_cached_dbuf, bpo);
+       bpo->bpo_dbuf = NULL;
+       bpo->bpo_phys = NULL;
+       bpo->bpo_cached_dbuf = NULL;
+       bpo->bpo_object = 0;
+
+       mutex_destroy(&bpo->bpo_lock);
+}
+
+static boolean_t
+bpobj_hasentries(bpobj_t *bpo)
+{
+       return (bpo->bpo_phys->bpo_num_blkptrs != 0 ||
+           (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_num_subobjs != 0));
+}
+
+static int
+bpobj_iterate_impl(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx,
+    boolean_t free)
+{
+       dmu_object_info_t doi;
+       int epb;
+       int64_t i;
+       int err = 0;
+       dmu_buf_t *dbuf = NULL;
+
+       mutex_enter(&bpo->bpo_lock);
+
+       if (free)
+               dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
+
+       for (i = bpo->bpo_phys->bpo_num_blkptrs - 1; i >= 0; i--) {
+               blkptr_t *bparray;
+               blkptr_t *bp;
+               uint64_t offset, blkoff;
+
+               offset = i * sizeof (blkptr_t);
+               blkoff = P2PHASE(i, bpo->bpo_epb);
+
+               if (dbuf == NULL || dbuf->db_offset > offset) {
+                       if (dbuf)
+                               dmu_buf_rele(dbuf, FTAG);
+                       err = dmu_buf_hold(bpo->bpo_os, bpo->bpo_object, offset,
+                           FTAG, &dbuf, 0);
+                       if (err)
+                               break;
+               }
+
+               ASSERT3U(offset, >=, dbuf->db_offset);
+               ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size);
+
+               bparray = dbuf->db_data;
+               bp = &bparray[blkoff];
+               err = func(arg, bp, tx);
+               if (err)
+                       break;
+               if (free) {
+                       bpo->bpo_phys->bpo_bytes -=
+                           bp_get_dsize_sync(dmu_objset_spa(bpo->bpo_os), bp);
+                       ASSERT3S(bpo->bpo_phys->bpo_bytes, >=, 0);
+                       if (bpo->bpo_havecomp) {
+                               bpo->bpo_phys->bpo_comp -= BP_GET_PSIZE(bp);
+                               bpo->bpo_phys->bpo_uncomp -= BP_GET_UCSIZE(bp);
+                       }
+                       bpo->bpo_phys->bpo_num_blkptrs--;
+                       ASSERT3S(bpo->bpo_phys->bpo_num_blkptrs, >=, 0);
+               }
+       }
+       if (dbuf) {
+               dmu_buf_rele(dbuf, FTAG);
+               dbuf = NULL;
+       }
+       if (free) {
+               VERIFY3U(0, ==, dmu_free_range(bpo->bpo_os, bpo->bpo_object,
+                   (i + 1) * sizeof (blkptr_t), -1ULL, tx));
+       }
+       if (err || !bpo->bpo_havesubobj || bpo->bpo_phys->bpo_subobjs == 0)
+               goto out;
+
+       ASSERT(bpo->bpo_havecomp);
+       err = dmu_object_info(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, &doi);
+       if (err) {
+               mutex_exit(&bpo->bpo_lock);
+               return (err);
+       }
+       ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ);
+       epb = doi.doi_data_block_size / sizeof (uint64_t);
+
+       for (i = bpo->bpo_phys->bpo_num_subobjs - 1; i >= 0; i--) {
+               uint64_t *objarray;
+               uint64_t offset, blkoff;
+               bpobj_t sublist;
+               uint64_t used_before, comp_before, uncomp_before;
+               uint64_t used_after, comp_after, uncomp_after;
+
+               offset = i * sizeof (uint64_t);
+               blkoff = P2PHASE(i, epb);
+
+               if (dbuf == NULL || dbuf->db_offset > offset) {
+                       if (dbuf)
+                               dmu_buf_rele(dbuf, FTAG);
+                       err = dmu_buf_hold(bpo->bpo_os,
+                           bpo->bpo_phys->bpo_subobjs, offset, FTAG, &dbuf, 0);
+                       if (err)
+                               break;
+               }
+
+               ASSERT3U(offset, >=, dbuf->db_offset);
+               ASSERT3U(offset, <, dbuf->db_offset + dbuf->db_size);
+
+               objarray = dbuf->db_data;
+               err = bpobj_open(&sublist, bpo->bpo_os, objarray[blkoff]);
+               if (err)
+                       break;
+               if (free) {
+                       err = bpobj_space(&sublist,
+                           &used_before, &comp_before, &uncomp_before);
+                       if (err != 0) {
+                               bpobj_close(&sublist);
+                               break;
+                       }
+               }
+               err = bpobj_iterate_impl(&sublist, func, arg, tx, free);
+               if (free) {
+                       VERIFY3U(0, ==, bpobj_space(&sublist,
+                           &used_after, &comp_after, &uncomp_after));
+                       bpo->bpo_phys->bpo_bytes -= used_before - used_after;
+                       ASSERT3S(bpo->bpo_phys->bpo_bytes, >=, 0);
+                       bpo->bpo_phys->bpo_comp -= comp_before - comp_after;
+                       bpo->bpo_phys->bpo_uncomp -=
+                           uncomp_before - uncomp_after;
+               }
+
+               bpobj_close(&sublist);
+               if (err)
+                       break;
+               if (free) {
+                       err = dmu_object_free(bpo->bpo_os,
+                           objarray[blkoff], tx);
+                       if (err)
+                               break;
+                       bpo->bpo_phys->bpo_num_subobjs--;
+                       ASSERT3S(bpo->bpo_phys->bpo_num_subobjs, >=, 0);
+               }
+       }
+       if (dbuf) {
+               dmu_buf_rele(dbuf, FTAG);
+               dbuf = NULL;
+       }
+       if (free) {
+               VERIFY3U(0, ==, dmu_free_range(bpo->bpo_os,
+                   bpo->bpo_phys->bpo_subobjs,
+                   (i + 1) * sizeof (uint64_t), -1ULL, tx));
+       }
+
+out:
+       /* If there are no entries, there should be no bytes. */
+       if (!bpobj_hasentries(bpo)) {
+               ASSERT0(bpo->bpo_phys->bpo_bytes);
+               ASSERT0(bpo->bpo_phys->bpo_comp);
+               ASSERT0(bpo->bpo_phys->bpo_uncomp);
+       }
+
+       mutex_exit(&bpo->bpo_lock);
+       return (err);
+}
+
+/*
+ * Iterate and remove the entries.  If func returns nonzero, iteration
+ * will stop and that entry will not be removed.
+ */
+int
+bpobj_iterate(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx)
+{
+       return (bpobj_iterate_impl(bpo, func, arg, tx, B_TRUE));
+}
+
+/*
+ * Iterate the entries.  If func returns nonzero, iteration will stop.
+ */
+int
+bpobj_iterate_nofree(bpobj_t *bpo, bpobj_itor_t func, void *arg, dmu_tx_t *tx)
+{
+       return (bpobj_iterate_impl(bpo, func, arg, tx, B_FALSE));
+}
+
+void
+bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx)
+{
+       bpobj_t subbpo;
+       uint64_t used, comp, uncomp, subsubobjs;
+       ASSERTV(dmu_object_info_t doi);
+
+       ASSERT(bpo->bpo_havesubobj);
+       ASSERT(bpo->bpo_havecomp);
+       ASSERT(bpo->bpo_object != dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj);
+
+       if (subobj == dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj) {
+               bpobj_decr_empty(bpo->bpo_os, tx);
+               return;
+       }
+
+       VERIFY3U(0, ==, bpobj_open(&subbpo, bpo->bpo_os, subobj));
+       VERIFY3U(0, ==, bpobj_space(&subbpo, &used, &comp, &uncomp));
+
+       if (!bpobj_hasentries(&subbpo)) {
+               /* No point in having an empty subobj. */
+               bpobj_close(&subbpo);
+               bpobj_free(bpo->bpo_os, subobj, tx);
+               return;
+       }
+
+       dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
+       if (bpo->bpo_phys->bpo_subobjs == 0) {
+               bpo->bpo_phys->bpo_subobjs = dmu_object_alloc(bpo->bpo_os,
+                   DMU_OT_BPOBJ_SUBOBJ, SPA_OLD_MAXBLOCKSIZE,
+                   DMU_OT_NONE, 0, tx);
+       }
+
+       ASSERT0(dmu_object_info(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, &doi));
+       ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ);
+
+       mutex_enter(&bpo->bpo_lock);
+       dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs,
+           bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj),
+           sizeof (subobj), &subobj, tx);
+       bpo->bpo_phys->bpo_num_subobjs++;
+
+       /*
+        * If subobj has only one block of subobjs, then move subobj's
+        * subobjs to bpo's subobj list directly.  This reduces
+        * recursion in bpobj_iterate due to nested subobjs.
+        */
+       subsubobjs = subbpo.bpo_phys->bpo_subobjs;
+       if (subsubobjs != 0) {
+               dmu_object_info_t doi;
+
+               VERIFY3U(0, ==, dmu_object_info(bpo->bpo_os, subsubobjs, &doi));
+               if (doi.doi_max_offset == doi.doi_data_block_size) {
+                       dmu_buf_t *subdb;
+                       uint64_t numsubsub = subbpo.bpo_phys->bpo_num_subobjs;
+
+                       VERIFY3U(0, ==, dmu_buf_hold(bpo->bpo_os, subsubobjs,
+                           0, FTAG, &subdb, 0));
+                       /*
+                        * Make sure that we are not asking dmu_write()
+                        * to write more data than we have in our buffer.
+                        */
+                       VERIFY3U(subdb->db_size, >=,
+                           numsubsub * sizeof (subobj));
+                       dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs,
+                           bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj),
+                           numsubsub * sizeof (subobj), subdb->db_data, tx);
+                       dmu_buf_rele(subdb, FTAG);
+                       bpo->bpo_phys->bpo_num_subobjs += numsubsub;
+
+                       dmu_buf_will_dirty(subbpo.bpo_dbuf, tx);
+                       subbpo.bpo_phys->bpo_subobjs = 0;
+                       VERIFY3U(0, ==, dmu_object_free(bpo->bpo_os,
+                           subsubobjs, tx));
+               }
+       }
+       bpo->bpo_phys->bpo_bytes += used;
+       bpo->bpo_phys->bpo_comp += comp;
+       bpo->bpo_phys->bpo_uncomp += uncomp;
+       mutex_exit(&bpo->bpo_lock);
+
+       bpobj_close(&subbpo);
+}
+
+void
+bpobj_enqueue(bpobj_t *bpo, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       blkptr_t stored_bp = *bp;
+       uint64_t offset;
+       int blkoff;
+       blkptr_t *bparray;
+
+       ASSERT(!BP_IS_HOLE(bp));
+       ASSERT(bpo->bpo_object != dmu_objset_pool(bpo->bpo_os)->dp_empty_bpobj);
+
+       if (BP_IS_EMBEDDED(bp)) {
+               /*
+                * The bpobj will compress better without the payload.
+                *
+                * Note that we store EMBEDDED bp's because they have an
+                * uncompressed size, which must be accounted for.  An
+                * alternative would be to add their size to bpo_uncomp
+                * without storing the bp, but that would create additional
+                * complications: bpo_uncomp would be inconsistent with the
+                * set of BP's stored, and bpobj_iterate() wouldn't visit
+                * all the space accounted for in the bpobj.
+                */
+               bzero(&stored_bp, sizeof (stored_bp));
+               stored_bp.blk_prop = bp->blk_prop;
+               stored_bp.blk_birth = bp->blk_birth;
+       } else if (!BP_GET_DEDUP(bp)) {
+               /* The bpobj will compress better without the checksum */
+               bzero(&stored_bp.blk_cksum, sizeof (stored_bp.blk_cksum));
+       }
+
+       /* We never need the fill count. */
+       stored_bp.blk_fill = 0;
+
+       mutex_enter(&bpo->bpo_lock);
+
+       offset = bpo->bpo_phys->bpo_num_blkptrs * sizeof (stored_bp);
+       blkoff = P2PHASE(bpo->bpo_phys->bpo_num_blkptrs, bpo->bpo_epb);
+
+       if (bpo->bpo_cached_dbuf == NULL ||
+           offset < bpo->bpo_cached_dbuf->db_offset ||
+           offset >= bpo->bpo_cached_dbuf->db_offset +
+           bpo->bpo_cached_dbuf->db_size) {
+               if (bpo->bpo_cached_dbuf)
+                       dmu_buf_rele(bpo->bpo_cached_dbuf, bpo);
+               VERIFY3U(0, ==, dmu_buf_hold(bpo->bpo_os, bpo->bpo_object,
+                   offset, bpo, &bpo->bpo_cached_dbuf, 0));
+       }
+
+       dmu_buf_will_dirty(bpo->bpo_cached_dbuf, tx);
+       bparray = bpo->bpo_cached_dbuf->db_data;
+       bparray[blkoff] = stored_bp;
+
+       dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
+       bpo->bpo_phys->bpo_num_blkptrs++;
+       bpo->bpo_phys->bpo_bytes +=
+           bp_get_dsize_sync(dmu_objset_spa(bpo->bpo_os), bp);
+       if (bpo->bpo_havecomp) {
+               bpo->bpo_phys->bpo_comp += BP_GET_PSIZE(bp);
+               bpo->bpo_phys->bpo_uncomp += BP_GET_UCSIZE(bp);
+       }
+       mutex_exit(&bpo->bpo_lock);
+}
+
+struct space_range_arg {
+       spa_t *spa;
+       uint64_t mintxg;
+       uint64_t maxtxg;
+       uint64_t used;
+       uint64_t comp;
+       uint64_t uncomp;
+};
+
+/* ARGSUSED */
+static int
+space_range_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       struct space_range_arg *sra = arg;
+
+       if (bp->blk_birth > sra->mintxg && bp->blk_birth <= sra->maxtxg) {
+               if (dsl_pool_sync_context(spa_get_dsl(sra->spa)))
+                       sra->used += bp_get_dsize_sync(sra->spa, bp);
+               else
+                       sra->used += bp_get_dsize(sra->spa, bp);
+               sra->comp += BP_GET_PSIZE(bp);
+               sra->uncomp += BP_GET_UCSIZE(bp);
+       }
+       return (0);
+}
+
+int
+bpobj_space(bpobj_t *bpo, uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+       mutex_enter(&bpo->bpo_lock);
+
+       *usedp = bpo->bpo_phys->bpo_bytes;
+       if (bpo->bpo_havecomp) {
+               *compp = bpo->bpo_phys->bpo_comp;
+               *uncompp = bpo->bpo_phys->bpo_uncomp;
+               mutex_exit(&bpo->bpo_lock);
+               return (0);
+       } else {
+               mutex_exit(&bpo->bpo_lock);
+               return (bpobj_space_range(bpo, 0, UINT64_MAX,
+                   usedp, compp, uncompp));
+       }
+}
+
+/*
+ * Return the amount of space in the bpobj which is:
+ * mintxg < blk_birth <= maxtxg
+ */
+int
+bpobj_space_range(bpobj_t *bpo, uint64_t mintxg, uint64_t maxtxg,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+       struct space_range_arg sra = { 0 };
+       int err;
+
+       /*
+        * As an optimization, if they want the whole txg range, just
+        * get bpo_bytes rather than iterating over the bps.
+        */
+       if (mintxg < TXG_INITIAL && maxtxg == UINT64_MAX && bpo->bpo_havecomp)
+               return (bpobj_space(bpo, usedp, compp, uncompp));
+
+       sra.spa = dmu_objset_spa(bpo->bpo_os);
+       sra.mintxg = mintxg;
+       sra.maxtxg = maxtxg;
+
+       err = bpobj_iterate_nofree(bpo, space_range_cb, &sra, NULL);
+       *usedp = sra.used;
+       *compp = sra.comp;
+       *uncompp = sra.uncomp;
+       return (err);
+}
diff --git a/zfs/module/zfs/bptree.c b/zfs/module/zfs/bptree.c
new file mode 100644 (file)
index 0000000..9f62d7b
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/arc.h>
+#include <sys/bptree.h>
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_pool.h>
+#include <sys/dnode.h>
+#include <sys/refcount.h>
+#include <sys/spa.h>
+
+/*
+ * A bptree is a queue of root block pointers from destroyed datasets. When a
+ * dataset is destroyed its root block pointer is put on the end of the pool's
+ * bptree queue so the dataset's blocks can be freed asynchronously by
+ * dsl_scan_sync. This allows the delete operation to finish without traversing
+ * all the dataset's blocks.
+ *
+ * Note that while bt_begin and bt_end are only ever incremented in this code,
+ * they are effectively reset to 0 every time the entire bptree is freed because
+ * the bptree's object is destroyed and re-created.
+ */
+
+struct bptree_args {
+       bptree_phys_t *ba_phys; /* data in bonus buffer, dirtied if freeing */
+       boolean_t ba_free;      /* true if freeing during traversal */
+
+       bptree_itor_t *ba_func; /* function to call for each blockpointer */
+       void *ba_arg;           /* caller supplied argument to ba_func */
+       dmu_tx_t *ba_tx;        /* caller supplied tx, NULL if not freeing */
+} bptree_args_t;
+
+uint64_t
+bptree_alloc(objset_t *os, dmu_tx_t *tx)
+{
+       uint64_t obj;
+       dmu_buf_t *db;
+       bptree_phys_t *bt;
+
+       obj = dmu_object_alloc(os, DMU_OTN_UINT64_METADATA,
+           SPA_OLD_MAXBLOCKSIZE, DMU_OTN_UINT64_METADATA,
+           sizeof (bptree_phys_t), tx);
+
+       /*
+        * Bonus buffer contents are already initialized to 0, but for
+        * readability we make it explicit.
+        */
+       VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
+       dmu_buf_will_dirty(db, tx);
+       bt = db->db_data;
+       bt->bt_begin = 0;
+       bt->bt_end = 0;
+       bt->bt_bytes = 0;
+       bt->bt_comp = 0;
+       bt->bt_uncomp = 0;
+       dmu_buf_rele(db, FTAG);
+
+       return (obj);
+}
+
+int
+bptree_free(objset_t *os, uint64_t obj, dmu_tx_t *tx)
+{
+       dmu_buf_t *db;
+       bptree_phys_t *bt;
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
+       bt = db->db_data;
+       ASSERT3U(bt->bt_begin, ==, bt->bt_end);
+       ASSERT0(bt->bt_bytes);
+       ASSERT0(bt->bt_comp);
+       ASSERT0(bt->bt_uncomp);
+       dmu_buf_rele(db, FTAG);
+
+       return (dmu_object_free(os, obj, tx));
+}
+
+boolean_t
+bptree_is_empty(objset_t *os, uint64_t obj)
+{
+       dmu_buf_t *db;
+       bptree_phys_t *bt;
+       boolean_t rv;
+
+       VERIFY0(dmu_bonus_hold(os, obj, FTAG, &db));
+       bt = db->db_data;
+       rv = (bt->bt_begin == bt->bt_end);
+       dmu_buf_rele(db, FTAG);
+       return (rv);
+}
+
+void
+bptree_add(objset_t *os, uint64_t obj, blkptr_t *bp, uint64_t birth_txg,
+    uint64_t bytes, uint64_t comp, uint64_t uncomp, dmu_tx_t *tx)
+{
+       dmu_buf_t *db;
+       bptree_phys_t *bt;
+       bptree_entry_phys_t *bte;
+
+       /*
+        * bptree objects are in the pool mos, therefore they can only be
+        * modified in syncing context. Furthermore, this is only modified
+        * by the sync thread, so no locking is necessary.
+        */
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
+       bt = db->db_data;
+
+       bte = kmem_zalloc(sizeof (*bte), KM_SLEEP);
+       bte->be_birth_txg = birth_txg;
+       bte->be_bp = *bp;
+       dmu_write(os, obj, bt->bt_end * sizeof (*bte), sizeof (*bte), bte, tx);
+       kmem_free(bte, sizeof (*bte));
+
+       dmu_buf_will_dirty(db, tx);
+       bt->bt_end++;
+       bt->bt_bytes += bytes;
+       bt->bt_comp += comp;
+       bt->bt_uncomp += uncomp;
+       dmu_buf_rele(db, FTAG);
+}
+
+/* ARGSUSED */
+static int
+bptree_visit_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       int err;
+       struct bptree_args *ba = arg;
+
+       if (BP_IS_HOLE(bp))
+               return (0);
+
+       err = ba->ba_func(ba->ba_arg, bp, ba->ba_tx);
+       if (err == 0 && ba->ba_free) {
+               ba->ba_phys->bt_bytes -= bp_get_dsize_sync(spa, bp);
+               ba->ba_phys->bt_comp -= BP_GET_PSIZE(bp);
+               ba->ba_phys->bt_uncomp -= BP_GET_UCSIZE(bp);
+       }
+       return (err);
+}
+
+/*
+ * If "free" is set:
+ *  - It is assumed that "func" will be freeing the block pointers.
+ *  - If "func" returns nonzero, the bookmark will be remembered and
+ *    iteration will be restarted from this point on next invocation.
+ *  - If an i/o error is encountered (e.g. "func" returns EIO or ECKSUM),
+ *    bptree_iterate will remember the bookmark, continue traversing
+ *    any additional entries, and return 0.
+ *
+ * If "free" is not set, traversal will stop and return an error if
+ * an i/o error is encountered.
+ *
+ * In either case, if zfs_free_leak_on_eio is set, i/o errors will be
+ * ignored and traversal will continue (i.e. TRAVERSE_HARD will be passed to
+ * traverse_dataset_destroyed()).
+ */
+int
+bptree_iterate(objset_t *os, uint64_t obj, boolean_t free, bptree_itor_t func,
+    void *arg, dmu_tx_t *tx)
+{
+       boolean_t ioerr = B_FALSE;
+       int err;
+       uint64_t i;
+       dmu_buf_t *db;
+       struct bptree_args ba;
+
+       ASSERT(!free || dmu_tx_is_syncing(tx));
+
+       err = dmu_bonus_hold(os, obj, FTAG, &db);
+       if (err != 0)
+               return (err);
+
+       if (free)
+               dmu_buf_will_dirty(db, tx);
+
+       ba.ba_phys = db->db_data;
+       ba.ba_free = free;
+       ba.ba_func = func;
+       ba.ba_arg = arg;
+       ba.ba_tx = tx;
+
+       err = 0;
+       for (i = ba.ba_phys->bt_begin; i < ba.ba_phys->bt_end; i++) {
+               bptree_entry_phys_t bte;
+               int flags = TRAVERSE_PREFETCH_METADATA | TRAVERSE_POST;
+
+               err = dmu_read(os, obj, i * sizeof (bte), sizeof (bte),
+                   &bte, DMU_READ_NO_PREFETCH);
+               if (err != 0)
+                       break;
+
+               if (zfs_free_leak_on_eio)
+                       flags |= TRAVERSE_HARD;
+               zfs_dbgmsg("bptree index %lld: traversing from min_txg=%lld "
+                   "bookmark %lld/%lld/%lld/%lld",
+                   i, (longlong_t)bte.be_birth_txg,
+                   (longlong_t)bte.be_zb.zb_objset,
+                   (longlong_t)bte.be_zb.zb_object,
+                   (longlong_t)bte.be_zb.zb_level,
+                   (longlong_t)bte.be_zb.zb_blkid);
+               err = traverse_dataset_destroyed(os->os_spa, &bte.be_bp,
+                   bte.be_birth_txg, &bte.be_zb, flags,
+                   bptree_visit_cb, &ba);
+               if (free) {
+                       /*
+                        * The callback has freed the visited block pointers.
+                        * Record our traversal progress on disk, either by
+                        * updating this record's bookmark, or by logically
+                        * removing this record by advancing bt_begin.
+                        */
+                       if (err != 0) {
+                               /* save bookmark for future resume */
+                               ASSERT3U(bte.be_zb.zb_objset, ==,
+                                   ZB_DESTROYED_OBJSET);
+                               ASSERT0(bte.be_zb.zb_level);
+                               dmu_write(os, obj, i * sizeof (bte),
+                                   sizeof (bte), &bte, tx);
+                               if (err == EIO || err == ECKSUM ||
+                                   err == ENXIO) {
+                                       /*
+                                        * Skip the rest of this tree and
+                                        * continue on to the next entry.
+                                        */
+                                       err = 0;
+                                       ioerr = B_TRUE;
+                               } else {
+                                       break;
+                               }
+                       } else if (ioerr) {
+                               /*
+                                * This entry is finished, but there were
+                                * i/o errors on previous entries, so we
+                                * can't adjust bt_begin.  Set this entry's
+                                * be_birth_txg such that it will be
+                                * treated as a no-op in future traversals.
+                                */
+                               bte.be_birth_txg = UINT64_MAX;
+                               dmu_write(os, obj, i * sizeof (bte),
+                                   sizeof (bte), &bte, tx);
+                       }
+
+                       if (!ioerr) {
+                               ba.ba_phys->bt_begin++;
+                               (void) dmu_free_range(os, obj,
+                                   i * sizeof (bte), sizeof (bte), tx);
+                       }
+               } else if (err != 0) {
+                       break;
+               }
+       }
+
+       ASSERT(!free || err != 0 || ioerr ||
+           ba.ba_phys->bt_begin == ba.ba_phys->bt_end);
+
+       /* if all blocks are free there should be no used space */
+       if (ba.ba_phys->bt_begin == ba.ba_phys->bt_end) {
+               if (zfs_free_leak_on_eio) {
+                       ba.ba_phys->bt_bytes = 0;
+                       ba.ba_phys->bt_comp = 0;
+                       ba.ba_phys->bt_uncomp = 0;
+               }
+
+               ASSERT0(ba.ba_phys->bt_bytes);
+               ASSERT0(ba.ba_phys->bt_comp);
+               ASSERT0(ba.ba_phys->bt_uncomp);
+       }
+
+       dmu_buf_rele(db, FTAG);
+
+       return (err);
+}
diff --git a/zfs/module/zfs/dbuf.c b/zfs/module/zfs/dbuf.c
new file mode 100644 (file)
index 0000000..483067c
--- /dev/null
@@ -0,0 +1,3164 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2012, 2015 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/zfs_context.h>
+#include <sys/arc.h>
+#include <sys/dmu.h>
+#include <sys/dmu_send.h>
+#include <sys/dmu_impl.h>
+#include <sys/dbuf.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dmu_tx.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/dmu_zfetch.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/zfeature.h>
+#include <sys/blkptr.h>
+#include <sys/range_tree.h>
+#include <sys/trace_dbuf.h>
+
+struct dbuf_hold_impl_data {
+       /* Function arguments */
+       dnode_t *dh_dn;
+       uint8_t dh_level;
+       uint64_t dh_blkid;
+       int dh_fail_sparse;
+       void *dh_tag;
+       dmu_buf_impl_t **dh_dbp;
+       /* Local variables */
+       dmu_buf_impl_t *dh_db;
+       dmu_buf_impl_t *dh_parent;
+       blkptr_t *dh_bp;
+       int dh_err;
+       dbuf_dirty_record_t *dh_dr;
+       arc_buf_contents_t dh_type;
+       int dh_depth;
+};
+
+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);
+static int __dbuf_hold_impl(struct dbuf_hold_impl_data *dh);
+
+/*
+ * 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);
+
+#ifndef __lint
+extern 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);
+#endif /* ! __lint */
+
+/*
+ * Global data structures and functions for the dbuf cache.
+ */
+static kmem_cache_t *dbuf_cache;
+static taskq_t *dbu_evict_taskq;
+
+/* ARGSUSED */
+static int
+dbuf_cons(void *vdb, void *unused, int kmflag)
+{
+       dmu_buf_impl_t *db = vdb;
+       bzero(db, sizeof (dmu_buf_impl_t));
+
+       mutex_init(&db->db_mtx, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&db->db_changed, NULL, CV_DEFAULT, NULL);
+       refcount_create(&db->db_holds);
+
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+dbuf_dest(void *vdb, void *unused)
+{
+       dmu_buf_impl_t *db = vdb;
+       mutex_destroy(&db->db_mtx);
+       cv_destroy(&db->db_changed);
+       refcount_destroy(&db->db_holds);
+}
+
+/*
+ * dbuf hash table routines
+ */
+static dbuf_hash_table_t dbuf_hash_table;
+
+static uint64_t dbuf_hash_count;
+
+static uint64_t
+dbuf_hash(void *os, uint64_t obj, uint8_t lvl, uint64_t blkid)
+{
+       uintptr_t osv = (uintptr_t)os;
+       uint64_t crc = -1ULL;
+
+       ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
+       crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ (lvl)) & 0xFF];
+       crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ (osv >> 6)) & 0xFF];
+       crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ (obj >> 0)) & 0xFF];
+       crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ (obj >> 8)) & 0xFF];
+       crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ (blkid >> 0)) & 0xFF];
+       crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ (blkid >> 8)) & 0xFF];
+
+       crc ^= (osv>>14) ^ (obj>>16) ^ (blkid>>16);
+
+       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) &&                    \
+       (dbuf)->db_level == (level) &&                  \
+       (dbuf)->db_blkid == (blkid))
+
+dmu_buf_impl_t *
+dbuf_find(objset_t *os, uint64_t obj, uint8_t level, uint64_t blkid)
+{
+       dbuf_hash_table_t *h = &dbuf_hash_table;
+       uint64_t hv;
+       uint64_t idx;
+       dmu_buf_impl_t *db;
+
+       hv = DBUF_HASH(os, obj, level, blkid);
+       idx = hv & h->hash_table_mask;
+
+       mutex_enter(DBUF_HASH_MUTEX(h, idx));
+       for (db = h->hash_table[idx]; db != NULL; db = db->db_hash_next) {
+               if (DBUF_EQUAL(db, os, obj, level, blkid)) {
+                       mutex_enter(&db->db_mtx);
+                       if (db->db_state != DB_EVICTING) {
+                               mutex_exit(DBUF_HASH_MUTEX(h, idx));
+                               return (db);
+                       }
+                       mutex_exit(&db->db_mtx);
+               }
+       }
+       mutex_exit(DBUF_HASH_MUTEX(h, idx));
+       return (NULL);
+}
+
+static dmu_buf_impl_t *
+dbuf_find_bonus(objset_t *os, uint64_t object)
+{
+       dnode_t *dn;
+       dmu_buf_impl_t *db = NULL;
+
+       if (dnode_hold(os, object, FTAG, &dn) == 0) {
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+               if (dn->dn_bonus != NULL) {
+                       db = dn->dn_bonus;
+                       mutex_enter(&db->db_mtx);
+               }
+               rw_exit(&dn->dn_struct_rwlock);
+               dnode_rele(dn, FTAG);
+       }
+       return (db);
+}
+
+/*
+ * Insert an entry into the hash table.  If there is already an element
+ * equal to elem in the hash table, then the already existing element
+ * will be returned and the new element will not be inserted.
+ * Otherwise returns NULL.
+ */
+static dmu_buf_impl_t *
+dbuf_hash_insert(dmu_buf_impl_t *db)
+{
+       dbuf_hash_table_t *h = &dbuf_hash_table;
+       objset_t *os = db->db_objset;
+       uint64_t obj = db->db.db_object;
+       int level = db->db_level;
+       uint64_t blkid, hv, idx;
+       dmu_buf_impl_t *dbf;
+
+       blkid = db->db_blkid;
+       hv = DBUF_HASH(os, obj, level, blkid);
+       idx = hv & h->hash_table_mask;
+
+       mutex_enter(DBUF_HASH_MUTEX(h, idx));
+       for (dbf = h->hash_table[idx]; dbf != NULL; dbf = dbf->db_hash_next) {
+               if (DBUF_EQUAL(dbf, os, obj, level, blkid)) {
+                       mutex_enter(&dbf->db_mtx);
+                       if (dbf->db_state != DB_EVICTING) {
+                               mutex_exit(DBUF_HASH_MUTEX(h, idx));
+                               return (dbf);
+                       }
+                       mutex_exit(&dbf->db_mtx);
+               }
+       }
+
+       mutex_enter(&db->db_mtx);
+       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);
+
+       return (NULL);
+}
+
+/*
+ * Remove an entry from the hash table.  It must be in the EVICTING state.
+ */
+static void
+dbuf_hash_remove(dmu_buf_impl_t *db)
+{
+       dbuf_hash_table_t *h = &dbuf_hash_table;
+       uint64_t hv, idx;
+       dmu_buf_impl_t *dbf, **dbp;
+
+       hv = DBUF_HASH(db->db_objset, db->db.db_object,
+           db->db_level, db->db_blkid);
+       idx = hv & h->hash_table_mask;
+
+       /*
+        * We musn't hold db_mtx to maintain lock ordering:
+        * DBUF_HASH_MUTEX > db_mtx.
+        */
+       ASSERT(refcount_is_zero(&db->db_holds));
+       ASSERT(db->db_state == DB_EVICTING);
+       ASSERT(!MUTEX_HELD(&db->db_mtx));
+
+       mutex_enter(DBUF_HASH_MUTEX(h, idx));
+       dbp = &h->hash_table[idx];
+       while ((dbf = *dbp) != db) {
+               dbp = &dbf->db_hash_next;
+               ASSERT(dbf != NULL);
+       }
+       *dbp = db->db_hash_next;
+       db->db_hash_next = NULL;
+       mutex_exit(DBUF_HASH_MUTEX(h, idx));
+       atomic_add_64(&dbuf_hash_count, -1);
+}
+
+static arc_evict_func_t dbuf_do_evict;
+
+typedef enum {
+       DBVU_EVICTING,
+       DBVU_NOT_EVICTING
+} dbvu_verify_type_t;
+
+static void
+dbuf_verify_user(dmu_buf_impl_t *db, dbvu_verify_type_t verify_type)
+{
+#ifdef ZFS_DEBUG
+       int64_t holds;
+
+       if (db->db_user == NULL)
+               return;
+
+       /* Only data blocks support the attachment of user data. */
+       ASSERT(db->db_level == 0);
+
+       /* Clients must resolve a dbuf before attaching user data. */
+       ASSERT(db->db.db_data != NULL);
+       ASSERT3U(db->db_state, ==, DB_CACHED);
+
+       holds = refcount_count(&db->db_holds);
+       if (verify_type == DBVU_EVICTING) {
+               /*
+                * Immediate eviction occurs when holds == dirtycnt.
+                * For normal eviction buffers, holds is zero on
+                * eviction, except when dbuf_fix_old_data() calls
+                * dbuf_clear_data().  However, the hold count can grow
+                * during eviction even though db_mtx is held (see
+                * dmu_bonus_hold() for an example), so we can only
+                * test the generic invariant that holds >= dirtycnt.
+                */
+               ASSERT3U(holds, >=, db->db_dirtycnt);
+       } else {
+               if (db->db_user_immediate_evict == TRUE)
+                       ASSERT3U(holds, >=, db->db_dirtycnt);
+               else
+                       ASSERT3U(holds, >, 0);
+       }
+#endif
+}
+
+static void
+dbuf_evict_user(dmu_buf_impl_t *db)
+{
+       dmu_buf_user_t *dbu = db->db_user;
+
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+
+       if (dbu == NULL)
+               return;
+
+       dbuf_verify_user(db, DBVU_EVICTING);
+       db->db_user = NULL;
+
+#ifdef ZFS_DEBUG
+       if (dbu->dbu_clear_on_evict_dbufp != NULL)
+               *dbu->dbu_clear_on_evict_dbufp = NULL;
+#endif
+
+       /*
+        * Invoke the callback from a taskq to avoid lock order reversals
+        * and limit stack depth.
+        */
+       taskq_dispatch_ent(dbu_evict_taskq, dbu->dbu_evict_func, dbu, 0,
+           &dbu->dbu_tqent);
+}
+
+boolean_t
+dbuf_is_metadata(dmu_buf_impl_t *db)
+{
+       /*
+        * Consider indirect blocks and spill blocks to be meta data.
+        */
+       if (db->db_level > 0 || db->db_blkid == DMU_SPILL_BLKID) {
+               return (B_TRUE);
+       } else {
+               boolean_t is_metadata;
+
+               DB_DNODE_ENTER(db);
+               is_metadata = DMU_OT_IS_METADATA(DB_DNODE(db)->dn_type);
+               DB_DNODE_EXIT(db);
+
+               return (is_metadata);
+       }
+}
+
+void
+dbuf_evict(dmu_buf_impl_t *db)
+{
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       ASSERT(db->db_buf == NULL);
+       ASSERT(db->db_data_pending == NULL);
+
+       dbuf_clear(db);
+       dbuf_destroy(db);
+}
+
+void
+dbuf_init(void)
+{
+       uint64_t hsize = 1ULL << 16;
+       dbuf_hash_table_t *h = &dbuf_hash_table;
+       int i;
+
+       /*
+        * The hash table is big enough to fill all of physical memory
+        * with an average block size of zfs_arc_average_blocksize (default 8K).
+        * By default, the table will take up
+        * totalmem * sizeof(void*) / 8K (1MB per GB with 8-byte pointers).
+        */
+       while (hsize * zfs_arc_average_blocksize < physmem * PAGESIZE)
+               hsize <<= 1;
+
+retry:
+       h->hash_table_mask = hsize - 1;
+#if defined(_KERNEL) && defined(HAVE_SPL)
+       /*
+        * Large allocations which do not require contiguous pages
+        * should be using vmem_alloc() in the linux kernel
+        */
+       h->hash_table = vmem_zalloc(hsize * sizeof (void *), KM_SLEEP);
+#else
+       h->hash_table = kmem_zalloc(hsize * sizeof (void *), KM_NOSLEEP);
+#endif
+       if (h->hash_table == NULL) {
+               /* XXX - we should really return an error instead of assert */
+               ASSERT(hsize > (1ULL << 10));
+               hsize >>= 1;
+               goto retry;
+       }
+
+       dbuf_cache = kmem_cache_create("dmu_buf_impl_t",
+           sizeof (dmu_buf_impl_t),
+           0, dbuf_cons, dbuf_dest, NULL, NULL, NULL, 0);
+
+       for (i = 0; i < DBUF_MUTEXES; i++)
+               mutex_init(&h->hash_mutexes[i], NULL, MUTEX_DEFAULT, NULL);
+
+       dbuf_stats_init(h);
+
+       /*
+        * 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);
+}
+
+void
+dbuf_fini(void)
+{
+       dbuf_hash_table_t *h = &dbuf_hash_table;
+       int i;
+
+       dbuf_stats_destroy();
+
+       for (i = 0; i < DBUF_MUTEXES; i++)
+               mutex_destroy(&h->hash_mutexes[i]);
+#if defined(_KERNEL) && defined(HAVE_SPL)
+       /*
+        * Large allocations which do not require contiguous pages
+        * should be using vmem_free() in the linux kernel
+        */
+       vmem_free(h->hash_table, (h->hash_table_mask + 1) * sizeof (void *));
+#else
+       kmem_free(h->hash_table, (h->hash_table_mask + 1) * sizeof (void *));
+#endif
+       kmem_cache_destroy(dbuf_cache);
+       taskq_destroy(dbu_evict_taskq);
+}
+
+/*
+ * Other stuff.
+ */
+
+#ifdef ZFS_DEBUG
+static void
+dbuf_verify(dmu_buf_impl_t *db)
+{
+       dnode_t *dn;
+       dbuf_dirty_record_t *dr;
+
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+
+       if (!(zfs_flags & ZFS_DEBUG_DBUF_VERIFY))
+               return;
+
+       ASSERT(db->db_objset != NULL);
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       if (dn == NULL) {
+               ASSERT(db->db_parent == NULL);
+               ASSERT(db->db_blkptr == NULL);
+       } else {
+               ASSERT3U(db->db.db_object, ==, dn->dn_object);
+               ASSERT3P(db->db_objset, ==, dn->dn_objset);
+               ASSERT3U(db->db_level, <, dn->dn_nlevels);
+               ASSERT(db->db_blkid == DMU_BONUS_BLKID ||
+                   db->db_blkid == DMU_SPILL_BLKID ||
+                   !avl_is_empty(&dn->dn_dbufs));
+       }
+       if (db->db_blkid == DMU_BONUS_BLKID) {
+               ASSERT(dn != NULL);
+               ASSERT3U(db->db.db_size, >=, dn->dn_bonuslen);
+               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);
+       }
+
+       for (dr = db->db_data_pending; dr != NULL; dr = dr->dr_next)
+               ASSERT(dr->dr_dbuf == db);
+
+       for (dr = db->db_last_dirty; dr != NULL; dr = dr->dr_next)
+               ASSERT(dr->dr_dbuf == db);
+
+       /*
+        * We can't assert that db_size matches dn_datablksz because it
+        * can be momentarily different when another thread is doing
+        * dnode_set_blksz().
+        */
+       if (db->db_level == 0 && db->db.db_object == DMU_META_DNODE_OBJECT) {
+               dr = db->db_data_pending;
+               /*
+                * It should only be modified in syncing context, so
+                * make sure we only have one copy of the data.
+                */
+               ASSERT(dr == NULL || dr->dt.dl.dr_data == db->db_buf);
+       }
+
+       /* verify db->db_blkptr */
+       if (db->db_blkptr) {
+               if (db->db_parent == dn->dn_dbuf) {
+                       /* db is pointed to by the dnode */
+                       /* ASSERT3U(db->db_blkid, <, dn->dn_nblkptr); */
+                       if (DMU_OBJECT_IS_SPECIAL(db->db.db_object))
+                               ASSERT(db->db_parent == NULL);
+                       else
+                               ASSERT(db->db_parent != NULL);
+                       if (db->db_blkid != DMU_SPILL_BLKID)
+                               ASSERT3P(db->db_blkptr, ==,
+                                   &dn->dn_phys->dn_blkptr[db->db_blkid]);
+               } else {
+                       /* db is pointed to by an indirect block */
+                       ASSERTV(int epb = db->db_parent->db.db_size >>
+                               SPA_BLKPTRSHIFT);
+                       ASSERT3U(db->db_parent->db_level, ==, db->db_level+1);
+                       ASSERT3U(db->db_parent->db.db_object, ==,
+                           db->db.db_object);
+                       /*
+                        * dnode_grow_indblksz() can make this fail if we don't
+                        * have the struct_rwlock.  XXX indblksz no longer
+                        * grows.  safe to do this now?
+                        */
+                       if (RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
+                               ASSERT3P(db->db_blkptr, ==,
+                                   ((blkptr_t *)db->db_parent->db.db_data +
+                                   db->db_blkid % epb));
+                       }
+               }
+       }
+       if ((db->db_blkptr == NULL || BP_IS_HOLE(db->db_blkptr)) &&
+           (db->db_buf == NULL || db->db_buf->b_data) &&
+           db->db.db_data && db->db_blkid != DMU_BONUS_BLKID &&
+           db->db_state != DB_FILL && !dn->dn_free_txg) {
+               /*
+                * 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.
+                */
+               if (db->db_dirtycnt == 0) {
+                       ASSERTV(uint64_t *buf = db->db.db_data);
+                       int i;
+
+                       for (i = 0; i < db->db.db_size >> 3; i++) {
+                               ASSERT(buf[i] == 0);
+                       }
+               }
+       }
+       DB_DNODE_EXIT(db);
+}
+#endif
+
+static void
+dbuf_clear_data(dmu_buf_impl_t *db)
+{
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       dbuf_evict_user(db);
+       db->db_buf = NULL;
+       db->db.db_data = NULL;
+       if (db->db_state != DB_NOFILL)
+               db->db_state = DB_UNCACHED;
+}
+
+static void
+dbuf_set_data(dmu_buf_impl_t *db, arc_buf_t *buf)
+{
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       ASSERT(buf != NULL);
+
+       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);
+}
+
+/*
+ * Loan out an arc_buf for read.  Return the loaned arc_buf.
+ */
+arc_buf_t *
+dbuf_loan_arcbuf(dmu_buf_impl_t *db)
+{
+       arc_buf_t *abuf;
+
+       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);
+               bcopy(db->db.db_data, abuf->b_data, blksz);
+       } else {
+               abuf = db->db_buf;
+               arc_loan_inuse_buf(abuf, db);
+               dbuf_clear_data(db);
+               mutex_exit(&db->db_mtx);
+       }
+       return (abuf);
+}
+
+uint64_t
+dbuf_whichblock(dnode_t *dn, uint64_t offset)
+{
+       if (dn->dn_datablkshift) {
+               return (offset >> dn->dn_datablkshift);
+       } else {
+               ASSERT3U(offset, <, dn->dn_datablksz);
+               return (0);
+       }
+}
+
+static void
+dbuf_read_done(zio_t *zio, arc_buf_t *buf, void *vdb)
+{
+       dmu_buf_impl_t *db = vdb;
+
+       mutex_enter(&db->db_mtx);
+       ASSERT3U(db->db_state, ==, DB_READ);
+       /*
+        * All reads are synchronous, so we must have a hold on the dbuf
+        */
+       ASSERT(refcount_count(&db->db_holds) > 0);
+       ASSERT(db->db_buf == NULL);
+       ASSERT(db->db.db_data == NULL);
+       if (db->db_level == 0 && db->db_freed_in_flight) {
+               /* we were freed in flight; disregard any error */
+               arc_release(buf, db);
+               bzero(buf->b_data, db->db.db_size);
+               arc_buf_freeze(buf);
+               db->db_freed_in_flight = FALSE;
+               dbuf_set_data(db, buf);
+               db->db_state = DB_CACHED;
+       } else if (zio == NULL || zio->io_error == 0) {
+               dbuf_set_data(db, buf);
+               db->db_state = DB_CACHED;
+       } else {
+               ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+               ASSERT3P(db->db_buf, ==, NULL);
+               VERIFY(arc_buf_remove_ref(buf, db));
+               db->db_state = DB_UNCACHED;
+       }
+       cv_broadcast(&db->db_changed);
+       dbuf_rele_and_unlock(db, NULL);
+}
+
+static int
+dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
+{
+       dnode_t *dn;
+       zbookmark_phys_t zb;
+       uint32_t aflags = ARC_FLAG_NOWAIT;
+       int err;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       ASSERT(!refcount_is_zero(&db->db_holds));
+       /* We need the struct_rwlock to prevent db_blkptr from changing. */
+       ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       ASSERT(db->db_state == DB_UNCACHED);
+       ASSERT(db->db_buf == NULL);
+
+       if (db->db_blkid == DMU_BONUS_BLKID) {
+               int bonuslen = MIN(dn->dn_bonuslen, dn->dn_phys->dn_bonuslen);
+
+               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);
+               if (bonuslen)
+                       bcopy(DN_BONUS(dn->dn_phys), db->db.db_data, bonuslen);
+               DB_DNODE_EXIT(db);
+               db->db_state = DB_CACHED;
+               mutex_exit(&db->db_mtx);
+               return (0);
+       }
+
+       /*
+        * Recheck BP_IS_HOLE() after dnode_block_freed() in case dnode_sync()
+        * processes the delete record and clears the bp while we are waiting
+        * for the dn_mtx (resulting in a "no" from block_freed).
+        */
+       if (db->db_blkptr == NULL || BP_IS_HOLE(db->db_blkptr) ||
+           (db->db_level == 0 && (dnode_block_freed(dn, db->db_blkid) ||
+           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));
+               bzero(db->db.db_data, db->db.db_size);
+               db->db_state = DB_CACHED;
+               *flags |= DB_RF_CACHED;
+               mutex_exit(&db->db_mtx);
+               return (0);
+       }
+
+       DB_DNODE_EXIT(db);
+
+       db->db_state = DB_READ;
+       mutex_exit(&db->db_mtx);
+
+       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,
+           db->db.db_object, db->db_level, db->db_blkid);
+
+       dbuf_add_ref(db, NULL);
+
+       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,
+           &aflags, &zb);
+       if (aflags & ARC_FLAG_CACHED)
+               *flags |= DB_RF_CACHED;
+
+       return (SET_ERROR(err));
+}
+
+int
+dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
+{
+       int err = 0;
+       boolean_t havepzio = (zio != NULL);
+       boolean_t prefetch;
+       dnode_t *dn;
+
+       /*
+        * We don't have to hold the mutex to check db_state because it
+        * can't be freed while we have a hold on the buffer.
+        */
+       ASSERT(!refcount_is_zero(&db->db_holds));
+
+       if (db->db_state == DB_NOFILL)
+               return (SET_ERROR(EIO));
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       if ((flags & DB_RF_HAVESTRUCT) == 0)
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+
+       prefetch = db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID &&
+           (flags & DB_RF_NOPREFETCH) == 0 && dn != NULL &&
+           DBUF_IS_CACHEABLE(db);
+
+       mutex_enter(&db->db_mtx);
+       if (db->db_state == DB_CACHED) {
+               mutex_exit(&db->db_mtx);
+               if (prefetch)
+                       dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
+                           db->db.db_size, TRUE);
+               if ((flags & DB_RF_HAVESTRUCT) == 0)
+                       rw_exit(&dn->dn_struct_rwlock);
+               DB_DNODE_EXIT(db);
+       } else if (db->db_state == DB_UNCACHED) {
+               spa_t *spa = dn->dn_objset->os_spa;
+
+               if (zio == NULL)
+                       zio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
+
+               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);
+
+               if ((flags & DB_RF_HAVESTRUCT) == 0)
+                       rw_exit(&dn->dn_struct_rwlock);
+               DB_DNODE_EXIT(db);
+
+               if (!err && !havepzio)
+                       err = zio_wait(zio);
+       } else {
+               /*
+                * Another reader came in while the dbuf was in flight
+                * between UNCACHED and CACHED.  Either a writer will finish
+                * writing the buffer (sending the dbuf to CACHED) or the
+                * first reader's request will reach the read_done callback
+                * and send the dbuf to CACHED.  Otherwise, a failure
+                * occurred and the dbuf went to UNCACHED.
+                */
+               mutex_exit(&db->db_mtx);
+               if (prefetch)
+                       dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
+                           db->db.db_size, TRUE);
+               if ((flags & DB_RF_HAVESTRUCT) == 0)
+                       rw_exit(&dn->dn_struct_rwlock);
+               DB_DNODE_EXIT(db);
+
+               /* Skip the wait per the caller's request. */
+               mutex_enter(&db->db_mtx);
+               if ((flags & DB_RF_NEVERWAIT) == 0) {
+                       while (db->db_state == DB_READ ||
+                           db->db_state == DB_FILL) {
+                               ASSERT(db->db_state == DB_READ ||
+                                   (flags & DB_RF_HAVESTRUCT) == 0);
+                               DTRACE_PROBE2(blocked__read, dmu_buf_impl_t *,
+                                   db, zio_t *, zio);
+                               cv_wait(&db->db_changed, &db->db_mtx);
+                       }
+                       if (db->db_state == DB_UNCACHED)
+                               err = SET_ERROR(EIO);
+               }
+               mutex_exit(&db->db_mtx);
+       }
+
+       ASSERT(err || havepzio || db->db_state == DB_CACHED);
+       return (err);
+}
+
+static void
+dbuf_noread(dmu_buf_impl_t *db)
+{
+       ASSERT(!refcount_is_zero(&db->db_holds));
+       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+       mutex_enter(&db->db_mtx);
+       while (db->db_state == DB_READ || db->db_state == DB_FILL)
+               cv_wait(&db->db_changed, &db->db_mtx);
+       if (db->db_state == DB_UNCACHED) {
+               arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
+               spa_t *spa = db->db_objset->os_spa;
+
+               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));
+               db->db_state = DB_FILL;
+       } else if (db->db_state == DB_NOFILL) {
+               dbuf_clear_data(db);
+       } else {
+               ASSERT3U(db->db_state, ==, DB_CACHED);
+       }
+       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)
+{
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+       blkptr_t *bp = &dr->dt.dl.dr_overridden_by;
+       uint64_t txg = dr->dr_txg;
+
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       ASSERT(dr->dt.dl.dr_override_state != DR_IN_DMU_SYNC);
+       ASSERT(db->db_level == 0);
+
+       if (db->db_blkid == DMU_BONUS_BLKID ||
+           dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN)
+               return;
+
+       ASSERT(db->db_data_pending != dr);
+
+       /* free this block */
+       if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite)
+               zio_free(db->db_objset->os_spa, txg, bp);
+
+       dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
+       dr->dt.dl.dr_nopwrite = B_FALSE;
+
+       /*
+        * Release the already-written buffer, so we leave it in
+        * a consistent dirty state.  Note that all callers are
+        * modifying the buffer, so they will immediately do
+        * another (redundant) arc_release().  Therefore, leave
+        * the buf thawed to save the effort of freezing &
+        * immediately re-thawing it.
+        */
+       arc_release(dr->dt.dl.dr_data, db);
+}
+
+/*
+ * Evict (if its unreferenced) or clear (if its referenced) any level-0
+ * data blocks in the free range, so that any future readers will find
+ * empty blocks.
+ *
+ * This is a no-op if the dataset is in the middle of an incremental
+ * receive; see comment below for details.
+ */
+void
+dbuf_free_range(dnode_t *dn, uint64_t start_blkid, uint64_t end_blkid,
+    dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db_search;
+       dmu_buf_impl_t *db, *db_next;
+       uint64_t txg = tx->tx_txg;
+       avl_index_t where;
+       boolean_t freespill =
+           (start_blkid == DMU_SPILL_BLKID || end_blkid == DMU_SPILL_BLKID);
+
+       if (end_blkid > dn->dn_maxblkid && !freespill)
+               end_blkid = dn->dn_maxblkid;
+       dprintf_dnode(dn, "start=%llu end=%llu\n", start_blkid, end_blkid);
+
+       db_search = kmem_alloc(sizeof (dmu_buf_impl_t), KM_SLEEP);
+       db_search->db_level = 0;
+       db_search->db_blkid = start_blkid;
+       db_search->db_state = DB_SEARCH;
+
+       mutex_enter(&dn->dn_dbufs_mtx);
+       if (start_blkid >= dn->dn_unlisted_l0_blkid && !freespill) {
+               /* There can't be any dbufs in this range; no need to search. */
+#ifdef DEBUG
+               db = avl_find(&dn->dn_dbufs, db_search, &where);
+               ASSERT3P(db, ==, NULL);
+               db = avl_nearest(&dn->dn_dbufs, where, AVL_AFTER);
+               ASSERT(db == NULL || db->db_level > 0);
+#endif
+               goto out;
+       } else if (dmu_objset_is_receiving(dn->dn_objset)) {
+               /*
+                * If we are receiving, we expect there to be no dbufs in
+                * the range to be freed, because receive modifies each
+                * block at most once, and in offset order.  If this is
+                * not the case, it can lead to performance problems,
+                * so note that we unexpectedly took the slow path.
+                */
+               atomic_inc_64(&zfs_free_range_recv_miss);
+       }
+
+       db = avl_find(&dn->dn_dbufs, db_search, &where);
+       ASSERT3P(db, ==, NULL);
+       db = avl_nearest(&dn->dn_dbufs, where, AVL_AFTER);
+
+       for (; db != NULL; db = db_next) {
+               db_next = AVL_NEXT(&dn->dn_dbufs, db);
+               ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+
+               if (db->db_level != 0 || db->db_blkid > end_blkid) {
+                       break;
+               }
+               ASSERT3U(db->db_blkid, >=, start_blkid);
+
+               /* found a level 0 buffer in the range */
+               mutex_enter(&db->db_mtx);
+               if (dbuf_undirty(db, tx)) {
+                       /* mutex has been dropped and dbuf destroyed */
+                       continue;
+               }
+
+               if (db->db_state == DB_UNCACHED ||
+                   db->db_state == DB_NOFILL ||
+                   db->db_state == DB_EVICTING) {
+                       ASSERT(db->db.db_data == NULL);
+                       mutex_exit(&db->db_mtx);
+                       continue;
+               }
+               if (db->db_state == DB_READ || db->db_state == DB_FILL) {
+                       /* will be handled in dbuf_read_done or dbuf_rele */
+                       db->db_freed_in_flight = TRUE;
+                       mutex_exit(&db->db_mtx);
+                       continue;
+               }
+               if (refcount_count(&db->db_holds) == 0) {
+                       ASSERT(db->db_buf);
+                       dbuf_clear(db);
+                       continue;
+               }
+               /* The dbuf is referenced */
+
+               if (db->db_last_dirty != NULL) {
+                       dbuf_dirty_record_t *dr = db->db_last_dirty;
+
+                       if (dr->dr_txg == txg) {
+                               /*
+                                * This buffer is "in-use", re-adjust the file
+                                * size to reflect that this buffer may
+                                * contain new data when we sync.
+                                */
+                               if (db->db_blkid != DMU_SPILL_BLKID &&
+                                   db->db_blkid > dn->dn_maxblkid)
+                                       dn->dn_maxblkid = db->db_blkid;
+                               dbuf_unoverride(dr);
+                       } else {
+                               /*
+                                * This dbuf is not dirty in the open context.
+                                * Either uncache it (if its not referenced in
+                                * the open context) or reset its contents to
+                                * empty.
+                                */
+                               dbuf_fix_old_data(db, txg);
+                       }
+               }
+               /* clear the contents if its cached */
+               if (db->db_state == DB_CACHED) {
+                       ASSERT(db->db.db_data != NULL);
+                       arc_release(db->db_buf, db);
+                       bzero(db->db.db_data, db->db.db_size);
+                       arc_buf_freeze(db->db_buf);
+               }
+
+               mutex_exit(&db->db_mtx);
+       }
+
+out:
+       kmem_free(db_search, sizeof (dmu_buf_impl_t));
+       mutex_exit(&dn->dn_dbufs_mtx);
+}
+
+static int
+dbuf_block_freeable(dmu_buf_impl_t *db)
+{
+       dsl_dataset_t *ds = db->db_objset->os_dsl_dataset;
+       uint64_t birth_txg = 0;
+
+       /*
+        * We don't need any locking to protect db_blkptr:
+        * If it's syncing, then db_last_dirty will be set
+        * so we'll ignore db_blkptr.
+        *
+        * This logic ensures that only block births for
+        * filled blocks are considered.
+        */
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       if (db->db_last_dirty && (db->db_blkptr == NULL ||
+           !BP_IS_HOLE(db->db_blkptr))) {
+               birth_txg = db->db_last_dirty->dr_txg;
+       } else if (db->db_blkptr != NULL && !BP_IS_HOLE(db->db_blkptr)) {
+               birth_txg = db->db_blkptr->blk_birth;
+       }
+
+       /*
+        * If this block don't exist or is in a snapshot, it can't be freed.
+        * Don't pass the bp to dsl_dataset_block_freeable() since we
+        * are holding the db_mtx lock and might deadlock if we are
+        * prefetching a dedup-ed block.
+        */
+       if (birth_txg != 0)
+               return (ds == NULL ||
+                   dsl_dataset_block_freeable(ds, NULL, birth_txg));
+       else
+               return (B_FALSE);
+}
+
+void
+dbuf_new_size(dmu_buf_impl_t *db, int size, dmu_tx_t *tx)
+{
+       arc_buf_t *buf, *obuf;
+       int osize = db->db.db_size;
+       arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
+       dnode_t *dn;
+
+       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       /* XXX does *this* func really need the lock? */
+       ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock));
+
+       /*
+        * This call to dmu_buf_will_dirty() with the dn_struct_rwlock held
+        * is OK, because there can be no other references to the db
+        * when we are changing its size, so no concurrent DB_FILL can
+        * be happening.
+        */
+       /*
+        * XXX we should be doing a dbuf_read, checking the return
+        * value and returning that up to our callers
+        */
+       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);
+
+       /* copy old block data to the new block */
+       obuf = db->db_buf;
+       bcopy(obuf->b_data, buf->b_data, MIN(osize, size));
+       /* zero the remainder */
+       if (size > osize)
+               bzero((uint8_t *)buf->b_data + osize, size - osize);
+
+       mutex_enter(&db->db_mtx);
+       dbuf_set_data(db, buf);
+       VERIFY(arc_buf_remove_ref(obuf, db));
+       db->db.db_size = size;
+
+       if (db->db_level == 0) {
+               ASSERT3U(db->db_last_dirty->dr_txg, ==, tx->tx_txg);
+               db->db_last_dirty->dt.dl.dr_data = buf;
+       }
+       mutex_exit(&db->db_mtx);
+
+       dnode_willuse_space(dn, size-osize, tx);
+       DB_DNODE_EXIT(db);
+}
+
+void
+dbuf_release_bp(dmu_buf_impl_t *db)
+{
+       ASSERTV(objset_t *os = db->db_objset);
+
+       ASSERT(dsl_pool_sync_context(dmu_objset_pool(os)));
+       ASSERT(arc_released(os->os_phys_buf) ||
+           list_link_active(&os->os_dsl_dataset->ds_synced_link));
+       ASSERT(db->db_parent == NULL || arc_released(db->db_parent->db_buf));
+
+       (void) arc_release(db->db_buf, db);
+}
+
+dbuf_dirty_record_t *
+dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       objset_t *os;
+       dbuf_dirty_record_t **drp, *dr;
+       int drop_struct_lock = FALSE;
+       boolean_t do_free_accounting = B_FALSE;
+       int txgoff = tx->tx_txg & TXG_MASK;
+
+       ASSERT(tx->tx_txg != 0);
+       ASSERT(!refcount_is_zero(&db->db_holds));
+       DMU_TX_DIRTY_BUF(tx, db);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       /*
+        * Shouldn't dirty a regular buffer in syncing context.  Private
+        * objects may be dirtied in syncing context, but only if they
+        * were already pre-dirtied in open context.
+        */
+       ASSERT(!dmu_tx_is_syncing(tx) ||
+           BP_IS_HOLE(dn->dn_objset->os_rootbp) ||
+           DMU_OBJECT_IS_SPECIAL(dn->dn_object) ||
+           dn->dn_objset->os_dsl_dataset == NULL);
+       /*
+        * We make this assert for private objects as well, but after we
+        * check if we're already dirty.  They are allowed to re-dirty
+        * in syncing context.
+        */
+       ASSERT(dn->dn_object == DMU_META_DNODE_OBJECT ||
+           dn->dn_dirtyctx == DN_UNDIRTIED || dn->dn_dirtyctx ==
+           (dmu_tx_is_syncing(tx) ? DN_DIRTY_SYNC : DN_DIRTY_OPEN));
+
+       mutex_enter(&db->db_mtx);
+       /*
+        * XXX make this true for indirects too?  The problem is that
+        * transactions created with dmu_tx_create_assigned() from
+        * syncing context don't bother holding ahead.
+        */
+       ASSERT(db->db_level != 0 ||
+           db->db_state == DB_CACHED || db->db_state == DB_FILL ||
+           db->db_state == DB_NOFILL);
+
+       mutex_enter(&dn->dn_mtx);
+       /*
+        * Don't set dirtyctx to SYNC if we're just modifying this as we
+        * initialize the objset.
+        */
+       if (dn->dn_dirtyctx == DN_UNDIRTIED &&
+           !BP_IS_HOLE(dn->dn_objset->os_rootbp)) {
+               dn->dn_dirtyctx =
+                   (dmu_tx_is_syncing(tx) ? DN_DIRTY_SYNC : DN_DIRTY_OPEN);
+               ASSERT(dn->dn_dirtyctx_firstset == NULL);
+               dn->dn_dirtyctx_firstset = kmem_alloc(1, KM_SLEEP);
+       }
+       mutex_exit(&dn->dn_mtx);
+
+       if (db->db_blkid == DMU_SPILL_BLKID)
+               dn->dn_have_spill = B_TRUE;
+
+       /*
+        * If this buffer is already dirty, we're done.
+        */
+       drp = &db->db_last_dirty;
+       ASSERT(*drp == NULL || (*drp)->dr_txg <= tx->tx_txg ||
+           db->db.db_object == DMU_META_DNODE_OBJECT);
+       while ((dr = *drp) != NULL && dr->dr_txg > tx->tx_txg)
+               drp = &dr->dr_next;
+       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);
+               }
+               mutex_exit(&db->db_mtx);
+               return (dr);
+       }
+
+       /*
+        * Only valid if not already dirty.
+        */
+       ASSERT(dn->dn_object == 0 ||
+           dn->dn_dirtyctx == DN_UNDIRTIED || dn->dn_dirtyctx ==
+           (dmu_tx_is_syncing(tx) ? DN_DIRTY_SYNC : DN_DIRTY_OPEN));
+
+       ASSERT3U(dn->dn_nlevels, >, db->db_level);
+       ASSERT((dn->dn_phys->dn_nlevels == 0 && db->db_level == 0) ||
+           dn->dn_phys->dn_nlevels > db->db_level ||
+           dn->dn_next_nlevels[txgoff] > db->db_level ||
+           dn->dn_next_nlevels[(tx->tx_txg-1) & TXG_MASK] > db->db_level ||
+           dn->dn_next_nlevels[(tx->tx_txg-2) & TXG_MASK] > db->db_level);
+
+       /*
+        * We should only be dirtying in syncing context if it's the
+        * mos or we're initializing the os or it's a special object.
+        * However, we are allowed to dirty in syncing context provided
+        * we already dirtied it in open context.  Hence we must make
+        * this assertion only if we're not already dirty.
+        */
+       os = dn->dn_objset;
+       ASSERT(!dmu_tx_is_syncing(tx) || DMU_OBJECT_IS_SPECIAL(dn->dn_object) ||
+           os->os_dsl_dataset == NULL || BP_IS_HOLE(os->os_rootbp));
+       ASSERT(db->db.db_size != 0);
+
+       dprintf_dbuf(db, "size=%llx\n", (u_longlong_t)db->db.db_size);
+
+       if (db->db_blkid != DMU_BONUS_BLKID) {
+               /*
+                * Update the accounting.
+                * Note: we delay "free accounting" until after we drop
+                * the db_mtx.  This keeps us from grabbing other locks
+                * (and possibly deadlocking) in bp_get_dsize() while
+                * also holding the db_mtx.
+                */
+               dnode_willuse_space(dn, db->db.db_size, tx);
+               do_free_accounting = dbuf_block_freeable(db);
+       }
+
+       /*
+        * If this buffer is dirty in an old transaction group we need
+        * to make a copy of it so that the changes we make in this
+        * transaction group won't leak out when we sync the older txg.
+        */
+       dr = kmem_zalloc(sizeof (dbuf_dirty_record_t), KM_SLEEP);
+       list_link_init(&dr->dr_dirty_node);
+       if (db->db_level == 0) {
+               void *data_old = db->db_buf;
+
+               if (db->db_state != DB_NOFILL) {
+                       if (db->db_blkid == DMU_BONUS_BLKID) {
+                               dbuf_fix_old_data(db, tx->tx_txg);
+                               data_old = db->db.db_data;
+                       } else if (db->db.db_object != DMU_META_DNODE_OBJECT) {
+                               /*
+                                * Release the data buffer from the cache so
+                                * that we can modify it without impacting
+                                * possible other users of this cached data
+                                * block.  Note that indirect blocks and
+                                * private objects are not released until the
+                                * syncing state (since they are only modified
+                                * then).
+                                */
+                               arc_release(db->db_buf, db);
+                               dbuf_fix_old_data(db, tx->tx_txg);
+                               data_old = db->db_buf;
+                       }
+                       ASSERT(data_old != NULL);
+               }
+               dr->dt.dl.dr_data = data_old;
+       } else {
+               mutex_init(&dr->dt.di.dr_mtx, NULL, MUTEX_DEFAULT, NULL);
+               list_create(&dr->dt.di.dr_children,
+                   sizeof (dbuf_dirty_record_t),
+                   offsetof(dbuf_dirty_record_t, dr_dirty_node));
+       }
+       if (db->db_blkid != DMU_BONUS_BLKID && os->os_dsl_dataset != NULL)
+               dr->dr_accounted = db->db.db_size;
+       dr->dr_dbuf = db;
+       dr->dr_txg = tx->tx_txg;
+       dr->dr_next = *drp;
+       *drp = dr;
+
+       /*
+        * We could have been freed_in_flight between the dbuf_noread
+        * and dbuf_dirty.  We win, as though the dbuf_noread() had
+        * happened after the free.
+        */
+       if (db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID &&
+           db->db_blkid != DMU_SPILL_BLKID) {
+               mutex_enter(&dn->dn_mtx);
+               if (dn->dn_free_ranges[txgoff] != NULL) {
+                       range_tree_clear(dn->dn_free_ranges[txgoff],
+                           db->db_blkid, 1);
+               }
+               mutex_exit(&dn->dn_mtx);
+               db->db_freed_in_flight = FALSE;
+       }
+
+       /*
+        * This buffer is now part of this txg
+        */
+       dbuf_add_ref(db, (void *)(uintptr_t)tx->tx_txg);
+       db->db_dirtycnt += 1;
+       ASSERT3U(db->db_dirtycnt, <=, 3);
+
+       mutex_exit(&db->db_mtx);
+
+       if (db->db_blkid == DMU_BONUS_BLKID ||
+           db->db_blkid == DMU_SPILL_BLKID) {
+               mutex_enter(&dn->dn_mtx);
+               ASSERT(!list_link_active(&dr->dr_dirty_node));
+               list_insert_tail(&dn->dn_dirty_records[txgoff], dr);
+               mutex_exit(&dn->dn_mtx);
+               dnode_setdirty(dn, tx);
+               DB_DNODE_EXIT(db);
+               return (dr);
+       } else 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;
+               /*
+                * This is only a guess -- if the dbuf is dirty
+                * in a previous txg, we don't know how much
+                * space it will use on disk yet.  We should
+                * really have the struct_rwlock to access
+                * db_blkptr, but since this is just a guess,
+                * it's OK if we get an odd answer.
+                */
+               ddt_prefetch(os->os_spa, bp);
+               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);
+       }
+
+       if (db->db_level+1 < dn->dn_nlevels) {
+               dmu_buf_impl_t *parent = db->db_parent;
+               dbuf_dirty_record_t *di;
+               int parent_held = FALSE;
+
+               if (db->db_parent == NULL || db->db_parent == dn->dn_dbuf) {
+                       int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+                       parent = dbuf_hold_level(dn, db->db_level+1,
+                           db->db_blkid >> epbs, FTAG);
+                       ASSERT(parent != NULL);
+                       parent_held = TRUE;
+               }
+               if (drop_struct_lock)
+                       rw_exit(&dn->dn_struct_rwlock);
+               ASSERT3U(db->db_level+1, ==, parent->db_level);
+               di = dbuf_dirty(parent, tx);
+               if (parent_held)
+                       dbuf_rele(parent, FTAG);
+
+               mutex_enter(&db->db_mtx);
+               /*
+                * Since we've dropped the mutex, it's possible that
+                * dbuf_undirty() might have changed this out from under us.
+                */
+               if (db->db_last_dirty == dr ||
+                   dn->dn_object == DMU_META_DNODE_OBJECT) {
+                       mutex_enter(&di->dt.di.dr_mtx);
+                       ASSERT3U(di->dr_txg, ==, tx->tx_txg);
+                       ASSERT(!list_link_active(&dr->dr_dirty_node));
+                       list_insert_tail(&di->dt.di.dr_children, dr);
+                       mutex_exit(&di->dt.di.dr_mtx);
+                       dr->dr_parent = di;
+               }
+               mutex_exit(&db->db_mtx);
+       } else {
+               ASSERT(db->db_level+1 == dn->dn_nlevels);
+               ASSERT(db->db_blkid < dn->dn_nblkptr);
+               ASSERT(db->db_parent == NULL || db->db_parent == dn->dn_dbuf);
+               mutex_enter(&dn->dn_mtx);
+               ASSERT(!list_link_active(&dr->dr_dirty_node));
+               list_insert_tail(&dn->dn_dirty_records[txgoff], dr);
+               mutex_exit(&dn->dn_mtx);
+               if (drop_struct_lock)
+                       rw_exit(&dn->dn_struct_rwlock);
+       }
+
+       dnode_setdirty(dn, tx);
+       DB_DNODE_EXIT(db);
+       return (dr);
+}
+
+/*
+ * Undirty a buffer in the transaction group referenced by the given
+ * transaction.  Return whether this evicted the dbuf.
+ */
+static boolean_t
+dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       uint64_t txg = tx->tx_txg;
+       dbuf_dirty_record_t *dr, **drp;
+
+       ASSERT(txg != 0);
+
+       /*
+        * Due to our use of dn_nlevels below, this can only be called
+        * in open context, unless we are operating on the MOS.
+        * From syncing context, dn_nlevels may be different from the
+        * dn_nlevels used when dbuf was dirtied.
+        */
+       ASSERT(db->db_objset ==
+           dmu_objset_pool(db->db_objset)->dp_meta_objset ||
+           txg != spa_syncing_txg(dmu_objset_spa(db->db_objset)));
+       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+       ASSERT0(db->db_level);
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+
+       /*
+        * If this buffer is not dirty, we're done.
+        */
+       for (drp = &db->db_last_dirty; (dr = *drp) != NULL; drp = &dr->dr_next)
+               if (dr->dr_txg <= txg)
+                       break;
+       if (dr == NULL || dr->dr_txg < txg)
+               return (B_FALSE);
+       ASSERT(dr->dr_txg == txg);
+       ASSERT(dr->dr_dbuf == db);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       dprintf_dbuf(db, "size=%llx\n", (u_longlong_t)db->db.db_size);
+
+       ASSERT(db->db.db_size != 0);
+
+       dsl_pool_undirty_space(dmu_objset_pool(dn->dn_objset),
+           dr->dr_accounted, txg);
+
+       *drp = dr->dr_next;
+
+       /*
+        * Note that there are three places in dbuf_dirty()
+        * where this dirty record may be put on a list.
+        * Make sure to do a list_remove corresponding to
+        * every one of those list_insert calls.
+        */
+       if (dr->dr_parent) {
+               mutex_enter(&dr->dr_parent->dt.di.dr_mtx);
+               list_remove(&dr->dr_parent->dt.di.dr_children, dr);
+               mutex_exit(&dr->dr_parent->dt.di.dr_mtx);
+       } else if (db->db_blkid == DMU_SPILL_BLKID ||
+           db->db_level + 1 == dn->dn_nlevels) {
+               ASSERT(db->db_blkptr == NULL || db->db_parent == dn->dn_dbuf);
+               mutex_enter(&dn->dn_mtx);
+               list_remove(&dn->dn_dirty_records[txg & TXG_MASK], dr);
+               mutex_exit(&dn->dn_mtx);
+       }
+       DB_DNODE_EXIT(db);
+
+       if (db->db_state != DB_NOFILL) {
+               dbuf_unoverride(dr);
+
+               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));
+       }
+
+       kmem_free(dr, sizeof (dbuf_dirty_record_t));
+
+       ASSERT(db->db_dirtycnt > 0);
+       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);
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+void
+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;
+
+       ASSERT(tx->tx_txg != 0);
+       ASSERT(!refcount_is_zero(&db->db_holds));
+
+       DB_DNODE_ENTER(db);
+       if (RW_WRITE_HELD(&DB_DNODE(db)->dn_struct_rwlock))
+               rf |= DB_RF_HAVESTRUCT;
+       DB_DNODE_EXIT(db);
+       (void) dbuf_read(db, NULL, rf);
+       (void) dbuf_dirty(db, tx);
+}
+
+void
+dmu_buf_will_not_fill(dmu_buf_t *db_fake, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       db->db_state = DB_NOFILL;
+
+       dmu_buf_will_fill(db_fake, tx);
+}
+
+void
+dmu_buf_will_fill(dmu_buf_t *db_fake, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+       ASSERT(tx->tx_txg != 0);
+       ASSERT(db->db_level == 0);
+       ASSERT(!refcount_is_zero(&db->db_holds));
+
+       ASSERT(db->db.db_object != DMU_META_DNODE_OBJECT ||
+           dmu_tx_private_ok(tx));
+
+       dbuf_noread(db);
+       (void) dbuf_dirty(db, tx);
+}
+
+#pragma weak dmu_buf_fill_done = dbuf_fill_done
+/* ARGSUSED */
+void
+dbuf_fill_done(dmu_buf_impl_t *db, dmu_tx_t *tx)
+{
+       mutex_enter(&db->db_mtx);
+       DBUF_VERIFY(db);
+
+       if (db->db_state == DB_FILL) {
+               if (db->db_level == 0 && db->db_freed_in_flight) {
+                       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+                       /* we were freed while filling */
+                       /* XXX dbuf_undirty? */
+                       bzero(db->db.db_data, db->db.db_size);
+                       db->db_freed_in_flight = FALSE;
+               }
+               db->db_state = DB_CACHED;
+               cv_broadcast(&db->db_changed);
+       }
+       mutex_exit(&db->db_mtx);
+}
+
+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)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbuf;
+       struct dirty_leaf *dl;
+       dmu_object_type_t type;
+
+       DB_DNODE_ENTER(db);
+       type = DB_DNODE(db)->dn_type;
+       DB_DNODE_EXIT(db);
+
+       ASSERT0(db->db_level);
+       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+
+       dmu_buf_will_not_fill(dbuf, tx);
+
+       ASSERT3U(db->db_last_dirty->dr_txg, ==, tx->tx_txg);
+       dl = &db->db_last_dirty->dt.dl;
+       encode_embedded_bp_compressed(&dl->dr_overridden_by,
+           data, comp, uncompressed_size, compressed_size);
+       BPE_SET_ETYPE(&dl->dr_overridden_by, etype);
+       BP_SET_TYPE(&dl->dr_overridden_by, type);
+       BP_SET_LEVEL(&dl->dr_overridden_by, 0);
+       BP_SET_BYTEORDER(&dl->dr_overridden_by, byteorder);
+
+       dl->dr_override_state = DR_OVERRIDDEN;
+       dl->dr_overridden_by.blk_birth = db->db_last_dirty->dr_txg;
+}
+
+/*
+ * Directly assign a provided arc buf to a given dbuf if it's not referenced
+ * by anybody except our caller. Otherwise copy arcbuf's contents to dbuf.
+ */
+void
+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);
+       ASSERT(buf != NULL);
+       ASSERT(arc_buf_size(buf) == db->db.db_size);
+       ASSERT(tx->tx_txg != 0);
+
+       arc_return_buf(buf, db);
+       ASSERT(arc_released(buf));
+
+       mutex_enter(&db->db_mtx);
+
+       while (db->db_state == DB_READ || db->db_state == DB_FILL)
+               cv_wait(&db->db_changed, &db->db_mtx);
+
+       ASSERT(db->db_state == DB_CACHED || db->db_state == DB_UNCACHED);
+
+       if (db->db_state == DB_CACHED &&
+           refcount_count(&db->db_holds) - 1 > db->db_dirtycnt) {
+               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));
+               xuio_stat_wbuf_copied();
+               return;
+       }
+
+       xuio_stat_wbuf_nocopy();
+       if (db->db_state == DB_CACHED) {
+               dbuf_dirty_record_t *dr = db->db_last_dirty;
+
+               ASSERT(db->db_buf != NULL);
+               if (dr != NULL && dr->dr_txg == tx->tx_txg) {
+                       ASSERT(dr->dt.dl.dr_data == db->db_buf);
+                       if (!arc_released(db->db_buf)) {
+                               ASSERT(dr->dt.dl.dr_override_state ==
+                                   DR_OVERRIDDEN);
+                               arc_release(db->db_buf, db);
+                       }
+                       dr->dt.dl.dr_data = buf;
+                       VERIFY(arc_buf_remove_ref(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));
+               }
+               db->db_buf = NULL;
+       }
+       ASSERT(db->db_buf == NULL);
+       dbuf_set_data(db, buf);
+       db->db_state = DB_FILL;
+       mutex_exit(&db->db_mtx);
+       (void) dbuf_dirty(db, 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)
+{
+       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_state == DB_CACHED) {
+               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;
+               db->db_state = DB_UNCACHED;
+       }
+
+       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;
+
+       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)) {
+               avl_remove(&dn->dn_dbufs, db);
+               atomic_dec_32(&dn->dn_dbufs_count);
+               membar_producer();
+               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.
+                * The membar_producer() ensures visibility of the decremented
+                * value in dnode_move(), since DB_DNODE_EXIT doesn't actually
+                * release any lock.
+                */
+               dnode_rele(dn, db);
+               db->db_dnode_handle = NULL;
+       } else {
+               DB_DNODE_EXIT(db);
+       }
+
+       if (db->db_buf)
+               dbuf_gone = arc_clear_callback(db->db_buf);
+
+       if (!dbuf_gone)
+               mutex_exit(&db->db_mtx);
+
+       /*
+        * If this dbuf is referenced from an indirect dbuf,
+        * decrement the ref count on the indirect dbuf.
+        */
+       if (parent && parent != dndb)
+               dbuf_rele(parent, db);
+}
+
+__attribute__((always_inline))
+static inline int
+dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse,
+    dmu_buf_impl_t **parentp, blkptr_t **bpp, struct dbuf_hold_impl_data *dh)
+{
+       int nlevels, epbs;
+
+       *parentp = NULL;
+       *bpp = NULL;
+
+       ASSERT(blkid != DMU_BONUS_BLKID);
+
+       if (blkid == DMU_SPILL_BLKID) {
+               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;
+               else
+                       *bpp = NULL;
+               dbuf_add_ref(dn->dn_dbuf, NULL);
+               *parentp = dn->dn_dbuf;
+               mutex_exit(&dn->dn_mtx);
+               return (0);
+       }
+
+       if (dn->dn_phys->dn_nlevels == 0)
+               nlevels = 1;
+       else
+               nlevels = dn->dn_phys->dn_nlevels;
+
+       epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+       ASSERT3U(level * epbs, <, 64);
+       ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+       if (level >= nlevels ||
+           (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);
+               } else {
+                       __dbuf_hold_impl_init(dh + 1, dn, dh->dh_level + 1,
+                                       blkid >> epbs, fail_sparse, NULL,
+                                       parentp, dh->dh_depth + 1);
+                       err = __dbuf_hold_impl(dh + 1);
+               }
+               if (err)
+                       return (err);
+               err = dbuf_read(*parentp, NULL,
+                   (DB_RF_HAVESTRUCT | DB_RF_NOPREFETCH | DB_RF_CANFAIL));
+               if (err) {
+                       dbuf_rele(*parentp, NULL);
+                       *parentp = NULL;
+                       return (err);
+               }
+               *bpp = ((blkptr_t *)(*parentp)->db.db_data) +
+                   (blkid & ((1ULL << epbs) - 1));
+               return (0);
+       } else {
+               /* the block is referenced from the dnode */
+               ASSERT3U(level, ==, nlevels-1);
+               ASSERT(dn->dn_phys->dn_nblkptr == 0 ||
+                   blkid < dn->dn_phys->dn_nblkptr);
+               if (dn->dn_dbuf) {
+                       dbuf_add_ref(dn->dn_dbuf, NULL);
+                       *parentp = dn->dn_dbuf;
+               }
+               *bpp = &dn->dn_phys->dn_blkptr[blkid];
+               return (0);
+       }
+}
+
+static dmu_buf_impl_t *
+dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
+    dmu_buf_impl_t *parent, blkptr_t *blkptr)
+{
+       objset_t *os = dn->dn_objset;
+       dmu_buf_impl_t *db, *odb;
+
+       ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+       ASSERT(dn->dn_type != DMU_OT_NONE);
+
+       db = kmem_cache_alloc(dbuf_cache, KM_SLEEP);
+
+       db->db_objset = os;
+       db->db.db_object = dn->dn_object;
+       db->db_level = level;
+       db->db_blkid = blkid;
+       db->db_last_dirty = NULL;
+       db->db_dirtycnt = 0;
+       db->db_dnode_handle = dn->dn_handle;
+       db->db_parent = parent;
+       db->db_blkptr = blkptr;
+
+       db->db_user = NULL;
+       db->db_user_immediate_evict = FALSE;
+       db->db_freed_in_flight = FALSE;
+       db->db_pending_evict = FALSE;
+
+       if (blkid == DMU_BONUS_BLKID) {
+               ASSERT3P(parent, ==, dn->dn_dbuf);
+               db->db.db_size = DN_MAX_BONUSLEN -
+                   (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);
+               return (db);
+       } else if (blkid == DMU_SPILL_BLKID) {
+               db->db.db_size = (blkptr != NULL) ?
+                   BP_GET_LSIZE(blkptr) : SPA_MINBLOCKSIZE;
+               db->db.db_offset = 0;
+       } else {
+               int blocksize =
+                   db->db_level ? 1 << dn->dn_indblkshift : dn->dn_datablksz;
+               db->db.db_size = blocksize;
+               db->db.db_offset = db->db_blkid * blocksize;
+       }
+
+       /*
+        * Hold the dn_dbufs_mtx while we get the new dbuf
+        * in the hash table *and* added to the dbufs list.
+        * This prevents a possible deadlock with someone
+        * trying to look up this dbuf before its added to the
+        * dn_dbufs list.
+        */
+       mutex_enter(&dn->dn_dbufs_mtx);
+       db->db_state = DB_EVICTING;
+       if ((odb = dbuf_hash_insert(db)) != NULL) {
+               /* someone else inserted it first */
+               kmem_cache_free(dbuf_cache, db);
+               mutex_exit(&dn->dn_dbufs_mtx);
+               return (odb);
+       }
+       avl_add(&dn->dn_dbufs, db);
+       if (db->db_level == 0 && db->db_blkid >=
+           dn->dn_unlisted_l0_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);
+
+       if (parent && parent != dn->dn_dbuf)
+               dbuf_add_ref(parent, db);
+
+       ASSERT(dn->dn_object == DMU_META_DNODE_OBJECT ||
+           refcount_count(&dn->dn_holds) > 0);
+       (void) refcount_add(&dn->dn_holds, db);
+       atomic_inc_32(&dn->dn_dbufs_count);
+
+       dprintf_dbuf(db, "db=%p\n", db);
+
+       return (db);
+}
+
+static int
+dbuf_do_evict(void *private)
+{
+       dmu_buf_impl_t *db = private;
+
+       if (!MUTEX_HELD(&db->db_mtx))
+               mutex_enter(&db->db_mtx);
+
+       ASSERT(refcount_is_zero(&db->db_holds));
+
+       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);
+}
+
+static void
+dbuf_destroy(dmu_buf_impl_t *db)
+{
+       ASSERT(refcount_is_zero(&db->db_holds));
+
+       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;
+
+                       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;
+               }
+               dbuf_hash_remove(db);
+       }
+       db->db_parent = NULL;
+       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);
+
+       kmem_cache_free(dbuf_cache, db);
+       arc_space_return(sizeof (dmu_buf_impl_t), ARC_SPACE_OTHER);
+}
+
+void
+dbuf_prefetch(dnode_t *dn, uint64_t blkid, zio_priority_t prio)
+{
+       dmu_buf_impl_t *db = NULL;
+       blkptr_t *bp = NULL;
+
+       ASSERT(blkid != DMU_BONUS_BLKID);
+       ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+
+       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 dbuf is already in the cache.  We assume that
+                * it is already CACHED, or else about to be either
+                * 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;
+
+                       SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET,
+                           dn->dn_object, 0, 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);
+       }
+}
+
+#define        DBUF_HOLD_IMPL_MAX_DEPTH        20
+
+/*
+ * Returns with db_holds incremented, and db_mtx not held.
+ * Note: dn_struct_rwlock must be held.
+ */
+static int
+__dbuf_hold_impl(struct dbuf_hold_impl_data *dh)
+{
+       ASSERT3S(dh->dh_depth, <, DBUF_HOLD_IMPL_MAX_DEPTH);
+       dh->dh_parent = NULL;
+
+       ASSERT(dh->dh_blkid != DMU_BONUS_BLKID);
+       ASSERT(RW_LOCK_HELD(&dh->dh_dn->dn_struct_rwlock));
+       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);
+
+       if (dh->dh_db == NULL) {
+               dh->dh_bp = NULL;
+
+               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,
+                                       &dh->dh_bp, dh);
+               if (dh->dh_fail_sparse) {
+                       if (dh->dh_err == 0 &&
+                           dh->dh_bp && BP_IS_HOLE(dh->dh_bp))
+                               dh->dh_err = SET_ERROR(ENOENT);
+                       if (dh->dh_err) {
+                               if (dh->dh_parent)
+                                       dbuf_rele(dh->dh_parent, NULL);
+                               return (dh->dh_err);
+                       }
+               }
+               if (dh->dh_err && dh->dh_err != ENOENT)
+                       return (dh->dh_err);
+               dh->dh_db = dbuf_create(dh->dh_dn, dh->dh_level, dh->dh_blkid,
+                                       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);
+       }
+
+       ASSERT(dh->dh_db->db_buf == NULL || arc_referenced(dh->dh_db->db_buf));
+
+       /*
+        * If this buffer is currently syncing out, and we are are
+        * still referencing it from db_data, we need to make a copy
+        * of it in case we decide we want to dirty it again in this txg.
+        */
+       if (dh->dh_db->db_level == 0 &&
+           dh->dh_db->db_blkid != DMU_BONUS_BLKID &&
+           dh->dh_dn->dn_object != DMU_META_DNODE_OBJECT &&
+           dh->dh_db->db_state == DB_CACHED && dh->dh_db->db_data_pending) {
+               dh->dh_dr = dh->dh_db->db_data_pending;
+
+               if (dh->dh_dr->dt.dl.dr_data == dh->dh_db->db_buf) {
+                       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));
+                       bcopy(dh->dh_dr->dt.dl.dr_data->b_data,
+                           dh->dh_db->db.db_data, dh->dh_db->db.db_size);
+               }
+       }
+
+       (void) refcount_add(&dh->dh_db->db_holds, dh->dh_tag);
+       DBUF_VERIFY(dh->dh_db);
+       mutex_exit(&dh->dh_db->db_mtx);
+
+       /* NOTE: we can't rele the parent until after we drop the db_mtx */
+       if (dh->dh_parent)
+               dbuf_rele(dh->dh_parent, NULL);
+
+       ASSERT3P(DB_DNODE(dh->dh_db), ==, dh->dh_dn);
+       ASSERT3U(dh->dh_db->db_blkid, ==, dh->dh_blkid);
+       ASSERT3U(dh->dh_db->db_level, ==, dh->dh_level);
+       *(dh->dh_dbp) = dh->dh_db;
+
+       return (0);
+}
+
+/*
+ * The following code preserves the recursive function dbuf_hold_impl()
+ * but moves the local variables AND function arguments to the heap to
+ * minimize the stack frame size.  Enough space is initially allocated
+ * on the stack for 20 levels of recursion.
+ */
+int
+dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
+    void *tag, dmu_buf_impl_t **dbp)
+{
+       struct dbuf_hold_impl_data *dh;
+       int error;
+
+       dh = kmem_zalloc(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);
+
+       error = __dbuf_hold_impl(dh);
+
+       kmem_free(dh, sizeof (struct dbuf_hold_impl_data) *
+           DBUF_HOLD_IMPL_MAX_DEPTH);
+
+       return (error);
+}
+
+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)
+{
+       dh->dh_dn = dn;
+       dh->dh_level = level;
+       dh->dh_blkid = blkid;
+       dh->dh_fail_sparse = fail_sparse;
+       dh->dh_tag = tag;
+       dh->dh_dbp = dbp;
+       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);
+}
+
+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);
+       return (err ? NULL : db);
+}
+
+void
+dbuf_create_bonus(dnode_t *dn)
+{
+       ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock));
+
+       ASSERT(dn->dn_bonus == NULL);
+       dn->dn_bonus = dbuf_create(dn, 0, DMU_BONUS_BLKID, dn->dn_dbuf, NULL);
+}
+
+int
+dbuf_spill_set_blksz(dmu_buf_t *db_fake, uint64_t blksz, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+
+       if (db->db_blkid != DMU_SPILL_BLKID)
+               return (SET_ERROR(ENOTSUP));
+       if (blksz == 0)
+               blksz = SPA_MINBLOCKSIZE;
+       ASSERT3U(blksz, <=, spa_maxblocksize(dmu_objset_spa(db->db_objset)));
+       blksz = P2ROUNDUP(blksz, SPA_MINBLOCKSIZE);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       dbuf_new_size(db, blksz, tx);
+       rw_exit(&dn->dn_struct_rwlock);
+       DB_DNODE_EXIT(db);
+
+       return (0);
+}
+
+void
+dbuf_rm_spill(dnode_t *dn, dmu_tx_t *tx)
+{
+       dbuf_free_range(dn, DMU_SPILL_BLKID, DMU_SPILL_BLKID, tx);
+}
+
+#pragma weak dmu_buf_add_ref = dbuf_add_ref
+void
+dbuf_add_ref(dmu_buf_impl_t *db, void *tag)
+{
+       VERIFY(refcount_add(&db->db_holds, tag) > 1);
+}
+
+#pragma weak dmu_buf_try_add_ref = dbuf_try_add_ref
+boolean_t
+dbuf_try_add_ref(dmu_buf_t *db_fake, objset_t *os, uint64_t obj, uint64_t blkid,
+    void *tag)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dmu_buf_impl_t *found_db;
+       boolean_t result = B_FALSE;
+
+       if (blkid == DMU_BONUS_BLKID)
+               found_db = dbuf_find_bonus(os, obj);
+       else
+               found_db = dbuf_find(os, obj, 0, blkid);
+
+       if (found_db != NULL) {
+               if (db == found_db && dbuf_refcount(db) > db->db_dirtycnt) {
+                       (void) refcount_add(&db->db_holds, tag);
+                       result = B_TRUE;
+               }
+               mutex_exit(&found_db->db_mtx);
+       }
+       return (result);
+}
+
+/*
+ * If you call dbuf_rele() you had better not be referencing the dnode handle
+ * unless you have some other direct or indirect hold on the dnode. (An indirect
+ * hold is a hold on one of the dnode's dbufs, including the bonus buffer.)
+ * Without that, the dbuf_rele() could lead to a dnode_rele() followed by the
+ * dnode's parent dbuf evicting its dnode handles.
+ */
+void
+dbuf_rele(dmu_buf_impl_t *db, void *tag)
+{
+       mutex_enter(&db->db_mtx);
+       dbuf_rele_and_unlock(db, tag);
+}
+
+void
+dmu_buf_rele(dmu_buf_t *db, void *tag)
+{
+       dbuf_rele((dmu_buf_impl_t *)db, tag);
+}
+
+/*
+ * dbuf_rele() for an already-locked dbuf.  This is necessary to allow
+ * db_dirtycnt and db_holds to be updated atomically.
+ */
+void
+dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag)
+{
+       int64_t holds;
+
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       DBUF_VERIFY(db);
+
+       /*
+        * Remove the reference to the dbuf before removing its hold on the
+        * dnode so we can guarantee in dnode_move() that a referenced bonus
+        * buffer has a corresponding dnode hold.
+        */
+       holds = refcount_remove(&db->db_holds, tag);
+       ASSERT(holds >= 0);
+
+       /*
+        * 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))
+               arc_buf_freeze(db->db_buf);
+
+       if (holds == db->db_dirtycnt &&
+           db->db_level == 0 && db->db_user_immediate_evict)
+               dbuf_evict_user(db);
+
+       if (holds == 0) {
+               if (db->db_blkid == DMU_BONUS_BLKID) {
+                       dnode_t *dn;
+                       boolean_t evict_dbuf = db->db_pending_evict;
+
+                       /*
+                        * If the dnode moves here, we cannot cross this
+                        * barrier until the move completes.
+                        */
+                       DB_DNODE_ENTER(db);
+
+                       dn = DB_DNODE(db);
+                       atomic_dec_32(&dn->dn_dbufs_count);
+
+                       /*
+                        * Decrementing the dbuf count means that the bonus
+                        * buffer's dnode hold is no longer discounted in
+                        * dnode_move(). The dnode cannot move until after
+                        * the dnode_rele() below.
+                        */
+                       DB_DNODE_EXIT(db);
+
+                       /*
+                        * Do not reference db after its lock is dropped.
+                        * Another thread may evict it.
+                        */
+                       mutex_exit(&db->db_mtx);
+
+                       if (evict_dbuf)
+                               dnode_evict_bonus(dn);
+
+                       dnode_rele(dn, db);
+               } else if (db->db_buf == NULL) {
+                       /*
+                        * This is a special case: we never associated this
+                        * dbuf with any data allocated from the ARC.
+                        */
+                       ASSERT(db->db_state == DB_UNCACHED ||
+                           db->db_state == DB_NOFILL);
+                       dbuf_evict(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);
+               } else {
+                       VERIFY(!arc_buf_remove_ref(db->db_buf, db));
+
+                       /*
+                        * 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 {
+                               mutex_exit(&db->db_mtx);
+                       }
+               }
+       } else {
+               mutex_exit(&db->db_mtx);
+       }
+}
+
+#pragma weak dmu_buf_refcount = dbuf_refcount
+uint64_t
+dbuf_refcount(dmu_buf_impl_t *db)
+{
+       return (refcount_count(&db->db_holds));
+}
+
+void *
+dmu_buf_replace_user(dmu_buf_t *db_fake, dmu_buf_user_t *old_user,
+    dmu_buf_user_t *new_user)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       mutex_enter(&db->db_mtx);
+       dbuf_verify_user(db, DBVU_NOT_EVICTING);
+       if (db->db_user == old_user)
+               db->db_user = new_user;
+       else
+               old_user = db->db_user;
+       dbuf_verify_user(db, DBVU_NOT_EVICTING);
+       mutex_exit(&db->db_mtx);
+
+       return (old_user);
+}
+
+void *
+dmu_buf_set_user(dmu_buf_t *db_fake, dmu_buf_user_t *user)
+{
+       return (dmu_buf_replace_user(db_fake, NULL, user));
+}
+
+void *
+dmu_buf_set_user_ie(dmu_buf_t *db_fake, dmu_buf_user_t *user)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       db->db_user_immediate_evict = TRUE;
+       return (dmu_buf_set_user(db_fake, user));
+}
+
+void *
+dmu_buf_remove_user(dmu_buf_t *db_fake, dmu_buf_user_t *user)
+{
+       return (dmu_buf_replace_user(db_fake, user, NULL));
+}
+
+void *
+dmu_buf_get_user(dmu_buf_t *db_fake)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       dbuf_verify_user(db, DBVU_NOT_EVICTING);
+       return (db->db_user);
+}
+
+void
+dmu_buf_user_evict_wait()
+{
+       taskq_wait(dbu_evict_taskq);
+}
+
+boolean_t
+dmu_buf_freeable(dmu_buf_t *dbuf)
+{
+       boolean_t res = B_FALSE;
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbuf;
+
+       if (db->db_blkptr)
+               res = dsl_dataset_block_freeable(db->db_objset->os_dsl_dataset,
+                   db->db_blkptr, db->db_blkptr->blk_birth);
+
+       return (res);
+}
+
+blkptr_t *
+dmu_buf_get_blkptr(dmu_buf_t *db)
+{
+       dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db;
+       return (dbi->db_blkptr);
+}
+
+static void
+dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db)
+{
+       /* ASSERT(dmu_tx_is_syncing(tx) */
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+
+       if (db->db_blkptr != NULL)
+               return;
+
+       if (db->db_blkid == DMU_SPILL_BLKID) {
+               db->db_blkptr = &dn->dn_phys->dn_spill;
+               BP_ZERO(db->db_blkptr);
+               return;
+       }
+       if (db->db_level == dn->dn_phys->dn_nlevels-1) {
+               /*
+                * This buffer was allocated at a time when there was
+                * no available blkptrs from the dnode, or it was
+                * inappropriate to hook it in (i.e., nlevels mis-match).
+                */
+               ASSERT(db->db_blkid < dn->dn_phys->dn_nblkptr);
+               ASSERT(db->db_parent == NULL);
+               db->db_parent = dn->dn_dbuf;
+               db->db_blkptr = &dn->dn_phys->dn_blkptr[db->db_blkid];
+               DBUF_VERIFY(db);
+       } else {
+               dmu_buf_impl_t *parent = db->db_parent;
+               int epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+               ASSERT(dn->dn_phys->dn_nlevels > 1);
+               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);
+                       rw_exit(&dn->dn_struct_rwlock);
+                       mutex_enter(&db->db_mtx);
+                       db->db_parent = parent;
+               }
+               db->db_blkptr = (blkptr_t *)parent->db.db_data +
+                   (db->db_blkid & ((1ULL << epbs) - 1));
+               DBUF_VERIFY(db);
+       }
+}
+
+/*
+ * dbuf_sync_indirect() is called recursively from dbuf_sync_list() so it
+ * is critical the we not allow the compiler to inline this function in to
+ * dbuf_sync_list() thereby drastically bloating the stack usage.
+ */
+noinline static void
+dbuf_sync_indirect(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+       dnode_t *dn;
+       zio_t *zio;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       dprintf_dbuf_bp(db, db->db_blkptr, "blkptr=%p", db->db_blkptr);
+
+       mutex_enter(&db->db_mtx);
+
+       ASSERT(db->db_level > 0);
+       DBUF_VERIFY(db);
+
+       /* Read the block if it hasn't been read yet. */
+       if (db->db_buf == NULL) {
+               mutex_exit(&db->db_mtx);
+               (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED);
+               mutex_enter(&db->db_mtx);
+       }
+       ASSERT3U(db->db_state, ==, DB_CACHED);
+       ASSERT(db->db_buf != NULL);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       /* Indirect block size must match what the dnode thinks it is. */
+       ASSERT3U(db->db.db_size, ==, 1<<dn->dn_phys->dn_indblkshift);
+       dbuf_check_blkptr(dn, db);
+       DB_DNODE_EXIT(db);
+
+       /* Provide the pending dirty record to child dbufs */
+       db->db_data_pending = dr;
+
+       mutex_exit(&db->db_mtx);
+       dbuf_write(dr, db->db_buf, tx);
+
+       zio = dr->dr_zio;
+       mutex_enter(&dr->dt.di.dr_mtx);
+       dbuf_sync_list(&dr->dt.di.dr_children, db->db_level - 1, tx);
+       ASSERT(list_head(&dr->dt.di.dr_children) == NULL);
+       mutex_exit(&dr->dt.di.dr_mtx);
+       zio_nowait(zio);
+}
+
+/*
+ * dbuf_sync_leaf() is called recursively from dbuf_sync_list() so it is
+ * critical the we not allow the compiler to inline this function in to
+ * dbuf_sync_list() thereby drastically bloating the stack usage.
+ */
+noinline static void
+dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
+{
+       arc_buf_t **datap = &dr->dt.dl.dr_data;
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+       dnode_t *dn;
+       objset_t *os;
+       uint64_t txg = tx->tx_txg;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       dprintf_dbuf_bp(db, db->db_blkptr, "blkptr=%p", db->db_blkptr);
+
+       mutex_enter(&db->db_mtx);
+       /*
+        * To be synced, we must be dirtied.  But we
+        * might have been freed after the dirty.
+        */
+       if (db->db_state == DB_UNCACHED) {
+               /* This buffer has been freed since it was dirtied */
+               ASSERT(db->db.db_data == NULL);
+       } else if (db->db_state == DB_FILL) {
+               /* This buffer was freed and is now being re-filled */
+               ASSERT(db->db.db_data != dr->dt.dl.dr_data);
+       } else {
+               ASSERT(db->db_state == DB_CACHED || db->db_state == DB_NOFILL);
+       }
+       DBUF_VERIFY(db);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       if (db->db_blkid == DMU_SPILL_BLKID) {
+               mutex_enter(&dn->dn_mtx);
+               if (!(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR)) {
+                       /*
+                        * In the previous transaction group, the bonus buffer
+                        * was entirely used to store the attributes for the
+                        * dnode which overrode the dn_spill field.  However,
+                        * when adding more attributes to the file a spill
+                        * block was required to hold the extra attributes.
+                        *
+                        * Make sure to clear the garbage left in the dn_spill
+                        * field from the previous attributes in the bonus
+                        * buffer.  Otherwise, after writing out the spill
+                        * block to the new allocated dva, it will free
+                        * the old block pointed to by the invalid dn_spill.
+                        */
+                       db->db_blkptr = NULL;
+               }
+               dn->dn_phys->dn_flags |= DNODE_FLAG_SPILL_BLKPTR;
+               mutex_exit(&dn->dn_mtx);
+       }
+
+       /*
+        * If this is a bonus buffer, simply copy the bonus data into the
+        * dnode.  It will be written out when the dnode is synced (and it
+        * will be synced, since it must have been dirty for dbuf_sync to
+        * be called).
+        */
+       if (db->db_blkid == DMU_BONUS_BLKID) {
+               dbuf_dirty_record_t **drp;
+
+               ASSERT(*datap != NULL);
+               ASSERT0(db->db_level);
+               ASSERT3U(dn->dn_phys->dn_bonuslen, <=, DN_MAX_BONUSLEN);
+               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);
+               }
+               db->db_data_pending = NULL;
+               drp = &db->db_last_dirty;
+               while (*drp != dr)
+                       drp = &(*drp)->dr_next;
+               ASSERT(dr->dr_next == NULL);
+               ASSERT(dr->dr_dbuf == db);
+               *drp = dr->dr_next;
+               if (dr->dr_dbuf->db_level != 0) {
+                       mutex_destroy(&dr->dt.di.dr_mtx);
+                       list_destroy(&dr->dt.di.dr_children);
+               }
+               kmem_free(dr, sizeof (dbuf_dirty_record_t));
+               ASSERT(db->db_dirtycnt > 0);
+               db->db_dirtycnt -= 1;
+               dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg);
+               return;
+       }
+
+       os = dn->dn_objset;
+
+       /*
+        * This function may have dropped the db_mtx lock allowing a dmu_sync
+        * operation to sneak in. As a result, we need to ensure that we
+        * don't check the dr_override_state until we have returned from
+        * dbuf_check_blkptr.
+        */
+       dbuf_check_blkptr(dn, db);
+
+       /*
+        * If this buffer is in the middle of an immediate write,
+        * wait for the synchronous IO to complete.
+        */
+       while (dr->dt.dl.dr_override_state == DR_IN_DMU_SYNC) {
+               ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT);
+               cv_wait(&db->db_changed, &db->db_mtx);
+               ASSERT(dr->dt.dl.dr_override_state != DR_NOT_OVERRIDDEN);
+       }
+
+       if (db->db_state != DB_NOFILL &&
+           dn->dn_object != DMU_META_DNODE_OBJECT &&
+           refcount_count(&db->db_holds) > 1 &&
+           dr->dt.dl.dr_override_state != DR_OVERRIDDEN &&
+           *datap == db->db_buf) {
+               /*
+                * If this buffer is currently "in use" (i.e., there
+                * are active holds and db_data still references it),
+                * then make a copy before we start the write so that
+                * any modifications from the open txg will not leak
+                * into this write.
+                *
+                * NOTE: this copy does not need to be made for
+                * objects only modified in the syncing context (e.g.
+                * DNONE_DNODE blocks).
+                */
+               int blksz = 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);
+       }
+       db->db_data_pending = dr;
+
+       mutex_exit(&db->db_mtx);
+
+       dbuf_write(dr, *datap, tx);
+
+       ASSERT(!list_link_active(&dr->dr_dirty_node));
+       if (dn->dn_object == DMU_META_DNODE_OBJECT) {
+               list_insert_tail(&dn->dn_dirty_records[txg&TXG_MASK], dr);
+               DB_DNODE_EXIT(db);
+       } else {
+               /*
+                * Although zio_nowait() does not "wait for an IO", it does
+                * initiate the IO. If this is an empty write it seems plausible
+                * that the IO could actually be completed before the nowait
+                * returns. We need to DB_DNODE_EXIT() first in case
+                * zio_nowait() invalidates the dbuf.
+                */
+               DB_DNODE_EXIT(db);
+               zio_nowait(dr->dr_zio);
+       }
+}
+
+void
+dbuf_sync_list(list_t *list, int level, dmu_tx_t *tx)
+{
+       dbuf_dirty_record_t *dr;
+
+       while ((dr = list_head(list))) {
+               if (dr->dr_zio != NULL) {
+                       /*
+                        * If we find an already initialized zio then we
+                        * are processing the meta-dnode, and we have finished.
+                        * The dbufs for all dnodes are put back on the list
+                        * during processing, so that we can zio_wait()
+                        * these IOs after initiating all child IOs.
+                        */
+                       ASSERT3U(dr->dr_dbuf->db.db_object, ==,
+                           DMU_META_DNODE_OBJECT);
+                       break;
+               }
+               if (dr->dr_dbuf->db_blkid != DMU_BONUS_BLKID &&
+                   dr->dr_dbuf->db_blkid != DMU_SPILL_BLKID) {
+                       VERIFY3U(dr->dr_dbuf->db_level, ==, level);
+               }
+               list_remove(list, dr);
+               if (dr->dr_dbuf->db_level > 0)
+                       dbuf_sync_indirect(dr, tx);
+               else
+                       dbuf_sync_leaf(dr, tx);
+       }
+}
+
+/* ARGSUSED */
+static void
+dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
+{
+       dmu_buf_impl_t *db = vdb;
+       dnode_t *dn;
+       blkptr_t *bp = zio->io_bp;
+       blkptr_t *bp_orig = &zio->io_bp_orig;
+       spa_t *spa = zio->io_spa;
+       int64_t delta;
+       uint64_t fill = 0;
+       int i;
+
+       ASSERT3P(db->db_blkptr, ==, bp);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       delta = bp_get_dsize_sync(spa, bp) - bp_get_dsize_sync(spa, bp_orig);
+       dnode_diduse_space(dn, delta - zio->io_prev_space_delta);
+       zio->io_prev_space_delta = delta;
+
+       if (bp->blk_birth != 0) {
+               ASSERT((db->db_blkid != DMU_SPILL_BLKID &&
+                   BP_GET_TYPE(bp) == dn->dn_type) ||
+                   (db->db_blkid == DMU_SPILL_BLKID &&
+                   BP_GET_TYPE(bp) == dn->dn_bonustype) ||
+                   BP_IS_EMBEDDED(bp));
+               ASSERT(BP_GET_LEVEL(bp) == db->db_level);
+       }
+
+       mutex_enter(&db->db_mtx);
+
+#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);
+       }
+#endif
+
+       if (db->db_level == 0) {
+               mutex_enter(&dn->dn_mtx);
+               if (db->db_blkid > dn->dn_phys->dn_maxblkid &&
+                   db->db_blkid != DMU_SPILL_BLKID)
+                       dn->dn_phys->dn_maxblkid = db->db_blkid;
+               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)
+                                       fill++;
+                       }
+               } else {
+                       if (BP_IS_HOLE(bp)) {
+                               fill = 0;
+                       } else {
+                               fill = 1;
+                       }
+               }
+       } else {
+               blkptr_t *ibp = db->db.db_data;
+               ASSERT3U(db->db.db_size, ==, 1<<dn->dn_phys->dn_indblkshift);
+               for (i = db->db.db_size >> SPA_BLKPTRSHIFT; i > 0; i--, ibp++) {
+                       if (BP_IS_HOLE(ibp))
+                               continue;
+                       fill += BP_GET_FILL(ibp);
+               }
+       }
+       DB_DNODE_EXIT(db);
+
+       if (!BP_IS_EMBEDDED(bp))
+               bp->blk_fill = fill;
+
+       mutex_exit(&db->db_mtx);
+}
+
+/*
+ * The SPA will call this callback several times for each zio - once
+ * for every physical child i/o (zio->io_phys_children times).  This
+ * allows the DMU to monitor the progress of each logical i/o.  For example,
+ * there may be 2 copies of an indirect block, or many fragments of a RAID-Z
+ * block.  There may be a long delay before all copies/fragments are completed,
+ * so this callback allows us to retire dirty space gradually, as the physical
+ * i/os complete.
+ */
+/* ARGSUSED */
+static void
+dbuf_write_physdone(zio_t *zio, arc_buf_t *buf, void *arg)
+{
+       dmu_buf_impl_t *db = arg;
+       objset_t *os = db->db_objset;
+       dsl_pool_t *dp = dmu_objset_pool(os);
+       dbuf_dirty_record_t *dr;
+       int delta = 0;
+
+       dr = db->db_data_pending;
+       ASSERT3U(dr->dr_txg, ==, zio->io_txg);
+
+       /*
+        * The callback will be called io_phys_children times.  Retire one
+        * portion of our dirty space each time we are called.  Any rounding
+        * error will be cleaned up by dsl_pool_sync()'s call to
+        * dsl_pool_undirty_space().
+        */
+       delta = dr->dr_accounted / zio->io_phys_children;
+       dsl_pool_undirty_space(dp, delta, zio->io_txg);
+}
+
+/* ARGSUSED */
+static void
+dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
+{
+       dmu_buf_impl_t *db = vdb;
+       blkptr_t *bp_orig = &zio->io_bp_orig;
+       blkptr_t *bp = db->db_blkptr;
+       objset_t *os = db->db_objset;
+       dmu_tx_t *tx = os->os_synctx;
+       dbuf_dirty_record_t **drp, *dr;
+
+       ASSERT0(zio->io_error);
+       ASSERT(db->db_blkptr == bp);
+
+       /*
+        * For nopwrites and rewrites we ensure that the bp matches our
+        * original and bypass all the accounting.
+        */
+       if (zio->io_flags & (ZIO_FLAG_IO_REWRITE | ZIO_FLAG_NOPWRITE)) {
+               ASSERT(BP_EQUAL(bp, bp_orig));
+       } else {
+               dsl_dataset_t *ds = os->os_dsl_dataset;
+               (void) dsl_dataset_block_kill(ds, bp_orig, tx, B_TRUE);
+               dsl_dataset_block_born(ds, bp, tx);
+       }
+
+       mutex_enter(&db->db_mtx);
+
+       DBUF_VERIFY(db);
+
+       drp = &db->db_last_dirty;
+       while ((dr = *drp) != db->db_data_pending)
+               drp = &dr->dr_next;
+       ASSERT(!list_link_active(&dr->dr_dirty_node));
+       ASSERT(dr->dr_dbuf == db);
+       ASSERT(dr->dr_next == NULL);
+       *drp = dr->dr_next;
+
+#ifdef ZFS_DEBUG
+       if (db->db_blkid == DMU_SPILL_BLKID) {
+               dnode_t *dn;
+
+               DB_DNODE_ENTER(db);
+               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_DNODE_EXIT(db);
+       }
+#endif
+
+       if (db->db_level == 0) {
+               ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+               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);
+               }
+       } else {
+               dnode_t *dn;
+
+               DB_DNODE_ENTER(db);
+               dn = DB_DNODE(db);
+               ASSERT(list_head(&dr->dt.di.dr_children) == NULL);
+               ASSERT3U(db->db.db_size, ==, 1 << dn->dn_phys->dn_indblkshift);
+               if (!BP_IS_HOLE(db->db_blkptr)) {
+                       ASSERTV(int epbs = dn->dn_phys->dn_indblkshift -
+                           SPA_BLKPTRSHIFT);
+                       ASSERT3U(db->db_blkid, <=,
+                           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);
+               list_destroy(&dr->dt.di.dr_children);
+       }
+       kmem_free(dr, sizeof (dbuf_dirty_record_t));
+
+       cv_broadcast(&db->db_changed);
+       ASSERT(db->db_dirtycnt > 0);
+       db->db_dirtycnt -= 1;
+       db->db_data_pending = NULL;
+       dbuf_rele_and_unlock(db, (void *)(uintptr_t)tx->tx_txg);
+}
+
+static void
+dbuf_write_nofill_ready(zio_t *zio)
+{
+       dbuf_write_ready(zio, NULL, zio->io_private);
+}
+
+static void
+dbuf_write_nofill_done(zio_t *zio)
+{
+       dbuf_write_done(zio, NULL, zio->io_private);
+}
+
+static void
+dbuf_write_override_ready(zio_t *zio)
+{
+       dbuf_dirty_record_t *dr = zio->io_private;
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+
+       dbuf_write_ready(zio, NULL, db);
+}
+
+static void
+dbuf_write_override_done(zio_t *zio)
+{
+       dbuf_dirty_record_t *dr = zio->io_private;
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+       blkptr_t *obp = &dr->dt.dl.dr_overridden_by;
+
+       mutex_enter(&db->db_mtx);
+       if (!BP_EQUAL(zio->io_bp, obp)) {
+               if (!BP_IS_HOLE(obp))
+                       dsl_free(spa_get_dsl(zio->io_spa), zio->io_txg, obp);
+               arc_release(dr->dt.dl.dr_data, db);
+       }
+       mutex_exit(&db->db_mtx);
+
+       dbuf_write_done(zio, NULL, db);
+}
+
+/* Issue I/O to commit a dirty buffer to disk. */
+static void
+dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+       dnode_t *dn;
+       objset_t *os;
+       dmu_buf_impl_t *parent = db->db_parent;
+       uint64_t txg = tx->tx_txg;
+       zbookmark_phys_t zb;
+       zio_prop_t zp;
+       zio_t *zio;
+       int wp_flag = 0;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       os = dn->dn_objset;
+
+       if (db->db_state != DB_NOFILL) {
+               if (db->db_level > 0 || dn->dn_type == DMU_OT_DNODE) {
+                       /*
+                        * Private object buffers are released here rather
+                        * than in dbuf_dirty() since they are only modified
+                        * in the syncing context and we don't want the
+                        * overhead of making multiple copies of the data.
+                        */
+                       if (BP_IS_HOLE(db->db_blkptr)) {
+                               arc_buf_thaw(data);
+                       } else {
+                               dbuf_release_bp(db);
+                       }
+               }
+       }
+
+       if (parent != dn->dn_dbuf) {
+               /* Our parent is an indirect block. */
+               /* We have a dirty parent that has been scheduled for write. */
+               ASSERT(parent && parent->db_data_pending);
+               /* Our parent's buffer is one level closer to the dnode. */
+               ASSERT(db->db_level == parent->db_level-1);
+               /*
+                * We're about to modify our parent's db_data by modifying
+                * our block pointer, so the parent must be released.
+                */
+               ASSERT(arc_released(parent->db_buf));
+               zio = parent->db_data_pending->dr_zio;
+       } else {
+               /* Our parent is the dnode itself. */
+               ASSERT((db->db_level == dn->dn_phys->dn_nlevels-1 &&
+                   db->db_blkid != DMU_SPILL_BLKID) ||
+                   (db->db_blkid == DMU_SPILL_BLKID && db->db_level == 0));
+               if (db->db_blkid != DMU_SPILL_BLKID)
+                       ASSERT3P(db->db_blkptr, ==,
+                           &dn->dn_phys->dn_blkptr[db->db_blkid]);
+               zio = dn->dn_zio;
+       }
+
+       ASSERT(db->db_level == 0 || data == db->db_buf);
+       ASSERT3U(db->db_blkptr->blk_birth, <=, txg);
+       ASSERT(zio);
+
+       SET_BOOKMARK(&zb, os->os_dsl_dataset ?
+           os->os_dsl_dataset->ds_object : DMU_META_OBJSET,
+           db->db.db_object, db->db_level, db->db_blkid);
+
+       if (db->db_blkid == DMU_SPILL_BLKID)
+               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);
+       DB_DNODE_EXIT(db);
+
+       if (db->db_level == 0 &&
+           dr->dt.dl.dr_override_state == DR_OVERRIDDEN) {
+               /*
+                * The BP for this block has been provided by open context
+                * (by dmu_sync() or dmu_buf_write_embedded()).
+                */
+               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, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
+               mutex_enter(&db->db_mtx);
+               dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
+               zio_write_override(dr->dr_zio, &dr->dt.dl.dr_overridden_by,
+                   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);
+               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,
+                   ZIO_PRIORITY_ASYNC_WRITE,
+                   ZIO_FLAG_MUSTSUCCEED | ZIO_FLAG_NODATA, &zb);
+       } else {
+               ASSERT(arc_released(data));
+               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);
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dbuf_find);
+EXPORT_SYMBOL(dbuf_is_metadata);
+EXPORT_SYMBOL(dbuf_evict);
+EXPORT_SYMBOL(dbuf_loan_arcbuf);
+EXPORT_SYMBOL(dbuf_whichblock);
+EXPORT_SYMBOL(dbuf_read);
+EXPORT_SYMBOL(dbuf_unoverride);
+EXPORT_SYMBOL(dbuf_free_range);
+EXPORT_SYMBOL(dbuf_new_size);
+EXPORT_SYMBOL(dbuf_release_bp);
+EXPORT_SYMBOL(dbuf_dirty);
+EXPORT_SYMBOL(dmu_buf_will_dirty);
+EXPORT_SYMBOL(dmu_buf_will_not_fill);
+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);
+EXPORT_SYMBOL(dbuf_hold_level);
+EXPORT_SYMBOL(dbuf_create_bonus);
+EXPORT_SYMBOL(dbuf_spill_set_blksz);
+EXPORT_SYMBOL(dbuf_rm_spill);
+EXPORT_SYMBOL(dbuf_add_ref);
+EXPORT_SYMBOL(dbuf_rele);
+EXPORT_SYMBOL(dbuf_rele_and_unlock);
+EXPORT_SYMBOL(dbuf_refcount);
+EXPORT_SYMBOL(dbuf_sync_list);
+EXPORT_SYMBOL(dmu_buf_set_user);
+EXPORT_SYMBOL(dmu_buf_set_user_ie);
+EXPORT_SYMBOL(dmu_buf_get_user);
+EXPORT_SYMBOL(dmu_buf_freeable);
+EXPORT_SYMBOL(dmu_buf_get_blkptr);
+#endif
diff --git a/zfs/module/zfs/dbuf_stats.c b/zfs/module/zfs/dbuf_stats.c
new file mode 100644 (file)
index 0000000..6f39f80
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this 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/zfs_context.h>
+#include <sys/dbuf.h>
+#include <sys/dmu_objset.h>
+
+/*
+ * Calculate the index of the arc header for the state, disabled by default.
+ */
+int zfs_dbuf_state_index = 0;
+
+/*
+ * ==========================================================================
+ * Dbuf Hash Read Routines
+ * ==========================================================================
+ */
+typedef struct dbuf_stats_t {
+       kmutex_t                lock;
+       kstat_t                 *kstat;
+       dbuf_hash_table_t       *hash;
+       int                     idx;
+} dbuf_stats_t;
+
+static dbuf_stats_t dbuf_stats_hash_table;
+
+static int
+dbuf_stats_hash_table_headers(char *buf, size_t size)
+{
+       (void) snprintf(buf, size,
+           "%-88s | %-124s | %s\n"
+           "%-16s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-5s %5s | "
+           "%-5s %-5s %-8s %-6s %-8s %-12s "
+           "%-6s %-6s %-6s %-6s %-6s %-8s %-8s %-8s %-5s | "
+           "%-6s %-6s %-8s %-8s %-6s %-6s %-5s %-8s %-8s\n",
+           "dbuf", "arcbuf", "dnode", "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");
+
+       return (0);
+}
+
+int
+__dbuf_stats_hash_table_data(char *buf, size_t size, dmu_buf_impl_t *db)
+{
+       arc_buf_info_t abi = { 0 };
+       dmu_object_info_t doi = { 0 };
+       dnode_t *dn = DB_DNODE(db);
+       size_t nwritten;
+
+       if (db->db_buf)
+               arc_buf_info(db->db_buf, &abi, zfs_dbuf_state_index);
+
+       if (dn)
+               __dmu_object_info_from_dnode(dn, &doi);
+
+       nwritten = snprintf(buf, size,
+           "%-16s %-8llu %-8lld %-8lld %-8lld %-8llu %-8llu %-5d %-5d %-5lu | "
+           "%-5d %-5d 0x%-6x %-6lu %-8llu %-12llu "
+           "%-6lu %-6lu %-6lu %-6lu %-6lu %-8llu %-8llu %-8d %-5lu | "
+           "%-6d %-6d %-8lu %-8lu %-6llu %-6lu %-5lu %-8llu %-8llu\n",
+           /* dmu_buf_impl_t */
+           spa_name(dn->dn_objset->os_spa),
+           (u_longlong_t)dmu_objset_id(db->db_objset),
+           (longlong_t)db->db.db_object,
+           (longlong_t)db->db_level,
+           (longlong_t)db->db_blkid,
+           (u_longlong_t)db->db.db_offset,
+           (u_longlong_t)db->db.db_size,
+           !!dbuf_is_metadata(db),
+           db->db_state,
+           (ulong_t)refcount_count(&db->db_holds),
+           /* arc_buf_info_t */
+           abi.abi_state_type,
+           abi.abi_state_contents,
+           abi.abi_flags,
+           (ulong_t)abi.abi_datacnt,
+           (u_longlong_t)abi.abi_size,
+           (u_longlong_t)abi.abi_access,
+           (ulong_t)abi.abi_mru_hits,
+           (ulong_t)abi.abi_mru_ghost_hits,
+           (ulong_t)abi.abi_mfu_hits,
+           (ulong_t)abi.abi_mfu_ghost_hits,
+           (ulong_t)abi.abi_l2arc_hits,
+           (u_longlong_t)abi.abi_l2arc_dattr,
+           (u_longlong_t)abi.abi_l2arc_asize,
+           abi.abi_l2arc_compress,
+           (ulong_t)abi.abi_holds,
+           /* dmu_object_info_t */
+           doi.doi_type,
+           doi.doi_bonus_type,
+           (ulong_t)doi.doi_data_block_size,
+           (ulong_t)doi.doi_metadata_block_size,
+           (u_longlong_t)doi.doi_bonus_size,
+           (ulong_t)doi.doi_indirection,
+           (ulong_t)refcount_count(&dn->dn_holds),
+           (u_longlong_t)doi.doi_fill_count,
+           (u_longlong_t)doi.doi_max_offset);
+
+       if (nwritten >= size)
+               return (size);
+
+       return (nwritten + 1);
+}
+
+static int
+dbuf_stats_hash_table_data(char *buf, size_t size, void *data)
+{
+       dbuf_stats_t *dsh = (dbuf_stats_t *)data;
+       dbuf_hash_table_t *h = dsh->hash;
+       dmu_buf_impl_t *db;
+       int length, error = 0;
+
+       ASSERT3S(dsh->idx, >=, 0);
+       ASSERT3S(dsh->idx, <=, h->hash_table_mask);
+       memset(buf, 0, size);
+
+       mutex_enter(DBUF_HASH_MUTEX(h, dsh->idx));
+       for (db = h->hash_table[dsh->idx]; db != NULL; db = db->db_hash_next) {
+               /*
+                * Returning ENOMEM will cause the data and header functions
+                * to be called with a larger scratch buffers.
+                */
+               if (size < 512) {
+                       error = ENOMEM;
+                       break;
+               }
+
+               mutex_enter(&db->db_mtx);
+
+               if (db->db_state != DB_EVICTING) {
+                       length = __dbuf_stats_hash_table_data(buf, size, db);
+                       buf += length;
+                       size -= length;
+               }
+
+               mutex_exit(&db->db_mtx);
+       }
+       mutex_exit(DBUF_HASH_MUTEX(h, dsh->idx));
+
+       return (error);
+}
+
+static void *
+dbuf_stats_hash_table_addr(kstat_t *ksp, loff_t n)
+{
+       dbuf_stats_t *dsh = ksp->ks_private;
+
+       ASSERT(MUTEX_HELD(&dsh->lock));
+
+       if (n <= dsh->hash->hash_table_mask) {
+               dsh->idx = n;
+               return (dsh);
+       }
+
+       return (NULL);
+}
+
+static void
+dbuf_stats_hash_table_init(dbuf_hash_table_t *hash)
+{
+       dbuf_stats_t *dsh = &dbuf_stats_hash_table;
+       kstat_t *ksp;
+
+       mutex_init(&dsh->lock, NULL, MUTEX_DEFAULT, NULL);
+       dsh->hash = hash;
+
+       ksp = kstat_create("zfs", 0, "dbufs", "misc",
+           KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+       dsh->kstat = ksp;
+
+       if (ksp) {
+               ksp->ks_lock = &dsh->lock;
+               ksp->ks_ndata = UINT32_MAX;
+               ksp->ks_private = dsh;
+               kstat_set_raw_ops(ksp, dbuf_stats_hash_table_headers,
+                   dbuf_stats_hash_table_data, dbuf_stats_hash_table_addr);
+               kstat_install(ksp);
+       }
+}
+
+static void
+dbuf_stats_hash_table_destroy(void)
+{
+       dbuf_stats_t *dsh = &dbuf_stats_hash_table;
+       kstat_t *ksp;
+
+       ksp = dsh->kstat;
+       if (ksp)
+               kstat_delete(ksp);
+
+       mutex_destroy(&dsh->lock);
+}
+
+void
+dbuf_stats_init(dbuf_hash_table_t *hash)
+{
+       dbuf_stats_hash_table_init(hash);
+}
+
+void
+dbuf_stats_destroy(void)
+{
+       dbuf_stats_hash_table_destroy();
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_dbuf_state_index, int, 0644);
+MODULE_PARM_DESC(zfs_dbuf_state_index, "Calculate arc header index");
+#endif
diff --git a/zfs/module/zfs/ddt.c b/zfs/module/zfs/ddt.c
new file mode 100644 (file)
index 0000000..12c1b73
--- /dev/null
@@ -0,0 +1,1235 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/zio.h>
+#include <sys/ddt.h>
+#include <sys/zap.h>
+#include <sys/dmu_tx.h>
+#include <sys/arc.h>
+#include <sys/dsl_pool.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/dsl_scan.h>
+
+static kmem_cache_t *ddt_cache;
+static kmem_cache_t *ddt_entry_cache;
+
+/*
+ * Enable/disable prefetching of dedup-ed blocks which are going to be freed.
+ */
+int zfs_dedup_prefetch = 0;
+
+static const ddt_ops_t *ddt_ops[DDT_TYPES] = {
+       &ddt_zap_ops,
+};
+
+static const char *ddt_class_name[DDT_CLASSES] = {
+       "ditto",
+       "duplicate",
+       "unique",
+};
+
+static void
+ddt_object_create(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    dmu_tx_t *tx)
+{
+       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;
+       char name[DDT_NAMELEN];
+
+       ddt_object_name(ddt, type, class, name);
+
+       ASSERT(*objectp == 0);
+       VERIFY(ddt_ops[type]->ddt_op_create(os, objectp, tx, prehash) == 0);
+       ASSERT(*objectp != 0);
+
+       VERIFY(zap_add(os, DMU_POOL_DIRECTORY_OBJECT, name,
+           sizeof (uint64_t), 1, objectp, tx) == 0);
+
+       VERIFY(zap_add(os, spa->spa_ddt_stat_object, name,
+           sizeof (uint64_t), sizeof (ddt_histogram_t) / sizeof (uint64_t),
+           &ddt->ddt_histogram[type][class], tx) == 0);
+}
+
+static void
+ddt_object_destroy(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    dmu_tx_t *tx)
+{
+       spa_t *spa = ddt->ddt_spa;
+       objset_t *os = ddt->ddt_os;
+       uint64_t *objectp = &ddt->ddt_object[type][class];
+       uint64_t count;
+       char name[DDT_NAMELEN];
+
+       ddt_object_name(ddt, type, class, name);
+
+       ASSERT(*objectp != 0);
+       ASSERT(ddt_histogram_empty(&ddt->ddt_histogram[type][class]));
+       VERIFY(ddt_object_count(ddt, type, class, &count) == 0 && count == 0);
+       VERIFY(zap_remove(os, DMU_POOL_DIRECTORY_OBJECT, name, tx) == 0);
+       VERIFY(zap_remove(os, spa->spa_ddt_stat_object, name, tx) == 0);
+       VERIFY(ddt_ops[type]->ddt_op_destroy(os, *objectp, tx) == 0);
+       bzero(&ddt->ddt_object_stats[type][class], sizeof (ddt_object_t));
+
+       *objectp = 0;
+}
+
+static int
+ddt_object_load(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
+{
+       ddt_object_t *ddo = &ddt->ddt_object_stats[type][class];
+       dmu_object_info_t doi;
+       uint64_t count;
+       char name[DDT_NAMELEN];
+       int error;
+
+       ddt_object_name(ddt, type, class, name);
+
+       error = zap_lookup(ddt->ddt_os, DMU_POOL_DIRECTORY_OBJECT, name,
+           sizeof (uint64_t), 1, &ddt->ddt_object[type][class]);
+       if (error != 0)
+               return (error);
+
+       error = zap_lookup(ddt->ddt_os, ddt->ddt_spa->spa_ddt_stat_object, name,
+           sizeof (uint64_t), sizeof (ddt_histogram_t) / sizeof (uint64_t),
+           &ddt->ddt_histogram[type][class]);
+       if (error != 0)
+               return (error);
+
+       /*
+        * Seed the cached statistics.
+        */
+       error = ddt_object_info(ddt, type, class, &doi);
+       if (error)
+               return (error);
+
+       error = ddt_object_count(ddt, type, class, &count);
+       if (error)
+               return (error);
+
+       ddo->ddo_count = count;
+       ddo->ddo_dspace = doi.doi_physical_blocks_512 << 9;
+       ddo->ddo_mspace = doi.doi_fill_count * doi.doi_data_block_size;
+
+       return (0);
+}
+
+static void
+ddt_object_sync(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    dmu_tx_t *tx)
+{
+       ddt_object_t *ddo = &ddt->ddt_object_stats[type][class];
+       dmu_object_info_t doi;
+       uint64_t count;
+       char name[DDT_NAMELEN];
+
+       ddt_object_name(ddt, type, class, name);
+
+       VERIFY(zap_update(ddt->ddt_os, ddt->ddt_spa->spa_ddt_stat_object, name,
+           sizeof (uint64_t), sizeof (ddt_histogram_t) / sizeof (uint64_t),
+           &ddt->ddt_histogram[type][class], tx) == 0);
+
+       /*
+        * Cache DDT statistics; this is the only time they'll change.
+        */
+       VERIFY(ddt_object_info(ddt, type, class, &doi) == 0);
+       VERIFY(ddt_object_count(ddt, type, class, &count) == 0);
+
+       ddo->ddo_count = count;
+       ddo->ddo_dspace = doi.doi_physical_blocks_512 << 9;
+       ddo->ddo_mspace = doi.doi_fill_count * doi.doi_data_block_size;
+}
+
+static int
+ddt_object_lookup(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    ddt_entry_t *dde)
+{
+       if (!ddt_object_exists(ddt, type, class))
+               return (SET_ERROR(ENOENT));
+
+       return (ddt_ops[type]->ddt_op_lookup(ddt->ddt_os,
+           ddt->ddt_object[type][class], dde));
+}
+
+static void
+ddt_object_prefetch(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    ddt_entry_t *dde)
+{
+       if (!ddt_object_exists(ddt, type, class))
+               return;
+
+       ddt_ops[type]->ddt_op_prefetch(ddt->ddt_os,
+           ddt->ddt_object[type][class], dde);
+}
+
+int
+ddt_object_update(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    ddt_entry_t *dde, dmu_tx_t *tx)
+{
+       ASSERT(ddt_object_exists(ddt, type, class));
+
+       return (ddt_ops[type]->ddt_op_update(ddt->ddt_os,
+           ddt->ddt_object[type][class], dde, tx));
+}
+
+static int
+ddt_object_remove(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    ddt_entry_t *dde, dmu_tx_t *tx)
+{
+       ASSERT(ddt_object_exists(ddt, type, class));
+
+       return (ddt_ops[type]->ddt_op_remove(ddt->ddt_os,
+           ddt->ddt_object[type][class], dde, tx));
+}
+
+int
+ddt_object_walk(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    uint64_t *walk, ddt_entry_t *dde)
+{
+       ASSERT(ddt_object_exists(ddt, type, class));
+
+       return (ddt_ops[type]->ddt_op_walk(ddt->ddt_os,
+           ddt->ddt_object[type][class], dde, walk));
+}
+
+int
+ddt_object_count(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    uint64_t *count)
+{
+       ASSERT(ddt_object_exists(ddt, type, class));
+
+       return (ddt_ops[type]->ddt_op_count(ddt->ddt_os,
+           ddt->ddt_object[type][class], count));
+}
+
+int
+ddt_object_info(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    dmu_object_info_t *doi)
+{
+       if (!ddt_object_exists(ddt, type, class))
+               return (SET_ERROR(ENOENT));
+
+       return (dmu_object_info(ddt->ddt_os, ddt->ddt_object[type][class],
+           doi));
+}
+
+boolean_t
+ddt_object_exists(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
+{
+       return (!!ddt->ddt_object[type][class]);
+}
+
+void
+ddt_object_name(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
+    char *name)
+{
+       (void) sprintf(name, DMU_POOL_DDT,
+           zio_checksum_table[ddt->ddt_checksum].ci_name,
+           ddt_ops[type]->ddt_op_name, ddt_class_name[class]);
+}
+
+void
+ddt_bp_fill(const ddt_phys_t *ddp, blkptr_t *bp, uint64_t txg)
+{
+       int d;
+       ASSERT(txg != 0);
+
+       for (d = 0; d < SPA_DVAS_PER_BP; d++)
+               bp->blk_dva[d] = ddp->ddp_dva[d];
+       BP_SET_BIRTH(bp, txg, ddp->ddp_phys_birth);
+}
+
+void
+ddt_bp_create(enum zio_checksum checksum,
+    const ddt_key_t *ddk, const ddt_phys_t *ddp, blkptr_t *bp)
+{
+       BP_ZERO(bp);
+
+       if (ddp != NULL)
+               ddt_bp_fill(ddp, bp, ddp->ddp_phys_birth);
+
+       bp->blk_cksum = ddk->ddk_cksum;
+       bp->blk_fill = 1;
+
+       BP_SET_LSIZE(bp, DDK_GET_LSIZE(ddk));
+       BP_SET_PSIZE(bp, DDK_GET_PSIZE(ddk));
+       BP_SET_COMPRESS(bp, DDK_GET_COMPRESS(ddk));
+       BP_SET_CHECKSUM(bp, checksum);
+       BP_SET_TYPE(bp, DMU_OT_DEDUP);
+       BP_SET_LEVEL(bp, 0);
+       BP_SET_DEDUP(bp, 0);
+       BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
+}
+
+void
+ddt_key_fill(ddt_key_t *ddk, const blkptr_t *bp)
+{
+       ddk->ddk_cksum = bp->blk_cksum;
+       ddk->ddk_prop = 0;
+
+       DDK_SET_LSIZE(ddk, BP_GET_LSIZE(bp));
+       DDK_SET_PSIZE(ddk, BP_GET_PSIZE(bp));
+       DDK_SET_COMPRESS(ddk, BP_GET_COMPRESS(bp));
+}
+
+void
+ddt_phys_fill(ddt_phys_t *ddp, const blkptr_t *bp)
+{
+       int d;
+       ASSERT(ddp->ddp_phys_birth == 0);
+
+       for (d = 0; d < SPA_DVAS_PER_BP; d++)
+               ddp->ddp_dva[d] = bp->blk_dva[d];
+       ddp->ddp_phys_birth = BP_PHYSICAL_BIRTH(bp);
+}
+
+void
+ddt_phys_clear(ddt_phys_t *ddp)
+{
+       bzero(ddp, sizeof (*ddp));
+}
+
+void
+ddt_phys_addref(ddt_phys_t *ddp)
+{
+       ddp->ddp_refcnt++;
+}
+
+void
+ddt_phys_decref(ddt_phys_t *ddp)
+{
+       if (ddp) {
+               ASSERT(ddp->ddp_refcnt > 0);
+               ddp->ddp_refcnt--;
+       }
+}
+
+void
+ddt_phys_free(ddt_t *ddt, ddt_key_t *ddk, ddt_phys_t *ddp, uint64_t txg)
+{
+       blkptr_t blk;
+
+       ddt_bp_create(ddt->ddt_checksum, ddk, ddp, &blk);
+       ddt_phys_clear(ddp);
+       zio_free(ddt->ddt_spa, txg, &blk);
+}
+
+ddt_phys_t *
+ddt_phys_select(const ddt_entry_t *dde, const blkptr_t *bp)
+{
+       ddt_phys_t *ddp = (ddt_phys_t *)dde->dde_phys;
+       int p;
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+               if (DVA_EQUAL(BP_IDENTITY(bp), &ddp->ddp_dva[0]) &&
+                   BP_PHYSICAL_BIRTH(bp) == ddp->ddp_phys_birth)
+                       return (ddp);
+       }
+       return (NULL);
+}
+
+uint64_t
+ddt_phys_total_refcnt(const ddt_entry_t *dde)
+{
+       uint64_t refcnt = 0;
+       int p;
+
+       for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++)
+               refcnt += dde->dde_phys[p].ddp_refcnt;
+
+       return (refcnt);
+}
+
+static void
+ddt_stat_generate(ddt_t *ddt, ddt_entry_t *dde, ddt_stat_t *dds)
+{
+       spa_t *spa = ddt->ddt_spa;
+       ddt_phys_t *ddp = dde->dde_phys;
+       ddt_key_t *ddk = &dde->dde_key;
+       uint64_t lsize = DDK_GET_LSIZE(ddk);
+       uint64_t psize = DDK_GET_PSIZE(ddk);
+       int p, d;
+
+       bzero(dds, sizeof (*dds));
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+               uint64_t dsize = 0;
+               uint64_t refcnt = ddp->ddp_refcnt;
+
+               if (ddp->ddp_phys_birth == 0)
+                       continue;
+
+               for (d = 0; d < SPA_DVAS_PER_BP; d++)
+                       dsize += dva_get_dsize_sync(spa, &ddp->ddp_dva[d]);
+
+               dds->dds_blocks += 1;
+               dds->dds_lsize += lsize;
+               dds->dds_psize += psize;
+               dds->dds_dsize += dsize;
+
+               dds->dds_ref_blocks += refcnt;
+               dds->dds_ref_lsize += lsize * refcnt;
+               dds->dds_ref_psize += psize * refcnt;
+               dds->dds_ref_dsize += dsize * refcnt;
+       }
+}
+
+void
+ddt_stat_add(ddt_stat_t *dst, const ddt_stat_t *src, uint64_t neg)
+{
+       const uint64_t *s = (const uint64_t *)src;
+       uint64_t *d = (uint64_t *)dst;
+       uint64_t *d_end = (uint64_t *)(dst + 1);
+
+       ASSERT(neg == 0 || neg == -1ULL);       /* add or subtract */
+
+       while (d < d_end)
+               *d++ += (*s++ ^ neg) - neg;
+}
+
+static void
+ddt_stat_update(ddt_t *ddt, ddt_entry_t *dde, uint64_t neg)
+{
+       ddt_stat_t dds;
+       ddt_histogram_t *ddh;
+       int bucket;
+
+       ddt_stat_generate(ddt, dde, &dds);
+
+       bucket = highbit64(dds.dds_ref_blocks) - 1;
+       ASSERT(bucket >= 0);
+
+       ddh = &ddt->ddt_histogram[dde->dde_type][dde->dde_class];
+
+       ddt_stat_add(&ddh->ddh_stat[bucket], &dds, neg);
+}
+
+void
+ddt_histogram_add(ddt_histogram_t *dst, const ddt_histogram_t *src)
+{
+       int h;
+
+       for (h = 0; h < 64; h++)
+               ddt_stat_add(&dst->ddh_stat[h], &src->ddh_stat[h], 0);
+}
+
+void
+ddt_histogram_stat(ddt_stat_t *dds, const ddt_histogram_t *ddh)
+{
+       int h;
+
+       bzero(dds, sizeof (*dds));
+
+       for (h = 0; h < 64; h++)
+               ddt_stat_add(dds, &ddh->ddh_stat[h], 0);
+}
+
+boolean_t
+ddt_histogram_empty(const ddt_histogram_t *ddh)
+{
+       const uint64_t *s = (const uint64_t *)ddh;
+       const uint64_t *s_end = (const uint64_t *)(ddh + 1);
+
+       while (s < s_end)
+               if (*s++ != 0)
+                       return (B_FALSE);
+
+       return (B_TRUE);
+}
+
+void
+ddt_get_dedup_object_stats(spa_t *spa, ddt_object_t *ddo_total)
+{
+       enum zio_checksum c;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       /* Sum the statistics we cached in ddt_object_sync(). */
+       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++) {
+                               ddt_object_t *ddo =
+                                   &ddt->ddt_object_stats[type][class];
+                               ddo_total->ddo_count += ddo->ddo_count;
+                               ddo_total->ddo_dspace += ddo->ddo_dspace;
+                               ddo_total->ddo_mspace += ddo->ddo_mspace;
+                       }
+               }
+       }
+
+       /* ... and compute the averages. */
+       if (ddo_total->ddo_count != 0) {
+               ddo_total->ddo_dspace /= ddo_total->ddo_count;
+               ddo_total->ddo_mspace /= ddo_total->ddo_count;
+       }
+}
+
+void
+ddt_get_dedup_histogram(spa_t *spa, ddt_histogram_t *ddh)
+{
+       enum zio_checksum c;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       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++) {
+                               ddt_histogram_add(ddh,
+                                   &ddt->ddt_histogram_cache[type][class]);
+                       }
+               }
+       }
+}
+
+void
+ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total)
+{
+       ddt_histogram_t *ddh_total;
+
+       ddh_total = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
+       ddt_get_dedup_histogram(spa, ddh_total);
+       ddt_histogram_stat(dds_total, ddh_total);
+       kmem_free(ddh_total, sizeof (ddt_histogram_t));
+}
+
+uint64_t
+ddt_get_dedup_dspace(spa_t *spa)
+{
+       ddt_stat_t dds_total = { 0 };
+
+       ddt_get_dedup_stats(spa, &dds_total);
+       return (dds_total.dds_ref_dsize - dds_total.dds_dsize);
+}
+
+uint64_t
+ddt_get_pool_dedup_ratio(spa_t *spa)
+{
+       ddt_stat_t dds_total = { 0 };
+
+       ddt_get_dedup_stats(spa, &dds_total);
+       if (dds_total.dds_dsize == 0)
+               return (100);
+
+       return (dds_total.dds_ref_dsize * 100 / dds_total.dds_dsize);
+}
+
+int
+ddt_ditto_copies_needed(ddt_t *ddt, ddt_entry_t *dde, ddt_phys_t *ddp_willref)
+{
+       spa_t *spa = ddt->ddt_spa;
+       uint64_t total_refcnt = 0;
+       uint64_t ditto = spa->spa_dedup_ditto;
+       int total_copies = 0;
+       int desired_copies = 0;
+       int p;
+
+       for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
+               ddt_phys_t *ddp = &dde->dde_phys[p];
+               zio_t *zio = dde->dde_lead_zio[p];
+               uint64_t refcnt = ddp->ddp_refcnt;      /* committed refs */
+               if (zio != NULL)
+                       refcnt += zio->io_parent_count; /* pending refs */
+               if (ddp == ddp_willref)
+                       refcnt++;                       /* caller's ref */
+               if (refcnt != 0) {
+                       total_refcnt += refcnt;
+                       total_copies += p;
+               }
+       }
+
+       if (ditto == 0 || ditto > UINT32_MAX)
+               ditto = UINT32_MAX;
+
+       if (total_refcnt >= 1)
+               desired_copies++;
+       if (total_refcnt >= ditto)
+               desired_copies++;
+       if (total_refcnt >= ditto * ditto)
+               desired_copies++;
+
+       return (MAX(desired_copies, total_copies) - total_copies);
+}
+
+int
+ddt_ditto_copies_present(ddt_entry_t *dde)
+{
+       ddt_phys_t *ddp = &dde->dde_phys[DDT_PHYS_DITTO];
+       dva_t *dva = ddp->ddp_dva;
+       int copies = 0 - DVA_GET_GANG(dva);
+       int d;
+
+       for (d = 0; d < SPA_DVAS_PER_BP; d++, dva++)
+               if (DVA_IS_VALID(dva))
+                       copies++;
+
+       ASSERT(copies >= 0 && copies < SPA_DVAS_PER_BP);
+
+       return (copies);
+}
+
+size_t
+ddt_compress(void *src, uchar_t *dst, size_t s_len, size_t d_len)
+{
+       uchar_t *version = dst++;
+       int cpfunc = ZIO_COMPRESS_ZLE;
+       zio_compress_info_t *ci = &zio_compress_table[cpfunc];
+       size_t c_len;
+
+       ASSERT(d_len >= s_len + 1);     /* no compression plus version byte */
+
+       c_len = ci->ci_compress(src, dst, s_len, d_len - 1, ci->ci_level);
+
+       if (c_len == s_len) {
+               cpfunc = ZIO_COMPRESS_OFF;
+               bcopy(src, dst, s_len);
+       }
+
+       *version = cpfunc;
+       /* CONSTCOND */
+       if (ZFS_HOST_BYTEORDER)
+               *version |= DDT_COMPRESS_BYTEORDER_MASK;
+
+       return (c_len + 1);
+}
+
+void
+ddt_decompress(uchar_t *src, void *dst, size_t s_len, size_t d_len)
+{
+       uchar_t version = *src++;
+       int cpfunc = version & DDT_COMPRESS_FUNCTION_MASK;
+       zio_compress_info_t *ci = &zio_compress_table[cpfunc];
+
+       if (ci->ci_decompress != NULL)
+               (void) ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level);
+       else
+               bcopy(src, dst, d_len);
+
+       if (((version & DDT_COMPRESS_BYTEORDER_MASK) != 0) !=
+           (ZFS_HOST_BYTEORDER != 0))
+               byteswap_uint64_array(dst, d_len);
+}
+
+ddt_t *
+ddt_select_by_checksum(spa_t *spa, enum zio_checksum c)
+{
+       return (spa->spa_ddt[c]);
+}
+
+ddt_t *
+ddt_select(spa_t *spa, const blkptr_t *bp)
+{
+       return (spa->spa_ddt[BP_GET_CHECKSUM(bp)]);
+}
+
+void
+ddt_enter(ddt_t *ddt)
+{
+       mutex_enter(&ddt->ddt_lock);
+}
+
+void
+ddt_exit(ddt_t *ddt)
+{
+       mutex_exit(&ddt->ddt_lock);
+}
+
+void
+ddt_init(void)
+{
+       ddt_cache = kmem_cache_create("ddt_cache",
+           sizeof (ddt_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+       ddt_entry_cache = kmem_cache_create("ddt_entry_cache",
+           sizeof (ddt_entry_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+void
+ddt_fini(void)
+{
+       kmem_cache_destroy(ddt_entry_cache);
+       kmem_cache_destroy(ddt_cache);
+}
+
+static ddt_entry_t *
+ddt_alloc(const ddt_key_t *ddk)
+{
+       ddt_entry_t *dde;
+
+       dde = kmem_cache_alloc(ddt_entry_cache, KM_SLEEP);
+       bzero(dde, sizeof (ddt_entry_t));
+       cv_init(&dde->dde_cv, NULL, CV_DEFAULT, NULL);
+
+       dde->dde_key = *ddk;
+
+       return (dde);
+}
+
+static void
+ddt_free(ddt_entry_t *dde)
+{
+       int p;
+
+       ASSERT(!dde->dde_loading);
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++)
+               ASSERT(dde->dde_lead_zio[p] == NULL);
+
+       if (dde->dde_repair_data != NULL)
+               zio_buf_free(dde->dde_repair_data,
+                   DDK_GET_PSIZE(&dde->dde_key));
+
+       cv_destroy(&dde->dde_cv);
+       kmem_cache_free(ddt_entry_cache, dde);
+}
+
+void
+ddt_remove(ddt_t *ddt, ddt_entry_t *dde)
+{
+       ASSERT(MUTEX_HELD(&ddt->ddt_lock));
+
+       avl_remove(&ddt->ddt_tree, dde);
+       ddt_free(dde);
+}
+
+ddt_entry_t *
+ddt_lookup(ddt_t *ddt, const blkptr_t *bp, boolean_t add)
+{
+       ddt_entry_t *dde, dde_search;
+       enum ddt_type type;
+       enum ddt_class class;
+       avl_index_t where;
+       int error;
+
+       ASSERT(MUTEX_HELD(&ddt->ddt_lock));
+
+       ddt_key_fill(&dde_search.dde_key, bp);
+
+       dde = avl_find(&ddt->ddt_tree, &dde_search, &where);
+       if (dde == NULL) {
+               if (!add)
+                       return (NULL);
+               dde = ddt_alloc(&dde_search.dde_key);
+               avl_insert(&ddt->ddt_tree, dde, where);
+       }
+
+       while (dde->dde_loading)
+               cv_wait(&dde->dde_cv, &ddt->ddt_lock);
+
+       if (dde->dde_loaded)
+               return (dde);
+
+       dde->dde_loading = B_TRUE;
+
+       ddt_exit(ddt);
+
+       error = ENOENT;
+
+       for (type = 0; type < DDT_TYPES; type++) {
+               for (class = 0; class < DDT_CLASSES; class++) {
+                       error = ddt_object_lookup(ddt, type, class, dde);
+                       if (error != ENOENT)
+                               break;
+               }
+               if (error != ENOENT)
+                       break;
+       }
+
+       ASSERT(error == 0 || error == ENOENT);
+
+       ddt_enter(ddt);
+
+       ASSERT(dde->dde_loaded == B_FALSE);
+       ASSERT(dde->dde_loading == B_TRUE);
+
+       dde->dde_type = type;   /* will be DDT_TYPES if no entry found */
+       dde->dde_class = class; /* will be DDT_CLASSES if no entry found */
+       dde->dde_loaded = B_TRUE;
+       dde->dde_loading = B_FALSE;
+
+       if (error == 0)
+               ddt_stat_update(ddt, dde, -1ULL);
+
+       cv_broadcast(&dde->dde_cv);
+
+       return (dde);
+}
+
+void
+ddt_prefetch(spa_t *spa, const blkptr_t *bp)
+{
+       ddt_t *ddt;
+       ddt_entry_t dde;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       if (!zfs_dedup_prefetch || bp == NULL || !BP_GET_DEDUP(bp))
+               return;
+
+       /*
+        * We only remove the DDT once all tables are empty and only
+        * prefetch dedup blocks when there are entries in the DDT.
+        * Thus no locking is required as the DDT can't disappear on us.
+        */
+       ddt = ddt_select(spa, bp);
+       ddt_key_fill(&dde.dde_key, bp);
+
+       for (type = 0; type < DDT_TYPES; type++) {
+               for (class = 0; class < DDT_CLASSES; class++) {
+                       ddt_object_prefetch(ddt, type, class, &dde);
+               }
+       }
+}
+
+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;
+       int i;
+
+       for (i = 0; i < DDT_KEY_WORDS; i++) {
+               if (u1[i] < u2[i])
+                       return (-1);
+               if (u1[i] > u2[i])
+                       return (1);
+       }
+
+       return (0);
+}
+
+static ddt_t *
+ddt_table_alloc(spa_t *spa, enum zio_checksum c)
+{
+       ddt_t *ddt;
+
+       ddt = kmem_cache_alloc(ddt_cache, KM_SLEEP);
+       bzero(ddt, sizeof (ddt_t));
+
+       mutex_init(&ddt->ddt_lock, NULL, MUTEX_DEFAULT, NULL);
+       avl_create(&ddt->ddt_tree, ddt_entry_compare,
+           sizeof (ddt_entry_t), offsetof(ddt_entry_t, dde_node));
+       avl_create(&ddt->ddt_repair_tree, ddt_entry_compare,
+           sizeof (ddt_entry_t), offsetof(ddt_entry_t, dde_node));
+       ddt->ddt_checksum = c;
+       ddt->ddt_spa = spa;
+       ddt->ddt_os = spa->spa_meta_objset;
+
+       return (ddt);
+}
+
+static void
+ddt_table_free(ddt_t *ddt)
+{
+       ASSERT(avl_numnodes(&ddt->ddt_tree) == 0);
+       ASSERT(avl_numnodes(&ddt->ddt_repair_tree) == 0);
+       avl_destroy(&ddt->ddt_tree);
+       avl_destroy(&ddt->ddt_repair_tree);
+       mutex_destroy(&ddt->ddt_lock);
+       kmem_cache_free(ddt_cache, ddt);
+}
+
+void
+ddt_create(spa_t *spa)
+{
+       enum zio_checksum c;
+
+       spa->spa_dedup_checksum = ZIO_DEDUPCHECKSUM;
+
+       for (c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++)
+               spa->spa_ddt[c] = ddt_table_alloc(spa, c);
+}
+
+int
+ddt_load(spa_t *spa)
+{
+       enum zio_checksum c;
+       enum ddt_type type;
+       enum ddt_class class;
+       int error;
+
+       ddt_create(spa);
+
+       error = zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_DDT_STATS, sizeof (uint64_t), 1,
+           &spa->spa_ddt_stat_object);
+
+       if (error)
+               return (error == ENOENT ? 0 : error);
+
+       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++) {
+                               error = ddt_object_load(ddt, type, class);
+                               if (error != 0 && error != ENOENT)
+                                       return (error);
+                       }
+               }
+
+               /*
+                * Seed the cached histograms.
+                */
+               bcopy(ddt->ddt_histogram, &ddt->ddt_histogram_cache,
+                   sizeof (ddt->ddt_histogram));
+       }
+
+       return (0);
+}
+
+void
+ddt_unload(spa_t *spa)
+{
+       enum zio_checksum c;
+
+       for (c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
+               if (spa->spa_ddt[c]) {
+                       ddt_table_free(spa->spa_ddt[c]);
+                       spa->spa_ddt[c] = NULL;
+               }
+       }
+}
+
+boolean_t
+ddt_class_contains(spa_t *spa, enum ddt_class max_class, const blkptr_t *bp)
+{
+       ddt_t *ddt;
+       ddt_entry_t *dde;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       if (!BP_GET_DEDUP(bp))
+               return (B_FALSE);
+
+       if (max_class == DDT_CLASS_UNIQUE)
+               return (B_TRUE);
+
+       ddt = spa->spa_ddt[BP_GET_CHECKSUM(bp)];
+       dde = kmem_cache_alloc(ddt_entry_cache, KM_SLEEP);
+
+       ddt_key_fill(&(dde->dde_key), bp);
+
+       for (type = 0; type < DDT_TYPES; type++) {
+               for (class = 0; class <= max_class; class++) {
+                       if (ddt_object_lookup(ddt, type, class, dde) == 0) {
+                               kmem_cache_free(ddt_entry_cache, dde);
+                               return (B_TRUE);
+                       }
+               }
+       }
+
+       kmem_cache_free(ddt_entry_cache, dde);
+       return (B_FALSE);
+}
+
+ddt_entry_t *
+ddt_repair_start(ddt_t *ddt, const blkptr_t *bp)
+{
+       ddt_key_t ddk;
+       ddt_entry_t *dde;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       ddt_key_fill(&ddk, bp);
+
+       dde = ddt_alloc(&ddk);
+
+       for (type = 0; type < DDT_TYPES; type++) {
+               for (class = 0; class < DDT_CLASSES; class++) {
+                       /*
+                        * We can only do repair if there are multiple copies
+                        * of the block.  For anything in the UNIQUE class,
+                        * there's definitely only one copy, so don't even try.
+                        */
+                       if (class != DDT_CLASS_UNIQUE &&
+                           ddt_object_lookup(ddt, type, class, dde) == 0)
+                               return (dde);
+               }
+       }
+
+       bzero(dde->dde_phys, sizeof (dde->dde_phys));
+
+       return (dde);
+}
+
+void
+ddt_repair_done(ddt_t *ddt, ddt_entry_t *dde)
+{
+       avl_index_t where;
+
+       ddt_enter(ddt);
+
+       if (dde->dde_repair_data != NULL && spa_writeable(ddt->ddt_spa) &&
+           avl_find(&ddt->ddt_repair_tree, dde, &where) == NULL)
+               avl_insert(&ddt->ddt_repair_tree, dde, where);
+       else
+               ddt_free(dde);
+
+       ddt_exit(ddt);
+}
+
+static void
+ddt_repair_entry_done(zio_t *zio)
+{
+       ddt_entry_t *rdde = zio->io_private;
+
+       ddt_free(rdde);
+}
+
+static void
+ddt_repair_entry(ddt_t *ddt, ddt_entry_t *dde, ddt_entry_t *rdde, zio_t *rio)
+{
+       ddt_phys_t *ddp = dde->dde_phys;
+       ddt_phys_t *rddp = rdde->dde_phys;
+       ddt_key_t *ddk = &dde->dde_key;
+       ddt_key_t *rddk = &rdde->dde_key;
+       zio_t *zio;
+       blkptr_t blk;
+       int p;
+
+       zio = zio_null(rio, rio->io_spa, NULL,
+           ddt_repair_entry_done, rdde, rio->io_flags);
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++, rddp++) {
+               if (ddp->ddp_phys_birth == 0 ||
+                   ddp->ddp_phys_birth != rddp->ddp_phys_birth ||
+                   bcmp(ddp->ddp_dva, rddp->ddp_dva, sizeof (ddp->ddp_dva)))
+                       continue;
+               ddt_bp_create(ddt->ddt_checksum, ddk, ddp, &blk);
+               zio_nowait(zio_rewrite(zio, zio->io_spa, 0, &blk,
+                   rdde->dde_repair_data, DDK_GET_PSIZE(rddk), NULL, NULL,
+                   ZIO_PRIORITY_SYNC_WRITE, ZIO_DDT_CHILD_FLAGS(zio), NULL));
+       }
+
+       zio_nowait(zio);
+}
+
+static void
+ddt_repair_table(ddt_t *ddt, zio_t *rio)
+{
+       spa_t *spa = ddt->ddt_spa;
+       ddt_entry_t *dde, *rdde_next, *rdde;
+       avl_tree_t *t = &ddt->ddt_repair_tree;
+       blkptr_t blk;
+
+       if (spa_sync_pass(spa) > 1)
+               return;
+
+       ddt_enter(ddt);
+       for (rdde = avl_first(t); rdde != NULL; rdde = rdde_next) {
+               rdde_next = AVL_NEXT(t, rdde);
+               avl_remove(&ddt->ddt_repair_tree, rdde);
+               ddt_exit(ddt);
+               ddt_bp_create(ddt->ddt_checksum, &rdde->dde_key, NULL, &blk);
+               dde = ddt_repair_start(ddt, &blk);
+               ddt_repair_entry(ddt, dde, rdde, rio);
+               ddt_repair_done(ddt, dde);
+               ddt_enter(ddt);
+       }
+       ddt_exit(ddt);
+}
+
+static void
+ddt_sync_entry(ddt_t *ddt, ddt_entry_t *dde, dmu_tx_t *tx, uint64_t txg)
+{
+       dsl_pool_t *dp = ddt->ddt_spa->spa_dsl_pool;
+       ddt_phys_t *ddp = dde->dde_phys;
+       ddt_key_t *ddk = &dde->dde_key;
+       enum ddt_type otype = dde->dde_type;
+       enum ddt_type ntype = DDT_TYPE_CURRENT;
+       enum ddt_class oclass = dde->dde_class;
+       enum ddt_class nclass;
+       uint64_t total_refcnt = 0;
+       int p;
+
+       ASSERT(dde->dde_loaded);
+       ASSERT(!dde->dde_loading);
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+               ASSERT(dde->dde_lead_zio[p] == NULL);
+               if (ddp->ddp_phys_birth == 0) {
+                       ASSERT(ddp->ddp_refcnt == 0);
+                       continue;
+               }
+               if (p == DDT_PHYS_DITTO) {
+                       if (ddt_ditto_copies_needed(ddt, dde, NULL) == 0)
+                               ddt_phys_free(ddt, ddk, ddp, txg);
+                       continue;
+               }
+               if (ddp->ddp_refcnt == 0)
+                       ddt_phys_free(ddt, ddk, ddp, txg);
+               total_refcnt += ddp->ddp_refcnt;
+       }
+
+       if (dde->dde_phys[DDT_PHYS_DITTO].ddp_phys_birth != 0)
+               nclass = DDT_CLASS_DITTO;
+       else if (total_refcnt > 1)
+               nclass = DDT_CLASS_DUPLICATE;
+       else
+               nclass = DDT_CLASS_UNIQUE;
+
+       if (otype != DDT_TYPES &&
+           (otype != ntype || oclass != nclass || total_refcnt == 0)) {
+               VERIFY(ddt_object_remove(ddt, otype, oclass, dde, tx) == 0);
+               ASSERT(ddt_object_lookup(ddt, otype, oclass, dde) == ENOENT);
+       }
+
+       if (total_refcnt != 0) {
+               dde->dde_type = ntype;
+               dde->dde_class = nclass;
+               ddt_stat_update(ddt, dde, 0);
+               if (!ddt_object_exists(ddt, ntype, nclass))
+                       ddt_object_create(ddt, ntype, nclass, tx);
+               VERIFY(ddt_object_update(ddt, ntype, nclass, dde, tx) == 0);
+
+               /*
+                * If the class changes, the order that we scan this bp
+                * changes.  If it decreases, we could miss it, so
+                * scan it right now.  (This covers both class changing
+                * while we are doing ddt_walk(), and when we are
+                * traversing.)
+                */
+               if (nclass < oclass) {
+                       dsl_scan_ddt_entry(dp->dp_scan,
+                           ddt->ddt_checksum, dde, tx);
+               }
+       }
+}
+
+static void
+ddt_sync_table(ddt_t *ddt, dmu_tx_t *tx, uint64_t txg)
+{
+       spa_t *spa = ddt->ddt_spa;
+       ddt_entry_t *dde;
+       void *cookie = NULL;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       if (avl_numnodes(&ddt->ddt_tree) == 0)
+               return;
+
+       ASSERT(spa->spa_uberblock.ub_version >= SPA_VERSION_DEDUP);
+
+       if (spa->spa_ddt_stat_object == 0) {
+               spa->spa_ddt_stat_object = zap_create_link(ddt->ddt_os,
+                   DMU_OT_DDT_STATS, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_DDT_STATS, tx);
+       }
+
+       while ((dde = avl_destroy_nodes(&ddt->ddt_tree, &cookie)) != NULL) {
+               ddt_sync_entry(ddt, dde, tx, txg);
+               ddt_free(dde);
+       }
+
+       for (type = 0; type < DDT_TYPES; type++) {
+               uint64_t add, count = 0;
+               for (class = 0; class < DDT_CLASSES; class++) {
+                       if (ddt_object_exists(ddt, type, class)) {
+                               ddt_object_sync(ddt, type, class, tx);
+                               VERIFY(ddt_object_count(ddt, type, class,
+                                   &add) == 0);
+                               count += add;
+                       }
+               }
+               for (class = 0; class < DDT_CLASSES; class++) {
+                       if (count == 0 && ddt_object_exists(ddt, type, class))
+                               ddt_object_destroy(ddt, type, class, tx);
+               }
+       }
+
+       bcopy(ddt->ddt_histogram, &ddt->ddt_histogram_cache,
+           sizeof (ddt->ddt_histogram));
+}
+
+void
+ddt_sync(spa_t *spa, uint64_t txg)
+{
+       dmu_tx_t *tx;
+       zio_t *rio = zio_root(spa, NULL, NULL,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE);
+       enum zio_checksum c;
+
+       ASSERT(spa_syncing_txg(spa) == txg);
+
+       tx = dmu_tx_create_assigned(spa->spa_dsl_pool, txg);
+
+       for (c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
+               ddt_t *ddt = spa->spa_ddt[c];
+               if (ddt == NULL)
+                       continue;
+               ddt_sync_table(ddt, tx, txg);
+               ddt_repair_table(ddt, rio);
+       }
+
+       (void) zio_wait(rio);
+
+       dmu_tx_commit(tx);
+}
+
+int
+ddt_walk(spa_t *spa, ddt_bookmark_t *ddb, ddt_entry_t *dde)
+{
+       do {
+               do {
+                       do {
+                               ddt_t *ddt = spa->spa_ddt[ddb->ddb_checksum];
+                               int error = ENOENT;
+                               if (ddt_object_exists(ddt, ddb->ddb_type,
+                                   ddb->ddb_class)) {
+                                       error = ddt_object_walk(ddt,
+                                           ddb->ddb_type, ddb->ddb_class,
+                                           &ddb->ddb_cursor, dde);
+                               }
+                               dde->dde_type = ddb->ddb_type;
+                               dde->dde_class = ddb->ddb_class;
+                               if (error == 0)
+                                       return (0);
+                               if (error != ENOENT)
+                                       return (error);
+                               ddb->ddb_cursor = 0;
+                       } while (++ddb->ddb_checksum < ZIO_CHECKSUM_FUNCTIONS);
+                       ddb->ddb_checksum = 0;
+               } while (++ddb->ddb_type < DDT_TYPES);
+               ddb->ddb_type = 0;
+       } while (++ddb->ddb_class < DDT_CLASSES);
+
+       return (SET_ERROR(ENOENT));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_dedup_prefetch, int, 0644);
+MODULE_PARM_DESC(zfs_dedup_prefetch, "Enable prefetching dedup-ed blks");
+#endif
diff --git a/zfs/module/zfs/ddt_zap.c b/zfs/module/zfs/ddt_zap.c
new file mode 100644 (file)
index 0000000..fc9cfec
--- /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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/ddt.h>
+#include <sys/zap.h>
+#include <sys/dmu_tx.h>
+#include <util/sscanf.h>
+
+int ddt_zap_leaf_blockshift = 12;
+int ddt_zap_indirect_blockshift = 12;
+
+static int
+ddt_zap_create(objset_t *os, uint64_t *objectp, dmu_tx_t *tx, boolean_t prehash)
+{
+       zap_flags_t flags = ZAP_FLAG_HASH64 | ZAP_FLAG_UINT64_KEY;
+
+       if (prehash)
+               flags |= ZAP_FLAG_PRE_HASHED_KEY;
+
+       *objectp = zap_create_flags(os, 0, flags, DMU_OT_DDT_ZAP,
+           ddt_zap_leaf_blockshift, ddt_zap_indirect_blockshift,
+           DMU_OT_NONE, 0, tx);
+
+       return (*objectp == 0 ? ENOTSUP : 0);
+}
+
+static int
+ddt_zap_destroy(objset_t *os, uint64_t object, dmu_tx_t *tx)
+{
+       return (zap_destroy(os, object, tx));
+}
+
+static int
+ddt_zap_lookup(objset_t *os, uint64_t object, ddt_entry_t *dde)
+{
+       uchar_t *cbuf;
+       uint64_t one, csize;
+       int error;
+
+       cbuf = kmem_alloc(sizeof (dde->dde_phys) + 1, KM_SLEEP);
+
+       error = zap_length_uint64(os, object, (uint64_t *)&dde->dde_key,
+           DDT_KEY_WORDS, &one, &csize);
+       if (error)
+               goto out;
+
+       ASSERT(one == 1);
+       ASSERT(csize <= (sizeof (dde->dde_phys) + 1));
+
+       error = zap_lookup_uint64(os, object, (uint64_t *)&dde->dde_key,
+           DDT_KEY_WORDS, 1, csize, cbuf);
+       if (error)
+               goto out;
+
+       ddt_decompress(cbuf, dde->dde_phys, csize, sizeof (dde->dde_phys));
+out:
+       kmem_free(cbuf, sizeof (dde->dde_phys) + 1);
+
+       return (error);
+}
+
+static void
+ddt_zap_prefetch(objset_t *os, uint64_t object, ddt_entry_t *dde)
+{
+       (void) zap_prefetch_uint64(os, object, (uint64_t *)&dde->dde_key,
+           DDT_KEY_WORDS);
+}
+
+static int
+ddt_zap_update(objset_t *os, uint64_t object, ddt_entry_t *dde, dmu_tx_t *tx)
+{
+       uchar_t cbuf[sizeof (dde->dde_phys) + 1];
+       uint64_t csize;
+
+       csize = ddt_compress(dde->dde_phys, cbuf,
+           sizeof (dde->dde_phys), sizeof (cbuf));
+
+       return (zap_update_uint64(os, object, (uint64_t *)&dde->dde_key,
+           DDT_KEY_WORDS, 1, csize, cbuf, tx));
+}
+
+static int
+ddt_zap_remove(objset_t *os, uint64_t object, ddt_entry_t *dde, dmu_tx_t *tx)
+{
+       return (zap_remove_uint64(os, object, (uint64_t *)&dde->dde_key,
+           DDT_KEY_WORDS, tx));
+}
+
+static int
+ddt_zap_walk(objset_t *os, uint64_t object, ddt_entry_t *dde, uint64_t *walk)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int error;
+
+       zap_cursor_init_serialized(&zc, os, object, *walk);
+       if ((error = zap_cursor_retrieve(&zc, &za)) == 0) {
+               uchar_t cbuf[sizeof (dde->dde_phys) + 1];
+               uint64_t csize = za.za_num_integers;
+               ASSERT(za.za_integer_length == 1);
+               error = zap_lookup_uint64(os, object, (uint64_t *)za.za_name,
+                   DDT_KEY_WORDS, 1, csize, cbuf);
+               ASSERT(error == 0);
+               if (error == 0) {
+                       ddt_decompress(cbuf, dde->dde_phys, csize,
+                           sizeof (dde->dde_phys));
+                       dde->dde_key = *(ddt_key_t *)za.za_name;
+               }
+               zap_cursor_advance(&zc);
+               *walk = zap_cursor_serialize(&zc);
+       }
+       zap_cursor_fini(&zc);
+       return (error);
+}
+
+static int
+ddt_zap_count(objset_t *os, uint64_t object, uint64_t *count)
+{
+       return (zap_count(os, object, count));
+}
+
+const ddt_ops_t ddt_zap_ops = {
+       "zap",
+       ddt_zap_create,
+       ddt_zap_destroy,
+       ddt_zap_lookup,
+       ddt_zap_prefetch,
+       ddt_zap_update,
+       ddt_zap_remove,
+       ddt_zap_walk,
+       ddt_zap_count,
+};
diff --git a/zfs/module/zfs/dmu.c b/zfs/module/zfs/dmu.c
new file mode 100644 (file)
index 0000000..5e2a1db
--- /dev/null
@@ -0,0 +1,2182 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/zfs_context.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dsl_prop.h>
+#include <sys/dmu_zfetch.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zap.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/sa.h>
+#include <sys/zfeature.h>
+#ifdef _KERNEL
+#include <sys/vmsystm.h>
+#include <sys/zfs_znode.h>
+#endif
+
+/*
+ * Enable/disable nopwrite feature.
+ */
+int zfs_nopwrite_enabled = 1;
+
+const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES] = {
+       {       DMU_BSWAP_UINT8,        TRUE,   "unallocated"           },
+       {       DMU_BSWAP_ZAP,          TRUE,   "object directory"      },
+       {       DMU_BSWAP_UINT64,       TRUE,   "object array"          },
+       {       DMU_BSWAP_UINT8,        TRUE,   "packed nvlist"         },
+       {       DMU_BSWAP_UINT64,       TRUE,   "packed nvlist size"    },
+       {       DMU_BSWAP_UINT64,       TRUE,   "bpobj"                 },
+       {       DMU_BSWAP_UINT64,       TRUE,   "bpobj header"          },
+       {       DMU_BSWAP_UINT64,       TRUE,   "SPA space map header"  },
+       {       DMU_BSWAP_UINT64,       TRUE,   "SPA space map"         },
+       {       DMU_BSWAP_UINT64,       TRUE,   "ZIL intent log"        },
+       {       DMU_BSWAP_DNODE,        TRUE,   "DMU dnode"             },
+       {       DMU_BSWAP_OBJSET,       TRUE,   "DMU objset"            },
+       {       DMU_BSWAP_UINT64,       TRUE,   "DSL directory"         },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL directory child map"},
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL dataset snap map"  },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL props"             },
+       {       DMU_BSWAP_UINT64,       TRUE,   "DSL dataset"           },
+       {       DMU_BSWAP_ZNODE,        TRUE,   "ZFS znode"             },
+       {       DMU_BSWAP_OLDACL,       TRUE,   "ZFS V0 ACL"            },
+       {       DMU_BSWAP_UINT8,        FALSE,  "ZFS plain file"        },
+       {       DMU_BSWAP_ZAP,          TRUE,   "ZFS directory"         },
+       {       DMU_BSWAP_ZAP,          TRUE,   "ZFS master node"       },
+       {       DMU_BSWAP_ZAP,          TRUE,   "ZFS delete queue"      },
+       {       DMU_BSWAP_UINT8,        FALSE,  "zvol object"           },
+       {       DMU_BSWAP_ZAP,          TRUE,   "zvol prop"             },
+       {       DMU_BSWAP_UINT8,        FALSE,  "other uint8[]"         },
+       {       DMU_BSWAP_UINT64,       FALSE,  "other uint64[]"        },
+       {       DMU_BSWAP_ZAP,          TRUE,   "other ZAP"             },
+       {       DMU_BSWAP_ZAP,          TRUE,   "persistent error log"  },
+       {       DMU_BSWAP_UINT8,        TRUE,   "SPA history"           },
+       {       DMU_BSWAP_UINT64,       TRUE,   "SPA history offsets"   },
+       {       DMU_BSWAP_ZAP,          TRUE,   "Pool properties"       },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL permissions"       },
+       {       DMU_BSWAP_ACL,          TRUE,   "ZFS ACL"               },
+       {       DMU_BSWAP_UINT8,        TRUE,   "ZFS SYSACL"            },
+       {       DMU_BSWAP_UINT8,        TRUE,   "FUID table"            },
+       {       DMU_BSWAP_UINT64,       TRUE,   "FUID table size"       },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL dataset next clones"},
+       {       DMU_BSWAP_ZAP,          TRUE,   "scan work queue"       },
+       {       DMU_BSWAP_ZAP,          TRUE,   "ZFS user/group used"   },
+       {       DMU_BSWAP_ZAP,          TRUE,   "ZFS user/group quota"  },
+       {       DMU_BSWAP_ZAP,          TRUE,   "snapshot refcount tags"},
+       {       DMU_BSWAP_ZAP,          TRUE,   "DDT ZAP algorithm"     },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DDT statistics"        },
+       {       DMU_BSWAP_UINT8,        TRUE,   "System attributes"     },
+       {       DMU_BSWAP_ZAP,          TRUE,   "SA master node"        },
+       {       DMU_BSWAP_ZAP,          TRUE,   "SA attr registration"  },
+       {       DMU_BSWAP_ZAP,          TRUE,   "SA attr layouts"       },
+       {       DMU_BSWAP_ZAP,          TRUE,   "scan translations"     },
+       {       DMU_BSWAP_UINT8,        FALSE,  "deduplicated block"    },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL deadlist map"      },
+       {       DMU_BSWAP_UINT64,       TRUE,   "DSL deadlist map hdr"  },
+       {       DMU_BSWAP_ZAP,          TRUE,   "DSL dir clones"        },
+       {       DMU_BSWAP_UINT64,       TRUE,   "bpobj subobj"          }
+};
+
+const dmu_object_byteswap_info_t dmu_ot_byteswap[DMU_BSWAP_NUMFUNCS] = {
+       {       byteswap_uint8_array,   "uint8"         },
+       {       byteswap_uint16_array,  "uint16"        },
+       {       byteswap_uint32_array,  "uint32"        },
+       {       byteswap_uint64_array,  "uint64"        },
+       {       zap_byteswap,           "zap"           },
+       {       dnode_buf_byteswap,     "dnode"         },
+       {       dmu_objset_byteswap,    "objset"        },
+       {       zfs_znode_byteswap,     "znode"         },
+       {       zfs_oldacl_byteswap,    "oldacl"        },
+       {       zfs_acl_byteswap,       "acl"           }
+};
+
+int
+dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset,
+    void *tag, dmu_buf_t **dbp)
+{
+       dnode_t *dn;
+       uint64_t blkid;
+       dmu_buf_impl_t *db;
+       int err;
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+       blkid = dbuf_whichblock(dn, offset);
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       db = dbuf_hold(dn, blkid, tag);
+       rw_exit(&dn->dn_struct_rwlock);
+       dnode_rele(dn, FTAG);
+
+       if (db == NULL) {
+               *dbp = NULL;
+               return (SET_ERROR(EIO));
+       }
+
+       *dbp = &db->db;
+       return (err);
+}
+
+int
+dmu_buf_hold(objset_t *os, uint64_t object, 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(os, object, 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_bonus_max(void)
+{
+       return (DN_MAX_BONUSLEN);
+}
+
+int
+dmu_set_bonus(dmu_buf_t *db_fake, int newsize, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+       int error;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       if (dn->dn_bonus != db) {
+               error = SET_ERROR(EINVAL);
+       } else if (newsize < 0 || newsize > db_fake->db_size) {
+               error = SET_ERROR(EINVAL);
+       } else {
+               dnode_setbonuslen(dn, newsize, tx);
+               error = 0;
+       }
+
+       DB_DNODE_EXIT(db);
+       return (error);
+}
+
+int
+dmu_set_bonustype(dmu_buf_t *db_fake, dmu_object_type_t type, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+       int error;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       if (!DMU_OT_IS_VALID(type)) {
+               error = SET_ERROR(EINVAL);
+       } else if (dn->dn_bonus != db) {
+               error = SET_ERROR(EINVAL);
+       } else {
+               dnode_setbonus_type(dn, type, tx);
+               error = 0;
+       }
+
+       DB_DNODE_EXIT(db);
+       return (error);
+}
+
+dmu_object_type_t
+dmu_get_bonustype(dmu_buf_t *db_fake)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+       dmu_object_type_t type;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       type = dn->dn_bonustype;
+       DB_DNODE_EXIT(db);
+
+       return (type);
+}
+
+int
+dmu_rm_spill(objset_t *os, uint64_t object, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       int error;
+
+       error = dnode_hold(os, object, FTAG, &dn);
+       dbuf_rm_spill(dn, tx);
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       dnode_rm_spill(dn, tx);
+       rw_exit(&dn->dn_struct_rwlock);
+       dnode_rele(dn, FTAG);
+       return (error);
+}
+
+/*
+ * returns ENOENT, EIO, or 0.
+ */
+int
+dmu_bonus_hold(objset_t *os, uint64_t object, void *tag, dmu_buf_t **dbp)
+{
+       dnode_t *dn;
+       dmu_buf_impl_t *db;
+       int error;
+
+       error = dnode_hold(os, object, FTAG, &dn);
+       if (error)
+               return (error);
+
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       if (dn->dn_bonus == NULL) {
+               rw_exit(&dn->dn_struct_rwlock);
+               rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+               if (dn->dn_bonus == NULL)
+                       dbuf_create_bonus(dn);
+       }
+       db = dn->dn_bonus;
+
+       /* as long as the bonus buf is held, the dnode will be held */
+       if (refcount_add(&db->db_holds, tag) == 1) {
+               VERIFY(dnode_add_ref(dn, db));
+               atomic_inc_32(&dn->dn_dbufs_count);
+       }
+
+       /*
+        * Wait to drop dn_struct_rwlock until after adding the bonus dbuf's
+        * hold and incrementing the dbuf count to ensure that dnode_move() sees
+        * a dnode hold for every dbuf.
+        */
+       rw_exit(&dn->dn_struct_rwlock);
+
+       dnode_rele(dn, FTAG);
+
+       VERIFY(0 == dbuf_read(db, NULL, DB_RF_MUST_SUCCEED | DB_RF_NOPREFETCH));
+
+       *dbp = &db->db;
+       return (0);
+}
+
+/*
+ * returns ENOENT, EIO, or 0.
+ *
+ * This interface will allocate a blank spill dbuf when a spill blk
+ * doesn't already exist on the dnode.
+ *
+ * if you only want to find an already existing spill db, then
+ * dmu_spill_hold_existing() should be used.
+ */
+int
+dmu_spill_hold_by_dnode(dnode_t *dn, uint32_t flags, void *tag, dmu_buf_t **dbp)
+{
+       dmu_buf_impl_t *db = NULL;
+       int err;
+
+       if ((flags & DB_RF_HAVESTRUCT) == 0)
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+
+       db = dbuf_hold(dn, DMU_SPILL_BLKID, tag);
+
+       if ((flags & DB_RF_HAVESTRUCT) == 0)
+               rw_exit(&dn->dn_struct_rwlock);
+
+       ASSERT(db != NULL);
+       err = dbuf_read(db, NULL, flags);
+       if (err == 0)
+               *dbp = &db->db;
+       else
+               dbuf_rele(db, tag);
+       return (err);
+}
+
+int
+dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)bonus;
+       dnode_t *dn;
+       int err;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       if (spa_version(dn->dn_objset->os_spa) < SPA_VERSION_SA) {
+               err = SET_ERROR(EINVAL);
+       } else {
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+
+               if (!dn->dn_have_spill) {
+                       err = SET_ERROR(ENOENT);
+               } else {
+                       err = dmu_spill_hold_by_dnode(dn,
+                           DB_RF_HAVESTRUCT | DB_RF_CANFAIL, tag, dbp);
+               }
+
+               rw_exit(&dn->dn_struct_rwlock);
+       }
+
+       DB_DNODE_EXIT(db);
+       return (err);
+}
+
+int
+dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)bonus;
+       dnode_t *dn;
+       int err;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       err = dmu_spill_hold_by_dnode(dn, DB_RF_CANFAIL, tag, dbp);
+       DB_DNODE_EXIT(db);
+
+       return (err);
+}
+
+/*
+ * Note: longer-term, we should modify all of the dmu_buf_*() interfaces
+ * to take a held dnode rather than <os, object> -- the lookup is wasteful,
+ * and can induce severe lock contention when writing to several files
+ * whose dnodes are in the same block.
+ */
+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)
+{
+       dmu_buf_t **dbp;
+       uint64_t blkid, nblks, i;
+       uint32_t dbuf_flags;
+       int err;
+       zio_t *zio;
+
+       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;
+
+       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;
+       } else {
+               if (offset + length > dn->dn_datablksz) {
+                       zfs_panic_recover("zfs: accessing past end of object "
+                           "%llx/%llx (size=%u access=%llu+%llu)",
+                           (longlong_t)dn->dn_objset->
+                           os_dsl_dataset->ds_object,
+                           (longlong_t)dn->dn_object, dn->dn_datablksz,
+                           (longlong_t)offset, (longlong_t)length);
+                       rw_exit(&dn->dn_struct_rwlock);
+                       return (SET_ERROR(EIO));
+               }
+               nblks = 1;
+       }
+       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);
+       for (i = 0; i < nblks; i++) {
+               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) {
+                       (void) dbuf_read(db, zio, dbuf_flags);
+               }
+               dbp[i] = &db->db;
+       }
+       rw_exit(&dn->dn_struct_rwlock);
+
+       /* wait for async i/o */
+       err = zio_wait(zio);
+       if (err) {
+               dmu_buf_rele_array(dbp, nblks, tag);
+               return (err);
+       }
+
+       /* wait for other io to complete */
+       if (read) {
+               for (i = 0; i < nblks; i++) {
+                       dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbp[i];
+                       mutex_enter(&db->db_mtx);
+                       while (db->db_state == DB_READ ||
+                           db->db_state == DB_FILL)
+                               cv_wait(&db->db_changed, &db->db_mtx);
+                       if (db->db_state == DB_UNCACHED)
+                               err = SET_ERROR(EIO);
+                       mutex_exit(&db->db_mtx);
+                       if (err) {
+                               dmu_buf_rele_array(dbp, nblks, tag);
+                               return (err);
+                       }
+               }
+       }
+
+       *numbufsp = nblks;
+       *dbpp = dbp;
+       return (0);
+}
+
+static int
+dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset,
+    uint64_t length, int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp)
+{
+       dnode_t *dn;
+       int err;
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+
+       err = dmu_buf_hold_array_by_dnode(dn, offset, length, read, tag,
+           numbufsp, dbpp, DMU_READ_PREFETCH);
+
+       dnode_rele(dn, FTAG);
+
+       return (err);
+}
+
+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)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+       int err;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       err = dmu_buf_hold_array_by_dnode(dn, offset, length, read, tag,
+           numbufsp, dbpp, DMU_READ_PREFETCH);
+       DB_DNODE_EXIT(db);
+
+       return (err);
+}
+
+void
+dmu_buf_rele_array(dmu_buf_t **dbp_fake, int numbufs, void *tag)
+{
+       int i;
+       dmu_buf_impl_t **dbp = (dmu_buf_impl_t **)dbp_fake;
+
+       if (numbufs == 0)
+               return;
+
+       for (i = 0; i < numbufs; i++) {
+               if (dbp[i])
+                       dbuf_rele(dbp[i], tag);
+       }
+
+       kmem_free(dbp, sizeof (dmu_buf_t *) * numbufs);
+}
+
+/*
+ * 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
+ *
+ * Note: indirect blocks and other metadata will be read synchronously,
+ * causing this function to block if they are not already cached.
+ */
+void
+dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset, uint64_t len)
+{
+       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);
+
+               if (object == 0 || object >= DN_MAX_OBJECT)
+                       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);
+               rw_exit(&dn->dn_struct_rwlock);
+               return;
+       }
+
+       /*
+        * XXX - Note, if the dnode for the requested object is not
+        * already cached, we will do a *synchronous* read in the
+        * dnode_hold() call.  The same is true for any indirects.
+        */
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err != 0)
+               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;
+       } else {
+               nblks = (offset < dn->dn_datablksz);
+       }
+
+       if (nblks != 0) {
+               int i;
+
+               blkid = dbuf_whichblock(dn, offset);
+               for (i = 0; i < nblks; i++)
+                       dbuf_prefetch(dn, blkid + i, ZIO_PRIORITY_SYNC_READ);
+       }
+
+       rw_exit(&dn->dn_struct_rwlock);
+
+       dnode_rele(dn, FTAG);
+}
+
+/*
+ * Get the next "chunk" of file data to free.  We traverse the file from
+ * the end so that the file gets shorter over time (if we crashes in the
+ * middle, this will leave us in a better state).  We find allocated file
+ * data by simply searching the allocated level 1 indirects.
+ *
+ * On input, *start should be the first offset that does not need to be
+ * freed (e.g. "offset + length").  On return, *start will be the first
+ * offset that should be freed.
+ */
+static int
+get_next_chunk(dnode_t *dn, uint64_t *start, uint64_t minimum)
+{
+       uint64_t maxblks = DMU_MAX_ACCESS >> (dn->dn_indblkshift + 1);
+       /* bytes of data covered by a level-1 indirect block */
+       uint64_t iblkrange =
+           dn->dn_datablksz * EPB(dn->dn_indblkshift, SPA_BLKPTRSHIFT);
+       uint64_t blks;
+
+       ASSERT3U(minimum, <=, *start);
+
+       if (*start - minimum <= iblkrange * maxblks) {
+               *start = minimum;
+               return (0);
+       }
+       ASSERT(ISP2(iblkrange));
+
+       for (blks = 0; *start > minimum && blks < maxblks; blks++) {
+               int err;
+
+               /*
+                * dnode_next_offset(BACKWARDS) will find an allocated L1
+                * indirect block at or before the input offset.  We must
+                * decrement *start so that it is at the end of the region
+                * to search.
+                */
+               (*start)--;
+               err = dnode_next_offset(dn,
+                   DNODE_FIND_BACKWARDS, start, 2, 1, 0);
+
+               /* if there are no indirect blocks before start, we are done */
+               if (err == ESRCH) {
+                       *start = minimum;
+                       break;
+               } else if (err != 0) {
+                       return (err);
+               }
+
+               /* set start to the beginning of this L1 indirect */
+               *start = P2ALIGN(*start, iblkrange);
+       }
+       if (*start < minimum)
+               *start = minimum;
+       return (0);
+}
+
+static int
+dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
+    uint64_t length)
+{
+       uint64_t object_size;
+       int err;
+
+       if (dn == NULL)
+               return (SET_ERROR(EINVAL));
+
+       object_size = (dn->dn_maxblkid + 1) * dn->dn_datablksz;
+       if (offset >= object_size)
+               return (0);
+
+       if (length == DMU_OBJECT_END || offset + length > object_size)
+               length = object_size - offset;
+
+       while (length != 0) {
+               uint64_t chunk_end, chunk_begin;
+               dmu_tx_t *tx;
+
+               chunk_end = chunk_begin = offset + length;
+
+               /* move chunk_begin backwards to the beginning of this chunk */
+               err = get_next_chunk(dn, &chunk_begin, offset);
+               if (err)
+                       return (err);
+               ASSERT3U(chunk_begin, >=, offset);
+               ASSERT3U(chunk_begin, <=, chunk_end);
+
+               tx = dmu_tx_create(os);
+               dmu_tx_hold_free(tx, dn->dn_object,
+                   chunk_begin, chunk_end - chunk_begin);
+               err = dmu_tx_assign(tx, TXG_WAIT);
+               if (err) {
+                       dmu_tx_abort(tx);
+                       return (err);
+               }
+               dnode_free_range(dn, chunk_begin, chunk_end - chunk_begin, tx);
+               dmu_tx_commit(tx);
+
+               length -= chunk_end - chunk_begin;
+       }
+       return (0);
+}
+
+int
+dmu_free_long_range(objset_t *os, uint64_t object,
+    uint64_t offset, uint64_t length)
+{
+       dnode_t *dn;
+       int err;
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err != 0)
+               return (err);
+       err = dmu_free_long_range_impl(os, dn, offset, length);
+
+       /*
+        * It is important to zero out the maxblkid when freeing the entire
+        * file, so that (a) subsequent calls to dmu_free_long_range_impl()
+        * will take the fast path, and (b) dnode_reallocate() can verify
+        * that the entire file has been freed.
+        */
+       if (err == 0 && offset == 0 && length == DMU_OBJECT_END)
+               dn->dn_maxblkid = 0;
+
+       dnode_rele(dn, FTAG);
+       return (err);
+}
+
+int
+dmu_free_long_object(objset_t *os, uint64_t object)
+{
+       dmu_tx_t *tx;
+       int err;
+
+       err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END);
+       if (err != 0)
+               return (err);
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_bonus(tx, object);
+       dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END);
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err == 0) {
+               err = dmu_object_free(os, object, tx);
+               dmu_tx_commit(tx);
+       } else {
+               dmu_tx_abort(tx);
+       }
+
+       return (err);
+}
+
+int
+dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
+    uint64_t size, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       int err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+       ASSERT(offset < UINT64_MAX);
+       ASSERT(size == -1ULL || size <= UINT64_MAX - offset);
+       dnode_free_range(dn, offset, size, tx);
+       dnode_rele(dn, FTAG);
+       return (0);
+}
+
+int
+dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+    void *buf, uint32_t flags)
+{
+       dnode_t *dn;
+       dmu_buf_t **dbp;
+       int numbufs, err;
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+
+       /*
+        * Deal with odd block sizes, where there can't be data past the first
+        * block.  If we ever do the tail block optimization, we will need to
+        * handle that here as well.
+        */
+       if (dn->dn_maxblkid == 0) {
+               uint64_t newsz = offset > dn->dn_datablksz ? 0 :
+                   MIN(size, dn->dn_datablksz - offset);
+               bzero((char *)buf + newsz, size - newsz);
+               size = newsz;
+       }
+
+       while (size > 0) {
+               uint64_t mylen = MIN(size, DMU_MAX_ACCESS / 2);
+               int i;
+
+               /*
+                * NB: we could do this block-at-a-time, but it's nice
+                * to be reading in parallel.
+                */
+               err = dmu_buf_hold_array_by_dnode(dn, offset, mylen,
+                   TRUE, FTAG, &numbufs, &dbp, flags);
+               if (err)
+                       break;
+
+               for (i = 0; i < numbufs; i++) {
+                       uint64_t tocpy;
+                       int64_t bufoff;
+                       dmu_buf_t *db = dbp[i];
+
+                       ASSERT(size > 0);
+
+                       bufoff = offset - db->db_offset;
+                       tocpy = MIN(db->db_size - bufoff, size);
+
+                       (void) memcpy(buf, (char *)db->db_data + bufoff, tocpy);
+
+                       offset += tocpy;
+                       size -= tocpy;
+                       buf = (char *)buf + tocpy;
+               }
+               dmu_buf_rele_array(dbp, numbufs, FTAG);
+       }
+       dnode_rele(dn, FTAG);
+       return (err);
+}
+
+void
+dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+    const void *buf, dmu_tx_t *tx)
+{
+       dmu_buf_t **dbp;
+       int numbufs, i;
+
+       if (size == 0)
+               return;
+
+       VERIFY0(dmu_buf_hold_array(os, object, offset, size,
+           FALSE, FTAG, &numbufs, &dbp));
+
+       for (i = 0; i < numbufs; i++) {
+               uint64_t tocpy;
+               int64_t bufoff;
+               dmu_buf_t *db = dbp[i];
+
+               ASSERT(size > 0);
+
+               bufoff = offset - db->db_offset;
+               tocpy = MIN(db->db_size - bufoff, size);
+
+               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);
+
+               (void) memcpy((char *)db->db_data + bufoff, buf, tocpy);
+
+               if (tocpy == db->db_size)
+                       dmu_buf_fill_done(db, tx);
+
+               offset += tocpy;
+               size -= tocpy;
+               buf = (char *)buf + tocpy;
+       }
+       dmu_buf_rele_array(dbp, numbufs, FTAG);
+}
+
+void
+dmu_prealloc(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+    dmu_tx_t *tx)
+{
+       dmu_buf_t **dbp;
+       int numbufs, i;
+
+       if (size == 0)
+               return;
+
+       VERIFY(0 == dmu_buf_hold_array(os, object, offset, size,
+           FALSE, FTAG, &numbufs, &dbp));
+
+       for (i = 0; i < numbufs; i++) {
+               dmu_buf_t *db = dbp[i];
+
+               dmu_buf_will_not_fill(db, tx);
+       }
+       dmu_buf_rele_array(dbp, numbufs, FTAG);
+}
+
+void
+dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset,
+    void *data, uint8_t etype, uint8_t comp, int uncompressed_size,
+    int compressed_size, int byteorder, dmu_tx_t *tx)
+{
+       dmu_buf_t *db;
+
+       ASSERT3U(etype, <, NUM_BP_EMBEDDED_TYPES);
+       ASSERT3U(comp, <, ZIO_COMPRESS_FUNCTIONS);
+       VERIFY0(dmu_buf_hold_noread(os, object, offset,
+           FTAG, &db));
+
+       dmu_buf_write_embedded(db,
+           data, (bp_embedded_type_t)etype, (enum zio_compress)comp,
+           uncompressed_size, compressed_size, byteorder, tx);
+
+       dmu_buf_rele(db, FTAG);
+}
+
+/*
+ * DMU support for xuio
+ */
+kstat_t *xuio_ksp = NULL;
+
+typedef struct xuio_stats {
+       /* loaned yet not returned arc_buf */
+       kstat_named_t xuiostat_onloan_rbuf;
+       kstat_named_t xuiostat_onloan_wbuf;
+       /* whether a copy is made when loaning out a read buffer */
+       kstat_named_t xuiostat_rbuf_copied;
+       kstat_named_t xuiostat_rbuf_nocopy;
+       /* whether a copy is made when assigning a write buffer */
+       kstat_named_t xuiostat_wbuf_copied;
+       kstat_named_t xuiostat_wbuf_nocopy;
+} xuio_stats_t;
+
+static xuio_stats_t xuio_stats = {
+       { "onloan_read_buf",    KSTAT_DATA_UINT64 },
+       { "onloan_write_buf",   KSTAT_DATA_UINT64 },
+       { "read_buf_copied",    KSTAT_DATA_UINT64 },
+       { "read_buf_nocopy",    KSTAT_DATA_UINT64 },
+       { "write_buf_copied",   KSTAT_DATA_UINT64 },
+       { "write_buf_nocopy",   KSTAT_DATA_UINT64 }
+};
+
+#define        XUIOSTAT_INCR(stat, val)        \
+       atomic_add_64(&xuio_stats.stat.value.ui64, (val))
+#define        XUIOSTAT_BUMP(stat)     XUIOSTAT_INCR(stat, 1)
+
+int
+dmu_xuio_init(xuio_t *xuio, int nblk)
+{
+       dmu_xuio_t *priv;
+       uio_t *uio = &xuio->xu_uio;
+
+       uio->uio_iovcnt = nblk;
+       uio->uio_iov = kmem_zalloc(nblk * sizeof (iovec_t), KM_SLEEP);
+
+       priv = kmem_zalloc(sizeof (dmu_xuio_t), KM_SLEEP);
+       priv->cnt = nblk;
+       priv->bufs = kmem_zalloc(nblk * sizeof (arc_buf_t *), KM_SLEEP);
+       priv->iovp = (iovec_t *)uio->uio_iov;
+       XUIO_XUZC_PRIV(xuio) = priv;
+
+       if (XUIO_XUZC_RW(xuio) == UIO_READ)
+               XUIOSTAT_INCR(xuiostat_onloan_rbuf, nblk);
+       else
+               XUIOSTAT_INCR(xuiostat_onloan_wbuf, nblk);
+
+       return (0);
+}
+
+void
+dmu_xuio_fini(xuio_t *xuio)
+{
+       dmu_xuio_t *priv = XUIO_XUZC_PRIV(xuio);
+       int nblk = priv->cnt;
+
+       kmem_free(priv->iovp, nblk * sizeof (iovec_t));
+       kmem_free(priv->bufs, nblk * sizeof (arc_buf_t *));
+       kmem_free(priv, sizeof (dmu_xuio_t));
+
+       if (XUIO_XUZC_RW(xuio) == UIO_READ)
+               XUIOSTAT_INCR(xuiostat_onloan_rbuf, -nblk);
+       else
+               XUIOSTAT_INCR(xuiostat_onloan_wbuf, -nblk);
+}
+
+/*
+ * Initialize iov[priv->next] and priv->bufs[priv->next] with { off, n, abuf }
+ * and increase priv->next by 1.
+ */
+int
+dmu_xuio_add(xuio_t *xuio, arc_buf_t *abuf, offset_t off, size_t n)
+{
+       struct iovec *iov;
+       uio_t *uio = &xuio->xu_uio;
+       dmu_xuio_t *priv = XUIO_XUZC_PRIV(xuio);
+       int i = priv->next++;
+
+       ASSERT(i < priv->cnt);
+       ASSERT(off + n <= arc_buf_size(abuf));
+       iov = (iovec_t *)uio->uio_iov + i;
+       iov->iov_base = (char *)abuf->b_data + off;
+       iov->iov_len = n;
+       priv->bufs[i] = abuf;
+       return (0);
+}
+
+int
+dmu_xuio_cnt(xuio_t *xuio)
+{
+       dmu_xuio_t *priv = XUIO_XUZC_PRIV(xuio);
+       return (priv->cnt);
+}
+
+arc_buf_t *
+dmu_xuio_arcbuf(xuio_t *xuio, int i)
+{
+       dmu_xuio_t *priv = XUIO_XUZC_PRIV(xuio);
+
+       ASSERT(i < priv->cnt);
+       return (priv->bufs[i]);
+}
+
+void
+dmu_xuio_clear(xuio_t *xuio, int i)
+{
+       dmu_xuio_t *priv = XUIO_XUZC_PRIV(xuio);
+
+       ASSERT(i < priv->cnt);
+       priv->bufs[i] = NULL;
+}
+
+static void
+xuio_stat_init(void)
+{
+       xuio_ksp = kstat_create("zfs", 0, "xuio_stats", "misc",
+           KSTAT_TYPE_NAMED, sizeof (xuio_stats) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+       if (xuio_ksp != NULL) {
+               xuio_ksp->ks_data = &xuio_stats;
+               kstat_install(xuio_ksp);
+       }
+}
+
+static void
+xuio_stat_fini(void)
+{
+       if (xuio_ksp != NULL) {
+               kstat_delete(xuio_ksp);
+               xuio_ksp = NULL;
+       }
+}
+
+void
+xuio_stat_wbuf_copied()
+{
+       XUIOSTAT_BUMP(xuiostat_wbuf_copied);
+}
+
+void
+xuio_stat_wbuf_nocopy()
+{
+       XUIOSTAT_BUMP(xuiostat_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;
+       xuio_t *xuio = NULL;
+
+       /*
+        * NB: we could do this block-at-a-time, but it's nice
+        * to be reading in parallel.
+        */
+       err = dmu_buf_hold_array_by_dnode(dn, uio->uio_loffset, size,
+           TRUE, FTAG, &numbufs, &dbp, 0);
+       if (err)
+               return (err);
+
+       for (i = 0; i < numbufs; i++) {
+               uint64_t tocpy;
+               int64_t bufoff;
+               dmu_buf_t *db = dbp[i];
+
+               ASSERT(size > 0);
+
+               bufoff = uio->uio_loffset - db->db_offset;
+               tocpy = MIN(db->db_size - bufoff, size);
+
+               if (xuio) {
+                       dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db;
+                       arc_buf_t *dbuf_abuf = dbi->db_buf;
+                       arc_buf_t *abuf = dbuf_loan_arcbuf(dbi);
+                       err = dmu_xuio_add(xuio, abuf, bufoff, tocpy);
+                       if (!err) {
+                               uio->uio_resid -= tocpy;
+                               uio->uio_loffset += tocpy;
+                       }
+
+                       if (abuf == dbuf_abuf)
+                               XUIOSTAT_BUMP(xuiostat_rbuf_nocopy);
+                       else
+                               XUIOSTAT_BUMP(xuiostat_rbuf_copied);
+               } else {
+                       err = uiomove((char *)db->db_data + bufoff, tocpy,
+                           UIO_READ, uio);
+               }
+               if (err)
+                       break;
+
+               size -= tocpy;
+       }
+       dmu_buf_rele_array(dbp, numbufs, FTAG);
+
+       return (err);
+}
+
+/*
+ * Read 'size' bytes into the uio buffer.
+ * From object zdb->db_object.
+ * Starting at offset uio->uio_loffset.
+ *
+ * If the caller already has a dbuf in the target object
+ * (e.g. its bonus buffer), this routine is faster than dmu_read_uio(),
+ * because we don't have to find the dnode_t for the object.
+ */
+int
+dmu_read_uio_dbuf(dmu_buf_t *zdb, uio_t *uio, uint64_t size)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)zdb;
+       dnode_t *dn;
+       int err;
+
+       if (size == 0)
+               return (0);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       err = dmu_read_uio_dnode(dn, uio, size);
+       DB_DNODE_EXIT(db);
+
+       return (err);
+}
+
+/*
+ * Read 'size' bytes into the uio buffer.
+ * From the specified object
+ * Starting at offset uio->uio_loffset.
+ */
+int
+dmu_read_uio(objset_t *os, uint64_t object, uio_t *uio, uint64_t size)
+{
+       dnode_t *dn;
+       int err;
+
+       if (size == 0)
+               return (0);
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+
+       err = dmu_read_uio_dnode(dn, uio, size);
+
+       dnode_rele(dn, FTAG);
+
+       return (err);
+}
+
+static int
+dmu_write_uio_dnode(dnode_t *dn, uio_t *uio, uint64_t size, dmu_tx_t *tx)
+{
+       dmu_buf_t **dbp;
+       int numbufs;
+       int err = 0;
+       int i;
+
+       err = dmu_buf_hold_array_by_dnode(dn, uio->uio_loffset, size,
+           FALSE, FTAG, &numbufs, &dbp, DMU_READ_PREFETCH);
+       if (err)
+               return (err);
+
+       for (i = 0; i < numbufs; i++) {
+               uint64_t tocpy;
+               int64_t bufoff;
+               dmu_buf_t *db = dbp[i];
+
+               ASSERT(size > 0);
+
+               bufoff = uio->uio_loffset - db->db_offset;
+               tocpy = MIN(db->db_size - bufoff, size);
+
+               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);
+
+               /*
+                * XXX uiomove could block forever (eg.nfs-backed
+                * pages).  There needs to be a uiolockdown() function
+                * to lock the pages in memory, so that uiomove won't
+                * block.
+                */
+               err = uiomove((char *)db->db_data + bufoff, tocpy,
+                   UIO_WRITE, uio);
+
+               if (tocpy == db->db_size)
+                       dmu_buf_fill_done(db, tx);
+
+               if (err)
+                       break;
+
+               size -= tocpy;
+       }
+
+       dmu_buf_rele_array(dbp, numbufs, FTAG);
+       return (err);
+}
+
+/*
+ * Write 'size' bytes from the uio buffer.
+ * To object zdb->db_object.
+ * Starting at offset uio->uio_loffset.
+ *
+ * If the caller already has a dbuf in the target object
+ * (e.g. its bonus buffer), this routine is faster than dmu_write_uio(),
+ * because we don't have to find the dnode_t for the object.
+ */
+int
+dmu_write_uio_dbuf(dmu_buf_t *zdb, uio_t *uio, uint64_t size,
+    dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)zdb;
+       dnode_t *dn;
+       int err;
+
+       if (size == 0)
+               return (0);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       err = dmu_write_uio_dnode(dn, uio, size, tx);
+       DB_DNODE_EXIT(db);
+
+       return (err);
+}
+
+/*
+ * Write 'size' bytes from the uio buffer.
+ * To the specified object.
+ * Starting at offset uio->uio_loffset.
+ */
+int
+dmu_write_uio(objset_t *os, uint64_t object, uio_t *uio, uint64_t size,
+    dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       int err;
+
+       if (size == 0)
+               return (0);
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+
+       err = dmu_write_uio_dnode(dn, uio, size, tx);
+
+       dnode_rele(dn, FTAG);
+
+       return (err);
+}
+#endif /* _KERNEL */
+
+/*
+ * Allocate a loaned anonymous arc buffer.
+ */
+arc_buf_t *
+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));
+}
+
+/*
+ * Free a loaned arc buffer.
+ */
+void
+dmu_return_arcbuf(arc_buf_t *buf)
+{
+       arc_return_buf(buf, FTAG);
+       VERIFY(arc_buf_remove_ref(buf, FTAG));
+}
+
+/*
+ * When possible directly assign passed loaned arc buffer to a dbuf.
+ * If this is not possible copy the contents of passed arc buf via
+ * dmu_write().
+ */
+void
+dmu_assign_arcbuf(dmu_buf_t *handle, uint64_t offset, arc_buf_t *buf,
+    dmu_tx_t *tx)
+{
+       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);
+       uint64_t blkid;
+
+       DB_DNODE_ENTER(dbuf);
+       dn = DB_DNODE(dbuf);
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       blkid = dbuf_whichblock(dn, 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.
+        */
+       if (offset == db->db.db_offset && blksz == db->db.db_size &&
+           DBUF_GET_BUFC_TYPE(db) == ARC_BUFC_DATA) {
+               dbuf_assign_arcbuf(db, buf, tx);
+               dbuf_rele(db, FTAG);
+       } else {
+               objset_t *os;
+               uint64_t object;
+
+               DB_DNODE_ENTER(dbuf);
+               dn = DB_DNODE(dbuf);
+               os = dn->dn_objset;
+               object = dn->dn_object;
+               DB_DNODE_EXIT(dbuf);
+
+               dbuf_rele(db, FTAG);
+               dmu_write(os, object, offset, blksz, buf->b_data, tx);
+               dmu_return_arcbuf(buf);
+               XUIOSTAT_BUMP(xuiostat_wbuf_copied);
+       }
+}
+
+typedef struct {
+       dbuf_dirty_record_t     *dsa_dr;
+       dmu_sync_cb_t           *dsa_done;
+       zgd_t                   *dsa_zgd;
+       dmu_tx_t                *dsa_tx;
+} dmu_sync_arg_t;
+
+/* ARGSUSED */
+static void
+dmu_sync_ready(zio_t *zio, arc_buf_t *buf, void *varg)
+{
+       dmu_sync_arg_t *dsa = varg;
+       dmu_buf_t *db = dsa->dsa_zgd->zgd_db;
+       blkptr_t *bp = zio->io_bp;
+
+       if (zio->io_error == 0) {
+               if (BP_IS_HOLE(bp)) {
+                       /*
+                        * A block of zeros may compress to a hole, but the
+                        * block size still needs to be known for replay.
+                        */
+                       BP_SET_LSIZE(bp, db->db_size);
+               } else if (!BP_IS_EMBEDDED(bp)) {
+                       ASSERT(BP_GET_LEVEL(bp) == 0);
+                       bp->blk_fill = 1;
+               }
+       }
+}
+
+static void
+dmu_sync_late_arrival_ready(zio_t *zio)
+{
+       dmu_sync_ready(zio, NULL, zio->io_private);
+}
+
+/* ARGSUSED */
+static void
+dmu_sync_done(zio_t *zio, arc_buf_t *buf, void *varg)
+{
+       dmu_sync_arg_t *dsa = varg;
+       dbuf_dirty_record_t *dr = dsa->dsa_dr;
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+
+       mutex_enter(&db->db_mtx);
+       ASSERT(dr->dt.dl.dr_override_state == DR_IN_DMU_SYNC);
+       if (zio->io_error == 0) {
+               dr->dt.dl.dr_nopwrite = !!(zio->io_flags & ZIO_FLAG_NOPWRITE);
+               if (dr->dt.dl.dr_nopwrite) {
+                       ASSERTV(blkptr_t *bp = zio->io_bp);
+                       ASSERTV(blkptr_t *bp_orig = &zio->io_bp_orig);
+                       ASSERTV(uint8_t chksum = BP_GET_CHECKSUM(bp_orig));
+
+                       ASSERT(BP_EQUAL(bp, bp_orig));
+                       ASSERT(zio->io_prop.zp_compress != ZIO_COMPRESS_OFF);
+                       ASSERT(zio_checksum_table[chksum].ci_dedup);
+               }
+               dr->dt.dl.dr_overridden_by = *zio->io_bp;
+               dr->dt.dl.dr_override_state = DR_OVERRIDDEN;
+               dr->dt.dl.dr_copies = zio->io_prop.zp_copies;
+
+               /*
+                * Old style holes are filled with all zeros, whereas
+                * new-style holes maintain their lsize, type, level,
+                * and birth time (see zio_write_compress). While we
+                * need to reset the BP_SET_LSIZE() call that happened
+                * in dmu_sync_ready for old style holes, we do *not*
+                * want to wipe out the information contained in new
+                * style holes. Thus, only zero out the block pointer if
+                * it's an old style hole.
+                */
+               if (BP_IS_HOLE(&dr->dt.dl.dr_overridden_by) &&
+                   dr->dt.dl.dr_overridden_by.blk_birth == 0)
+                       BP_ZERO(&dr->dt.dl.dr_overridden_by);
+       } else {
+               dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
+       }
+       cv_broadcast(&db->db_changed);
+       mutex_exit(&db->db_mtx);
+
+       dsa->dsa_done(dsa->dsa_zgd, zio->io_error);
+
+       kmem_free(dsa, sizeof (*dsa));
+}
+
+static void
+dmu_sync_late_arrival_done(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       dmu_sync_arg_t *dsa = zio->io_private;
+       ASSERTV(blkptr_t *bp_orig = &zio->io_bp_orig);
+
+       if (zio->io_error == 0 && !BP_IS_HOLE(bp)) {
+               /*
+                * If we didn't allocate a new block (i.e. ZIO_FLAG_NOPWRITE)
+                * then there is nothing to do here. Otherwise, free the
+                * newly allocated block in this txg.
+                */
+               if (zio->io_flags & ZIO_FLAG_NOPWRITE) {
+                       ASSERT(BP_EQUAL(bp, bp_orig));
+               } else {
+                       ASSERT(BP_IS_HOLE(bp_orig) || !BP_EQUAL(bp, bp_orig));
+                       ASSERT(zio->io_bp->blk_birth == zio->io_txg);
+                       ASSERT(zio->io_txg > spa_syncing_txg(zio->io_spa));
+                       zio_free(zio->io_spa, zio->io_txg, zio->io_bp);
+               }
+       }
+
+       dmu_tx_commit(dsa->dsa_tx);
+
+       dsa->dsa_done(dsa->dsa_zgd, zio->io_error);
+
+       kmem_free(dsa, sizeof (*dsa));
+}
+
+static int
+dmu_sync_late_arrival(zio_t *pio, objset_t *os, dmu_sync_cb_t *done, zgd_t *zgd,
+    zio_prop_t *zp, zbookmark_phys_t *zb)
+{
+       dmu_sync_arg_t *dsa;
+       dmu_tx_t *tx;
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_space(tx, zgd->zgd_db->db_size);
+       if (dmu_tx_assign(tx, TXG_WAIT) != 0) {
+               dmu_tx_abort(tx);
+               /* Make zl_get_data do txg_waited_synced() */
+               return (SET_ERROR(EIO));
+       }
+
+       dsa = kmem_alloc(sizeof (dmu_sync_arg_t), KM_SLEEP);
+       dsa->dsa_dr = NULL;
+       dsa->dsa_done = done;
+       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));
+
+       return (0);
+}
+
+/*
+ * Intent log support: sync the block associated with db to disk.
+ * N.B. and XXX: the caller is responsible for making sure that the
+ * data isn't changing while dmu_sync() is writing it.
+ *
+ * Return values:
+ *
+ *     EEXIST: this txg has already been synced, so there's nothing to do.
+ *             The caller should not log the write.
+ *
+ *     ENOENT: the block was dbuf_free_range()'d, so there's nothing to do.
+ *             The caller should not log the write.
+ *
+ *     EALREADY: this block is already in the process of being synced.
+ *             The caller should track its progress (somehow).
+ *
+ *     EIO: could not do the I/O.
+ *             The caller should do a txg_wait_synced().
+ *
+ *     0: the I/O has been initiated.
+ *             The caller should log this blkptr in the done callback.
+ *             It is possible that the I/O will fail, in which case
+ *             the error will be reported to the done callback and
+ *             propagated to pio from zio_done().
+ */
+int
+dmu_sync(zio_t *pio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd)
+{
+       blkptr_t *bp = zgd->zgd_bp;
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)zgd->zgd_db;
+       objset_t *os = db->db_objset;
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+       dbuf_dirty_record_t *dr;
+       dmu_sync_arg_t *dsa;
+       zbookmark_phys_t zb;
+       zio_prop_t zp;
+       dnode_t *dn;
+
+       ASSERT(pio != NULL);
+       ASSERT(txg != 0);
+
+       SET_BOOKMARK(&zb, ds->ds_object,
+           db->db.db_object, db->db_level, db->db_blkid);
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       dmu_write_policy(os, dn, db->db_level, WP_DMU_SYNC, &zp);
+       DB_DNODE_EXIT(db);
+
+       /*
+        * If we're frozen (running ziltest), we always need to generate a bp.
+        */
+       if (txg > spa_freeze_txg(os->os_spa))
+               return (dmu_sync_late_arrival(pio, os, done, zgd, &zp, &zb));
+
+       /*
+        * Grabbing db_mtx now provides a barrier between dbuf_sync_leaf()
+        * and us.  If we determine that this txg is not yet syncing,
+        * but it begins to sync a moment later, that's OK because the
+        * sync thread will block in dbuf_sync_leaf() until we drop db_mtx.
+        */
+       mutex_enter(&db->db_mtx);
+
+       if (txg <= spa_last_synced_txg(os->os_spa)) {
+               /*
+                * This txg has already synced.  There's nothing to do.
+                */
+               mutex_exit(&db->db_mtx);
+               return (SET_ERROR(EEXIST));
+       }
+
+       if (txg <= spa_syncing_txg(os->os_spa)) {
+               /*
+                * This txg is currently syncing, so we can't mess with
+                * the dirty record anymore; just write a new log block.
+                */
+               mutex_exit(&db->db_mtx);
+               return (dmu_sync_late_arrival(pio, os, done, zgd, &zp, &zb));
+       }
+
+       dr = db->db_last_dirty;
+       while (dr && dr->dr_txg != txg)
+               dr = dr->dr_next;
+
+       if (dr == NULL) {
+               /*
+                * There's no dr for this dbuf, so it must have been freed.
+                * There's no need to log writes to freed blocks, so we're done.
+                */
+               mutex_exit(&db->db_mtx);
+               return (SET_ERROR(ENOENT));
+       }
+
+       ASSERT(dr->dr_next == NULL || dr->dr_next->dr_txg < txg);
+
+       /*
+        * Assume the on-disk data is X, the current syncing data (in
+        * txg - 1) is Y, and the current in-memory data is Z (currently
+        * in dmu_sync).
+        *
+        * We usually want to perform a nopwrite if X and Z are the
+        * same.  However, if Y is different (i.e. the BP is going to
+        * change before this write takes effect), then a nopwrite will
+        * be incorrect - we would override with X, which could have
+        * been freed when Y was written.
+        *
+        * (Note that this is not a concern when we are nop-writing from
+        * syncing context, because X and Y must be identical, because
+        * all previous txgs have been synced.)
+        *
+        * Therefore, we disable nopwrite if the current BP could change
+        * before this TXG.  There are two ways it could change: by
+        * being dirty (dr_next is non-NULL), or by being freed
+        * (dnode_block_freed()).  This behavior is verified by
+        * zio_done(), which VERIFYs that the override BP is identical
+        * to the on-disk BP.
+        */
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       if (dr->dr_next != NULL || dnode_block_freed(dn, db->db_blkid))
+               zp.zp_nopwrite = B_FALSE;
+       DB_DNODE_EXIT(db);
+
+       ASSERT(dr->dr_txg == txg);
+       if (dr->dt.dl.dr_override_state == DR_IN_DMU_SYNC ||
+           dr->dt.dl.dr_override_state == DR_OVERRIDDEN) {
+               /*
+                * We have already issued a sync write for this buffer,
+                * or this buffer has already been synced.  It could not
+                * have been dirtied since, or we would have cleared the state.
+                */
+               mutex_exit(&db->db_mtx);
+               return (SET_ERROR(EALREADY));
+       }
+
+       ASSERT(dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN);
+       dr->dt.dl.dr_override_state = DR_IN_DMU_SYNC;
+       mutex_exit(&db->db_mtx);
+
+       dsa = kmem_alloc(sizeof (dmu_sync_arg_t), KM_SLEEP);
+       dsa->dsa_dr = dr;
+       dsa->dsa_done = done;
+       dsa->dsa_zgd = zgd;
+       dsa->dsa_tx = NULL;
+
+       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));
+
+       return (0);
+}
+
+int
+dmu_object_set_blocksize(objset_t *os, uint64_t object, uint64_t size, int ibs,
+       dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       int err;
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+       err = dnode_set_blksz(dn, size, ibs, tx);
+       dnode_rele(dn, FTAG);
+       return (err);
+}
+
+void
+dmu_object_set_checksum(objset_t *os, uint64_t object, uint8_t checksum,
+       dmu_tx_t *tx)
+{
+       dnode_t *dn;
+
+       /*
+        * Send streams include each object's checksum function.  This
+        * check ensures that the receiving system can understand the
+        * checksum function transmitted.
+        */
+       ASSERT3U(checksum, <, ZIO_CHECKSUM_LEGACY_FUNCTIONS);
+
+       VERIFY0(dnode_hold(os, object, FTAG, &dn));
+       ASSERT3U(checksum, <, ZIO_CHECKSUM_FUNCTIONS);
+       dn->dn_checksum = checksum;
+       dnode_setdirty(dn, tx);
+       dnode_rele(dn, FTAG);
+}
+
+void
+dmu_object_set_compress(objset_t *os, uint64_t object, uint8_t compress,
+       dmu_tx_t *tx)
+{
+       dnode_t *dn;
+
+       /*
+        * Send streams include each object's compression function.  This
+        * check ensures that the receiving system can understand the
+        * compression function transmitted.
+        */
+       ASSERT3U(compress, <, ZIO_COMPRESS_LEGACY_FUNCTIONS);
+
+       VERIFY0(dnode_hold(os, object, FTAG, &dn));
+       dn->dn_compress = compress;
+       dnode_setdirty(dn, tx);
+       dnode_rele(dn, FTAG);
+}
+
+int zfs_mdcomp_disable = 0;
+
+/*
+ * When the "redundant_metadata" property is set to "most", only indirect
+ * blocks of this level and higher will have an additional ditto block.
+ */
+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_object_type_t type = dn ? dn->dn_type : DMU_OT_OBJSET;
+       boolean_t ismd = (level > 0 || DMU_OT_IS_METADATA(type) ||
+           (wp & WP_SPILL));
+       enum zio_checksum checksum = os->os_checksum;
+       enum zio_compress compress = os->os_compress;
+       enum zio_checksum dedup_checksum = os->os_dedup_checksum;
+       boolean_t dedup = B_FALSE;
+       boolean_t nopwrite = B_FALSE;
+       boolean_t dedup_verify = os->os_dedup_verify;
+       int copies = os->os_copies;
+
+       /*
+        * We maintain different write policies for each of the following
+        * types of data:
+        *       1. metadata
+        *       2. preallocated blocks (i.e. level-0 blocks of a dump device)
+        *       3. all other level 0 blocks
+        */
+       if (ismd) {
+               if (zfs_mdcomp_disable) {
+                       compress = ZIO_COMPRESS_EMPTY;
+               } else {
+                       /*
+                        * XXX -- we should design a compression algorithm
+                        * that specializes in arrays of bps.
+                        */
+                       compress = zio_compress_select(os->os_spa,
+                           ZIO_COMPRESS_ON, ZIO_COMPRESS_ON);
+               }
+
+               /*
+                * Metadata always gets checksummed.  If the data
+                * checksum is multi-bit correctable, and it's not a
+                * ZBT-style checksum, then it's suitable for metadata
+                * as well.  Otherwise, the metadata checksum defaults
+                * to fletcher4.
+                */
+               if (zio_checksum_table[checksum].ci_correctable < 1 ||
+                   zio_checksum_table[checksum].ci_eck)
+                       checksum = ZIO_CHECKSUM_FLETCHER_4;
+
+               if (os->os_redundant_metadata == ZFS_REDUNDANT_METADATA_ALL ||
+                   (os->os_redundant_metadata ==
+                   ZFS_REDUNDANT_METADATA_MOST &&
+                   (level >= zfs_redundant_metadata_most_ditto_level ||
+                   DMU_OT_IS_METADATA(type) || (wp & WP_SPILL))))
+                       copies++;
+       } else if (wp & WP_NOFILL) {
+               ASSERT(level == 0);
+
+               /*
+                * If we're writing preallocated blocks, we aren't actually
+                * writing them so don't set any policy properties.  These
+                * blocks are currently only used by an external subsystem
+                * outside of zfs (i.e. dump) and not written by the zio
+                * pipeline.
+                */
+               compress = ZIO_COMPRESS_OFF;
+               checksum = ZIO_CHECKSUM_OFF;
+       } else {
+               compress = zio_compress_select(os->os_spa, dn->dn_compress,
+                   compress);
+
+               checksum = (dedup_checksum == ZIO_CHECKSUM_OFF) ?
+                   zio_checksum_select(dn->dn_checksum, checksum) :
+                   dedup_checksum;
+
+               /*
+                * Determine dedup setting.  If we are in dmu_sync(),
+                * we won't actually dedup now because that's all
+                * done in syncing context; but we do want to use the
+                * dedup checkum.  If the checksum is not strong
+                * enough to ensure unique signatures, force
+                * dedup_verify.
+                */
+               if (dedup_checksum != ZIO_CHECKSUM_OFF) {
+                       dedup = (wp & WP_DMU_SYNC) ? B_FALSE : B_TRUE;
+                       if (!zio_checksum_table[checksum].ci_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.
+                */
+               nopwrite = (!dedup && zio_checksum_table[checksum].ci_dedup &&
+                   compress != ZIO_COMPRESS_OFF && zfs_nopwrite_enabled);
+       }
+
+       zp->zp_checksum = checksum;
+       zp->zp_compress = compress;
+       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));
+       zp->zp_dedup = dedup;
+       zp->zp_dedup_verify = dedup && dedup_verify;
+       zp->zp_nopwrite = nopwrite;
+}
+
+int
+dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off)
+{
+       dnode_t *dn;
+       int i, err;
+
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err)
+               return (err);
+       /*
+        * Sync any current changes before
+        * we go trundling through the block pointers.
+        */
+       for (i = 0; i < TXG_SIZE; i++) {
+               if (list_link_active(&dn->dn_dirty_link[i]))
+                       break;
+       }
+       if (i != TXG_SIZE) {
+               dnode_rele(dn, FTAG);
+               txg_wait_synced(dmu_objset_pool(os), 0);
+               err = dnode_hold(os, object, FTAG, &dn);
+               if (err)
+                       return (err);
+       }
+
+       err = dnode_next_offset(dn, (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0);
+       dnode_rele(dn, FTAG);
+
+       return (err);
+}
+
+void
+__dmu_object_info_from_dnode(dnode_t *dn, dmu_object_info_t *doi)
+{
+       dnode_phys_t *dnp = dn->dn_phys;
+       int i;
+
+       doi->doi_data_block_size = dn->dn_datablksz;
+       doi->doi_metadata_block_size = dn->dn_indblkshift ?
+           1ULL << dn->dn_indblkshift : 0;
+       doi->doi_type = dn->dn_type;
+       doi->doi_bonus_type = dn->dn_bonustype;
+       doi->doi_bonus_size = dn->dn_bonuslen;
+       doi->doi_indirection = dn->dn_nlevels;
+       doi->doi_checksum = dn->dn_checksum;
+       doi->doi_compress = dn->dn_compress;
+       doi->doi_nblkptr = dn->dn_nblkptr;
+       doi->doi_physical_blocks_512 = (DN_USED_BYTES(dnp) + 256) >> 9;
+       doi->doi_max_offset = (dn->dn_maxblkid + 1) * dn->dn_datablksz;
+       doi->doi_fill_count = 0;
+       for (i = 0; i < dnp->dn_nblkptr; i++)
+               doi->doi_fill_count += BP_GET_FILL(&dnp->dn_blkptr[i]);
+}
+
+void
+dmu_object_info_from_dnode(dnode_t *dn, dmu_object_info_t *doi)
+{
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       mutex_enter(&dn->dn_mtx);
+
+       __dmu_object_info_from_dnode(dn, doi);
+
+       mutex_exit(&dn->dn_mtx);
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+/*
+ * Get information on a DMU object.
+ * If doi is NULL, just indicates whether the object exists.
+ */
+int
+dmu_object_info(objset_t *os, uint64_t object, dmu_object_info_t *doi)
+{
+       dnode_t *dn;
+       int err = dnode_hold(os, object, FTAG, &dn);
+
+       if (err)
+               return (err);
+
+       if (doi != NULL)
+               dmu_object_info_from_dnode(dn, doi);
+
+       dnode_rele(dn, FTAG);
+       return (0);
+}
+
+/*
+ * As above, but faster; can be used when you have a held dbuf in hand.
+ */
+void
+dmu_object_info_from_db(dmu_buf_t *db_fake, dmu_object_info_t *doi)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       DB_DNODE_ENTER(db);
+       dmu_object_info_from_dnode(DB_DNODE(db), doi);
+       DB_DNODE_EXIT(db);
+}
+
+/*
+ * Faster still when you only care about the size.
+ * This is specifically optimized for zfs_getattr().
+ */
+void
+dmu_object_size_from_db(dmu_buf_t *db_fake, uint32_t *blksize,
+    u_longlong_t *nblk512)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+
+       *blksize = dn->dn_datablksz;
+       /* add 1 for dnode space */
+       *nblk512 = ((DN_USED_BYTES(dn->dn_phys) + SPA_MINBLOCKSIZE/2) >>
+           SPA_MINBLOCKSHIFT) + 1;
+       DB_DNODE_EXIT(db);
+}
+
+void
+byteswap_uint64_array(void *vbuf, size_t size)
+{
+       uint64_t *buf = vbuf;
+       size_t count = size >> 3;
+       int i;
+
+       ASSERT((size & 7) == 0);
+
+       for (i = 0; i < count; i++)
+               buf[i] = BSWAP_64(buf[i]);
+}
+
+void
+byteswap_uint32_array(void *vbuf, size_t size)
+{
+       uint32_t *buf = vbuf;
+       size_t count = size >> 2;
+       int i;
+
+       ASSERT((size & 3) == 0);
+
+       for (i = 0; i < count; i++)
+               buf[i] = BSWAP_32(buf[i]);
+}
+
+void
+byteswap_uint16_array(void *vbuf, size_t size)
+{
+       uint16_t *buf = vbuf;
+       size_t count = size >> 1;
+       int i;
+
+       ASSERT((size & 1) == 0);
+
+       for (i = 0; i < count; i++)
+               buf[i] = BSWAP_16(buf[i]);
+}
+
+/* ARGSUSED */
+void
+byteswap_uint8_array(void *vbuf, size_t size)
+{
+}
+
+void
+dmu_init(void)
+{
+       zfs_dbgmsg_init();
+       sa_cache_init();
+       xuio_stat_init();
+       dmu_objset_init();
+       dnode_init();
+       dbuf_init();
+       zfetch_init();
+       dmu_tx_init();
+       l2arc_init();
+       arc_init();
+}
+
+void
+dmu_fini(void)
+{
+       arc_fini(); /* arc depends on l2arc, so arc must go first */
+       l2arc_fini();
+       dmu_tx_fini();
+       zfetch_fini();
+       dbuf_fini();
+       dnode_fini();
+       dmu_objset_fini();
+       xuio_stat_fini();
+       sa_cache_fini();
+       zfs_dbgmsg_fini();
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dmu_bonus_hold);
+EXPORT_SYMBOL(dmu_buf_hold_array_by_bonus);
+EXPORT_SYMBOL(dmu_buf_rele_array);
+EXPORT_SYMBOL(dmu_prefetch);
+EXPORT_SYMBOL(dmu_free_range);
+EXPORT_SYMBOL(dmu_free_long_range);
+EXPORT_SYMBOL(dmu_free_long_object);
+EXPORT_SYMBOL(dmu_read);
+EXPORT_SYMBOL(dmu_write);
+EXPORT_SYMBOL(dmu_prealloc);
+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_set_blocksize);
+EXPORT_SYMBOL(dmu_object_set_checksum);
+EXPORT_SYMBOL(dmu_object_set_compress);
+EXPORT_SYMBOL(dmu_write_policy);
+EXPORT_SYMBOL(dmu_sync);
+EXPORT_SYMBOL(dmu_request_arcbuf);
+EXPORT_SYMBOL(dmu_return_arcbuf);
+EXPORT_SYMBOL(dmu_assign_arcbuf);
+EXPORT_SYMBOL(dmu_buf_hold);
+EXPORT_SYMBOL(dmu_ot);
+
+module_param(zfs_mdcomp_disable, int, 0644);
+MODULE_PARM_DESC(zfs_mdcomp_disable, "Disable meta data compression");
+
+module_param(zfs_nopwrite_enabled, int, 0644);
+MODULE_PARM_DESC(zfs_nopwrite_enabled, "Enable NOP writes");
+
+#endif
diff --git a/zfs/module/zfs/dmu_diff.c b/zfs/module/zfs/dmu_diff.c
new file mode 100644 (file)
index 0000000..91415d0
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/zfs_context.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_synctask.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zap.h>
+#include <sys/zio_checksum.h>
+#include <sys/zfs_znode.h>
+
+struct diffarg {
+       struct vnode *da_vp;            /* file to which we are reporting */
+       offset_t *da_offp;
+       int da_err;                     /* error that stopped diff search */
+       dmu_diff_record_t da_ddr;
+};
+
+static int
+write_record(struct diffarg *da)
+{
+       ssize_t resid; /* have to get resid to get detailed errno */
+
+       if (da->da_ddr.ddr_type == DDR_NONE) {
+               da->da_err = 0;
+               return (0);
+       }
+
+       da->da_err = vn_rdwr(UIO_WRITE, da->da_vp, (caddr_t)&da->da_ddr,
+           sizeof (da->da_ddr), 0, UIO_SYSSPACE, FAPPEND,
+           RLIM64_INFINITY, CRED(), &resid);
+       *da->da_offp += sizeof (da->da_ddr);
+       return (da->da_err);
+}
+
+static int
+report_free_dnode_range(struct diffarg *da, uint64_t first, uint64_t last)
+{
+       ASSERT(first <= last);
+       if (da->da_ddr.ddr_type != DDR_FREE ||
+           first != da->da_ddr.ddr_last + 1) {
+               if (write_record(da) != 0)
+                       return (da->da_err);
+               da->da_ddr.ddr_type = DDR_FREE;
+               da->da_ddr.ddr_first = first;
+               da->da_ddr.ddr_last = last;
+               return (0);
+       }
+       da->da_ddr.ddr_last = last;
+       return (0);
+}
+
+static int
+report_dnode(struct diffarg *da, uint64_t object, dnode_phys_t *dnp)
+{
+       ASSERT(dnp != NULL);
+       if (dnp->dn_type == DMU_OT_NONE)
+               return (report_free_dnode_range(da, object, object));
+
+       if (da->da_ddr.ddr_type != DDR_INUSE ||
+           object != da->da_ddr.ddr_last + 1) {
+               if (write_record(da) != 0)
+                       return (da->da_err);
+               da->da_ddr.ddr_type = DDR_INUSE;
+               da->da_ddr.ddr_first = da->da_ddr.ddr_last = object;
+               return (0);
+       }
+       da->da_ddr.ddr_last = object;
+       return (0);
+}
+
+#define        DBP_SPAN(dnp, level)                              \
+       (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \
+       (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT)))
+
+/* ARGSUSED */
+static int
+diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       struct diffarg *da = arg;
+       int err = 0;
+
+       if (issig(JUSTLOOKING) && issig(FORREAL))
+               return (SET_ERROR(EINTR));
+
+       if (zb->zb_object != DMU_META_DNODE_OBJECT)
+               return (0);
+
+       if (BP_IS_HOLE(bp)) {
+               uint64_t span = DBP_SPAN(dnp, zb->zb_level);
+               uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT;
+
+               err = report_free_dnode_range(da, dnobj,
+                   dnobj + (span >> DNODE_SHIFT) - 1);
+               if (err)
+                       return (err);
+       } else if (zb->zb_level == 0) {
+               dnode_phys_t *blk;
+               arc_buf_t *abuf;
+               arc_flags_t aflags = ARC_FLAG_WAIT;
+               int blksz = BP_GET_LSIZE(bp);
+               int i;
+
+               if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
+                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
+                   &aflags, zb) != 0)
+                       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 = report_dnode(da, dnobj, blk+i);
+                       if (err)
+                               break;
+               }
+               (void) arc_buf_remove_ref(abuf, &abuf);
+               if (err)
+                       return (err);
+               /* Don't care about the data blocks */
+               return (TRAVERSE_VISIT_NO_CHILDREN);
+       }
+       return (0);
+}
+
+int
+dmu_diff(const char *tosnap_name, const char *fromsnap_name,
+    struct vnode *vp, offset_t *offp)
+{
+       struct diffarg da;
+       dsl_dataset_t *fromsnap;
+       dsl_dataset_t *tosnap;
+       dsl_pool_t *dp;
+       int error;
+       uint64_t fromtxg;
+
+       if (strchr(tosnap_name, '@') == NULL ||
+           strchr(fromsnap_name, '@') == NULL)
+               return (SET_ERROR(EINVAL));
+
+       error = dsl_pool_hold(tosnap_name, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold(dp, tosnap_name, FTAG, &tosnap);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       error = dsl_dataset_hold(dp, fromsnap_name, FTAG, &fromsnap);
+       if (error != 0) {
+               dsl_dataset_rele(tosnap, FTAG);
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       if (!dsl_dataset_is_before(tosnap, fromsnap, 0)) {
+               dsl_dataset_rele(fromsnap, FTAG);
+               dsl_dataset_rele(tosnap, FTAG);
+               dsl_pool_rele(dp, FTAG);
+               return (SET_ERROR(EXDEV));
+       }
+
+       fromtxg = dsl_dataset_phys(fromsnap)->ds_creation_txg;
+       dsl_dataset_rele(fromsnap, FTAG);
+
+       dsl_dataset_long_hold(tosnap, FTAG);
+       dsl_pool_rele(dp, FTAG);
+
+       da.da_vp = vp;
+       da.da_offp = offp;
+       da.da_ddr.ddr_type = DDR_NONE;
+       da.da_ddr.ddr_first = da.da_ddr.ddr_last = 0;
+       da.da_err = 0;
+
+       error = traverse_dataset(tosnap, fromtxg,
+           TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA, diff_cb, &da);
+
+       if (error != 0) {
+               da.da_err = error;
+       } else {
+               /* we set the da.da_err we return as side-effect */
+               (void) write_record(&da);
+       }
+
+       dsl_dataset_long_rele(tosnap, FTAG);
+       dsl_dataset_rele(tosnap, FTAG);
+
+       return (da.da_err);
+}
diff --git a/zfs/module/zfs/dmu_object.c b/zfs/module/zfs/dmu_object.c
new file mode 100644 (file)
index 0000000..177162f
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2015 by Delphix. All rights reserved.
+ * Copyright 2014 HybridCluster. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
+#include <sys/dnode.h>
+#include <sys/zap.h>
+#include <sys/zfeature.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)
+{
+       uint64_t object;
+       uint64_t L2_dnode_count = DNODES_PER_BLOCK <<
+           (DMU_META_DNODE(os)->dn_indblkshift - SPA_BLKPTRSHIFT);
+       dnode_t *dn = NULL;
+       int restarted = B_FALSE;
+
+       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.
+                *
+                * Note that dmu_traverse depends on the behavior that we use
+                * multiple blocks of the dnode object before going back to
+                * reuse objects.  Any change to this algorithm should preserve
+                * 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);
+                       restarted = B_TRUE;
+                       if (error == 0)
+                               object = offset >> DNODE_SHIFT;
+               }
+               os->os_obj_next = ++object;
+
+               /*
+                * XXX We should check for an i/o error here and return
+                * up to our caller.  Actually we should pre-read it in
+                * dmu_tx_assign(), but there is currently no mechanism
+                * to do so.
+                */
+               (void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE,
+                   FTAG, &dn);
+               if (dn)
+                       break;
+
+               if (dmu_object_next(os, &object, B_TRUE, 0) == 0)
+                       os->os_obj_next = object - 1;
+       }
+
+       dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
+       dnode_rele(dn, FTAG);
+
+       mutex_exit(&os->os_obj_lock);
+
+       dmu_tx_add_new_object(tx, os, object);
+       return (object);
+}
+
+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)
+{
+       dnode_t *dn;
+       int err;
+
+       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);
+       if (err)
+               return (err);
+       dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
+       dnode_rele(dn, FTAG);
+
+       dmu_tx_add_new_object(tx, os, object);
+       return (0);
+}
+
+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)
+{
+       dnode_t *dn;
+       int err;
+
+       if (object == DMU_META_DNODE_OBJECT)
+               return (SET_ERROR(EBADF));
+
+       err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
+           FTAG, &dn);
+       if (err)
+               return (err);
+
+       dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
+
+       dnode_rele(dn, FTAG);
+       return (err);
+}
+
+int
+dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       int err;
+
+       ASSERT(object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx));
+
+       err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
+           FTAG, &dn);
+       if (err)
+               return (err);
+
+       ASSERT(dn->dn_type != DMU_OT_NONE);
+       dnode_free_range(dn, 0, DMU_OBJECT_END, tx);
+       dnode_free(dn, tx);
+       dnode_rele(dn, FTAG);
+
+       return (0);
+}
+
+int
+dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
+{
+       uint64_t offset = (*objectp + 1) << DNODE_SHIFT;
+       int error;
+
+       error = dnode_next_offset(DMU_META_DNODE(os),
+           (hole ? DNODE_FIND_HOLE : 0), &offset, 0, DNODES_PER_BLOCK, txg);
+
+       *objectp = offset >> DNODE_SHIFT;
+
+       return (error);
+}
+
+/*
+ * Turn this object from old_type into DMU_OTN_ZAP_METADATA, and bump the
+ * refcount on SPA_FEATURE_EXTENSIBLE_DATASET.
+ *
+ * Only for use from syncing context, on MOS objects.
+ */
+void
+dmu_object_zapify(objset_t *mos, uint64_t object, dmu_object_type_t old_type,
+    dmu_tx_t *tx)
+{
+       dnode_t *dn;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       VERIFY0(dnode_hold(mos, object, FTAG, &dn));
+       if (dn->dn_type == DMU_OTN_ZAP_METADATA) {
+               dnode_rele(dn, FTAG);
+               return;
+       }
+       ASSERT3U(dn->dn_type, ==, old_type);
+       ASSERT0(dn->dn_maxblkid);
+       dn->dn_next_type[tx->tx_txg & TXG_MASK] = dn->dn_type =
+           DMU_OTN_ZAP_METADATA;
+       dnode_setdirty(dn, tx);
+       dnode_rele(dn, FTAG);
+
+       mzap_create_impl(mos, object, 0, 0, tx);
+
+       spa_feature_incr(dmu_objset_spa(mos),
+           SPA_FEATURE_EXTENSIBLE_DATASET, tx);
+}
+
+void
+dmu_object_free_zapified(objset_t *mos, uint64_t object, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       dmu_object_type_t t;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       VERIFY0(dnode_hold(mos, object, FTAG, &dn));
+       t = dn->dn_type;
+       dnode_rele(dn, FTAG);
+
+       if (t == DMU_OTN_ZAP_METADATA) {
+               spa_feature_decr(dmu_objset_spa(mos),
+                   SPA_FEATURE_EXTENSIBLE_DATASET, tx);
+       }
+       VERIFY0(dmu_object_free(mos, object, tx));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dmu_object_alloc);
+EXPORT_SYMBOL(dmu_object_claim);
+EXPORT_SYMBOL(dmu_object_reclaim);
+EXPORT_SYMBOL(dmu_object_free);
+EXPORT_SYMBOL(dmu_object_next);
+EXPORT_SYMBOL(dmu_object_zapify);
+EXPORT_SYMBOL(dmu_object_free_zapified);
+#endif
diff --git a/zfs/module/zfs/dmu_objset.c b/zfs/module/zfs/dmu_objset.c
new file mode 100644 (file)
index 0000000..f2d492e
--- /dev/null
@@ -0,0 +1,2052 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 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.
+ * Copyright (c) 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2015, STRATO AG, Inc. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#include <sys/cred.h>
+#include <sys/zfs_context.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dsl_deleg.h>
+#include <sys/dnode.h>
+#include <sys/dbuf.h>
+#include <sys/zvol.h>
+#include <sys/dmu_tx.h>
+#include <sys/zap.h>
+#include <sys/zil.h>
+#include <sys/dmu_impl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/sa.h>
+#include <sys/zfs_onexit.h>
+#include <sys/dsl_destroy.h>
+#include <sys/vdev.h>
+
+/*
+ * Needed to close a window in dnode_move() that allows the objset to be freed
+ * before it can be safely accessed.
+ */
+krwlock_t os_lock;
+
+/*
+ * Tunable to overwrite the maximum number of threads for the parallization
+ * of dmu_objset_find_dp, needed to speed up the import of pools with many
+ * datasets.
+ * Default is 4 times the number of leaf vdevs.
+ */
+int dmu_find_threads = 0;
+
+static void dmu_objset_find_dp_cb(void *arg);
+
+void
+dmu_objset_init(void)
+{
+       rw_init(&os_lock, NULL, RW_DEFAULT, NULL);
+}
+
+void
+dmu_objset_fini(void)
+{
+       rw_destroy(&os_lock);
+}
+
+spa_t *
+dmu_objset_spa(objset_t *os)
+{
+       return (os->os_spa);
+}
+
+zilog_t *
+dmu_objset_zil(objset_t *os)
+{
+       return (os->os_zil);
+}
+
+dsl_pool_t *
+dmu_objset_pool(objset_t *os)
+{
+       dsl_dataset_t *ds;
+
+       if ((ds = os->os_dsl_dataset) != NULL && ds->ds_dir)
+               return (ds->ds_dir->dd_pool);
+       else
+               return (spa_get_dsl(os->os_spa));
+}
+
+dsl_dataset_t *
+dmu_objset_ds(objset_t *os)
+{
+       return (os->os_dsl_dataset);
+}
+
+dmu_objset_type_t
+dmu_objset_type(objset_t *os)
+{
+       return (os->os_phys->os_type);
+}
+
+void
+dmu_objset_name(objset_t *os, char *buf)
+{
+       dsl_dataset_name(os->os_dsl_dataset, buf);
+}
+
+uint64_t
+dmu_objset_id(objset_t *os)
+{
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+
+       return (ds ? ds->ds_object : 0);
+}
+
+zfs_sync_type_t
+dmu_objset_syncprop(objset_t *os)
+{
+       return (os->os_sync);
+}
+
+zfs_logbias_op_t
+dmu_objset_logbias(objset_t *os)
+{
+       return (os->os_logbias);
+}
+
+static void
+checksum_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance should have been done by now.
+        */
+       ASSERT(newval != ZIO_CHECKSUM_INHERIT);
+
+       os->os_checksum = zio_checksum_select(newval, ZIO_CHECKSUM_ON_VALUE);
+}
+
+static void
+compression_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance and range checking should have been done by now.
+        */
+       ASSERT(newval != ZIO_COMPRESS_INHERIT);
+
+       os->os_compress = zio_compress_select(os->os_spa, newval,
+           ZIO_COMPRESS_ON);
+}
+
+static void
+copies_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance and range checking should have been done by now.
+        */
+       ASSERT(newval > 0);
+       ASSERT(newval <= spa_max_replication(os->os_spa));
+
+       os->os_copies = newval;
+}
+
+static void
+dedup_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+       spa_t *spa = os->os_spa;
+       enum zio_checksum checksum;
+
+       /*
+        * Inheritance should have been done by now.
+        */
+       ASSERT(newval != ZIO_CHECKSUM_INHERIT);
+
+       checksum = zio_checksum_dedup_select(spa, newval, ZIO_CHECKSUM_OFF);
+
+       os->os_dedup_checksum = checksum & ZIO_CHECKSUM_MASK;
+       os->os_dedup_verify = !!(checksum & ZIO_CHECKSUM_VERIFY);
+}
+
+static void
+primary_cache_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance and range checking should have been done by now.
+        */
+       ASSERT(newval == ZFS_CACHE_ALL || newval == ZFS_CACHE_NONE ||
+           newval == ZFS_CACHE_METADATA);
+
+       os->os_primary_cache = newval;
+}
+
+static void
+secondary_cache_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance and range checking should have been done by now.
+        */
+       ASSERT(newval == ZFS_CACHE_ALL || newval == ZFS_CACHE_NONE ||
+           newval == ZFS_CACHE_METADATA);
+
+       os->os_secondary_cache = newval;
+}
+
+static void
+sync_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance and range checking should have been done by now.
+        */
+       ASSERT(newval == ZFS_SYNC_STANDARD || newval == ZFS_SYNC_ALWAYS ||
+           newval == ZFS_SYNC_DISABLED);
+
+       os->os_sync = newval;
+       if (os->os_zil)
+               zil_set_sync(os->os_zil, newval);
+}
+
+static void
+redundant_metadata_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       /*
+        * Inheritance and range checking should have been done by now.
+        */
+       ASSERT(newval == ZFS_REDUNDANT_METADATA_ALL ||
+           newval == ZFS_REDUNDANT_METADATA_MOST);
+
+       os->os_redundant_metadata = newval;
+}
+
+static void
+logbias_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       ASSERT(newval == ZFS_LOGBIAS_LATENCY ||
+           newval == ZFS_LOGBIAS_THROUGHPUT);
+       os->os_logbias = newval;
+       if (os->os_zil)
+               zil_set_logbias(os->os_zil, newval);
+}
+
+static void
+recordsize_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       os->os_recordsize = newval;
+}
+
+void
+dmu_objset_byteswap(void *buf, size_t size)
+{
+       objset_phys_t *osp = buf;
+
+       ASSERT(size == OBJSET_OLD_PHYS_SIZE || size == sizeof (objset_phys_t));
+       dnode_byteswap(&osp->os_meta_dnode);
+       byteswap_uint64_array(&osp->os_zil_header, sizeof (zil_header_t));
+       osp->os_type = BSWAP_64(osp->os_type);
+       osp->os_flags = BSWAP_64(osp->os_flags);
+       if (size == sizeof (objset_phys_t)) {
+               dnode_byteswap(&osp->os_userused_dnode);
+               dnode_byteswap(&osp->os_groupused_dnode);
+       }
+}
+
+int
+dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
+    objset_t **osp)
+{
+       objset_t *os;
+       int i, err;
+
+       ASSERT(ds == NULL || MUTEX_HELD(&ds->ds_opening_lock));
+
+       os = kmem_zalloc(sizeof (objset_t), KM_SLEEP);
+       os->os_dsl_dataset = ds;
+       os->os_spa = spa;
+       os->os_rootbp = bp;
+       if (!BP_IS_HOLE(os->os_rootbp)) {
+               arc_flags_t aflags = ARC_FLAG_WAIT;
+               zbookmark_phys_t zb;
+               SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET,
+                   ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
+
+               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,
+                   arc_getbuf_func, &os->os_phys_buf,
+                   ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &aflags, &zb);
+               if (err != 0) {
+                       kmem_free(os, sizeof (objset_t));
+                       /* convert checksum errors into IO errors */
+                       if (err == ECKSUM)
+                               err = SET_ERROR(EIO);
+                       return (err);
+               }
+
+               /* 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);
+                       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);
+                       os->os_phys_buf = buf;
+               }
+
+               os->os_phys = os->os_phys_buf->b_data;
+               os->os_flags = os->os_phys->os_flags;
+       } 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 = os->os_phys_buf->b_data;
+               bzero(os->os_phys, size);
+       }
+
+       /*
+        * Note: the changed_cb will be called once before the register
+        * func returns, thus changing the checksum/compression from the
+        * default (fletcher2/off).  Snapshots don't need to know about
+        * checksum/compression/copies.
+        */
+       if (ds != NULL) {
+               err = dsl_prop_register(ds,
+                   zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE),
+                   primary_cache_changed_cb, os);
+               if (err == 0) {
+                       err = dsl_prop_register(ds,
+                           zfs_prop_to_name(ZFS_PROP_SECONDARYCACHE),
+                           secondary_cache_changed_cb, os);
+               }
+               if (!ds->ds_is_snapshot) {
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_CHECKSUM),
+                                   checksum_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_COMPRESSION),
+                                   compression_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_COPIES),
+                                   copies_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_DEDUP),
+                                   dedup_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_LOGBIAS),
+                                   logbias_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_SYNC),
+                                   sync_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(
+                                   ZFS_PROP_REDUNDANT_METADATA),
+                                   redundant_metadata_changed_cb, os);
+                       }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
+                                   recordsize_changed_cb, os);
+                       }
+               }
+               if (err != 0) {
+                       VERIFY(arc_buf_remove_ref(os->os_phys_buf,
+                           &os->os_phys_buf));
+                       kmem_free(os, sizeof (objset_t));
+                       return (err);
+               }
+       } else {
+               /* It's the meta-objset. */
+               os->os_checksum = ZIO_CHECKSUM_FLETCHER_4;
+               os->os_compress = ZIO_COMPRESS_ON;
+               os->os_copies = spa_max_replication(spa);
+               os->os_dedup_checksum = ZIO_CHECKSUM_OFF;
+               os->os_dedup_verify = B_FALSE;
+               os->os_logbias = ZFS_LOGBIAS_LATENCY;
+               os->os_sync = ZFS_SYNC_STANDARD;
+               os->os_primary_cache = ZFS_CACHE_ALL;
+               os->os_secondary_cache = ZFS_CACHE_ALL;
+       }
+
+       if (ds == NULL || !ds->ds_is_snapshot)
+               os->os_zil_header = os->os_phys->os_zil_header;
+       os->os_zil = zil_alloc(os, &os->os_zil_header);
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               list_create(&os->os_dirty_dnodes[i], sizeof (dnode_t),
+                   offsetof(dnode_t, dn_dirty_link[i]));
+               list_create(&os->os_free_dnodes[i], sizeof (dnode_t),
+                   offsetof(dnode_t, dn_dirty_link[i]));
+       }
+       list_create(&os->os_dnodes, sizeof (dnode_t),
+           offsetof(dnode_t, dn_link));
+       list_create(&os->os_downgraded_dbufs, sizeof (dmu_buf_impl_t),
+           offsetof(dmu_buf_impl_t, db_link));
+
+       list_link_init(&os->os_evicting_node);
+
+       mutex_init(&os->os_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&os->os_obj_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&os->os_user_ptr_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       dnode_special_open(os, &os->os_phys->os_meta_dnode,
+           DMU_META_DNODE_OBJECT, &os->os_meta_dnode);
+       if (arc_buf_size(os->os_phys_buf) >= sizeof (objset_phys_t)) {
+               dnode_special_open(os, &os->os_phys->os_userused_dnode,
+                   DMU_USERUSED_OBJECT, &os->os_userused_dnode);
+               dnode_special_open(os, &os->os_phys->os_groupused_dnode,
+                   DMU_GROUPUSED_OBJECT, &os->os_groupused_dnode);
+       }
+
+       *osp = os;
+       return (0);
+}
+
+int
+dmu_objset_from_ds(dsl_dataset_t *ds, objset_t **osp)
+{
+       int err = 0;
+
+       mutex_enter(&ds->ds_opening_lock);
+       if (ds->ds_objset == NULL) {
+               objset_t *os;
+               err = dmu_objset_open_impl(dsl_dataset_get_spa(ds),
+                   ds, dsl_dataset_get_blkptr(ds), &os);
+
+               if (err == 0) {
+                       mutex_enter(&ds->ds_lock);
+                       ASSERT(ds->ds_objset == NULL);
+                       ds->ds_objset = os;
+                       mutex_exit(&ds->ds_lock);
+               }
+       }
+       *osp = ds->ds_objset;
+       mutex_exit(&ds->ds_opening_lock);
+       return (err);
+}
+
+/*
+ * Holds the pool while the objset is held.  Therefore only one objset
+ * can be held at a time.
+ */
+int
+dmu_objset_hold(const char *name, void *tag, objset_t **osp)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int err;
+
+       err = dsl_pool_hold(name, tag, &dp);
+       if (err != 0)
+               return (err);
+       err = dsl_dataset_hold(dp, name, tag, &ds);
+       if (err != 0) {
+               dsl_pool_rele(dp, tag);
+               return (err);
+       }
+
+       err = dmu_objset_from_ds(ds, osp);
+       if (err != 0) {
+               dsl_dataset_rele(ds, tag);
+               dsl_pool_rele(dp, tag);
+       }
+
+       return (err);
+}
+
+static int
+dmu_objset_own_impl(dsl_dataset_t *ds, dmu_objset_type_t type,
+    boolean_t readonly, void *tag, objset_t **osp)
+{
+       int err;
+
+       err = dmu_objset_from_ds(ds, osp);
+       if (err != 0) {
+               dsl_dataset_disown(ds, tag);
+       } else if (type != DMU_OST_ANY && type != (*osp)->os_phys->os_type) {
+               dsl_dataset_disown(ds, tag);
+               return (SET_ERROR(EINVAL));
+       } else if (!readonly && dsl_dataset_is_snapshot(ds)) {
+               dsl_dataset_disown(ds, tag);
+               return (SET_ERROR(EROFS));
+       }
+       return (err);
+}
+
+/*
+ * dsl_pool must not be held when this is called.
+ * Upon successful return, there will be a longhold on the dataset,
+ * and the dsl_pool will not be held.
+ */
+int
+dmu_objset_own(const char *name, dmu_objset_type_t type,
+    boolean_t readonly, void *tag, objset_t **osp)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int err;
+
+       err = dsl_pool_hold(name, FTAG, &dp);
+       if (err != 0)
+               return (err);
+       err = dsl_dataset_own(dp, name, tag, &ds);
+       if (err != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (err);
+       }
+       err = dmu_objset_own_impl(ds, type, readonly, tag, osp);
+       dsl_pool_rele(dp, FTAG);
+
+       return (err);
+}
+
+int
+dmu_objset_own_obj(dsl_pool_t *dp, uint64_t obj, dmu_objset_type_t type,
+    boolean_t readonly, void *tag, objset_t **osp)
+{
+       dsl_dataset_t *ds;
+       int err;
+
+       err = dsl_dataset_own_obj(dp, obj, tag, &ds);
+       if (err != 0)
+               return (err);
+
+       return (dmu_objset_own_impl(ds, type, readonly, tag, osp));
+}
+
+void
+dmu_objset_rele(objset_t *os, void *tag)
+{
+       dsl_pool_t *dp = dmu_objset_pool(os);
+       dsl_dataset_rele(os->os_dsl_dataset, tag);
+       dsl_pool_rele(dp, tag);
+}
+
+/*
+ * When we are called, os MUST refer to an objset associated with a dataset
+ * that is owned by 'tag'; that is, is held and long held by 'tag' and ds_owner
+ * == tag.  We will then release and reacquire ownership of the dataset while
+ * holding the pool config_rwlock to avoid intervening namespace or ownership
+ * changes may occur.
+ *
+ * This exists solely to accommodate zfs_ioc_userspace_upgrade()'s desire to
+ * release the hold on its dataset and acquire a new one on the dataset of the
+ * same name so that it can be partially torn down and reconstructed.
+ */
+void
+dmu_objset_refresh_ownership(objset_t *os, void *tag)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds, *newds;
+       char name[MAXNAMELEN];
+
+       ds = os->os_dsl_dataset;
+       VERIFY3P(ds, !=, NULL);
+       VERIFY3P(ds->ds_owner, ==, tag);
+       VERIFY(dsl_dataset_long_held(ds));
+
+       dsl_dataset_name(ds, name);
+       dp = dmu_objset_pool(os);
+       dsl_pool_config_enter(dp, FTAG);
+       dmu_objset_disown(os, tag);
+       VERIFY0(dsl_dataset_own(dp, name, tag, &newds));
+       VERIFY3P(newds, ==, os->os_dsl_dataset);
+       dsl_pool_config_exit(dp, FTAG);
+}
+
+void
+dmu_objset_disown(objset_t *os, void *tag)
+{
+       dsl_dataset_disown(os->os_dsl_dataset, tag);
+}
+
+void
+dmu_objset_evict_dbufs(objset_t *os)
+{
+       dnode_t *dn_marker;
+       dnode_t *dn;
+
+       dn_marker = kmem_alloc(sizeof (dnode_t), KM_SLEEP);
+
+       mutex_enter(&os->os_lock);
+       dn = list_head(&os->os_dnodes);
+       while (dn != NULL) {
+               /*
+                * Skip dnodes without holds.  We have to do this dance
+                * because dnode_add_ref() only works if there is already a
+                * hold.  If the dnode has no holds, then it has no dbufs.
+                */
+               if (dnode_add_ref(dn, FTAG)) {
+                       list_insert_after(&os->os_dnodes, dn, dn_marker);
+                       mutex_exit(&os->os_lock);
+
+                       dnode_evict_dbufs(dn);
+                       dnode_rele(dn, FTAG);
+
+                       mutex_enter(&os->os_lock);
+                       dn = list_next(&os->os_dnodes, dn_marker);
+                       list_remove(&os->os_dnodes, dn_marker);
+               } else {
+                       dn = list_next(&os->os_dnodes, dn);
+               }
+       }
+       mutex_exit(&os->os_lock);
+
+       kmem_free(dn_marker, sizeof (dnode_t));
+
+       if (DMU_USERUSED_DNODE(os) != NULL) {
+               dnode_evict_dbufs(DMU_GROUPUSED_DNODE(os));
+               dnode_evict_dbufs(DMU_USERUSED_DNODE(os));
+       }
+       dnode_evict_dbufs(DMU_META_DNODE(os));
+}
+
+/*
+ * Objset eviction processing is split into into two pieces.
+ * The first marks the objset as evicting, evicts any dbufs that
+ * have a refcount of zero, and then queues up the objset for the
+ * second phase of eviction.  Once os->os_dnodes has been cleared by
+ * dnode_buf_pageout()->dnode_destroy(), the second phase is executed.
+ * The second phase closes the special dnodes, dequeues the objset from
+ * the list of those undergoing eviction, and finally frees the objset.
+ *
+ * NOTE: Due to asynchronous eviction processing (invocation of
+ *       dnode_buf_pageout()), it is possible for the meta dnode for the
+ *       objset to have no holds even though os->os_dnodes is not empty.
+ */
+void
+dmu_objset_evict(objset_t *os)
+{
+       int t;
+
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+
+       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 (os->os_sa)
+               sa_tear_down(os);
+
+       dmu_objset_evict_dbufs(os);
+
+       mutex_enter(&os->os_lock);
+       spa_evicting_os_register(os->os_spa, os);
+       if (list_is_empty(&os->os_dnodes)) {
+               mutex_exit(&os->os_lock);
+               dmu_objset_evict_done(os);
+       } else {
+               mutex_exit(&os->os_lock);
+       }
+}
+
+void
+dmu_objset_evict_done(objset_t *os)
+{
+       ASSERT3P(list_head(&os->os_dnodes), ==, NULL);
+
+       dnode_special_close(&os->os_meta_dnode);
+       if (DMU_USERUSED_DNODE(os)) {
+               dnode_special_close(&os->os_userused_dnode);
+               dnode_special_close(&os->os_groupused_dnode);
+       }
+       zil_free(os->os_zil);
+
+       VERIFY(arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf));
+
+       /*
+        * This is a barrier to prevent the objset from going away in
+        * dnode_move() until we can safely ensure that the objset is still in
+        * use. We consider the objset valid before the barrier and invalid
+        * after the barrier.
+        */
+       rw_enter(&os_lock, RW_READER);
+       rw_exit(&os_lock);
+
+       mutex_destroy(&os->os_lock);
+       mutex_destroy(&os->os_obj_lock);
+       mutex_destroy(&os->os_user_ptr_lock);
+       spa_evicting_os_deregister(os->os_spa, os);
+       kmem_free(os, sizeof (objset_t));
+}
+
+timestruc_t
+dmu_objset_snap_cmtime(objset_t *os)
+{
+       return (dsl_dir_snap_cmtime(os->os_dsl_dataset->ds_dir));
+}
+
+/* called from dsl for meta-objset */
+objset_t *
+dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
+    dmu_objset_type_t type, dmu_tx_t *tx)
+{
+       objset_t *os;
+       dnode_t *mdn;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       if (ds != NULL)
+               VERIFY0(dmu_objset_from_ds(ds, &os));
+       else
+               VERIFY0(dmu_objset_open_impl(spa, NULL, bp, &os));
+
+       mdn = DMU_META_DNODE(os);
+
+       dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
+           DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx);
+
+       /*
+        * We don't want to have to increase the meta-dnode's nlevels
+        * later, because then we could do it in quescing context while
+        * we are also accessing it in open context.
+        *
+        * This precaution is not necessary for the MOS (ds == NULL),
+        * because the MOS is only updated in syncing context.
+        * This is most fortunate: the MOS is the only objset that
+        * needs to be synced multiple times as spa_sync() iterates
+        * to convergence, so minimizing its dn_nlevels matters.
+        */
+       if (ds != NULL) {
+               int levels = 1;
+
+               /*
+                * Determine the number of levels necessary for the meta-dnode
+                * to contain DN_MAX_OBJECT dnodes.
+                */
+               while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift +
+                   (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) <
+                   DN_MAX_OBJECT * sizeof (dnode_phys_t))
+                       levels++;
+
+               mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] =
+                   mdn->dn_nlevels = levels;
+       }
+
+       ASSERT(type != DMU_OST_NONE);
+       ASSERT(type != DMU_OST_ANY);
+       ASSERT(type < DMU_OST_NUMTYPES);
+       os->os_phys->os_type = type;
+       if (dmu_objset_userused_enabled(os)) {
+               os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
+               os->os_flags = os->os_phys->os_flags;
+       }
+
+       dsl_dataset_dirty(ds, tx);
+
+       return (os);
+}
+
+typedef struct dmu_objset_create_arg {
+       const char *doca_name;
+       cred_t *doca_cred;
+       void (*doca_userfunc)(objset_t *os, void *arg,
+           cred_t *cr, dmu_tx_t *tx);
+       void *doca_userarg;
+       dmu_objset_type_t doca_type;
+       uint64_t doca_flags;
+} dmu_objset_create_arg_t;
+
+/*ARGSUSED*/
+static int
+dmu_objset_create_check(void *arg, dmu_tx_t *tx)
+{
+       dmu_objset_create_arg_t *doca = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *pdd;
+       const char *tail;
+       int error;
+
+       if (strchr(doca->doca_name, '@') != NULL)
+               return (SET_ERROR(EINVAL));
+
+       error = dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail);
+       if (error != 0)
+               return (error);
+       if (tail == NULL) {
+               dsl_dir_rele(pdd, FTAG);
+               return (SET_ERROR(EEXIST));
+       }
+       error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
+           doca->doca_cred);
+       dsl_dir_rele(pdd, FTAG);
+
+       return (error);
+}
+
+static void
+dmu_objset_create_sync(void *arg, dmu_tx_t *tx)
+{
+       dmu_objset_create_arg_t *doca = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *pdd;
+       const char *tail;
+       dsl_dataset_t *ds;
+       uint64_t obj;
+       blkptr_t *bp;
+       objset_t *os;
+
+       VERIFY0(dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail));
+
+       obj = dsl_dataset_create_sync(pdd, tail, NULL, doca->doca_flags,
+           doca->doca_cred, tx);
+
+       VERIFY0(dsl_dataset_hold_obj(pdd->dd_pool, obj, FTAG, &ds));
+       bp = dsl_dataset_get_blkptr(ds);
+       os = dmu_objset_create_impl(pdd->dd_pool->dp_spa,
+           ds, bp, doca->doca_type, tx);
+
+       if (doca->doca_userfunc != NULL) {
+               doca->doca_userfunc(os, doca->doca_userarg,
+                   doca->doca_cred, tx);
+       }
+
+       spa_history_log_internal_ds(ds, "create", tx, "");
+       zvol_create_minors(dp->dp_spa, doca->doca_name, B_TRUE);
+
+       dsl_dataset_rele(ds, FTAG);
+       dsl_dir_rele(pdd, FTAG);
+}
+
+int
+dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
+    void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg)
+{
+       dmu_objset_create_arg_t doca;
+
+       doca.doca_name = name;
+       doca.doca_cred = CRED();
+       doca.doca_flags = flags;
+       doca.doca_userfunc = func;
+       doca.doca_userarg = arg;
+       doca.doca_type = type;
+
+       return (dsl_sync_task(name,
+           dmu_objset_create_check, dmu_objset_create_sync, &doca,
+           5, ZFS_SPACE_CHECK_NORMAL));
+}
+
+typedef struct dmu_objset_clone_arg {
+       const char *doca_clone;
+       const char *doca_origin;
+       cred_t *doca_cred;
+} dmu_objset_clone_arg_t;
+
+/*ARGSUSED*/
+static int
+dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
+{
+       dmu_objset_clone_arg_t *doca = arg;
+       dsl_dir_t *pdd;
+       const char *tail;
+       int error;
+       dsl_dataset_t *origin;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+
+       if (strchr(doca->doca_clone, '@') != NULL)
+               return (SET_ERROR(EINVAL));
+
+       error = dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail);
+       if (error != 0)
+               return (error);
+       if (tail == NULL) {
+               dsl_dir_rele(pdd, FTAG);
+               return (SET_ERROR(EEXIST));
+       }
+
+       error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
+           doca->doca_cred);
+       if (error != 0) {
+               dsl_dir_rele(pdd, FTAG);
+               return (SET_ERROR(EDQUOT));
+       }
+       dsl_dir_rele(pdd, FTAG);
+
+       error = dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin);
+       if (error != 0)
+               return (error);
+
+       /* You can only clone snapshots, not the head datasets. */
+       if (!origin->ds_is_snapshot) {
+               dsl_dataset_rele(origin, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+       dsl_dataset_rele(origin, FTAG);
+
+       return (0);
+}
+
+static void
+dmu_objset_clone_sync(void *arg, dmu_tx_t *tx)
+{
+       dmu_objset_clone_arg_t *doca = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *pdd;
+       const char *tail;
+       dsl_dataset_t *origin, *ds;
+       uint64_t obj;
+       char namebuf[MAXNAMELEN];
+
+       VERIFY0(dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail));
+       VERIFY0(dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin));
+
+       obj = dsl_dataset_create_sync(pdd, tail, origin, 0,
+           doca->doca_cred, tx);
+
+       VERIFY0(dsl_dataset_hold_obj(pdd->dd_pool, obj, FTAG, &ds));
+       dsl_dataset_name(origin, namebuf);
+       spa_history_log_internal_ds(ds, "clone", tx,
+           "origin=%s (%llu)", namebuf, origin->ds_object);
+       zvol_create_minors(dp->dp_spa, doca->doca_clone, B_TRUE);
+       dsl_dataset_rele(ds, FTAG);
+       dsl_dataset_rele(origin, FTAG);
+       dsl_dir_rele(pdd, FTAG);
+}
+
+int
+dmu_objset_clone(const char *clone, const char *origin)
+{
+       dmu_objset_clone_arg_t doca;
+
+       doca.doca_clone = clone;
+       doca.doca_origin = origin;
+       doca.doca_cred = CRED();
+
+       return (dsl_sync_task(clone,
+           dmu_objset_clone_check, dmu_objset_clone_sync, &doca,
+           5, ZFS_SPACE_CHECK_NORMAL));
+}
+
+int
+dmu_objset_snapshot_one(const char *fsname, const char *snapname)
+{
+       int err;
+       char *longsnap = kmem_asprintf("%s@%s", fsname, snapname);
+       nvlist_t *snaps = fnvlist_alloc();
+
+       fnvlist_add_boolean(snaps, longsnap);
+       strfree(longsnap);
+       err = dsl_dataset_snapshot(snaps, NULL, NULL);
+       fnvlist_free(snaps);
+       return (err);
+}
+
+static void
+dmu_objset_sync_dnodes(list_t *list, list_t *newlist, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+
+       while ((dn = list_head(list))) {
+               ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT);
+               ASSERT(dn->dn_dbuf->db_data_pending);
+               /*
+                * Initialize dn_zio outside dnode_sync() because the
+                * meta-dnode needs to set it ouside dnode_sync().
+                */
+               dn->dn_zio = dn->dn_dbuf->db_data_pending->dr_zio;
+               ASSERT(dn->dn_zio);
+
+               ASSERT3U(dn->dn_nlevels, <=, DN_MAX_LEVELS);
+               list_remove(list, dn);
+
+               if (newlist) {
+                       (void) dnode_add_ref(dn, newlist);
+                       list_insert_tail(newlist, dn);
+               }
+
+               dnode_sync(dn, tx);
+       }
+}
+
+/* ARGSUSED */
+static void
+dmu_objset_write_ready(zio_t *zio, arc_buf_t *abuf, void *arg)
+{
+       int i;
+
+       blkptr_t *bp = zio->io_bp;
+       objset_t *os = arg;
+       dnode_phys_t *dnp = &os->os_phys->os_meta_dnode;
+
+       ASSERT(!BP_IS_EMBEDDED(bp));
+       ASSERT3P(bp, ==, os->os_rootbp);
+       ASSERT3U(BP_GET_TYPE(bp), ==, DMU_OT_OBJSET);
+       ASSERT0(BP_GET_LEVEL(bp));
+
+       /*
+        * Update rootbp fill count: it should be the number of objects
+        * allocated in the object set (not counting the "special"
+        * objects that are stored in the objset_phys_t -- the meta
+        * dnode and user/group accounting objects).
+        */
+       bp->blk_fill = 0;
+       for (i = 0; i < dnp->dn_nblkptr; i++)
+               bp->blk_fill += BP_GET_FILL(&dnp->dn_blkptr[i]);
+}
+
+/* ARGSUSED */
+static void
+dmu_objset_write_done(zio_t *zio, arc_buf_t *abuf, void *arg)
+{
+       blkptr_t *bp = zio->io_bp;
+       blkptr_t *bp_orig = &zio->io_bp_orig;
+       objset_t *os = arg;
+
+       if (zio->io_flags & ZIO_FLAG_IO_REWRITE) {
+               ASSERT(BP_EQUAL(bp, bp_orig));
+       } else {
+               dsl_dataset_t *ds = os->os_dsl_dataset;
+               dmu_tx_t *tx = os->os_synctx;
+
+               (void) dsl_dataset_block_kill(ds, bp_orig, tx, B_TRUE);
+               dsl_dataset_block_born(ds, bp, tx);
+       }
+}
+
+/* called from dsl */
+void
+dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
+{
+       int txgoff;
+       zbookmark_phys_t zb;
+       zio_prop_t zp;
+       zio_t *zio;
+       list_t *list;
+       list_t *newlist = NULL;
+       dbuf_dirty_record_t *dr;
+
+       dprintf_ds(os->os_dsl_dataset, "txg=%llu\n", tx->tx_txg);
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       /* XXX the write_done callback should really give us the tx... */
+       os->os_synctx = tx;
+
+       if (os->os_dsl_dataset == NULL) {
+               /*
+                * This is the MOS.  If we have upgraded,
+                * spa_max_replication() could change, so reset
+                * os_copies here.
+                */
+               os->os_copies = spa_max_replication(os->os_spa);
+       }
+
+       /*
+        * Create the root block IO
+        */
+       SET_BOOKMARK(&zb, os->os_dsl_dataset ?
+           os->os_dsl_dataset->ds_object : DMU_META_OBJSET,
+           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);
+
+       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);
+
+       /*
+        * Sync special dnodes - the parent IO for the sync is the root block
+        */
+       DMU_META_DNODE(os)->dn_zio = zio;
+       dnode_sync(DMU_META_DNODE(os), tx);
+
+       os->os_phys->os_flags = os->os_flags;
+
+       if (DMU_USERUSED_DNODE(os) &&
+           DMU_USERUSED_DNODE(os)->dn_type != DMU_OT_NONE) {
+               DMU_USERUSED_DNODE(os)->dn_zio = zio;
+               dnode_sync(DMU_USERUSED_DNODE(os), tx);
+               DMU_GROUPUSED_DNODE(os)->dn_zio = zio;
+               dnode_sync(DMU_GROUPUSED_DNODE(os), tx);
+       }
+
+       txgoff = tx->tx_txg & TXG_MASK;
+
+       if (dmu_objset_userused_enabled(os)) {
+               newlist = &os->os_synced_dnodes;
+               /*
+                * We must create the list here because it uses the
+                * dn_dirty_link[] of this txg.
+                */
+               list_create(newlist, sizeof (dnode_t),
+                   offsetof(dnode_t, dn_dirty_link[txgoff]));
+       }
+
+       dmu_objset_sync_dnodes(&os->os_free_dnodes[txgoff], newlist, tx);
+       dmu_objset_sync_dnodes(&os->os_dirty_dnodes[txgoff], newlist, tx);
+
+       list = &DMU_META_DNODE(os)->dn_dirty_records[txgoff];
+       while ((dr = list_head(list))) {
+               ASSERT0(dr->dr_dbuf->db_level);
+               list_remove(list, dr);
+               if (dr->dr_zio)
+                       zio_nowait(dr->dr_zio);
+       }
+       /*
+        * Free intent log blocks up to this tx.
+        */
+       zil_sync(os->os_zil, tx);
+       os->os_phys->os_zil_header = os->os_zil_header;
+       zio_nowait(zio);
+}
+
+boolean_t
+dmu_objset_is_dirty(objset_t *os, uint64_t txg)
+{
+       return (!list_is_empty(&os->os_dirty_dnodes[txg & TXG_MASK]) ||
+           !list_is_empty(&os->os_free_dnodes[txg & TXG_MASK]));
+}
+
+static objset_used_cb_t *used_cbs[DMU_OST_NUMTYPES];
+
+void
+dmu_objset_register_type(dmu_objset_type_t ost, objset_used_cb_t *cb)
+{
+       used_cbs[ost] = cb;
+}
+
+boolean_t
+dmu_objset_userused_enabled(objset_t *os)
+{
+       return (spa_version(os->os_spa) >= SPA_VERSION_USERSPACE &&
+           used_cbs[os->os_phys->os_type] != NULL &&
+           DMU_USERUSED_DNODE(os) != NULL);
+}
+
+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)
+{
+       if ((flags & DNODE_FLAG_USERUSED_ACCOUNTED)) {
+               int64_t delta = DNODE_SIZE + used;
+               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
+dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       list_t *list = &os->os_synced_dnodes;
+
+       ASSERT(list_head(list) == NULL || dmu_objset_userused_enabled(os));
+
+       while ((dn = list_head(list))) {
+               int flags;
+               ASSERT(!DMU_OBJECT_IS_SPECIAL(dn->dn_object));
+               ASSERT(dn->dn_phys->dn_type == DMU_OT_NONE ||
+                   dn->dn_phys->dn_flags &
+                   DNODE_FLAG_USERUSED_ACCOUNTED);
+
+               /* 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,
+                           DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx));
+                       VERIFY(0 == 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);
+               }
+               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);
+               }
+
+               mutex_enter(&dn->dn_mtx);
+               dn->dn_oldused = 0;
+               dn->dn_oldflags = 0;
+               if (dn->dn_id_flags & DN_ID_NEW_EXIST) {
+                       dn->dn_olduid = dn->dn_newuid;
+                       dn->dn_oldgid = dn->dn_newgid;
+                       dn->dn_id_flags |= DN_ID_OLD_EXIST;
+                       if (dn->dn_bonuslen == 0)
+                               dn->dn_id_flags |= DN_ID_CHKED_SPILL;
+                       else
+                               dn->dn_id_flags |= DN_ID_CHKED_BONUS;
+               }
+               dn->dn_id_flags &= ~(DN_ID_NEW_EXIST);
+               mutex_exit(&dn->dn_mtx);
+
+               list_remove(list, dn);
+               dnode_rele(dn, list);
+       }
+}
+
+/*
+ * Returns a pointer to data to find uid/gid from
+ *
+ * If a dirty record for transaction group that is syncing can't
+ * be found then NULL is returned.  In the NULL case it is assumed
+ * the uid/gid aren't changing.
+ */
+static void *
+dmu_objset_userquota_find_data(dmu_buf_impl_t *db, dmu_tx_t *tx)
+{
+       dbuf_dirty_record_t *dr, **drp;
+       void *data;
+
+       if (db->db_dirtycnt == 0)
+               return (db->db.db_data);  /* Nothing is changing */
+
+       for (drp = &db->db_last_dirty; (dr = *drp) != NULL; drp = &dr->dr_next)
+               if (dr->dr_txg == tx->tx_txg)
+                       break;
+
+       if (dr == NULL) {
+               data = NULL;
+       } else {
+               dnode_t *dn;
+
+               DB_DNODE_ENTER(dr->dr_dbuf);
+               dn = DB_DNODE(dr->dr_dbuf);
+
+               if (dn->dn_bonuslen == 0 &&
+                   dr->dr_dbuf->db_blkid == DMU_SPILL_BLKID)
+                       data = dr->dt.dl.dr_data->b_data;
+               else
+                       data = dr->dt.dl.dr_data;
+
+               DB_DNODE_EXIT(dr->dr_dbuf);
+       }
+
+       return (data);
+}
+
+void
+dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx)
+{
+       objset_t *os = dn->dn_objset;
+       void *data = NULL;
+       dmu_buf_impl_t *db = NULL;
+       uint64_t *user = NULL;
+       uint64_t *group = NULL;
+       int flags = dn->dn_id_flags;
+       int error;
+       boolean_t have_spill = B_FALSE;
+
+       if (!dmu_objset_userused_enabled(dn->dn_objset))
+               return;
+
+       if (before && (flags & (DN_ID_CHKED_BONUS|DN_ID_OLD_EXIST|
+           DN_ID_CHKED_SPILL)))
+               return;
+
+       if (before && dn->dn_bonuslen != 0)
+               data = DN_BONUS(dn->dn_phys);
+       else if (!before && dn->dn_bonuslen != 0) {
+               if (dn->dn_bonus) {
+                       db = dn->dn_bonus;
+                       mutex_enter(&db->db_mtx);
+                       data = dmu_objset_userquota_find_data(db, tx);
+               } else {
+                       data = DN_BONUS(dn->dn_phys);
+               }
+       } else if (dn->dn_bonuslen == 0 && dn->dn_bonustype == DMU_OT_SA) {
+                       int rf = 0;
+
+                       if (RW_WRITE_HELD(&dn->dn_struct_rwlock))
+                               rf |= DB_RF_HAVESTRUCT;
+                       error = dmu_spill_hold_by_dnode(dn,
+                           rf | DB_RF_MUST_SUCCEED,
+                           FTAG, (dmu_buf_t **)&db);
+                       ASSERT(error == 0);
+                       mutex_enter(&db->db_mtx);
+                       data = (before) ? db->db.db_data :
+                           dmu_objset_userquota_find_data(db, tx);
+                       have_spill = B_TRUE;
+       } else {
+               mutex_enter(&dn->dn_mtx);
+               dn->dn_id_flags |= DN_ID_CHKED_BONUS;
+               mutex_exit(&dn->dn_mtx);
+               return;
+       }
+
+       if (before) {
+               ASSERT(data);
+               user = &dn->dn_olduid;
+               group = &dn->dn_oldgid;
+       } else if (data) {
+               user = &dn->dn_newuid;
+               group = &dn->dn_newgid;
+       }
+
+       /*
+        * Must always call the callback in case the object
+        * type has changed and that type isn't an object type to track
+        */
+       error = used_cbs[os->os_phys->os_type](dn->dn_bonustype, data,
+           user, group);
+
+       /*
+        * Preserve existing uid/gid when the callback can't determine
+        * what the new uid/gid are and the callback returned EEXIST.
+        * The EEXIST error tells us to just use the existing uid/gid.
+        * If we don't know what the old values are then just assign
+        * them to 0, since that is a new file  being created.
+        */
+       if (!before && data == NULL && error == EEXIST) {
+               if (flags & DN_ID_OLD_EXIST) {
+                       dn->dn_newuid = dn->dn_olduid;
+                       dn->dn_newgid = dn->dn_oldgid;
+               } else {
+                       dn->dn_newuid = 0;
+                       dn->dn_newgid = 0;
+               }
+               error = 0;
+       }
+
+       if (db)
+               mutex_exit(&db->db_mtx);
+
+       mutex_enter(&dn->dn_mtx);
+       if (error == 0 && before)
+               dn->dn_id_flags |= DN_ID_OLD_EXIST;
+       if (error == 0 && !before)
+               dn->dn_id_flags |= DN_ID_NEW_EXIST;
+
+       if (have_spill) {
+               dn->dn_id_flags |= DN_ID_CHKED_SPILL;
+       } else {
+               dn->dn_id_flags |= DN_ID_CHKED_BONUS;
+       }
+       mutex_exit(&dn->dn_mtx);
+       if (have_spill)
+               dmu_buf_rele((dmu_buf_t *)db, FTAG);
+}
+
+boolean_t
+dmu_objset_userspace_present(objset_t *os)
+{
+       return (os->os_phys->os_flags &
+           OBJSET_FLAG_USERACCOUNTING_COMPLETE);
+}
+
+int
+dmu_objset_userspace_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
+        * concurrently, or if we already did some work before crashing,
+        * that's fine, since we track each object's accounted state
+        * independently.
+        */
+
+       for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 0)) {
+               dmu_tx_t *tx;
+               dmu_buf_t *db;
+               int objerr;
+
+               if (issig(JUSTLOOKING) && issig(FORREAL))
+                       return (SET_ERROR(EINTR));
+
+               objerr = dmu_bonus_hold(os, obj, FTAG, &db);
+               if (objerr != 0)
+                       continue;
+               tx = dmu_tx_create(os);
+               dmu_tx_hold_bonus(tx, obj);
+               objerr = dmu_tx_assign(tx, TXG_WAIT);
+               if (objerr != 0) {
+                       dmu_tx_abort(tx);
+                       continue;
+               }
+               dmu_buf_will_dirty(db, tx);
+               dmu_buf_rele(db, FTAG);
+               dmu_tx_commit(tx);
+       }
+
+       os->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
+       txg_wait_synced(dmu_objset_pool(os), 0);
+       return (0);
+}
+
+void
+dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp,
+    uint64_t *usedobjsp, uint64_t *availobjsp)
+{
+       dsl_dataset_space(os->os_dsl_dataset, refdbytesp, availbytesp,
+           usedobjsp, availobjsp);
+}
+
+uint64_t
+dmu_objset_fsid_guid(objset_t *os)
+{
+       return (dsl_dataset_fsid_guid(os->os_dsl_dataset));
+}
+
+void
+dmu_objset_fast_stat(objset_t *os, dmu_objset_stats_t *stat)
+{
+       stat->dds_type = os->os_phys->os_type;
+       if (os->os_dsl_dataset)
+               dsl_dataset_fast_stat(os->os_dsl_dataset, stat);
+}
+
+void
+dmu_objset_stats(objset_t *os, nvlist_t *nv)
+{
+       ASSERT(os->os_dsl_dataset ||
+           os->os_phys->os_type == DMU_OST_META);
+
+       if (os->os_dsl_dataset != NULL)
+               dsl_dataset_stats(os->os_dsl_dataset, nv);
+
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_TYPE,
+           os->os_phys->os_type);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERACCOUNTING,
+           dmu_objset_userspace_present(os));
+}
+
+int
+dmu_objset_is_snapshot(objset_t *os)
+{
+       if (os->os_dsl_dataset != NULL)
+               return (os->os_dsl_dataset->ds_is_snapshot);
+       else
+               return (B_FALSE);
+}
+
+int
+dmu_snapshot_realname(objset_t *os, char *name, char *real, int maxlen,
+    boolean_t *conflict)
+{
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+       uint64_t ignored;
+
+       if (dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0)
+               return (SET_ERROR(ENOENT));
+
+       return (zap_lookup_norm(ds->ds_dir->dd_pool->dp_meta_objset,
+           dsl_dataset_phys(ds)->ds_snapnames_zapobj, name, 8, 1, &ignored,
+           MT_FIRST, real, maxlen, conflict));
+}
+
+int
+dmu_snapshot_list_next(objset_t *os, int namelen, char *name,
+    uint64_t *idp, uint64_t *offp, boolean_t *case_conflict)
+{
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+       zap_cursor_t cursor;
+       zap_attribute_t attr;
+
+       ASSERT(dsl_pool_config_held(dmu_objset_pool(os)));
+
+       if (dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0)
+               return (SET_ERROR(ENOENT));
+
+       zap_cursor_init_serialized(&cursor,
+           ds->ds_dir->dd_pool->dp_meta_objset,
+           dsl_dataset_phys(ds)->ds_snapnames_zapobj, *offp);
+
+       if (zap_cursor_retrieve(&cursor, &attr) != 0) {
+               zap_cursor_fini(&cursor);
+               return (SET_ERROR(ENOENT));
+       }
+
+       if (strlen(attr.za_name) + 1 > namelen) {
+               zap_cursor_fini(&cursor);
+               return (SET_ERROR(ENAMETOOLONG));
+       }
+
+       (void) strcpy(name, attr.za_name);
+       if (idp)
+               *idp = attr.za_first_integer;
+       if (case_conflict)
+               *case_conflict = attr.za_normalization_conflict;
+       zap_cursor_advance(&cursor);
+       *offp = zap_cursor_serialize(&cursor);
+       zap_cursor_fini(&cursor);
+
+       return (0);
+}
+
+int
+dmu_snapshot_lookup(objset_t *os, const char *name, uint64_t *value)
+{
+       return (dsl_dataset_snap_lookup(os->os_dsl_dataset, name, value));
+}
+
+int
+dmu_dir_list_next(objset_t *os, int namelen, char *name,
+    uint64_t *idp, uint64_t *offp)
+{
+       dsl_dir_t *dd = os->os_dsl_dataset->ds_dir;
+       zap_cursor_t cursor;
+       zap_attribute_t attr;
+
+       /* there is no next dir on a snapshot! */
+       if (os->os_dsl_dataset->ds_object !=
+           dsl_dir_phys(dd)->dd_head_dataset_obj)
+               return (SET_ERROR(ENOENT));
+
+       zap_cursor_init_serialized(&cursor,
+           dd->dd_pool->dp_meta_objset,
+           dsl_dir_phys(dd)->dd_child_dir_zapobj, *offp);
+
+       if (zap_cursor_retrieve(&cursor, &attr) != 0) {
+               zap_cursor_fini(&cursor);
+               return (SET_ERROR(ENOENT));
+       }
+
+       if (strlen(attr.za_name) + 1 > namelen) {
+               zap_cursor_fini(&cursor);
+               return (SET_ERROR(ENAMETOOLONG));
+       }
+
+       (void) strcpy(name, attr.za_name);
+       if (idp)
+               *idp = attr.za_first_integer;
+       zap_cursor_advance(&cursor);
+       *offp = zap_cursor_serialize(&cursor);
+       zap_cursor_fini(&cursor);
+
+       return (0);
+}
+
+typedef struct dmu_objset_find_ctx {
+       taskq_t         *dc_tq;
+       dsl_pool_t      *dc_dp;
+       uint64_t        dc_ddobj;
+       int             (*dc_func)(dsl_pool_t *, dsl_dataset_t *, void *);
+       void            *dc_arg;
+       int             dc_flags;
+       kmutex_t        *dc_error_lock;
+       int             *dc_error;
+} dmu_objset_find_ctx_t;
+
+static void
+dmu_objset_find_dp_impl(dmu_objset_find_ctx_t *dcp)
+{
+       dsl_pool_t *dp = dcp->dc_dp;
+       dmu_objset_find_ctx_t *child_dcp;
+       dsl_dir_t *dd;
+       dsl_dataset_t *ds;
+       zap_cursor_t zc;
+       zap_attribute_t *attr;
+       uint64_t thisobj;
+       int err = 0;
+
+       /* don't process if there already was an error */
+       if (*dcp->dc_error != 0)
+               goto out;
+
+       err = dsl_dir_hold_obj(dp, dcp->dc_ddobj, NULL, FTAG, &dd);
+       if (err != 0)
+               goto out;
+
+       /* Don't visit hidden ($MOS & $ORIGIN) objsets. */
+       if (dd->dd_myname[0] == '$') {
+               dsl_dir_rele(dd, FTAG);
+               goto out;
+       }
+
+       thisobj = dsl_dir_phys(dd)->dd_head_dataset_obj;
+       attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+
+       /*
+        * Iterate over all children.
+        */
+       if (dcp->dc_flags & DS_FIND_CHILDREN) {
+               for (zap_cursor_init(&zc, dp->dp_meta_objset,
+                   dsl_dir_phys(dd)->dd_child_dir_zapobj);
+                   zap_cursor_retrieve(&zc, attr) == 0;
+                   (void) zap_cursor_advance(&zc)) {
+                       ASSERT3U(attr->za_integer_length, ==,
+                           sizeof (uint64_t));
+                       ASSERT3U(attr->za_num_integers, ==, 1);
+
+                       child_dcp = kmem_alloc(sizeof (*child_dcp), KM_SLEEP);
+                       *child_dcp = *dcp;
+                       child_dcp->dc_ddobj = attr->za_first_integer;
+                       if (dcp->dc_tq != NULL)
+                               (void) taskq_dispatch(dcp->dc_tq,
+                                   dmu_objset_find_dp_cb, child_dcp, TQ_SLEEP);
+                       else
+                               dmu_objset_find_dp_impl(child_dcp);
+               }
+               zap_cursor_fini(&zc);
+       }
+
+       /*
+        * Iterate over all snapshots.
+        */
+       if (dcp->dc_flags & DS_FIND_SNAPSHOTS) {
+               dsl_dataset_t *ds;
+               err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds);
+
+               if (err == 0) {
+                       uint64_t snapobj;
+
+                       snapobj = dsl_dataset_phys(ds)->ds_snapnames_zapobj;
+                       dsl_dataset_rele(ds, FTAG);
+
+                       for (zap_cursor_init(&zc, dp->dp_meta_objset, snapobj);
+                           zap_cursor_retrieve(&zc, attr) == 0;
+                           (void) zap_cursor_advance(&zc)) {
+                               ASSERT3U(attr->za_integer_length, ==,
+                                   sizeof (uint64_t));
+                               ASSERT3U(attr->za_num_integers, ==, 1);
+
+                               err = dsl_dataset_hold_obj(dp,
+                                   attr->za_first_integer, FTAG, &ds);
+                               if (err != 0)
+                                       break;
+                               err = dcp->dc_func(dp, ds, dcp->dc_arg);
+                               dsl_dataset_rele(ds, FTAG);
+                               if (err != 0)
+                                       break;
+                       }
+                       zap_cursor_fini(&zc);
+               }
+       }
+
+       dsl_dir_rele(dd, FTAG);
+       kmem_free(attr, sizeof (zap_attribute_t));
+
+       if (err != 0)
+               goto out;
+
+       /*
+        * Apply to self.
+        */
+       err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds);
+       if (err != 0)
+               goto out;
+       err = dcp->dc_func(dp, ds, dcp->dc_arg);
+       dsl_dataset_rele(ds, FTAG);
+
+out:
+       if (err != 0) {
+               mutex_enter(dcp->dc_error_lock);
+               /* only keep first error */
+               if (*dcp->dc_error == 0)
+                       *dcp->dc_error = err;
+               mutex_exit(dcp->dc_error_lock);
+       }
+
+       kmem_free(dcp, sizeof (*dcp));
+}
+
+static void
+dmu_objset_find_dp_cb(void *arg)
+{
+       dmu_objset_find_ctx_t *dcp = arg;
+       dsl_pool_t *dp = dcp->dc_dp;
+
+       /*
+        * We need to get a pool_config_lock here, as there are several
+        * asssert(pool_config_held) down the stack. Getting a lock via
+        * dsl_pool_config_enter is risky, as it might be stalled by a
+        * pending writer. This would deadlock, as the write lock can
+        * only be granted when our parent thread gives up the lock.
+        * The _prio interface gives us priority over a pending writer.
+        */
+       dsl_pool_config_enter_prio(dp, FTAG);
+
+       dmu_objset_find_dp_impl(dcp);
+
+       dsl_pool_config_exit(dp, FTAG);
+}
+
+/*
+ * Find objsets under and including ddobj, call func(ds) on each.
+ * The order for the enumeration is completely undefined.
+ * func is called with dsl_pool_config held.
+ */
+int
+dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj,
+    int func(dsl_pool_t *, dsl_dataset_t *, void *), void *arg, int flags)
+{
+       int error = 0;
+       taskq_t *tq = NULL;
+       int ntasks;
+       dmu_objset_find_ctx_t *dcp;
+       kmutex_t err_lock;
+
+       mutex_init(&err_lock, NULL, MUTEX_DEFAULT, NULL);
+       dcp = kmem_alloc(sizeof (*dcp), KM_SLEEP);
+       dcp->dc_tq = NULL;
+       dcp->dc_dp = dp;
+       dcp->dc_ddobj = ddobj;
+       dcp->dc_func = func;
+       dcp->dc_arg = arg;
+       dcp->dc_flags = flags;
+       dcp->dc_error_lock = &err_lock;
+       dcp->dc_error = &error;
+
+       if ((flags & DS_FIND_SERIALIZE) || dsl_pool_config_held_writer(dp)) {
+               /*
+                * In case a write lock is held we can't make use of
+                * parallelism, as down the stack of the worker threads
+                * the lock is asserted via dsl_pool_config_held.
+                * In case of a read lock this is solved by getting a read
+                * lock in each worker thread, which isn't possible in case
+                * of a writer lock. So we fall back to the synchronous path
+                * here.
+                * In the future it might be possible to get some magic into
+                * dsl_pool_config_held in a way that it returns true for
+                * the worker threads so that a single lock held from this
+                * thread suffices. For now, stay single threaded.
+                */
+               dmu_objset_find_dp_impl(dcp);
+
+               return (error);
+       }
+
+       ntasks = dmu_find_threads;
+       if (ntasks == 0)
+               ntasks = vdev_count_leaves(dp->dp_spa) * 4;
+       tq = taskq_create("dmu_objset_find", ntasks, maxclsyspri, ntasks,
+           INT_MAX, 0);
+       if (tq == NULL) {
+               kmem_free(dcp, sizeof (*dcp));
+               return (SET_ERROR(ENOMEM));
+       }
+       dcp->dc_tq = tq;
+
+       /* dcp will be freed by task */
+       (void) taskq_dispatch(tq, dmu_objset_find_dp_cb, dcp, TQ_SLEEP);
+
+       /*
+        * PORTING: this code relies on the property of taskq_wait to wait
+        * until no more tasks are queued and no more tasks are active. As
+        * we always queue new tasks from within other tasks, task_wait
+        * reliably waits for the full recursion to finish, even though we
+        * enqueue new tasks after taskq_wait has been called.
+        * On platforms other than illumos, taskq_wait may not have this
+        * property.
+        */
+       taskq_wait(tq);
+       taskq_destroy(tq);
+       mutex_destroy(&err_lock);
+
+       return (error);
+}
+
+/*
+ * Find all objsets under name, and for each, call 'func(child_name, arg)'.
+ * The dp_config_rwlock must not be held when this is called, and it
+ * will not be held when the callback is called.
+ * Therefore this function should only be used when the pool is not changing
+ * (e.g. in syncing context), or the callback can deal with the possible races.
+ */
+static int
+dmu_objset_find_impl(spa_t *spa, const char *name,
+    int func(const char *, void *), void *arg, int flags)
+{
+       dsl_dir_t *dd;
+       dsl_pool_t *dp = spa_get_dsl(spa);
+       dsl_dataset_t *ds;
+       zap_cursor_t zc;
+       zap_attribute_t *attr;
+       char *child;
+       uint64_t thisobj;
+       int err;
+
+       dsl_pool_config_enter(dp, FTAG);
+
+       err = dsl_dir_hold(dp, name, FTAG, &dd, NULL);
+       if (err != 0) {
+               dsl_pool_config_exit(dp, FTAG);
+               return (err);
+       }
+
+       /* Don't visit hidden ($MOS & $ORIGIN) objsets. */
+       if (dd->dd_myname[0] == '$') {
+               dsl_dir_rele(dd, FTAG);
+               dsl_pool_config_exit(dp, FTAG);
+               return (0);
+       }
+
+       thisobj = dsl_dir_phys(dd)->dd_head_dataset_obj;
+       attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+
+       /*
+        * Iterate over all children.
+        */
+       if (flags & DS_FIND_CHILDREN) {
+               for (zap_cursor_init(&zc, dp->dp_meta_objset,
+                   dsl_dir_phys(dd)->dd_child_dir_zapobj);
+                   zap_cursor_retrieve(&zc, attr) == 0;
+                   (void) zap_cursor_advance(&zc)) {
+                       ASSERT3U(attr->za_integer_length, ==,
+                           sizeof (uint64_t));
+                       ASSERT3U(attr->za_num_integers, ==, 1);
+
+                       child = kmem_asprintf("%s/%s", name, attr->za_name);
+                       dsl_pool_config_exit(dp, FTAG);
+                       err = dmu_objset_find_impl(spa, child,
+                           func, arg, flags);
+                       dsl_pool_config_enter(dp, FTAG);
+                       strfree(child);
+                       if (err != 0)
+                               break;
+               }
+               zap_cursor_fini(&zc);
+
+               if (err != 0) {
+                       dsl_dir_rele(dd, FTAG);
+                       dsl_pool_config_exit(dp, FTAG);
+                       kmem_free(attr, sizeof (zap_attribute_t));
+                       return (err);
+               }
+       }
+
+       /*
+        * Iterate over all snapshots.
+        */
+       if (flags & DS_FIND_SNAPSHOTS) {
+               err = dsl_dataset_hold_obj(dp, thisobj, FTAG, &ds);
+
+               if (err == 0) {
+                       uint64_t snapobj;
+
+                       snapobj = dsl_dataset_phys(ds)->ds_snapnames_zapobj;
+                       dsl_dataset_rele(ds, FTAG);
+
+                       for (zap_cursor_init(&zc, dp->dp_meta_objset, snapobj);
+                           zap_cursor_retrieve(&zc, attr) == 0;
+                           (void) zap_cursor_advance(&zc)) {
+                               ASSERT3U(attr->za_integer_length, ==,
+                                   sizeof (uint64_t));
+                               ASSERT3U(attr->za_num_integers, ==, 1);
+
+                               child = kmem_asprintf("%s@%s",
+                                   name, attr->za_name);
+                               dsl_pool_config_exit(dp, FTAG);
+                               err = func(child, arg);
+                               dsl_pool_config_enter(dp, FTAG);
+                               strfree(child);
+                               if (err != 0)
+                                       break;
+                       }
+                       zap_cursor_fini(&zc);
+               }
+       }
+
+       dsl_dir_rele(dd, FTAG);
+       kmem_free(attr, sizeof (zap_attribute_t));
+       dsl_pool_config_exit(dp, FTAG);
+
+       if (err != 0)
+               return (err);
+
+       /* Apply to self. */
+       return (func(name, arg));
+}
+
+/*
+ * See comment above dmu_objset_find_impl().
+ */
+int
+dmu_objset_find(char *name, int func(const char *, void *), void *arg,
+    int flags)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+       error = dmu_objset_find_impl(spa, name, func, arg, flags);
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+void
+dmu_objset_set_user(objset_t *os, void *user_ptr)
+{
+       ASSERT(MUTEX_HELD(&os->os_user_ptr_lock));
+       os->os_user_ptr = user_ptr;
+}
+
+void *
+dmu_objset_get_user(objset_t *os)
+{
+       ASSERT(MUTEX_HELD(&os->os_user_ptr_lock));
+       return (os->os_user_ptr);
+}
+
+/*
+ * Determine name of filesystem, given name of snapshot.
+ * buf must be at least MAXNAMELEN bytes
+ */
+int
+dmu_fsname(const char *snapname, char *buf)
+{
+       char *atp = strchr(snapname, '@');
+       if (atp == NULL)
+               return (SET_ERROR(EINVAL));
+       if (atp - snapname >= MAXNAMELEN)
+               return (SET_ERROR(ENAMETOOLONG));
+       (void) strlcpy(buf, snapname, atp - snapname + 1);
+       return (0);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dmu_objset_zil);
+EXPORT_SYMBOL(dmu_objset_pool);
+EXPORT_SYMBOL(dmu_objset_ds);
+EXPORT_SYMBOL(dmu_objset_type);
+EXPORT_SYMBOL(dmu_objset_name);
+EXPORT_SYMBOL(dmu_objset_hold);
+EXPORT_SYMBOL(dmu_objset_own);
+EXPORT_SYMBOL(dmu_objset_rele);
+EXPORT_SYMBOL(dmu_objset_disown);
+EXPORT_SYMBOL(dmu_objset_from_ds);
+EXPORT_SYMBOL(dmu_objset_create);
+EXPORT_SYMBOL(dmu_objset_clone);
+EXPORT_SYMBOL(dmu_objset_stats);
+EXPORT_SYMBOL(dmu_objset_fast_stat);
+EXPORT_SYMBOL(dmu_objset_spa);
+EXPORT_SYMBOL(dmu_objset_space);
+EXPORT_SYMBOL(dmu_objset_fsid_guid);
+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_sync);
+EXPORT_SYMBOL(dmu_objset_is_dirty);
+EXPORT_SYMBOL(dmu_objset_create_impl);
+EXPORT_SYMBOL(dmu_objset_open_impl);
+EXPORT_SYMBOL(dmu_objset_evict);
+EXPORT_SYMBOL(dmu_objset_register_type);
+EXPORT_SYMBOL(dmu_objset_do_userquota_updates);
+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);
+#endif
diff --git a/zfs/module/zfs/dmu_send.c b/zfs/module/zfs/dmu_send.c
new file mode 100644 (file)
index 0000000..9404549
--- /dev/null
@@ -0,0 +1,2281 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 by Delphix. All rights reserved.
+ * Copyright 2011 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) 2016 Actifio, Inc. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/zfs_context.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_synctask.h>
+#include <sys/spa_impl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zap.h>
+#include <sys/zio_checksum.h>
+#include <sys/zfs_znode.h>
+#include <zfs_fletcher.h>
+#include <sys/avl.h>
+#include <sys/ddt.h>
+#include <sys/zfs_onexit.h>
+#include <sys/dmu_send.h>
+#include <sys/dsl_destroy.h>
+#include <sys/blkptr.h>
+#include <sys/dsl_bookmark.h>
+#include <sys/zfeature.h>
+#include <sys/zvol.h>
+
+/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
+int zfs_send_corrupt_data = B_FALSE;
+
+static char *dmu_recv_tag = "dmu_recv_tag";
+static const char *recv_clone_name = "%recv";
+
+typedef struct dump_bytes_io {
+       dmu_sendarg_t   *dbi_dsp;
+       void            *dbi_buf;
+       int             dbi_len;
+} dump_bytes_io_t;
+
+static void
+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;
+       ssize_t resid; /* have to get resid to get detailed errno */
+       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);
+
+       mutex_enter(&ds->ds_sendstream_lock);
+       *dsp->dsa_off += dbi->dbi_len;
+       mutex_exit(&ds->ds_sendstream_lock);
+}
+
+static int
+dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
+{
+       dump_bytes_io_t dbi;
+
+       dbi.dbi_dsp = dsp;
+       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.
+        * The ZIO_TYPE_FREE threads are used because there can be a lot of
+        * 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_cb, &dbi, TQ_SLEEP);
+#endif /* HAVE_LARGE_STACKS */
+
+       return (dsp->dsa_err);
+}
+
+static int
+dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
+    uint64_t length)
+{
+       struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free);
+
+       /*
+        * When we receive a free record, dbuf_free_range() assumes
+        * 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
+        * true because we always send data in increasing order by
+        * object,offset.
+        *
+        * If the increasing-order constraint ever changes, we should find
+        * another way to assert that the one-record constraint is still
+        * satisfied.
+        */
+       ASSERT(object > dsp->dsa_last_data_object ||
+           (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;
+
+       /*
+        * If there is a pending op, but it's not PENDING_FREE, push it out,
+        * since free block aggregation can only be done for blocks of the
+        * same type (i.e., DRR_FREE records can only be aggregated with
+        * other DRR_FREE records.  DRR_FREEOBJECTS records can only be
+        * aggregated with other DRR_FREEOBJECTS records.
+        */
+       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)
+                       return (SET_ERROR(EINTR));
+               dsp->dsa_pending_op = PENDING_NONE;
+       }
+
+       if (dsp->dsa_pending_op == PENDING_FREE) {
+               /*
+                * There should never be a PENDING_FREE if length is -1
+                * (because dump_dnode is the only place where this
+                * function is called with a -1, and only after flushing
+                * any pending record).
+                */
+               ASSERT(length != -1ULL);
+               /*
+                * Check to see whether this free block can be aggregated
+                * with pending one.
+                */
+               if (drrf->drr_object == object && drrf->drr_offset +
+                   drrf->drr_length == offset) {
+                       drrf->drr_length += length;
+                       return (0);
+               } else {
+                       /* not a continuation.  Push out pending record */
+                       if (dump_bytes(dsp, dsp->dsa_drr,
+                           sizeof (dmu_replay_record_t)) != 0)
+                               return (SET_ERROR(EINTR));
+                       dsp->dsa_pending_op = PENDING_NONE;
+               }
+       }
+       /* create a FREE record and make it pending */
+       bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t));
+       dsp->dsa_drr->drr_type = DRR_FREE;
+       drrf->drr_object = object;
+       drrf->drr_offset = 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)
+                       return (SET_ERROR(EINTR));
+       } else {
+               dsp->dsa_pending_op = PENDING_FREE;
+       }
+
+       return (0);
+}
+
+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)
+{
+       struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write);
+
+       /*
+        * We send data in increasing object, offset order.
+        * See comment in dump_free() for details.
+        */
+       ASSERT(object > dsp->dsa_last_data_object ||
+           (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;
+
+       /*
+        * If there is any kind of pending aggregation (currently either
+        * a grouping of free objects or free blocks), push it out to
+        * the stream, since aggregation can't be done across operations
+        * of different types.
+        */
+       if (dsp->dsa_pending_op != PENDING_NONE) {
+               if (dump_bytes(dsp, dsp->dsa_drr,
+                   sizeof (dmu_replay_record_t)) != 0)
+                       return (SET_ERROR(EINTR));
+               dsp->dsa_pending_op = PENDING_NONE;
+       }
+       /* write a DATA 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;
+       if (bp == NULL || BP_IS_EMBEDDED(bp)) {
+               /*
+                * There's no pre-computed checksum for partial-block
+                * writes or embedded BP's, so (like
+                * fletcher4-checkummed blocks) userland will have to
+                * compute a dedup-capable checksum itself.
+                */
+               drrw->drr_checksumtype = ZIO_CHECKSUM_OFF;
+       } else {
+               drrw->drr_checksumtype = BP_GET_CHECKSUM(bp);
+               if (zio_checksum_table[drrw->drr_checksumtype].ci_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));
+               DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp));
+               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)
+               return (SET_ERROR(EINTR));
+       return (0);
+}
+
+static int
+dump_write_embedded(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
+    int blksz, const blkptr_t *bp)
+{
+       char buf[BPE_PAYLOAD_SIZE];
+       struct drr_write_embedded *drrw =
+           &(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)
+                       return (EINTR);
+               dsp->dsa_pending_op = PENDING_NONE;
+       }
+
+       ASSERT(BP_IS_EMBEDDED(bp));
+
+       bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t));
+       dsp->dsa_drr->drr_type = DRR_WRITE_EMBEDDED;
+       drrw->drr_object = object;
+       drrw->drr_offset = offset;
+       drrw->drr_length = blksz;
+       drrw->drr_toguid = dsp->dsa_toguid;
+       drrw->drr_compression = BP_GET_COMPRESS(bp);
+       drrw->drr_etype = BPE_GET_ETYPE(bp);
+       drrw->drr_lsize = BPE_GET_LSIZE(bp);
+       drrw->drr_psize = BPE_GET_PSIZE(bp);
+
+       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)
+               return (EINTR);
+       return (0);
+}
+
+static int
+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)
+                       return (SET_ERROR(EINTR));
+               dsp->dsa_pending_op = PENDING_NONE;
+       }
+
+       /* write a SPILL record */
+       bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t));
+       dsp->dsa_drr->drr_type = DRR_SPILL;
+       drrs->drr_object = object;
+       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))
+               return (SET_ERROR(EINTR));
+       return (0);
+}
+
+static int
+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
+        * blocks of the same type (i.e., DRR_FREE records can only be
+        * aggregated with other DRR_FREE records.  DRR_FREEOBJECTS records
+        * can only be aggregated with other DRR_FREEOBJECTS records.
+        */
+       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)
+                       return (SET_ERROR(EINTR));
+               dsp->dsa_pending_op = PENDING_NONE;
+       }
+       if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) {
+               /*
+                * See whether this free object array can be aggregated
+                * with pending one
+                */
+               if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) {
+                       drrfo->drr_numobjs += 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)
+                               return (SET_ERROR(EINTR));
+                       dsp->dsa_pending_op = PENDING_NONE;
+               }
+       }
+
+       /* write a FREEOBJECTS record */
+       bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t));
+       dsp->dsa_drr->drr_type = DRR_FREEOBJECTS;
+       drrfo->drr_firstobj = firstobj;
+       drrfo->drr_numobjs = numobjs;
+       drrfo->drr_toguid = dsp->dsa_toguid;
+
+       dsp->dsa_pending_op = PENDING_FREEOBJECTS;
+
+       return (0);
+}
+
+static int
+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 (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)
+                       return (SET_ERROR(EINTR));
+               dsp->dsa_pending_op = PENDING_NONE;
+       }
+
+       /* write an OBJECT record */
+       bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t));
+       dsp->dsa_drr->drr_type = DRR_OBJECT;
+       drro->drr_object = object;
+       drro->drr_type = dnp->dn_type;
+       drro->drr_bonustype = dnp->dn_bonustype;
+       drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT;
+       drro->drr_bonuslen = dnp->dn_bonuslen;
+       drro->drr_checksumtype = dnp->dn_checksum;
+       drro->drr_compress = dnp->dn_compress;
+       drro->drr_toguid = dsp->dsa_toguid;
+
+       if (!(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
+           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)
+               return (SET_ERROR(EINTR));
+
+       /* Free anything past the end of the file. */
+       if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) *
+           (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL) != 0)
+               return (SET_ERROR(EINTR));
+       if (dsp->dsa_err != 0)
+               return (SET_ERROR(EINTR));
+       return (0);
+}
+
+static boolean_t
+backup_do_embed(dmu_sendarg_t *dsp, const blkptr_t *bp)
+{
+       if (!BP_IS_EMBEDDED(bp))
+               return (B_FALSE);
+
+       /*
+        * 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)))
+               return (B_FALSE);
+
+       /*
+        * Embed type must be explicitly enabled.
+        */
+       switch (BPE_GET_ETYPE(bp)) {
+       case BP_EMBEDDED_TYPE_DATA:
+               if (dsp->dsa_featureflags & DMU_BACKUP_FEATURE_EMBED_DATA)
+                       return (B_TRUE);
+               break;
+       default:
+               return (B_FALSE);
+       }
+       return (B_FALSE);
+}
+
+#define        BP_SPAN(dnp, level) \
+       (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \
+       (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT)))
+
+/* ARGSUSED */
+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)
+{
+       dmu_sendarg_t *dsp = arg;
+       dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE;
+       int err = 0;
+
+       if (issig(JUSTLOOKING) && issig(FORREAL))
+               return (SET_ERROR(EINTR));
+
+       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 dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT;
+               err = dump_freeobjects(dsp, 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);
+       } 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);
+               arc_flags_t aflags = ARC_FLAG_WAIT;
+               arc_buf_t *abuf;
+
+               if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
+                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
+                   &aflags, zb) != 0)
+                       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);
+                       if (err != 0)
+                               break;
+               }
+               (void) arc_buf_remove_ref(abuf, &abuf);
+       } else if (type == DMU_OT_SA) {
+               arc_flags_t aflags = ARC_FLAG_WAIT;
+               arc_buf_t *abuf;
+               int blksz = BP_GET_LSIZE(bp);
+
+               if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
+                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
+                   &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)) {
+               /* 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,
+                   zb->zb_blkid * blksz, blksz, bp);
+       } else { /* it's a level-0 block of a regular object */
+               uint64_t offset;
+               arc_flags_t aflags = ARC_FLAG_WAIT;
+               arc_buf_t *abuf;
+               int blksz = BP_GET_LSIZE(bp);
+
+               ASSERT3U(blksz, ==, dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
+               ASSERT0(zb->zb_level);
+               if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
+                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
+                   &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);
+                               for (ptr = abuf->b_data;
+                                   (char *)ptr < (char *)abuf->b_data + blksz;
+                                   ptr++)
+                                       *ptr = 0x2f5baddb10cULL;
+                       } else {
+                               return (SET_ERROR(EIO));
+                       }
+               }
+
+               offset = zb->zb_blkid * blksz;
+
+               if (!(dsp->dsa_featureflags &
+                   DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
+                   blksz > SPA_OLD_MAXBLOCKSIZE) {
+                       char *buf = abuf->b_data;
+                       while (blksz > 0 && err == 0) {
+                               int n = MIN(blksz, SPA_OLD_MAXBLOCKSIZE);
+                               err = dump_write(dsp, type, zb->zb_object,
+                                   offset, n, NULL, buf);
+                               offset += n;
+                               buf += n;
+                               blksz -= n;
+                       }
+               } else {
+                       err = dump_write(dsp, type, zb->zb_object,
+                           offset, blksz, bp, abuf->b_data);
+               }
+               (void) arc_buf_remove_ref(abuf, &abuf);
+       }
+
+       ASSERT(err == 0 || err == EINTR);
+       return (err);
+}
+
+/*
+ * 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)
+{
+       objset_t *os;
+       dmu_replay_record_t *drr;
+       dmu_sendarg_t *dsp;
+       int err;
+       uint64_t fromtxg = 0;
+       uint64_t featureflags = 0;
+
+       err = dmu_objset_from_ds(ds, &os);
+       if (err != 0) {
+               dsl_pool_rele(dp, tag);
+               return (err);
+       }
+
+       drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
+       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_SUBSTREAM);
+
+#ifdef _KERNEL
+       if (dmu_objset_type(os) == DMU_OST_ZFS) {
+               uint64_t version;
+               if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) {
+                       kmem_free(drr, sizeof (dmu_replay_record_t));
+                       dsl_pool_rele(dp, tag);
+                       return (SET_ERROR(EINVAL));
+               }
+               if (version >= ZPL_VERSION_SA) {
+                       featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;
+               }
+       }
+#endif
+
+       if (large_block_ok && ds->ds_large_blocks)
+               featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
+       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;
+       }
+
+       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;
+       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_flags |= DRR_FLAG_CI_DATA;
+
+       if (fromzb != NULL) {
+               drr->drr_u.drr_begin.drr_fromguid = fromzb->zbm_guid;
+               fromtxg = fromzb->zbm_creation_txg;
+       }
+       dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
+       if (!ds->ds_is_snapshot) {
+               (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--",
+                   sizeof (drr->drr_u.drr_begin.drr_toname));
+       }
+
+       dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
+
+       dsp->dsa_drr = drr;
+       dsp->dsa_vp = vp;
+       dsp->dsa_outfd = outfd;
+       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_pending_op = PENDING_NONE;
+       dsp->dsa_incremental = (fromzb != NULL);
+       dsp->dsa_featureflags = featureflags;
+
+       mutex_enter(&ds->ds_sendstream_lock);
+       list_insert_head(&ds->ds_sendstreams, dsp);
+       mutex_exit(&ds->ds_sendstream_lock);
+
+       dsl_dataset_long_hold(ds, FTAG);
+       dsl_pool_rele(dp, tag);
+
+       if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) {
+               err = dsp->dsa_err;
+               goto out;
+       }
+
+       err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH,
+           backup_cb, dsp);
+
+       if (dsp->dsa_pending_op != PENDING_NONE)
+               if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0)
+                       err = SET_ERROR(EINTR);
+
+       if (err != 0) {
+               if (err == EINTR && dsp->dsa_err != 0)
+                       err = dsp->dsa_err;
+               goto out;
+       }
+
+       bzero(drr, sizeof (dmu_replay_record_t));
+       drr->drr_type = DRR_END;
+       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) {
+               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);
+
+       kmem_free(drr, sizeof (dmu_replay_record_t));
+       kmem_free(dsp, sizeof (dmu_sendarg_t));
+
+       dsl_dataset_long_rele(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,
+    int outfd, vnode_t *vp, offset_t *off)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       dsl_dataset_t *fromds = NULL;
+       int err;
+
+       err = dsl_pool_hold(pool, FTAG, &dp);
+       if (err != 0)
+               return (err);
+
+       err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds);
+       if (err != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (err);
+       }
+
+       if (fromsnap != 0) {
+               zfs_bookmark_phys_t zb;
+               boolean_t is_clone;
+
+               err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds);
+               if (err != 0) {
+                       dsl_dataset_rele(ds, FTAG);
+                       dsl_pool_rele(dp, FTAG);
+                       return (err);
+               }
+               if (!dsl_dataset_is_before(ds, fromds, 0))
+                       err = SET_ERROR(EXDEV);
+               zb.zbm_creation_time =
+                   dsl_dataset_phys(fromds)->ds_creation_time;
+               zb.zbm_creation_txg = dsl_dataset_phys(fromds)->ds_creation_txg;
+               zb.zbm_guid = dsl_dataset_phys(fromds)->ds_guid;
+               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);
+       } else {
+               err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
+                   embedok, large_block_ok, outfd, 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)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int err;
+       boolean_t owned = B_FALSE;
+
+       if (fromsnap != NULL && strpbrk(fromsnap, "@#") == NULL)
+               return (SET_ERROR(EINVAL));
+
+       err = dsl_pool_hold(tosnap, FTAG, &dp);
+       if (err != 0)
+               return (err);
+
+       if (strchr(tosnap, '@') == NULL && spa_writeable(dp->dp_spa)) {
+               /*
+                * We are sending a filesystem or volume.  Ensure
+                * that it doesn't change by owning the dataset.
+                */
+               err = dsl_dataset_own(dp, tosnap, FTAG, &ds);
+               owned = B_TRUE;
+       } else {
+               err = dsl_dataset_hold(dp, tosnap, FTAG, &ds);
+       }
+       if (err != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (err);
+       }
+
+       if (fromsnap != NULL) {
+               zfs_bookmark_phys_t zb;
+               boolean_t is_clone = B_FALSE;
+               int fsnamelen = strchr(tosnap, '@') - tosnap;
+
+               /*
+                * If the fromsnap is in a different filesystem, then
+                * mark the send stream as a clone.
+                */
+               if (strncmp(tosnap, fromsnap, fsnamelen) != 0 ||
+                   (fromsnap[fsnamelen] != '@' &&
+                   fromsnap[fsnamelen] != '#')) {
+                       is_clone = B_TRUE;
+               }
+
+               if (strchr(fromsnap, '@')) {
+                       dsl_dataset_t *fromds;
+                       err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds);
+                       if (err == 0) {
+                               if (!dsl_dataset_is_before(ds, fromds, 0))
+                                       err = SET_ERROR(EXDEV);
+                               zb.zbm_creation_time =
+                                   dsl_dataset_phys(fromds)->ds_creation_time;
+                               zb.zbm_creation_txg =
+                                   dsl_dataset_phys(fromds)->ds_creation_txg;
+                               zb.zbm_guid = dsl_dataset_phys(fromds)->ds_guid;
+                               is_clone = (ds->ds_dir != fromds->ds_dir);
+                               dsl_dataset_rele(fromds, FTAG);
+                       }
+               } else {
+                       err = dsl_bookmark_lookup(dp, fromsnap, ds, &zb);
+               }
+               if (err != 0) {
+                       dsl_dataset_rele(ds, FTAG);
+                       dsl_pool_rele(dp, FTAG);
+                       return (err);
+               }
+               err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
+                   embedok, large_block_ok, outfd, vp, off);
+       } else {
+               err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
+                   embedok, large_block_ok, outfd, vp, off);
+       }
+       if (owned)
+               dsl_dataset_disown(ds, FTAG);
+       else
+               dsl_dataset_rele(ds, FTAG);
+       return (err);
+}
+
+static int
+dmu_adjust_send_estimate_for_indirects(dsl_dataset_t *ds, uint64_t size,
+    uint64_t *sizep)
+{
+       int err;
+       /*
+        * 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).
+        */
+
+       /*
+        * 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.
+        *
+        * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
+        * block, which we observe in practice.
+        */
+       uint64_t recordsize;
+       err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
+       if (err != 0)
+               return (err);
+       size -= size / recordsize * sizeof (blkptr_t);
+
+       /* Add in the space for the record associated with each block. */
+       size += size / recordsize * sizeof (dmu_replay_record_t);
+
+       *sizep = size;
+
+       return (0);
+}
+
+int
+dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep)
+{
+       int err;
+       uint64_t size;
+
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
+
+       /* tosnap must be a snapshot */
+       if (!ds->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       /* fromsnap, if provided, must be a snapshot */
+       if (fromds != NULL && !fromds->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       /*
+        * fromsnap must be an earlier snapshot from the same fs as tosnap,
+        * or the origin's fs.
+        */
+       if (fromds != NULL && !dsl_dataset_is_before(ds, fromds, 0))
+               return (SET_ERROR(EXDEV));
+
+       /* Get uncompressed size estimate of changed data. */
+       if (fromds == NULL) {
+               size = dsl_dataset_phys(ds)->ds_uncompressed_bytes;
+       } else {
+               uint64_t used, comp;
+               err = dsl_dataset_space_written(fromds, ds,
+                   &used, &comp, &size);
+               if (err != 0)
+                       return (err);
+       }
+
+       err = dmu_adjust_send_estimate_for_indirects(ds, size, sizep);
+       return (err);
+}
+
+/*
+ * Simple callback used to traverse the blocks of a snapshot and sum their
+ * uncompressed size
+ */
+/* 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;
+       if (bp != NULL && !BP_IS_HOLE(bp)) {
+               *spaceptr += BP_GET_UCSIZE(bp);
+       }
+       return (0);
+}
+
+/*
+ * Given a desination snapshot and a TXG, calculate the approximate size of a
+ * send stream sent from that TXG. from_txg may be zero, indicating that the
+ * whole snapshot will be sent.
+ */
+int
+dmu_send_estimate_from_txg(dsl_dataset_t *ds, uint64_t from_txg,
+    uint64_t *sizep)
+{
+       int err;
+       uint64_t size = 0;
+
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
+
+       /* tosnap must be a snapshot */
+       if (!dsl_dataset_is_snapshot(ds))
+               return (SET_ERROR(EINVAL));
+
+       /* verify that from_txg is before the provided snapshot was taken */
+       if (from_txg >= dsl_dataset_phys(ds)->ds_creation_txg) {
+               return (SET_ERROR(EXDEV));
+       }
+       /*
+        * traverse the blocks of the snapshot with birth times after
+        * from_txg, summing their uncompressed size
+        */
+       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);
+       return (err);
+}
+
+typedef struct dmu_recv_begin_arg {
+       const char *drba_origin;
+       dmu_recv_cookie_t *drba_cookie;
+       cred_t *drba_cred;
+       uint64_t drba_snapobj;
+} dmu_recv_begin_arg_t;
+
+static int
+recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
+    uint64_t fromguid)
+{
+       uint64_t val;
+       int error;
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+
+       /* temporary clone name must not exist */
+       error = zap_lookup(dp->dp_meta_objset,
+           dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name,
+           8, 1, &val);
+       if (error != ENOENT)
+               return (error == 0 ? EBUSY : error);
+
+       /* new snapshot name must not exist */
+       error = zap_lookup(dp->dp_meta_objset,
+           dsl_dataset_phys(ds)->ds_snapnames_zapobj,
+           drba->drba_cookie->drc_tosnap, 8, 1, &val);
+       if (error != ENOENT)
+               return (error == 0 ? EEXIST : error);
+
+       /*
+        * Check snapshot limit before receiving. We'll recheck again at the
+        * end, but might as well abort before receiving if we're already over
+        * the limit.
+        *
+        * Note that we do not check the file system limit with
+        * dsl_dir_fscount_check because the temporary %clones don't count
+        * against that limit.
+        */
+       error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT,
+           NULL, drba->drba_cred);
+       if (error != 0)
+               return (error);
+
+       if (fromguid != 0) {
+               dsl_dataset_t *snap;
+               uint64_t obj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
+
+               /* Find snapshot in this dir that matches fromguid. */
+               while (obj != 0) {
+                       error = dsl_dataset_hold_obj(dp, obj, FTAG,
+                           &snap);
+                       if (error != 0)
+                               return (SET_ERROR(ENODEV));
+                       if (snap->ds_dir != ds->ds_dir) {
+                               dsl_dataset_rele(snap, FTAG);
+                               return (SET_ERROR(ENODEV));
+                       }
+                       if (dsl_dataset_phys(snap)->ds_guid == fromguid)
+                               break;
+                       obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+                       dsl_dataset_rele(snap, FTAG);
+               }
+               if (obj == 0)
+                       return (SET_ERROR(ENODEV));
+
+               if (drba->drba_cookie->drc_force) {
+                       drba->drba_snapobj = obj;
+               } else {
+                       /*
+                        * If we are not forcing, there must be no
+                        * changes since fromsnap.
+                        */
+                       if (dsl_dataset_modified_since_snap(ds, snap)) {
+                               dsl_dataset_rele(snap, FTAG);
+                               return (SET_ERROR(ETXTBSY));
+                       }
+                       drba->drba_snapobj = ds->ds_prev->ds_object;
+               }
+
+               dsl_dataset_rele(snap, FTAG);
+       } else {
+               /* if full, then must be forced */
+               if (!drba->drba_cookie->drc_force)
+                       return (SET_ERROR(EEXIST));
+               /* start from $ORIGIN@$ORIGIN, if supported */
+               drba->drba_snapobj = dp->dp_origin_snap != NULL ?
+                   dp->dp_origin_snap->ds_object : 0;
+       }
+
+       return (0);
+
+}
+
+static int
+dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
+{
+       dmu_recv_begin_arg_t *drba = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
+       uint64_t fromguid = drrb->drr_fromguid;
+       int flags = drrb->drr_flags;
+       int error;
+       uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+       dsl_dataset_t *ds;
+       const char *tofs = drba->drba_cookie->drc_tofs;
+
+       /* already checked */
+       ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+
+       if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
+           DMU_COMPOUNDSTREAM ||
+           drrb->drr_type >= DMU_OST_NUMTYPES ||
+           ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL))
+               return (SET_ERROR(EINVAL));
+
+       /* 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 plan 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) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
+               return (SET_ERROR(ENOTSUP));
+
+       /*
+        * The receiving code doesn't know how to translate large blocks
+        * to smaller ones, so the pool must have the LARGE_BLOCKS
+        * feature enabled if the stream has LARGE_BLOCKS.
+        */
+       if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
+               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) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (SET_ERROR(EINVAL));
+               }
+
+               error = recv_begin_check_existing_impl(drba, ds, fromguid);
+               dsl_dataset_rele(ds, FTAG);
+       } else if (error == ENOENT) {
+               /* target fs does not exist; must be a full backup or clone */
+               char buf[MAXNAMELEN];
+
+               /*
+                * If it's a non-clone incremental, we are missing the
+                * target fs, so fail the recv.
+                */
+               if (fromguid != 0 && !(flags & DRR_FLAG_CLONE))
+                       return (SET_ERROR(ENOENT));
+
+               /* Open the parent of tofs */
+               ASSERT3U(strlen(tofs), <, MAXNAMELEN);
+               (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1);
+               error = dsl_dataset_hold(dp, buf, FTAG, &ds);
+               if (error != 0)
+                       return (error);
+
+               /*
+                * Check filesystem and snapshot limits before receiving. We'll
+                * recheck snapshot limits again at the end (we create the
+                * filesystems and increment those counts during begin_sync).
+                */
+               error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
+                   ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred);
+               if (error != 0) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (error);
+               }
+
+               error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
+                   ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred);
+               if (error != 0) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (error);
+               }
+
+               if (drba->drba_origin != NULL) {
+                       dsl_dataset_t *origin;
+                       error = dsl_dataset_hold(dp, drba->drba_origin,
+                           FTAG, &origin);
+                       if (error != 0) {
+                               dsl_dataset_rele(ds, FTAG);
+                               return (error);
+                       }
+                       if (!origin->ds_is_snapshot) {
+                               dsl_dataset_rele(origin, FTAG);
+                               dsl_dataset_rele(ds, FTAG);
+                               return (SET_ERROR(EINVAL));
+                       }
+                       if (dsl_dataset_phys(origin)->ds_guid != fromguid) {
+                               dsl_dataset_rele(origin, FTAG);
+                               dsl_dataset_rele(ds, FTAG);
+                               return (SET_ERROR(ENODEV));
+                       }
+                       dsl_dataset_rele(origin, FTAG);
+               }
+               dsl_dataset_rele(ds, FTAG);
+               error = 0;
+       }
+       return (error);
+}
+
+static void
+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);
+       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;
+
+       crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ?
+           DS_FLAG_CI_DATASET : 0;
+
+       error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
+       if (error == 0) {
+               /* create temporary clone */
+               dsl_dataset_t *snap = NULL;
+               if (drba->drba_snapobj != 0) {
+                       VERIFY0(dsl_dataset_hold_obj(dp,
+                           drba->drba_snapobj, FTAG, &snap));
+               }
+               dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
+                   snap, crflags, drba->drba_cred, tx);
+               dsl_dataset_rele(snap, FTAG);
+               dsl_dataset_rele(ds, FTAG);
+       } else {
+               dsl_dir_t *dd;
+               const char *tail;
+               dsl_dataset_t *origin = NULL;
+
+               VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
+
+               if (drba->drba_origin != NULL) {
+                       VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
+                           FTAG, &origin));
+               }
+
+               /* Create new dataset. */
+               dsobj = dsl_dataset_create_sync(dd,
+                   strrchr(tofs, '/') + 1,
+                   origin, crflags, drba->drba_cred, tx);
+               if (origin != NULL)
+                       dsl_dataset_rele(origin, FTAG);
+               dsl_dir_rele(dd, FTAG);
+               drba->drba_cookie->drc_newfs = B_TRUE;
+       }
+       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;
+       }
+
+       dmu_buf_will_dirty(newds->ds_dbuf, tx);
+       dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
+
+       /*
+        * If we actually created a non-clone, we need to create the
+        * objset in our new dataset.
+        */
+       if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) {
+               (void) dmu_objset_create_impl(dp->dp_spa,
+                   newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx);
+       }
+
+       drba->drba_cookie->drc_ds = newds;
+
+       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)
+{
+       dmu_recv_begin_arg_t drba = { 0 };
+       dmu_replay_record_t *drr;
+
+       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();
+
+       if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
+               drc->drc_byteswap = B_TRUE;
+       else if (drrb->drr_magic != DMU_BACKUP_MAGIC)
+               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);
+       }
+       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);
+       }
+
+       drba.drba_origin = origin;
+       drba.drba_cookie = drc;
+       drba.drba_cred = CRED();
+
+       return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync,
+           &drba, 5, ZFS_SPACE_CHECK_NORMAL));
+}
+
+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;
+};
+
+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 = arg1;
+       const guid_map_entry_t *gmep2 = arg2;
+
+       if (gmep1->guid < gmep2->guid)
+               return (-1);
+       else if (gmep1->guid > gmep2->guid)
+               return (1);
+       return (0);
+}
+
+static void
+free_guid_map_onexit(void *arg)
+{
+       avl_tree_t *ca = arg;
+       void *cookie = NULL;
+       guid_map_entry_t *gmep;
+
+       while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) {
+               dsl_dataset_long_rele(gmep->gme_ds, gmep);
+               dsl_dataset_rele(gmep->gme_ds, gmep);
+               kmem_free(gmep, sizeof (guid_map_entry_t));
+       }
+       avl_destroy(ca);
+       kmem_free(ca, sizeof (avl_tree_t));
+}
+
+static void *
+restore_read(struct restorearg *ra, int len, char *buf)
+{
+       int done = 0;
+
+       if (buf == NULL)
+               buf = ra->buf;
+
+       /* some things will require 8-byte alignment, so everything must */
+       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,
+                   ra->voff, UIO_SYSSPACE, FAPPEND,
+                   RLIM64_INFINITY, CRED(), &resid);
+
+               if (resid == len - done)
+                       ra->err = SET_ERROR(EINVAL);
+               ra->voff += len - done - resid;
+               done = len - resid;
+               if (ra->err != 0)
+                       return (NULL);
+       }
+
+       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);
+}
+
+noinline static void
+backup_byteswap(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);
+               DO64(drr_begin.drr_versioninfo);
+               DO64(drr_begin.drr_creation_time);
+               DO32(drr_begin.drr_type);
+               DO32(drr_begin.drr_flags);
+               DO64(drr_begin.drr_toguid);
+               DO64(drr_begin.drr_fromguid);
+               break;
+       case DRR_OBJECT:
+               DO64(drr_object.drr_object);
+               DO32(drr_object.drr_type);
+               DO32(drr_object.drr_bonustype);
+               DO32(drr_object.drr_blksz);
+               DO32(drr_object.drr_bonuslen);
+               DO64(drr_object.drr_toguid);
+               break;
+       case DRR_FREEOBJECTS:
+               DO64(drr_freeobjects.drr_firstobj);
+               DO64(drr_freeobjects.drr_numobjs);
+               DO64(drr_freeobjects.drr_toguid);
+               break;
+       case DRR_WRITE:
+               DO64(drr_write.drr_object);
+               DO32(drr_write.drr_type);
+               DO64(drr_write.drr_offset);
+               DO64(drr_write.drr_length);
+               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]);
+               DO64(drr_write.drr_key.ddk_prop);
+               break;
+       case DRR_WRITE_BYREF:
+               DO64(drr_write_byref.drr_object);
+               DO64(drr_write_byref.drr_offset);
+               DO64(drr_write_byref.drr_length);
+               DO64(drr_write_byref.drr_toguid);
+               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]);
+               DO64(drr_write_byref.drr_key.ddk_prop);
+               break;
+       case DRR_WRITE_EMBEDDED:
+               DO64(drr_write_embedded.drr_object);
+               DO64(drr_write_embedded.drr_offset);
+               DO64(drr_write_embedded.drr_length);
+               DO64(drr_write_embedded.drr_toguid);
+               DO32(drr_write_embedded.drr_lsize);
+               DO32(drr_write_embedded.drr_psize);
+               break;
+       case DRR_FREE:
+               DO64(drr_free.drr_object);
+               DO64(drr_free.drr_offset);
+               DO64(drr_free.drr_length);
+               DO64(drr_free.drr_toguid);
+               break;
+       case DRR_SPILL:
+               DO64(drr_spill.drr_object);
+               DO64(drr_spill.drr_length);
+               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);
+               break;
+       default:
+               break;
+       }
+#undef DO64
+#undef DO32
+}
+
+static inline uint8_t
+deduce_nblkptr(dmu_object_type_t bonus_type, uint64_t bonus_size)
+{
+       if (bonus_type == DMU_OT_SA) {
+               return (1);
+       } else {
+               return (1 +
+                   ((DN_MAX_BONUSLEN - bonus_size) >> SPA_BLKPTRSHIFT));
+       }
+}
+
+noinline static int
+restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
+{
+       dmu_object_info_t doi;
+       dmu_tx_t *tx;
+       void *data = NULL;
+       uint64_t object;
+       int err;
+
+       if (drro->drr_type == DMU_OT_NONE ||
+           !DMU_OT_IS_VALID(drro->drr_type) ||
+           !DMU_OT_IS_VALID(drro->drr_bonustype) ||
+           drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS ||
+           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) {
+               return (SET_ERROR(EINVAL));
+       }
+
+       err = dmu_object_info(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
+        * contents before we can change this type of metadata in the dnode.
+        */
+       if (err == 0) {
+               int nblkptr;
+
+               nblkptr = deduce_nblkptr(drro->drr_bonustype,
+                   drro->drr_bonuslen);
+
+               if (drro->drr_blksz != doi.doi_data_block_size ||
+                   nblkptr < doi.doi_nblkptr) {
+                       err = dmu_free_long_range(os, drro->drr_object,
+                           0, DMU_OBJECT_END);
+                       if (err != 0)
+                               return (SET_ERROR(EINVAL));
+               }
+       }
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_bonus(tx, object);
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err != 0) {
+               dmu_tx_abort(tx);
+               return (err);
+       }
+
+       if (object == DMU_NEW_OBJECT) {
+               /* currently free, want to be allocated */
+               err = dmu_object_claim(os, drro->drr_object,
+                   drro->drr_type, drro->drr_blksz,
+                   drro->drr_bonustype, drro->drr_bonuslen, 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,
+                   drro->drr_type, drro->drr_blksz,
+                   drro->drr_bonustype, drro->drr_bonuslen, tx);
+       }
+       if (err != 0) {
+               dmu_tx_commit(tx);
+               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);
+
+       if (data != NULL) {
+               dmu_buf_t *db;
+
+               VERIFY(0 == dmu_bonus_hold(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) {
+                       dmu_object_byteswap_t byteswap =
+                           DMU_OT_BYTESWAP(drro->drr_bonustype);
+                       dmu_ot_byteswap[byteswap].ob_func(db->db_data,
+                           drro->drr_bonuslen);
+               }
+               dmu_buf_rele(db, FTAG);
+       }
+       dmu_tx_commit(tx);
+       return (0);
+}
+
+/* ARGSUSED */
+noinline static int
+restore_freeobjects(struct restorearg *ra, objset_t *os,
+    struct drr_freeobjects *drrfo)
+{
+       uint64_t obj;
+
+       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)) {
+               int err;
+
+               if (dmu_object_info(os, obj, NULL) != 0)
+                       continue;
+
+               err = dmu_free_long_object(os, obj);
+               if (err != 0)
+                       return (err);
+       }
+       return (0);
+}
+
+noinline static int
+restore_write(struct restorearg *ra, objset_t *os,
+    struct drr_write *drrw)
+{
+       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 ||
+           !DMU_OT_IS_VALID(drrw->drr_type))
+               return (SET_ERROR(EINVAL));
+
+       if (dmu_object_info(os, drrw->drr_object, NULL) != 0)
+               return (SET_ERROR(EINVAL));
+
+       if (dmu_bonus_hold(os, drrw->drr_object, FTAG, &bonus) != 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);
+
+       dmu_tx_hold_write(tx, drrw->drr_object,
+           drrw->drr_offset, drrw->drr_length);
+       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) {
+               dmu_object_byteswap_t byteswap =
+                   DMU_OT_BYTESWAP(drrw->drr_type);
+               dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length);
+       }
+       dmu_assign_arcbuf(bonus, drrw->drr_offset, abuf, tx);
+       dmu_tx_commit(tx);
+       dmu_buf_rele(bonus, FTAG);
+       return (0);
+}
+
+/*
+ * Handle a DRR_WRITE_BYREF record.  This record is used in dedup'ed
+ * streams to refer to a copy of the data that is already on the
+ * system because it came in earlier in the stream.  This function
+ * finds the earlier copy of the data, and uses that copy instead of
+ * data from the stream to fulfill this write.
+ */
+static int
+restore_write_byref(struct restorearg *ra, objset_t *os,
+    struct drr_write_byref *drrwbr)
+{
+       dmu_tx_t *tx;
+       int err;
+       guid_map_entry_t gmesrch;
+       guid_map_entry_t *gmep;
+       avl_index_t where;
+       objset_t *ref_os = NULL;
+       dmu_buf_t *dbp;
+
+       if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset)
+               return (SET_ERROR(EINVAL));
+
+       /*
+        * If the GUID of the referenced dataset is different from the
+        * GUID of the target dataset, find the referenced dataset.
+        */
+       if (drrwbr->drr_toguid != drrwbr->drr_refguid) {
+               gmesrch.guid = drrwbr->drr_refguid;
+               if ((gmep = avl_find(ra->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;
+       }
+
+       err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
+           drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH);
+       if (err != 0)
+               return (err);
+
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_write(tx, drrwbr->drr_object,
+           drrwbr->drr_offset, drrwbr->drr_length);
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err != 0) {
+               dmu_tx_abort(tx);
+               return (err);
+       }
+       dmu_write(os, drrwbr->drr_object,
+           drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
+       dmu_buf_rele(dbp, FTAG);
+       dmu_tx_commit(tx);
+       return (0);
+}
+
+static int
+restore_write_embedded(struct restorearg *ra, objset_t *os,
+    struct drr_write_embedded *drrwnp)
+{
+       dmu_tx_t *tx;
+       int err;
+       void *data;
+
+       if (drrwnp->drr_offset + drrwnp->drr_length < drrwnp->drr_offset)
+               return (EINVAL);
+
+       if (drrwnp->drr_psize > BPE_PAYLOAD_SIZE)
+               return (EINVAL);
+
+       if (drrwnp->drr_etype >= NUM_BP_EMBEDDED_TYPES)
+               return (EINVAL);
+       if (drrwnp->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);
+
+       dmu_tx_hold_write(tx, drrwnp->drr_object,
+           drrwnp->drr_offset, drrwnp->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_tx_commit(tx);
+       return (0);
+}
+
+static int
+restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs)
+{
+       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)))
+               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)
+               return (SET_ERROR(EINVAL));
+
+       VERIFY(0 == dmu_bonus_hold(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);
+
+       dmu_tx_hold_spill(tx, db->db_object);
+
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err != 0) {
+               dmu_buf_rele(db, FTAG);
+               dmu_buf_rele(db_spill, FTAG);
+               dmu_tx_abort(tx);
+               return (err);
+       }
+       dmu_buf_will_dirty(db_spill, tx);
+
+       if (db_spill->db_size < drrs->drr_length)
+               VERIFY(0 == dbuf_spill_set_blksz(db_spill,
+                   drrs->drr_length, tx));
+       bcopy(data, db_spill->db_data, drrs->drr_length);
+
+       dmu_buf_rele(db, FTAG);
+       dmu_buf_rele(db_spill, FTAG);
+
+       dmu_tx_commit(tx);
+       return (0);
+}
+
+/* ARGSUSED */
+noinline static int
+restore_free(struct restorearg *ra, objset_t *os,
+    struct drr_free *drrf)
+{
+       int err;
+
+       if (drrf->drr_length != -1ULL &&
+           drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
+               return (SET_ERROR(EINVAL));
+
+       if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
+               return (SET_ERROR(EINVAL));
+
+       err = dmu_free_long_range(os, drrf->drr_object,
+           drrf->drr_offset, drrf->drr_length);
+       return (err);
+}
+
+/* used to destroy the drc_ds on error */
+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);
+}
+
+/*
+ * 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 featureflags;
+
+       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);
+
+       /* these were verified in dmu_recv_begin */
+       ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==,
+           DMU_SUBSTREAM);
+       ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES);
+
+       /*
+        * Open the objset we are modifying.
+        */
+       VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os));
+
+       ASSERT(dsl_dataset_phys(drc->drc_ds)->ds_flags & DS_FLAG_INCONSISTENT);
+
+       featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo);
+
+       /* if this stream is dedup'ed, set up the avl tree for guid mapping */
+       if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {
+               minor_t minor;
+
+               if (cleanup_fd == -1) {
+                       ra.err = SET_ERROR(EBADF);
+                       goto out;
+               }
+               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 =
+                           kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
+                       avl_create(ra.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,
+                           action_handlep);
+                       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)
+                               goto out;
+               }
+
+               drc->drc_guid_to_ds_map = ra.guid_to_ds_map;
+       }
+
+       /*
+        * Read records and process them.
+        */
+       pcksum = ra.cksum;
+       while (ra.err == 0 &&
+           NULL != (drr = restore_read(&ra, sizeof (*drr), NULL))) {
+               if (issig(JUSTLOOKING) && issig(FORREAL)) {
+                       ra.err = SET_ERROR(EINTR);
+                       goto out;
+               }
+
+               if (ra.byteswap)
+                       backup_byteswap(drr);
+
+               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);
+                       break;
+               }
+               default:
+                       ra.err = SET_ERROR(EINVAL);
+                       goto out;
+               }
+               pcksum = ra.cksum;
+       }
+       ASSERT(ra.err != 0);
+
+out:
+       if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1))
+               zfs_onexit_fd_rele(cleanup_fd);
+
+       if (ra.err != 0) {
+               /*
+                * destroy what we created, so we don't leave it in the
+                * inconsistent restoring state.
+                */
+               dmu_recv_cleanup_ds(drc);
+       }
+
+       vmem_free(ra.buf, ra.bufsize);
+       *voffp = ra.voff;
+       return (ra.err);
+}
+
+static int
+dmu_recv_end_check(void *arg, dmu_tx_t *tx)
+{
+       dmu_recv_cookie_t *drc = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       int error;
+
+       ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
+
+       if (!drc->drc_newfs) {
+               dsl_dataset_t *origin_head;
+
+               error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
+               if (error != 0)
+                       return (error);
+               if (drc->drc_force) {
+                       /*
+                        * We will destroy any snapshots in tofs (i.e. before
+                        * origin_head) that are after the origin (which is
+                        * the snap before drc_ds, because drc_ds can not
+                        * have any snaps of its own).
+                        */
+                       uint64_t obj;
+
+                       obj = dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
+                       while (obj !=
+                           dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj) {
+                               dsl_dataset_t *snap;
+                               error = dsl_dataset_hold_obj(dp, obj, FTAG,
+                                   &snap);
+                               if (error != 0)
+                                       break;
+                               if (snap->ds_dir != origin_head->ds_dir)
+                                       error = SET_ERROR(EINVAL);
+                               if (error == 0)  {
+                                       error = dsl_destroy_snapshot_check_impl(
+                                           snap, B_FALSE);
+                               }
+                               obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+                               dsl_dataset_rele(snap, FTAG);
+                               if (error != 0)
+                                       break;
+                       }
+                       if (error != 0) {
+                               dsl_dataset_rele(origin_head, FTAG);
+                               return (error);
+                       }
+               }
+               error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
+                   origin_head, drc->drc_force, drc->drc_owner, tx);
+               if (error != 0) {
+                       dsl_dataset_rele(origin_head, FTAG);
+                       return (error);
+               }
+               error = dsl_dataset_snapshot_check_impl(origin_head,
+                   drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+               dsl_dataset_rele(origin_head, FTAG);
+               if (error != 0)
+                       return (error);
+
+               error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
+       } else {
+               error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
+                   drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+       }
+       return (error);
+}
+
+static void
+dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
+{
+       dmu_recv_cookie_t *drc = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+
+       spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
+           tx, "snap=%s", drc->drc_tosnap);
+
+       if (!drc->drc_newfs) {
+               dsl_dataset_t *origin_head;
+
+               VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
+                   &origin_head));
+
+               if (drc->drc_force) {
+                       /*
+                        * Destroy any snapshots of drc_tofs (origin_head)
+                        * after the origin (the snap before drc_ds).
+                        */
+                       uint64_t obj;
+
+                       obj = dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
+                       while (obj !=
+                           dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj) {
+                               dsl_dataset_t *snap;
+                               VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG,
+                                   &snap));
+                               ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir);
+                               obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+                               dsl_destroy_snapshot_sync_impl(snap,
+                                   B_FALSE, tx);
+                               dsl_dataset_rele(snap, FTAG);
+                       }
+               }
+               VERIFY3P(drc->drc_ds->ds_prev, ==,
+                   origin_head->ds_prev);
+
+               dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
+                   origin_head, tx);
+               dsl_dataset_snapshot_sync_impl(origin_head,
+                   drc->drc_tosnap, tx);
+
+               /* set snapshot's creation time and guid */
+               dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
+               dsl_dataset_phys(origin_head->ds_prev)->ds_creation_time =
+                   drc->drc_drrb->drr_creation_time;
+               dsl_dataset_phys(origin_head->ds_prev)->ds_guid =
+                   drc->drc_drrb->drr_toguid;
+               dsl_dataset_phys(origin_head->ds_prev)->ds_flags &=
+                   ~DS_FLAG_INCONSISTENT;
+
+               dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
+               dsl_dataset_phys(origin_head)->ds_flags &=
+                   ~DS_FLAG_INCONSISTENT;
+
+               dsl_dataset_rele(origin_head, FTAG);
+               dsl_destroy_head_sync_impl(drc->drc_ds, tx);
+
+               if (drc->drc_owner != NULL)
+                       VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner);
+       } else {
+               dsl_dataset_t *ds = drc->drc_ds;
+
+               dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx);
+
+               /* set snapshot's creation time and guid */
+               dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
+               dsl_dataset_phys(ds->ds_prev)->ds_creation_time =
+                   drc->drc_drrb->drr_creation_time;
+               dsl_dataset_phys(ds->ds_prev)->ds_guid =
+                   drc->drc_drrb->drr_toguid;
+               dsl_dataset_phys(ds->ds_prev)->ds_flags &=
+                   ~DS_FLAG_INCONSISTENT;
+
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
+       }
+       drc->drc_newsnapobj = dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
+       zvol_create_minors(dp->dp_spa, drc->drc_tofs, B_TRUE);
+       /*
+        * Release the hold from dmu_recv_begin.  This must be done before
+        * we return to open context, so that when we free the dataset's dnode,
+        * we can evict its bonus buffer.
+        */
+       dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
+       drc->drc_ds = NULL;
+}
+
+static int
+add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *snapds;
+       guid_map_entry_t *gmep;
+       int err;
+
+       ASSERT(guid_map != NULL);
+
+       err = dsl_pool_hold(name, FTAG, &dp);
+       if (err != 0)
+               return (err);
+       gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP);
+       err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds);
+       if (err == 0) {
+               gmep->guid = dsl_dataset_phys(snapds)->ds_guid;
+               gmep->gme_ds = snapds;
+               avl_add(guid_map, gmep);
+               dsl_dataset_long_hold(snapds, gmep);
+       } else {
+               kmem_free(gmep, sizeof (*gmep));
+       }
+
+       dsl_pool_rele(dp, FTAG);
+       return (err);
+}
+
+static int dmu_recv_end_modified_blocks = 3;
+
+static int
+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);
+       dsl_dataset_name(drc->drc_ds, name);
+       zfs_destroy_unmount_origin(name);
+       kmem_free(name, MAXNAMELEN);
+#endif
+
+       error = dsl_sync_task(drc->drc_tofs,
+           dmu_recv_end_check, dmu_recv_end_sync, drc,
+           dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
+
+       if (error != 0)
+               dmu_recv_cleanup_ds(drc);
+       return (error);
+}
+
+static int
+dmu_recv_new_end(dmu_recv_cookie_t *drc)
+{
+       int error;
+
+       error = dsl_sync_task(drc->drc_tofs,
+           dmu_recv_end_check, dmu_recv_end_sync, drc,
+           dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL);
+
+       if (error != 0) {
+               dmu_recv_cleanup_ds(drc);
+       } else if (drc->drc_guid_to_ds_map != NULL) {
+               (void) add_ds_to_guidmap(drc->drc_tofs,
+                   drc->drc_guid_to_ds_map,
+                   drc->drc_newsnapobj);
+       }
+       return (error);
+}
+
+int
+dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
+{
+       drc->drc_owner = owner;
+
+       if (drc->drc_newfs)
+               return (dmu_recv_new_end(drc));
+       else
+               return (dmu_recv_existing_end(drc));
+}
+
+/*
+ * Return TRUE if this objset is currently being received into.
+ */
+boolean_t
+dmu_objset_is_receiving(objset_t *os)
+{
+       return (os->os_dsl_dataset != NULL &&
+           os->os_dsl_dataset->ds_owner == dmu_recv_tag);
+}
+
+#if defined(_KERNEL)
+module_param(zfs_send_corrupt_data, int, 0644);
+MODULE_PARM_DESC(zfs_send_corrupt_data, "Allow sending corrupt data");
+#endif
diff --git a/zfs/module/zfs/dmu_traverse.c b/zfs/module/zfs/dmu_traverse.c
new file mode 100644 (file)
index 0000000..a58f77f
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2016 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_pool.h>
+#include <sys/dnode.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/dmu_impl.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/callb.h>
+#include <sys/zfeature.h>
+
+int32_t zfs_pd_bytes_max = 50 * 1024 * 1024;   /* 50MB */
+int32_t ignore_hole_birth = 1;
+
+typedef struct prefetch_data {
+       kmutex_t pd_mtx;
+       kcondvar_t pd_cv;
+       int32_t pd_bytes_fetched;
+       int pd_flags;
+       boolean_t pd_cancel;
+       boolean_t pd_exited;
+} prefetch_data_t;
+
+typedef struct traverse_data {
+       spa_t *td_spa;
+       uint64_t td_objset;
+       blkptr_t *td_rootbp;
+       uint64_t td_min_txg;
+       zbookmark_phys_t *td_resume;
+       int td_flags;
+       prefetch_data_t *td_pfd;
+       boolean_t td_paused;
+       uint64_t td_hole_birth_enabled_txg;
+       blkptr_cb_t *td_func;
+       void *td_arg;
+       boolean_t td_realloc_possible;
+} traverse_data_t;
+
+static int traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
+    uint64_t objset, uint64_t object);
+static void prefetch_dnode_metadata(traverse_data_t *td, const dnode_phys_t *,
+    uint64_t objset, uint64_t object);
+
+static int
+traverse_zil_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
+{
+       traverse_data_t *td = arg;
+       zbookmark_phys_t zb;
+
+       if (BP_IS_HOLE(bp))
+               return (0);
+
+       if (claim_txg == 0 && bp->blk_birth >= spa_first_txg(td->td_spa))
+               return (0);
+
+       SET_BOOKMARK(&zb, td->td_objset, ZB_ZIL_OBJECT, ZB_ZIL_LEVEL,
+           bp->blk_cksum.zc_word[ZIL_ZC_SEQ]);
+
+       (void) td->td_func(td->td_spa, zilog, bp, &zb, NULL, td->td_arg);
+
+       return (0);
+}
+
+static int
+traverse_zil_record(zilog_t *zilog, lr_t *lrc, void *arg, uint64_t claim_txg)
+{
+       traverse_data_t *td = arg;
+
+       if (lrc->lrc_txtype == TX_WRITE) {
+               lr_write_t *lr = (lr_write_t *)lrc;
+               blkptr_t *bp = &lr->lr_blkptr;
+               zbookmark_phys_t zb;
+
+               if (BP_IS_HOLE(bp))
+                       return (0);
+
+               if (claim_txg == 0 || bp->blk_birth < claim_txg)
+                       return (0);
+
+               SET_BOOKMARK(&zb, td->td_objset, lr->lr_foid,
+                   ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp));
+
+               (void) td->td_func(td->td_spa, zilog, bp, &zb, NULL,
+                   td->td_arg);
+       }
+       return (0);
+}
+
+static void
+traverse_zil(traverse_data_t *td, zil_header_t *zh)
+{
+       uint64_t claim_txg = zh->zh_claim_txg;
+       zilog_t *zilog;
+
+       /*
+        * We only want to visit blocks that have been claimed but not yet
+        * replayed; plus, in read-only mode, blocks that are already stable.
+        */
+       if (claim_txg == 0 && spa_writeable(td->td_spa))
+               return;
+
+       zilog = zil_alloc(spa_get_dsl(td->td_spa)->dp_meta_objset, zh);
+
+       (void) zil_parse(zilog, traverse_zil_block, traverse_zil_record, td,
+           claim_txg);
+
+       zil_free(zilog);
+}
+
+typedef enum resume_skip {
+       RESUME_SKIP_ALL,
+       RESUME_SKIP_NONE,
+       RESUME_SKIP_CHILDREN
+} resume_skip_t;
+
+/*
+ * Returns RESUME_SKIP_ALL if td indicates that we are resuming a traversal and
+ * the block indicated by zb does not need to be visited at all. Returns
+ * RESUME_SKIP_CHILDREN if we are resuming a post traversal and we reach the
+ * resume point. This indicates that this block should be visited but not its
+ * children (since they must have been visited in a previous traversal).
+ * Otherwise returns RESUME_SKIP_NONE.
+ */
+static resume_skip_t
+resume_skip_check(traverse_data_t *td, const dnode_phys_t *dnp,
+    const zbookmark_phys_t *zb)
+{
+       if (td->td_resume != NULL && !ZB_IS_ZERO(td->td_resume)) {
+               /*
+                * If we already visited this bp & everything below,
+                * don't bother doing it again.
+                */
+               if (zbookmark_is_before(dnp, zb, td->td_resume))
+                       return (RESUME_SKIP_ALL);
+
+               /*
+                * If we found the block we're trying to resume from, zero
+                * the bookmark out to indicate that we have resumed.
+                */
+               if (bcmp(zb, td->td_resume, sizeof (*zb)) == 0) {
+                       bzero(td->td_resume, sizeof (*zb));
+                       if (td->td_flags & TRAVERSE_POST)
+                               return (RESUME_SKIP_CHILDREN);
+               }
+       }
+       return (RESUME_SKIP_NONE);
+}
+
+static void
+traverse_prefetch_metadata(traverse_data_t *td,
+    const blkptr_t *bp, const zbookmark_phys_t *zb)
+{
+       arc_flags_t flags = ARC_FLAG_NOWAIT | ARC_FLAG_PREFETCH;
+
+       if (!(td->td_flags & TRAVERSE_PREFETCH_METADATA))
+               return;
+       /*
+        * If we are in the process of resuming, don't prefetch, because
+        * some children will not be needed (and in fact may have already
+        * been freed).
+        */
+       if (td->td_resume != NULL && !ZB_IS_ZERO(td->td_resume))
+               return;
+       if (BP_IS_HOLE(bp) || bp->blk_birth <= td->td_min_txg)
+               return;
+       if (BP_GET_LEVEL(bp) == 0 && BP_GET_TYPE(bp) != DMU_OT_DNODE)
+               return;
+
+       (void) arc_read(NULL, td->td_spa, bp, NULL, NULL,
+           ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
+}
+
+static boolean_t
+prefetch_needed(prefetch_data_t *pfd, const blkptr_t *bp)
+{
+       ASSERT(pfd->pd_flags & TRAVERSE_PREFETCH_DATA);
+       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp) ||
+           BP_GET_TYPE(bp) == DMU_OT_INTENT_LOG)
+               return (B_FALSE);
+       return (B_TRUE);
+}
+
+static int
+traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
+    const blkptr_t *bp, const zbookmark_phys_t *zb)
+{
+       int err = 0;
+       arc_buf_t *buf = NULL;
+       prefetch_data_t *pd = td->td_pfd;
+
+       switch (resume_skip_check(td, dnp, zb)) {
+       case RESUME_SKIP_ALL:
+               return (0);
+       case RESUME_SKIP_CHILDREN:
+               goto post;
+       case RESUME_SKIP_NONE:
+               break;
+       default:
+               ASSERT(0);
+       }
+
+       if (bp->blk_birth == 0) {
+               /*
+                * Since this block has a birth time of 0 it must be one of
+                * two things: a hole created before the
+                * SPA_FEATURE_HOLE_BIRTH feature was enabled, or a hole
+                * which has always been a hole in an object.
+                *
+                * If a file is written sparsely, then the unwritten parts of
+                * the file were "always holes" -- that is, they have been
+                * holes since this object was allocated.  However, we (and
+                * our callers) can not necessarily tell when an object was
+                * allocated.  Therefore, if it's possible that this object
+                * was freed and then its object number reused, we need to
+                * visit all the holes with birth==0.
+                *
+                * If it isn't possible that the object number was reused,
+                * then if SPA_FEATURE_HOLE_BIRTH was enabled before we wrote
+                * all the blocks we will visit as part of this traversal,
+                * then this hole must have always existed, so we can skip
+                * it.  We visit blocks born after (exclusive) td_min_txg.
+                *
+                * 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)
+                       return (0);
+       } else if (bp->blk_birth <= td->td_min_txg) {
+               return (0);
+       }
+
+       if (pd != NULL && !pd->pd_exited && prefetch_needed(pd, bp)) {
+               uint64_t size = BP_GET_LSIZE(bp);
+               mutex_enter(&pd->pd_mtx);
+               ASSERT(pd->pd_bytes_fetched >= 0);
+               while (pd->pd_bytes_fetched < size && !pd->pd_exited)
+                       cv_wait_sig(&pd->pd_cv, &pd->pd_mtx);
+               pd->pd_bytes_fetched -= size;
+               cv_broadcast(&pd->pd_cv);
+               mutex_exit(&pd->pd_mtx);
+       }
+
+       if (BP_IS_HOLE(bp)) {
+               err = td->td_func(td->td_spa, NULL, bp, zb, dnp, td->td_arg);
+               if (err != 0)
+                       goto post;
+               return (0);
+       }
+
+       if (td->td_flags & TRAVERSE_PRE) {
+               err = td->td_func(td->td_spa, NULL, bp, zb, dnp,
+                   td->td_arg);
+               if (err == TRAVERSE_VISIT_NO_CHILDREN)
+                       return (0);
+               if (err != 0)
+                       goto post;
+       }
+
+       if (BP_GET_LEVEL(bp) > 0) {
+               uint32_t flags = ARC_FLAG_WAIT;
+               int32_t i;
+               int32_t epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
+               zbookmark_phys_t *czb;
+
+               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;
+
+               czb = kmem_alloc(sizeof (zbookmark_phys_t), KM_SLEEP);
+
+               for (i = 0; i < epb; i++) {
+                       SET_BOOKMARK(czb, zb->zb_objset, zb->zb_object,
+                           zb->zb_level - 1,
+                           zb->zb_blkid * epb + i);
+                       traverse_prefetch_metadata(td,
+                           &((blkptr_t *)buf->b_data)[i], czb);
+               }
+
+               /* recursively visitbp() blocks below this */
+               for (i = 0; i < epb; i++) {
+                       SET_BOOKMARK(czb, zb->zb_objset, zb->zb_object,
+                           zb->zb_level - 1,
+                           zb->zb_blkid * epb + i);
+                       err = traverse_visitbp(td, dnp,
+                           &((blkptr_t *)buf->b_data)[i], czb);
+                       if (err != 0)
+                               break;
+               }
+
+               kmem_free(czb, sizeof (zbookmark_phys_t));
+
+       } else if (BP_GET_TYPE(bp) == DMU_OT_DNODE) {
+               uint32_t flags = ARC_FLAG_WAIT;
+               int32_t i;
+               int32_t epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
+               dnode_phys_t *cdnp;
+
+               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;
+
+               for (i = 0; i < epb; i++) {
+                       prefetch_dnode_metadata(td, &cdnp[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);
+                       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);
+               if (err != 0)
+                       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,
+                   DMU_META_DNODE_OBJECT);
+               /*
+                * See the block comment above for the goal of this variable.
+                * If the maxblkid of the meta-dnode is 0, then we know that
+                * we've never had more than DNODES_PER_BLOCK objects in the
+                * dataset, which means we can't have reused any object ids.
+                */
+               if (osp->os_meta_dnode.dn_maxblkid == 0)
+                       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);
+               }
+
+               err = traverse_dnode(td, mdnp, 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);
+               }
+               if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
+                       err = traverse_dnode(td, udnp, zb->zb_objset,
+                           DMU_USERUSED_OBJECT);
+               }
+       }
+
+       if (buf)
+               (void) arc_buf_remove_ref(buf, &buf);
+
+post:
+       if (err == 0 && (td->td_flags & TRAVERSE_POST))
+               err = td->td_func(td->td_spa, NULL, bp, zb, dnp, td->td_arg);
+
+       if ((td->td_flags & TRAVERSE_HARD) && (err == EIO || err == ECKSUM)) {
+               /*
+                * Ignore this disk error as requested by the HARD flag,
+                * and continue traversal.
+                */
+               err = 0;
+       }
+
+       /*
+        * If we are stopping here, set td_resume.
+        */
+       if (td->td_resume != NULL && err != 0 && !td->td_paused) {
+               td->td_resume->zb_objset = zb->zb_objset;
+               td->td_resume->zb_object = zb->zb_object;
+               td->td_resume->zb_level = 0;
+               /*
+                * If we have stopped on an indirect block (e.g. due to
+                * i/o error), we have not visited anything below it.
+                * 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.
+                */
+               td->td_resume->zb_blkid = zb->zb_blkid <<
+                   (zb->zb_level * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT));
+               td->td_paused = B_TRUE;
+       }
+
+       return (err);
+}
+
+static void
+prefetch_dnode_metadata(traverse_data_t *td, const dnode_phys_t *dnp,
+    uint64_t objset, uint64_t object)
+{
+       int j;
+       zbookmark_phys_t czb;
+
+       for (j = 0; j < dnp->dn_nblkptr; j++) {
+               SET_BOOKMARK(&czb, objset, object, dnp->dn_nlevels - 1, j);
+               traverse_prefetch_metadata(td, &dnp->dn_blkptr[j], &czb);
+       }
+
+       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);
+       }
+}
+
+static int
+traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
+    uint64_t objset, uint64_t object)
+{
+       int j, err = 0;
+       zbookmark_phys_t czb;
+
+       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);
+               if (err != 0)
+                       break;
+       }
+
+       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);
+       }
+       return (err);
+}
+
+/* ARGSUSED */
+static int
+traverse_prefetcher(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       prefetch_data_t *pfd = arg;
+       arc_flags_t aflags = ARC_FLAG_NOWAIT | ARC_FLAG_PREFETCH;
+
+       ASSERT(pfd->pd_bytes_fetched >= 0);
+       if (pfd->pd_cancel)
+               return (SET_ERROR(EINTR));
+
+       if (!prefetch_needed(pfd, bp))
+               return (0);
+
+       mutex_enter(&pfd->pd_mtx);
+       while (!pfd->pd_cancel && pfd->pd_bytes_fetched >= zfs_pd_bytes_max)
+               cv_wait_sig(&pfd->pd_cv, &pfd->pd_mtx);
+       pfd->pd_bytes_fetched += BP_GET_LSIZE(bp);
+       cv_broadcast(&pfd->pd_cv);
+       mutex_exit(&pfd->pd_mtx);
+
+       (void) arc_read(NULL, spa, bp, NULL, NULL, ZIO_PRIORITY_ASYNC_READ,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE, &aflags, zb);
+
+       return (0);
+}
+
+static void
+traverse_prefetch_thread(void *arg)
+{
+       traverse_data_t *td_main = arg;
+       traverse_data_t td = *td_main;
+       zbookmark_phys_t czb;
+       fstrans_cookie_t cookie = spl_fstrans_mark();
+
+       td.td_func = traverse_prefetcher;
+       td.td_arg = td_main->td_pfd;
+       td.td_pfd = NULL;
+
+       SET_BOOKMARK(&czb, td.td_objset,
+           ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
+       (void) traverse_visitbp(&td, NULL, td.td_rootbp, &czb);
+
+       mutex_enter(&td_main->td_pfd->pd_mtx);
+       td_main->td_pfd->pd_exited = B_TRUE;
+       cv_broadcast(&td_main->td_pfd->pd_cv);
+       mutex_exit(&td_main->td_pfd->pd_mtx);
+       spl_fstrans_unmark(cookie);
+}
+
+/*
+ * NB: dataset must not be changing on-disk (eg, is a snapshot or we are
+ * in syncing context).
+ */
+static int
+traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
+    uint64_t txg_start, zbookmark_phys_t *resume, int flags,
+    blkptr_cb_t func, void *arg)
+{
+       traverse_data_t *td;
+       prefetch_data_t *pd;
+       zbookmark_phys_t *czb;
+       int err;
+
+       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);
+
+       td->td_spa = spa;
+       td->td_objset = objset;
+       td->td_rootbp = rootbp;
+       td->td_min_txg = txg_start;
+       td->td_resume = resume;
+       td->td_func = func;
+       td->td_arg = arg;
+       td->td_pfd = pd;
+       td->td_flags = flags;
+       td->td_paused = B_FALSE;
+       td->td_realloc_possible = (txg_start == 0 ? B_FALSE : B_TRUE);
+
+       if (spa_feature_is_active(spa, SPA_FEATURE_HOLE_BIRTH)) {
+               VERIFY(spa_feature_enabled_txg(spa,
+                   SPA_FEATURE_HOLE_BIRTH, &td->td_hole_birth_enabled_txg));
+       } else {
+               td->td_hole_birth_enabled_txg = UINT64_MAX;
+       }
+
+       pd->pd_flags = flags;
+       mutex_init(&pd->pd_mtx, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&pd->pd_cv, NULL, CV_DEFAULT, NULL);
+
+       SET_BOOKMARK(czb, td->td_objset,
+           ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
+
+       /* See comment on ZIL traversal in dsl_scan_visitds. */
+       if (ds != NULL && !ds->ds_is_snapshot && !BP_IS_HOLE(rootbp)) {
+               uint32_t flags = ARC_FLAG_WAIT;
+               objset_phys_t *osp;
+               arc_buf_t *buf;
+
+               err = arc_read(NULL, td->td_spa, rootbp,
+                   arc_getbuf_func, &buf,
+                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, czb);
+               if (err != 0)
+                       return (err);
+
+               osp = buf->b_data;
+               traverse_zil(td, &osp->os_zil_header);
+               (void) arc_buf_remove_ref(buf, &buf);
+       }
+
+       if (!(flags & TRAVERSE_PREFETCH_DATA) ||
+           0 == taskq_dispatch(system_taskq, traverse_prefetch_thread,
+           td, TQ_NOQUEUE))
+               pd->pd_exited = B_TRUE;
+
+       err = traverse_visitbp(td, NULL, rootbp, czb);
+
+       mutex_enter(&pd->pd_mtx);
+       pd->pd_cancel = B_TRUE;
+       cv_broadcast(&pd->pd_cv);
+       while (!pd->pd_exited)
+               cv_wait_sig(&pd->pd_cv, &pd->pd_mtx);
+       mutex_exit(&pd->pd_mtx);
+
+       mutex_destroy(&pd->pd_mtx);
+       cv_destroy(&pd->pd_cv);
+
+       kmem_free(czb, sizeof (zbookmark_phys_t));
+       kmem_free(pd, sizeof (struct prefetch_data));
+       kmem_free(td, sizeof (struct traverse_data));
+
+       return (err);
+}
+
+/*
+ * NB: dataset must not be changing on-disk (eg, is a snapshot or we are
+ * in syncing context).
+ */
+int
+traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start, 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));
+}
+
+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)
+{
+       return (traverse_impl(spa, NULL, ZB_DESTROYED_OBJSET,
+           blkptr, txg_start, resume, flags, func, arg));
+}
+
+/*
+ * NB: pool must not be changing on-disk (eg, from zdb or sync context).
+ */
+int
+traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
+    blkptr_cb_t func, void *arg)
+{
+       int err;
+       uint64_t obj;
+       dsl_pool_t *dp = spa_get_dsl(spa);
+       objset_t *mos = dp->dp_meta_objset;
+       boolean_t hard = (flags & TRAVERSE_HARD);
+
+       /* visit the MOS */
+       err = traverse_impl(spa, NULL, 0, spa_get_rootblkptr(spa),
+           txg_start, NULL, flags, func, arg);
+       if (err != 0)
+               return (err);
+
+       /* visit each dataset */
+       for (obj = 1; err == 0;
+           err = dmu_object_next(mos, &obj, FALSE, txg_start)) {
+               dmu_object_info_t doi;
+
+               err = dmu_object_info(mos, obj, &doi);
+               if (err != 0) {
+                       if (hard)
+                               continue;
+                       break;
+               }
+
+               if (doi.doi_bonus_type == DMU_OT_DSL_DATASET) {
+                       dsl_dataset_t *ds;
+                       uint64_t txg = txg_start;
+
+                       dsl_pool_config_enter(dp, FTAG);
+                       err = dsl_dataset_hold_obj(dp, obj, FTAG, &ds);
+                       dsl_pool_config_exit(dp, FTAG);
+                       if (err != 0) {
+                               if (hard)
+                                       continue;
+                               break;
+                       }
+                       if (dsl_dataset_phys(ds)->ds_prev_snap_txg > txg)
+                               txg = dsl_dataset_phys(ds)->ds_prev_snap_txg;
+                       err = traverse_dataset(ds, txg, flags, func, arg);
+                       dsl_dataset_rele(ds, FTAG);
+                       if (err != 0)
+                               break;
+               }
+       }
+       if (err == ESRCH)
+               err = 0;
+       return (err);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(traverse_dataset);
+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");
+#endif
diff --git a/zfs/module/zfs/dmu_tx.c b/zfs/module/zfs/dmu_tx.c
new file mode 100644 (file)
index 0000000..5ae429f
--- /dev/null
@@ -0,0 +1,1692 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2012, 2015 by Delphix. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dbuf.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h> /* for dsl_dataset_block_freeable() */
+#include <sys/dsl_dir.h> /* for dsl_dir_tempreserve_*() */
+#include <sys/dsl_pool.h>
+#include <sys/zap_impl.h> /* for fzap_default_block_shift */
+#include <sys/spa.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/zfs_context.h>
+#include <sys/varargs.h>
+#include <sys/trace_dmu.h>
+
+typedef void (*dmu_tx_hold_func_t)(dmu_tx_t *tx, struct dnode *dn,
+    uint64_t arg1, uint64_t arg2);
+
+dmu_tx_stats_t dmu_tx_stats = {
+       { "dmu_tx_assigned",            KSTAT_DATA_UINT64 },
+       { "dmu_tx_delay",               KSTAT_DATA_UINT64 },
+       { "dmu_tx_error",               KSTAT_DATA_UINT64 },
+       { "dmu_tx_suspended",           KSTAT_DATA_UINT64 },
+       { "dmu_tx_group",               KSTAT_DATA_UINT64 },
+       { "dmu_tx_memory_reserve",      KSTAT_DATA_UINT64 },
+       { "dmu_tx_memory_reclaim",      KSTAT_DATA_UINT64 },
+       { "dmu_tx_dirty_throttle",      KSTAT_DATA_UINT64 },
+       { "dmu_tx_dirty_delay",         KSTAT_DATA_UINT64 },
+       { "dmu_tx_dirty_over_max",      KSTAT_DATA_UINT64 },
+       { "dmu_tx_quota",               KSTAT_DATA_UINT64 },
+};
+
+static kstat_t *dmu_tx_ksp;
+
+dmu_tx_t *
+dmu_tx_create_dd(dsl_dir_t *dd)
+{
+       dmu_tx_t *tx = kmem_zalloc(sizeof (dmu_tx_t), KM_SLEEP);
+       tx->tx_dir = dd;
+       if (dd != NULL)
+               tx->tx_pool = dd->dd_pool;
+       list_create(&tx->tx_holds, sizeof (dmu_tx_hold_t),
+           offsetof(dmu_tx_hold_t, txh_node));
+       list_create(&tx->tx_callbacks, sizeof (dmu_tx_callback_t),
+           offsetof(dmu_tx_callback_t, dcb_node));
+       tx->tx_start = gethrtime();
+#ifdef DEBUG_DMU_TX
+       refcount_create(&tx->tx_space_written);
+       refcount_create(&tx->tx_space_freed);
+#endif
+       return (tx);
+}
+
+dmu_tx_t *
+dmu_tx_create(objset_t *os)
+{
+       dmu_tx_t *tx = dmu_tx_create_dd(os->os_dsl_dataset->ds_dir);
+       tx->tx_objset = os;
+       tx->tx_lastsnap_txg = dsl_dataset_prev_snap_txg(os->os_dsl_dataset);
+       return (tx);
+}
+
+dmu_tx_t *
+dmu_tx_create_assigned(struct dsl_pool *dp, uint64_t txg)
+{
+       dmu_tx_t *tx = dmu_tx_create_dd(NULL);
+
+       ASSERT3U(txg, <=, dp->dp_tx.tx_open_txg);
+       tx->tx_pool = dp;
+       tx->tx_txg = txg;
+       tx->tx_anyobj = TRUE;
+
+       return (tx);
+}
+
+int
+dmu_tx_is_syncing(dmu_tx_t *tx)
+{
+       return (tx->tx_anyobj);
+}
+
+int
+dmu_tx_private_ok(dmu_tx_t *tx)
+{
+       return (tx->tx_anyobj);
+}
+
+static dmu_tx_hold_t *
+dmu_tx_hold_object_impl(dmu_tx_t *tx, objset_t *os, uint64_t object,
+    enum dmu_tx_hold_type type, uint64_t arg1, uint64_t arg2)
+{
+       dmu_tx_hold_t *txh;
+       dnode_t *dn = NULL;
+       int err;
+
+       if (object != DMU_NEW_OBJECT) {
+               err = dnode_hold(os, object, tx, &dn);
+               if (err) {
+                       tx->tx_err = err;
+                       return (NULL);
+               }
+
+               if (err == 0 && tx->tx_txg != 0) {
+                       mutex_enter(&dn->dn_mtx);
+                       /*
+                        * dn->dn_assigned_txg == tx->tx_txg doesn't pose a
+                        * problem, but there's no way for it to happen (for
+                        * now, at least).
+                        */
+                       ASSERT(dn->dn_assigned_txg == 0);
+                       dn->dn_assigned_txg = tx->tx_txg;
+                       (void) refcount_add(&dn->dn_tx_holds, tx);
+                       mutex_exit(&dn->dn_mtx);
+               }
+       }
+
+       txh = kmem_zalloc(sizeof (dmu_tx_hold_t), KM_SLEEP);
+       txh->txh_tx = tx;
+       txh->txh_dnode = dn;
+#ifdef DEBUG_DMU_TX
+       txh->txh_type = type;
+       txh->txh_arg1 = arg1;
+       txh->txh_arg2 = arg2;
+#endif
+       list_insert_tail(&tx->tx_holds, txh);
+
+       return (txh);
+}
+
+void
+dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, uint64_t object)
+{
+       /*
+        * If we're syncing, they can manipulate any object anyhow, and
+        * the hold on the dnode_t can cause problems.
+        */
+       if (!dmu_tx_is_syncing(tx)) {
+               (void) dmu_tx_hold_object_impl(tx, os,
+                   object, THT_NEWOBJECT, 0, 0);
+       }
+}
+
+static int
+dmu_tx_check_ioerr(zio_t *zio, dnode_t *dn, int level, uint64_t blkid)
+{
+       int err;
+       dmu_buf_impl_t *db;
+
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       db = dbuf_hold_level(dn, level, blkid, FTAG);
+       rw_exit(&dn->dn_struct_rwlock);
+       if (db == NULL)
+               return (SET_ERROR(EIO));
+       err = dbuf_read(db, zio, DB_RF_CANFAIL | DB_RF_NOPREFETCH);
+       dbuf_rele(db, FTAG);
+       return (err);
+}
+
+static void
+dmu_tx_count_twig(dmu_tx_hold_t *txh, dnode_t *dn, dmu_buf_impl_t *db,
+    int level, uint64_t blkid, boolean_t freeable, uint64_t *history)
+{
+       objset_t *os = dn->dn_objset;
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+       int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+       dmu_buf_impl_t *parent = NULL;
+       blkptr_t *bp = NULL;
+       uint64_t space;
+
+       if (level >= dn->dn_nlevels || history[level] == blkid)
+               return;
+
+       history[level] = blkid;
+
+       space = (level == 0) ? dn->dn_datablksz : (1ULL << dn->dn_indblkshift);
+
+       if (db == NULL || db == dn->dn_dbuf) {
+               ASSERT(level != 0);
+               db = NULL;
+       } else {
+               ASSERT(DB_DNODE(db) == dn);
+               ASSERT(db->db_level == level);
+               ASSERT(db->db.db_size == space);
+               ASSERT(db->db_blkid == blkid);
+               bp = db->db_blkptr;
+               parent = db->db_parent;
+       }
+
+       freeable = (bp && (freeable ||
+           dsl_dataset_block_freeable(ds, bp, bp->blk_birth)));
+
+       if (freeable)
+               txh->txh_space_tooverwrite += space;
+       else
+               txh->txh_space_towrite += space;
+       if (bp)
+               txh->txh_space_tounref += bp_get_dsize(os->os_spa, bp);
+
+       dmu_tx_count_twig(txh, dn, parent, level + 1,
+           blkid >> epbs, freeable, history);
+}
+
+/* ARGSUSED */
+static void
+dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
+{
+       dnode_t *dn = txh->txh_dnode;
+       uint64_t start, end, i;
+       int min_bs, max_bs, min_ibs, max_ibs, epbs, bits;
+       int err = 0;
+       int l;
+
+       if (len == 0)
+               return;
+
+       min_bs = SPA_MINBLOCKSHIFT;
+       max_bs = highbit64(txh->txh_tx->tx_objset->os_recordsize) - 1;
+       min_ibs = DN_MIN_INDBLKSHIFT;
+       max_ibs = DN_MAX_INDBLKSHIFT;
+
+       if (dn) {
+               uint64_t history[DN_MAX_LEVELS];
+               int nlvls = dn->dn_nlevels;
+               int delta;
+
+               /*
+                * For i/o error checking, read the first and last level-0
+                * blocks (if they are not aligned), and all the level-1 blocks.
+                */
+               if (dn->dn_maxblkid == 0) {
+                       delta = dn->dn_datablksz;
+                       start = (off < dn->dn_datablksz) ? 0 : 1;
+                       end = (off+len <= dn->dn_datablksz) ? 0 : 1;
+                       if (start == 0 && (off > 0 || len < dn->dn_datablksz)) {
+                               err = dmu_tx_check_ioerr(NULL, dn, 0, 0);
+                               if (err)
+                                       goto out;
+                               delta -= off;
+                       }
+               } else {
+                       zio_t *zio = zio_root(dn->dn_objset->os_spa,
+                           NULL, NULL, ZIO_FLAG_CANFAIL);
+
+                       /* first level-0 block */
+                       start = off >> dn->dn_datablkshift;
+                       if (P2PHASE(off, dn->dn_datablksz) ||
+                           len < dn->dn_datablksz) {
+                               err = dmu_tx_check_ioerr(zio, dn, 0, start);
+                               if (err)
+                                       goto out;
+                       }
+
+                       /* last level-0 block */
+                       end = (off+len-1) >> dn->dn_datablkshift;
+                       if (end != start && end <= dn->dn_maxblkid &&
+                           P2PHASE(off+len, dn->dn_datablksz)) {
+                               err = dmu_tx_check_ioerr(zio, dn, 0, end);
+                               if (err)
+                                       goto out;
+                       }
+
+                       /* level-1 blocks */
+                       if (nlvls > 1) {
+                               int shft = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+                               for (i = (start>>shft)+1; i < end>>shft; i++) {
+                                       err = dmu_tx_check_ioerr(zio, dn, 1, i);
+                                       if (err)
+                                               goto out;
+                               }
+                       }
+
+                       err = zio_wait(zio);
+                       if (err)
+                               goto out;
+                       delta = P2NPHASE(off, dn->dn_datablksz);
+               }
+
+               min_ibs = max_ibs = dn->dn_indblkshift;
+               if (dn->dn_maxblkid > 0) {
+                       /*
+                        * The blocksize can't change,
+                        * so we can make a more precise estimate.
+                        */
+                       ASSERT(dn->dn_datablkshift != 0);
+                       min_bs = max_bs = dn->dn_datablkshift;
+               } else {
+                       /*
+                        * The blocksize can increase up to the recordsize,
+                        * or if it is already more than the recordsize,
+                        * up to the next power of 2.
+                        */
+                       min_bs = highbit64(dn->dn_datablksz - 1);
+                       max_bs = MAX(max_bs, highbit64(dn->dn_datablksz - 1));
+               }
+
+               /*
+                * If this write is not off the end of the file
+                * we need to account for overwrites/unref.
+                */
+               if (start <= dn->dn_maxblkid) {
+                       for (l = 0; l < DN_MAX_LEVELS; l++)
+                               history[l] = -1ULL;
+               }
+               while (start <= dn->dn_maxblkid) {
+                       dmu_buf_impl_t *db;
+
+                       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+                       err = dbuf_hold_impl(dn, 0, start, FALSE, FTAG, &db);
+                       rw_exit(&dn->dn_struct_rwlock);
+
+                       if (err) {
+                               txh->txh_tx->tx_err = err;
+                               return;
+                       }
+
+                       dmu_tx_count_twig(txh, dn, db, 0, start, B_FALSE,
+                           history);
+                       dbuf_rele(db, FTAG);
+                       if (++start > end) {
+                               /*
+                                * Account for new indirects appearing
+                                * before this IO gets assigned into a txg.
+                                */
+                               bits = 64 - min_bs;
+                               epbs = min_ibs - SPA_BLKPTRSHIFT;
+                               for (bits -= epbs * (nlvls - 1);
+                                   bits >= 0; bits -= epbs)
+                                       txh->txh_fudge += 1ULL << max_ibs;
+                               goto out;
+                       }
+                       off += delta;
+                       if (len >= delta)
+                               len -= delta;
+                       delta = dn->dn_datablksz;
+               }
+       }
+
+       /*
+        * 'end' is the last thing we will access, not one past.
+        * This way we won't overflow when accessing the last byte.
+        */
+       start = P2ALIGN(off, 1ULL << max_bs);
+       end = P2ROUNDUP(off + len, 1ULL << max_bs) - 1;
+       txh->txh_space_towrite += end - start + 1;
+
+       start >>= min_bs;
+       end >>= min_bs;
+
+       epbs = min_ibs - SPA_BLKPTRSHIFT;
+
+       /*
+        * The object contains at most 2^(64 - min_bs) blocks,
+        * and each indirect level maps 2^epbs.
+        */
+       for (bits = 64 - min_bs; bits >= 0; bits -= epbs) {
+               start >>= epbs;
+               end >>= epbs;
+               ASSERT3U(end, >=, start);
+               txh->txh_space_towrite += (end - start + 1) << max_ibs;
+               if (start != 0) {
+                       /*
+                        * We also need a new blkid=0 indirect block
+                        * to reference any existing file data.
+                        */
+                       txh->txh_space_towrite += 1ULL << max_ibs;
+               }
+       }
+
+out:
+       if (txh->txh_space_towrite + txh->txh_space_tooverwrite >
+           2 * DMU_MAX_ACCESS)
+               err = SET_ERROR(EFBIG);
+
+       if (err)
+               txh->txh_tx->tx_err = err;
+}
+
+static void
+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);
+
+       if (dn && dn->dn_dbuf->db_blkptr &&
+           dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
+           dn->dn_dbuf->db_blkptr, dn->dn_dbuf->db_blkptr->blk_birth)) {
+               txh->txh_space_tooverwrite += space;
+               txh->txh_space_tounref += space;
+       } else {
+               txh->txh_space_towrite += space;
+               if (dn && dn->dn_dbuf->db_blkptr)
+                       txh->txh_space_tounref += space;
+       }
+}
+
+void
+dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+       ASSERT(len <= DMU_MAX_ACCESS);
+       ASSERT(len == 0 || UINT64_MAX - off >= len - 1);
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           object, THT_WRITE, off, len);
+       if (txh == NULL)
+               return;
+
+       dmu_tx_count_write(txh, off, len);
+       dmu_tx_count_dnode(txh);
+}
+
+static void
+dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
+{
+       uint64_t blkid, nblks, lastblk;
+       uint64_t space = 0, unref = 0, skipped = 0;
+       dnode_t *dn = txh->txh_dnode;
+       dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
+       spa_t *spa = txh->txh_tx->tx_pool->dp_spa;
+       int epbs;
+       uint64_t l0span = 0, nl1blks = 0;
+
+       if (dn->dn_nlevels == 0)
+               return;
+
+       /*
+        * The struct_rwlock protects us against dn_nlevels
+        * changing, in case (against all odds) we manage to dirty &
+        * sync out the changes after we check for being dirty.
+        * Also, dbuf_hold_impl() wants us to have the struct_rwlock.
+        */
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+       if (dn->dn_maxblkid == 0) {
+               if (off == 0 && len >= dn->dn_datablksz) {
+                       blkid = 0;
+                       nblks = 1;
+               } else {
+                       rw_exit(&dn->dn_struct_rwlock);
+                       return;
+               }
+       } else {
+               blkid = off >> dn->dn_datablkshift;
+               nblks = (len + dn->dn_datablksz - 1) >> dn->dn_datablkshift;
+
+               if (blkid > dn->dn_maxblkid) {
+                       rw_exit(&dn->dn_struct_rwlock);
+                       return;
+               }
+               if (blkid + nblks > dn->dn_maxblkid)
+                       nblks = dn->dn_maxblkid - blkid + 1;
+
+       }
+       l0span = nblks;    /* save for later use to calc level > 1 overhead */
+       if (dn->dn_nlevels == 1) {
+               int i;
+               for (i = 0; i < nblks; i++) {
+                       blkptr_t *bp = dn->dn_phys->dn_blkptr;
+                       ASSERT3U(blkid + i, <, dn->dn_nblkptr);
+                       bp += blkid + i;
+                       if (dsl_dataset_block_freeable(ds, bp, bp->blk_birth)) {
+                               dprintf_bp(bp, "can free old%s", "");
+                               space += bp_get_dsize(spa, bp);
+                       }
+                       unref += BP_GET_ASIZE(bp);
+               }
+               nl1blks = 1;
+               nblks = 0;
+       }
+
+       lastblk = blkid + nblks - 1;
+       while (nblks) {
+               dmu_buf_impl_t *dbuf;
+               uint64_t ibyte, new_blkid;
+               int epb = 1 << epbs;
+               int err, i, blkoff, tochk;
+               blkptr_t *bp;
+
+               ibyte = blkid << dn->dn_datablkshift;
+               err = dnode_next_offset(dn,
+                   DNODE_FIND_HAVELOCK, &ibyte, 2, 1, 0);
+               new_blkid = ibyte >> dn->dn_datablkshift;
+               if (err == ESRCH) {
+                       skipped += (lastblk >> epbs) - (blkid >> epbs) + 1;
+                       break;
+               }
+               if (err) {
+                       txh->txh_tx->tx_err = err;
+                       break;
+               }
+               if (new_blkid > lastblk) {
+                       skipped += (lastblk >> epbs) - (blkid >> epbs) + 1;
+                       break;
+               }
+
+               if (new_blkid > blkid) {
+                       ASSERT((new_blkid >> epbs) > (blkid >> epbs));
+                       skipped += (new_blkid >> epbs) - (blkid >> epbs) - 1;
+                       nblks -= new_blkid - blkid;
+                       blkid = new_blkid;
+               }
+               blkoff = P2PHASE(blkid, epb);
+               tochk = MIN(epb - blkoff, nblks);
+
+               err = dbuf_hold_impl(dn, 1, blkid >> epbs, FALSE, FTAG, &dbuf);
+               if (err) {
+                       txh->txh_tx->tx_err = err;
+                       break;
+               }
+
+               txh->txh_memory_tohold += dbuf->db.db_size;
+
+               /*
+                * We don't check memory_tohold against DMU_MAX_ACCESS because
+                * memory_tohold is an over-estimation (especially the >L1
+                * indirect blocks), so it could fail.  Callers should have
+                * already verified that they will not be holding too much
+                * memory.
+                */
+
+               err = dbuf_read(dbuf, NULL, DB_RF_HAVESTRUCT | DB_RF_CANFAIL);
+               if (err != 0) {
+                       txh->txh_tx->tx_err = err;
+                       dbuf_rele(dbuf, FTAG);
+                       break;
+               }
+
+               bp = dbuf->db.db_data;
+               bp += blkoff;
+
+               for (i = 0; i < tochk; i++) {
+                       if (dsl_dataset_block_freeable(ds, &bp[i],
+                           bp[i].blk_birth)) {
+                               dprintf_bp(&bp[i], "can free old%s", "");
+                               space += bp_get_dsize(spa, &bp[i]);
+                       }
+                       unref += BP_GET_ASIZE(bp);
+               }
+               dbuf_rele(dbuf, FTAG);
+
+               ++nl1blks;
+               blkid += tochk;
+               nblks -= tochk;
+       }
+       rw_exit(&dn->dn_struct_rwlock);
+
+       /*
+        * Add in memory requirements of higher-level indirects.
+        * This assumes a worst-possible scenario for dn_nlevels and a
+        * worst-possible distribution of l1-blocks over the region to free.
+        */
+       {
+               uint64_t blkcnt = 1 + ((l0span >> epbs) >> epbs);
+               int level = 2;
+               /*
+                * Here we don't use DN_MAX_LEVEL, but calculate it with the
+                * given datablkshift and indblkshift. This makes the
+                * difference between 19 and 8 on large files.
+                */
+               int maxlevel = 2 + (DN_MAX_OFFSET_SHIFT - dn->dn_datablkshift) /
+                   (dn->dn_indblkshift - SPA_BLKPTRSHIFT);
+
+               while (level++ < maxlevel) {
+                       txh->txh_memory_tohold += MAX(MIN(blkcnt, nl1blks), 1)
+                           << dn->dn_indblkshift;
+                       blkcnt = 1 + (blkcnt >> epbs);
+               }
+       }
+
+       /* account for new level 1 indirect blocks that might show up */
+       if (skipped > 0) {
+               txh->txh_fudge += skipped << dn->dn_indblkshift;
+               skipped = MIN(skipped, DMU_MAX_DELETEBLKCNT >> epbs);
+               txh->txh_memory_tohold += skipped << dn->dn_indblkshift;
+       }
+       txh->txh_space_tofree += space;
+       txh->txh_space_tounref += unref;
+}
+
+void
+dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
+{
+       dmu_tx_hold_t *txh;
+       dnode_t *dn;
+       int err;
+       zio_t *zio;
+
+       ASSERT(tx->tx_txg == 0);
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           object, THT_FREE, off, len);
+       if (txh == NULL)
+               return;
+       dn = txh->txh_dnode;
+       dmu_tx_count_dnode(txh);
+
+       if (off >= (dn->dn_maxblkid+1) * dn->dn_datablksz)
+               return;
+       if (len == DMU_OBJECT_END)
+               len = (dn->dn_maxblkid+1) * dn->dn_datablksz - off;
+
+       dmu_tx_count_dnode(txh);
+
+       /*
+        * For i/o error checking, we read the first and last level-0
+        * blocks if they are not aligned, and all the level-1 blocks.
+        *
+        * Note:  dbuf_free_range() assumes that we have not instantiated
+        * any level-0 dbufs that will be completely freed.  Therefore we must
+        * exercise care to not read or count the first and last blocks
+        * if they are blocksize-aligned.
+        */
+       if (dn->dn_datablkshift == 0) {
+               if (off != 0 || len < dn->dn_datablksz)
+                       dmu_tx_count_write(txh, 0, dn->dn_datablksz);
+       } else {
+               /* first block will be modified if it is not aligned */
+               if (!IS_P2ALIGNED(off, 1 << dn->dn_datablkshift))
+                       dmu_tx_count_write(txh, off, 1);
+               /* last block will be modified if it is not aligned */
+               if (!IS_P2ALIGNED(off + len, 1 << dn->dn_datablkshift))
+                       dmu_tx_count_write(txh, off+len, 1);
+       }
+
+       /*
+        * Check level-1 blocks.
+        */
+       if (dn->dn_nlevels > 1) {
+               int shift = dn->dn_datablkshift + dn->dn_indblkshift -
+                   SPA_BLKPTRSHIFT;
+               uint64_t start = off >> shift;
+               uint64_t end = (off + len) >> shift;
+               uint64_t i;
+
+               ASSERT(dn->dn_indblkshift != 0);
+
+               /*
+                * dnode_reallocate() can result in an object with indirect
+                * blocks having an odd data block size.  In this case,
+                * just check the single block.
+                */
+               if (dn->dn_datablkshift == 0)
+                       start = end = 0;
+
+               zio = zio_root(tx->tx_pool->dp_spa,
+                   NULL, NULL, ZIO_FLAG_CANFAIL);
+               for (i = start; i <= end; i++) {
+                       uint64_t ibyte = i << shift;
+                       err = dnode_next_offset(dn, 0, &ibyte, 2, 1, 0);
+                       i = ibyte >> shift;
+                       if (err == ESRCH || i > end)
+                               break;
+                       if (err) {
+                               tx->tx_err = err;
+                               return;
+                       }
+
+                       err = dmu_tx_check_ioerr(zio, dn, 1, i);
+                       if (err) {
+                               tx->tx_err = err;
+                               return;
+                       }
+               }
+               err = zio_wait(zio);
+               if (err) {
+                       tx->tx_err = err;
+                       return;
+               }
+       }
+
+       dmu_tx_count_free(txh, off, len);
+}
+
+void
+dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
+{
+       dmu_tx_hold_t *txh;
+       dnode_t *dn;
+       dsl_dataset_phys_t *ds_phys;
+       uint64_t nblocks;
+       int epbs, err;
+
+       ASSERT(tx->tx_txg == 0);
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           object, THT_ZAP, add, (uintptr_t)name);
+       if (txh == NULL)
+               return;
+       dn = txh->txh_dnode;
+
+       dmu_tx_count_dnode(txh);
+
+       if (dn == NULL) {
+               /*
+                * We will be able to fit a new object's entries into one leaf
+                * block.  So there will be at most 2 blocks total,
+                * including the header block.
+                */
+               dmu_tx_count_write(txh, 0, 2 << fzap_default_block_shift);
+               return;
+       }
+
+       ASSERT3U(DMU_OT_BYTESWAP(dn->dn_type), ==, DMU_BSWAP_ZAP);
+
+       if (dn->dn_maxblkid == 0 && !add) {
+               blkptr_t *bp;
+
+               /*
+                * If there is only one block  (i.e. this is a micro-zap)
+                * and we are not adding anything, the accounting is simple.
+                */
+               err = dmu_tx_check_ioerr(NULL, dn, 0, 0);
+               if (err) {
+                       tx->tx_err = err;
+                       return;
+               }
+
+               /*
+                * Use max block size here, since we don't know how much
+                * the size will change between now and the dbuf dirty call.
+                */
+               bp = &dn->dn_phys->dn_blkptr[0];
+               if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
+                   bp, bp->blk_birth))
+                       txh->txh_space_tooverwrite += MZAP_MAX_BLKSZ;
+               else
+                       txh->txh_space_towrite += MZAP_MAX_BLKSZ;
+               if (!BP_IS_HOLE(bp))
+                       txh->txh_space_tounref += MZAP_MAX_BLKSZ;
+               return;
+       }
+
+       if (dn->dn_maxblkid > 0 && 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);
+               if (err == EIO) {
+                       tx->tx_err = err;
+                       return;
+               }
+       }
+
+       err = zap_count_write(dn->dn_objset, dn->dn_object, name, add,
+           &txh->txh_space_towrite, &txh->txh_space_tooverwrite);
+
+       /*
+        * If the modified blocks are scattered to the four winds,
+        * we'll have to modify an indirect twig for each.
+        */
+       epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+       ds_phys = dsl_dataset_phys(dn->dn_objset->os_dsl_dataset);
+       for (nblocks = dn->dn_maxblkid >> epbs; nblocks != 0; nblocks >>= epbs)
+               if (ds_phys->ds_prev_snap_obj)
+                       txh->txh_space_towrite += 3 << dn->dn_indblkshift;
+               else
+                       txh->txh_space_tooverwrite += 3 << dn->dn_indblkshift;
+}
+
+void
+dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           object, THT_BONUS, 0, 0);
+       if (txh)
+               dmu_tx_count_dnode(txh);
+}
+
+void
+dmu_tx_hold_space(dmu_tx_t *tx, uint64_t space)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           DMU_NEW_OBJECT, THT_SPACE, space, 0);
+       if (txh)
+               txh->txh_space_towrite += space;
+}
+
+int
+dmu_tx_holds(dmu_tx_t *tx, uint64_t object)
+{
+       dmu_tx_hold_t *txh;
+       int holds = 0;
+
+       /*
+        * By asserting that the tx is assigned, we're counting the
+        * number of dn_tx_holds, which is the same as the number of
+        * dn_holds.  Otherwise, we'd be counting dn_holds, but
+        * dn_tx_holds could be 0.
+        */
+       ASSERT(tx->tx_txg != 0);
+
+       /* if (tx->tx_anyobj == TRUE) */
+               /* return (0); */
+
+       for (txh = list_head(&tx->tx_holds); txh;
+           txh = list_next(&tx->tx_holds, txh)) {
+               if (txh->txh_dnode && txh->txh_dnode->dn_object == object)
+                       holds++;
+       }
+
+       return (holds);
+}
+
+#ifdef DEBUG_DMU_TX
+void
+dmu_tx_dirty_buf(dmu_tx_t *tx, dmu_buf_impl_t *db)
+{
+       dmu_tx_hold_t *txh;
+       int match_object = FALSE, match_offset = FALSE;
+       dnode_t *dn;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       ASSERT(dn != NULL);
+       ASSERT(tx->tx_txg != 0);
+       ASSERT(tx->tx_objset == NULL || dn->dn_objset == tx->tx_objset);
+       ASSERT3U(dn->dn_object, ==, db->db.db_object);
+
+       if (tx->tx_anyobj) {
+               DB_DNODE_EXIT(db);
+               return;
+       }
+
+       /* XXX No checking on the meta dnode for now */
+       if (db->db.db_object == DMU_META_DNODE_OBJECT) {
+               DB_DNODE_EXIT(db);
+               return;
+       }
+
+       for (txh = list_head(&tx->tx_holds); txh;
+           txh = list_next(&tx->tx_holds, txh)) {
+               ASSERT3U(dn->dn_assigned_txg, ==, tx->tx_txg);
+               if (txh->txh_dnode == dn && txh->txh_type != THT_NEWOBJECT)
+                       match_object = TRUE;
+               if (txh->txh_dnode == NULL || txh->txh_dnode == dn) {
+                       int datablkshift = dn->dn_datablkshift ?
+                           dn->dn_datablkshift : SPA_MAXBLOCKSHIFT;
+                       int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+                       int shift = datablkshift + epbs * db->db_level;
+                       uint64_t beginblk = shift >= 64 ? 0 :
+                           (txh->txh_arg1 >> shift);
+                       uint64_t endblk = shift >= 64 ? 0 :
+                           ((txh->txh_arg1 + txh->txh_arg2 - 1) >> shift);
+                       uint64_t blkid = db->db_blkid;
+
+                       /* XXX txh_arg2 better not be zero... */
+
+                       dprintf("found txh type %x beginblk=%llx endblk=%llx\n",
+                           txh->txh_type, beginblk, endblk);
+
+                       switch (txh->txh_type) {
+                       case THT_WRITE:
+                               if (blkid >= beginblk && blkid <= endblk)
+                                       match_offset = TRUE;
+                               /*
+                                * We will let this hold work for the bonus
+                                * or spill buffer so that we don't need to
+                                * hold it when creating a new object.
+                                */
+                               if (blkid == DMU_BONUS_BLKID ||
+                                   blkid == DMU_SPILL_BLKID)
+                                       match_offset = TRUE;
+                               /*
+                                * They might have to increase nlevels,
+                                * thus dirtying the new TLIBs.  Or the
+                                * might have to change the block size,
+                                * thus dirying the new lvl=0 blk=0.
+                                */
+                               if (blkid == 0)
+                                       match_offset = TRUE;
+                               break;
+                       case THT_FREE:
+                               /*
+                                * We will dirty all the level 1 blocks in
+                                * the free range and perhaps the first and
+                                * last level 0 block.
+                                */
+                               if (blkid >= beginblk && (blkid <= endblk ||
+                                   txh->txh_arg2 == DMU_OBJECT_END))
+                                       match_offset = TRUE;
+                               break;
+                       case THT_SPILL:
+                               if (blkid == DMU_SPILL_BLKID)
+                                       match_offset = TRUE;
+                               break;
+                       case THT_BONUS:
+                               if (blkid == DMU_BONUS_BLKID)
+                                       match_offset = TRUE;
+                               break;
+                       case THT_ZAP:
+                               match_offset = TRUE;
+                               break;
+                       case THT_NEWOBJECT:
+                               match_object = TRUE;
+                               break;
+                       default:
+                               cmn_err(CE_PANIC, "bad txh_type %d",
+                                   txh->txh_type);
+                       }
+               }
+               if (match_object && match_offset) {
+                       DB_DNODE_EXIT(db);
+                       return;
+               }
+       }
+       DB_DNODE_EXIT(db);
+       panic("dirtying dbuf obj=%llx lvl=%u blkid=%llx but not tx_held\n",
+           (u_longlong_t)db->db.db_object, db->db_level,
+           (u_longlong_t)db->db_blkid);
+}
+#endif
+
+/*
+ * If we can't do 10 iops, something is wrong.  Let us go ahead
+ * and hit zfs_dirty_data_max.
+ */
+hrtime_t zfs_delay_max_ns = 100 * MICROSEC; /* 100 milliseconds */
+int zfs_delay_resolution_ns = 100 * 1000; /* 100 microseconds */
+
+/*
+ * We delay transactions when we've determined that the backend storage
+ * isn't able to accommodate the rate of incoming writes.
+ *
+ * If there is already a transaction waiting, we delay relative to when
+ * that transaction finishes waiting.  This way the calculated min_time
+ * is independent of the number of threads concurrently executing
+ * transactions.
+ *
+ * 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.
+ *
+ * The minimum time for a transaction to take is calculated as:
+ *     min_time = scale * (dirty - min) / (max - dirty)
+ *     min_time is then capped at zfs_delay_max_ns.
+ *
+ * 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
+ * zfs_delay_min_dirty_percent. This should typically be at or above
+ * zfs_vdev_async_write_active_max_dirty_percent 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 zfs_delay_scale. Roughly
+ * speaking, this variable determines the amount of delay at the midpoint of
+ * the curve.
+ *
+ * delay
+ *  10ms +-------------------------------------------------------------*+
+ *       |                                                             *|
+ *   9ms +                                                             *+
+ *       |                                                             *|
+ *   8ms +                                                             *+
+ *       |                                                            * |
+ *   7ms +                                                            * +
+ *       |                                                            * |
+ *   6ms +                                                            * +
+ *       |                                                            * |
+ *   5ms +                                                           *  +
+ *       |                                                           *  |
+ *   4ms +                                                           *  +
+ *       |                                                           *  |
+ *   3ms +                                                          *   +
+ *       |                                                          *   |
+ *   2ms +                                              (midpoint) *    +
+ *       |                                                  |    **     |
+ *   1ms +                                                  v ***       +
+ *       |             zfs_delay_scale ---------->     ********         |
+ *     0 +-------------------------------------*********----------------+
+ *       0%                    <- zfs_dirty_data_max ->               100%
+ *
+ * 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.
+ *
+ * The effects can be easier to understand when the amount of delay is
+ * represented on a log scale:
+ *
+ * delay
+ * 100ms +-------------------------------------------------------------++
+ *       +                                                              +
+ *       |                                                              |
+ *       +                                                             *+
+ *  10ms +                                                             *+
+ *       +                                                           ** +
+ *       |                                              (midpoint)  **  |
+ *       +                                                  |     **    +
+ *   1ms +                                                  v ****      +
+ *       +             zfs_delay_scale ---------->        *****         +
+ *       |                                             ****             |
+ *       +                                          ****                +
+ * 100us +                                        **                    +
+ *       +                                       *                      +
+ *       |                                      *                       |
+ *       +                                     *                        +
+ *  10us +                                     *                        +
+ *       +                                                              +
+ *       |                                                              |
+ *       +                                                              +
+ *       +--------------------------------------------------------------+
+ *       0%                    <- zfs_dirty_data_max ->               100%
+ *
+ * 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 zfs_delay_scale to increase the steepness of the curve.
+ */
+static void
+dmu_tx_delay(dmu_tx_t *tx, uint64_t dirty)
+{
+       dsl_pool_t *dp = tx->tx_pool;
+       uint64_t delay_min_bytes =
+           zfs_dirty_data_max * zfs_delay_min_dirty_percent / 100;
+       hrtime_t wakeup, min_tx_time, now;
+
+       if (dirty <= delay_min_bytes)
+               return;
+
+       /*
+        * The caller has already waited until we are under the max.
+        * We make them pass us the amount of dirty data so we don't
+        * have to handle the case of it being >= the max, which could
+        * cause a divide-by-zero if it's == the max.
+        */
+       ASSERT3U(dirty, <, zfs_dirty_data_max);
+
+       now = gethrtime();
+       min_tx_time = zfs_delay_scale *
+           (dirty - delay_min_bytes) / (zfs_dirty_data_max - dirty);
+       min_tx_time = MIN(min_tx_time, zfs_delay_max_ns);
+       if (now > tx->tx_start + min_tx_time)
+               return;
+
+       DTRACE_PROBE3(delay__mintime, dmu_tx_t *, tx, uint64_t, dirty,
+           uint64_t, min_tx_time);
+
+       mutex_enter(&dp->dp_lock);
+       wakeup = MAX(tx->tx_start + min_tx_time,
+           dp->dp_last_wakeup + min_tx_time);
+       dp->dp_last_wakeup = wakeup;
+       mutex_exit(&dp->dp_lock);
+
+       zfs_sleep_until(wakeup);
+}
+
+static int
+dmu_tx_try_assign(dmu_tx_t *tx, txg_how_t txg_how)
+{
+       dmu_tx_hold_t *txh;
+       spa_t *spa = tx->tx_pool->dp_spa;
+       uint64_t memory, asize, fsize, usize;
+       uint64_t towrite, tofree, tooverwrite, tounref, tohold, fudge;
+
+       ASSERT0(tx->tx_txg);
+
+       if (tx->tx_err) {
+               DMU_TX_STAT_BUMP(dmu_tx_error);
+               return (tx->tx_err);
+       }
+
+       if (spa_suspended(spa)) {
+               DMU_TX_STAT_BUMP(dmu_tx_suspended);
+
+               /*
+                * If the user has indicated a blocking failure mode
+                * then return ERESTART which will block in dmu_tx_wait().
+                * Otherwise, return EIO so that an error can get
+                * propagated back to the VOP calls.
+                *
+                * Note that we always honor the txg_how flag regardless
+                * of the failuremode setting.
+                */
+               if (spa_get_failmode(spa) == ZIO_FAILURE_MODE_CONTINUE &&
+                   txg_how != TXG_WAIT)
+                       return (SET_ERROR(EIO));
+
+               return (SET_ERROR(ERESTART));
+       }
+
+       if (!tx->tx_waited &&
+           dsl_pool_need_dirty_delay(tx->tx_pool)) {
+               tx->tx_wait_dirty = B_TRUE;
+               DMU_TX_STAT_BUMP(dmu_tx_dirty_delay);
+               return (ERESTART);
+       }
+
+       tx->tx_txg = txg_hold_open(tx->tx_pool, &tx->tx_txgh);
+       tx->tx_needassign_txh = NULL;
+
+       /*
+        * NB: No error returns are allowed after txg_hold_open, but
+        * before processing the dnode holds, due to the
+        * dmu_tx_unassign() logic.
+        */
+
+       towrite = tofree = tooverwrite = tounref = tohold = fudge = 0;
+       for (txh = list_head(&tx->tx_holds); txh;
+           txh = list_next(&tx->tx_holds, txh)) {
+               dnode_t *dn = txh->txh_dnode;
+               if (dn != NULL) {
+                       mutex_enter(&dn->dn_mtx);
+                       if (dn->dn_assigned_txg == tx->tx_txg - 1) {
+                               mutex_exit(&dn->dn_mtx);
+                               tx->tx_needassign_txh = txh;
+                               DMU_TX_STAT_BUMP(dmu_tx_group);
+                               return (SET_ERROR(ERESTART));
+                       }
+                       if (dn->dn_assigned_txg == 0)
+                               dn->dn_assigned_txg = tx->tx_txg;
+                       ASSERT3U(dn->dn_assigned_txg, ==, tx->tx_txg);
+                       (void) refcount_add(&dn->dn_tx_holds, tx);
+                       mutex_exit(&dn->dn_mtx);
+               }
+               towrite += txh->txh_space_towrite;
+               tofree += txh->txh_space_tofree;
+               tooverwrite += txh->txh_space_tooverwrite;
+               tounref += txh->txh_space_tounref;
+               tohold += txh->txh_memory_tohold;
+               fudge += txh->txh_fudge;
+       }
+
+       /*
+        * If a snapshot has been taken since we made our estimates,
+        * assume that we won't be able to free or overwrite anything.
+        */
+       if (tx->tx_objset &&
+           dsl_dataset_prev_snap_txg(tx->tx_objset->os_dsl_dataset) >
+           tx->tx_lastsnap_txg) {
+               towrite += tooverwrite;
+               tooverwrite = tofree = 0;
+       }
+
+       /* needed allocation: worst-case estimate of write space */
+       asize = spa_get_asize(tx->tx_pool->dp_spa, towrite + tooverwrite);
+       /* freed space estimate: worst-case overwrite + free estimate */
+       fsize = spa_get_asize(tx->tx_pool->dp_spa, tooverwrite) + tofree;
+       /* convert unrefd space to worst-case estimate */
+       usize = spa_get_asize(tx->tx_pool->dp_spa, tounref);
+       /* calculate memory footprint estimate */
+       memory = towrite + tooverwrite + tohold;
+
+#ifdef DEBUG_DMU_TX
+       /*
+        * Add in 'tohold' to account for our dirty holds on this memory
+        * XXX - the "fudge" factor is to account for skipped blocks that
+        * we missed because dnode_next_offset() misses in-core-only blocks.
+        */
+       tx->tx_space_towrite = asize +
+           spa_get_asize(tx->tx_pool->dp_spa, tohold + fudge);
+       tx->tx_space_tofree = tofree;
+       tx->tx_space_tooverwrite = tooverwrite;
+       tx->tx_space_tounref = tounref;
+#endif
+
+       if (tx->tx_dir && asize != 0) {
+               int err = dsl_dir_tempreserve_space(tx->tx_dir, memory,
+                   asize, fsize, usize, &tx->tx_tempreserve_cookie, tx);
+               if (err)
+                       return (err);
+       }
+
+       DMU_TX_STAT_BUMP(dmu_tx_assigned);
+
+       return (0);
+}
+
+static void
+dmu_tx_unassign(dmu_tx_t *tx)
+{
+       dmu_tx_hold_t *txh;
+
+       if (tx->tx_txg == 0)
+               return;
+
+       txg_rele_to_quiesce(&tx->tx_txgh);
+
+       /*
+        * Walk the transaction's hold list, removing the hold on the
+        * associated dnode, and notifying waiters if the refcount drops to 0.
+        */
+       for (txh = list_head(&tx->tx_holds); txh != tx->tx_needassign_txh;
+           txh = list_next(&tx->tx_holds, txh)) {
+               dnode_t *dn = txh->txh_dnode;
+
+               if (dn == NULL)
+                       continue;
+               mutex_enter(&dn->dn_mtx);
+               ASSERT3U(dn->dn_assigned_txg, ==, tx->tx_txg);
+
+               if (refcount_remove(&dn->dn_tx_holds, tx) == 0) {
+                       dn->dn_assigned_txg = 0;
+                       cv_broadcast(&dn->dn_notxholds);
+               }
+               mutex_exit(&dn->dn_mtx);
+       }
+
+       txg_rele_to_sync(&tx->tx_txgh);
+
+       tx->tx_lasttried_txg = tx->tx_txg;
+       tx->tx_txg = 0;
+}
+
+/*
+ * Assign tx to a transaction group.  txg_how can be one of:
+ *
+ * (1) TXG_WAIT.  If the current open txg is full, waits until there's
+ *     a new one.  This should be used when you're not holding locks.
+ *     It will only fail if we're truly out of space (or over quota).
+ *
+ * (2) TXG_NOWAIT.  If we can't assign into the current open txg without
+ *     blocking, returns immediately with ERESTART.  This should be used
+ *     whenever you're holding locks.  On an ERESTART error, the caller
+ *     should drop locks, do a dmu_tx_wait(tx), and try again.
+ *
+ * (3) TXG_WAITED.  Like TXG_NOWAIT, but indicates that dmu_tx_wait()
+ *     has already been called on behalf of this operation (though
+ *     most likely on a different tx).
+ */
+int
+dmu_tx_assign(dmu_tx_t *tx, txg_how_t txg_how)
+{
+       int err;
+
+       ASSERT(tx->tx_txg == 0);
+       ASSERT(txg_how == TXG_WAIT || txg_how == TXG_NOWAIT ||
+           txg_how == TXG_WAITED);
+       ASSERT(!dsl_pool_sync_context(tx->tx_pool));
+
+       if (txg_how == TXG_WAITED)
+               tx->tx_waited = B_TRUE;
+
+       /* If we might wait, we must not hold the config lock. */
+       ASSERT(txg_how != TXG_WAIT || !dsl_pool_config_held(tx->tx_pool));
+
+       while ((err = dmu_tx_try_assign(tx, txg_how)) != 0) {
+               dmu_tx_unassign(tx);
+
+               if (err != ERESTART || txg_how != TXG_WAIT)
+                       return (err);
+
+               dmu_tx_wait(tx);
+       }
+
+       txg_rele_to_quiesce(&tx->tx_txgh);
+
+       return (0);
+}
+
+void
+dmu_tx_wait(dmu_tx_t *tx)
+{
+       spa_t *spa = tx->tx_pool->dp_spa;
+       dsl_pool_t *dp = tx->tx_pool;
+       hrtime_t before;
+
+       ASSERT(tx->tx_txg == 0);
+       ASSERT(!dsl_pool_config_held(tx->tx_pool));
+
+       before = gethrtime();
+
+       if (tx->tx_wait_dirty) {
+               uint64_t dirty;
+
+               /*
+                * dmu_tx_try_assign() has determined that we need to wait
+                * because we've consumed much or all of the dirty buffer
+                * space.
+                */
+               mutex_enter(&dp->dp_lock);
+               if (dp->dp_dirty_total >= zfs_dirty_data_max)
+                       DMU_TX_STAT_BUMP(dmu_tx_dirty_over_max);
+               while (dp->dp_dirty_total >= zfs_dirty_data_max)
+                       cv_wait(&dp->dp_spaceavail_cv, &dp->dp_lock);
+               dirty = dp->dp_dirty_total;
+               mutex_exit(&dp->dp_lock);
+
+               dmu_tx_delay(tx, dirty);
+
+               tx->tx_wait_dirty = B_FALSE;
+
+               /*
+                * Note: setting tx_waited only has effect if the caller
+                * used TX_WAIT.  Otherwise they are going to destroy
+                * this tx and try again.  The common case, zfs_write(),
+                * uses TX_WAIT.
+                */
+               tx->tx_waited = B_TRUE;
+       } else if (spa_suspended(spa) || tx->tx_lasttried_txg == 0) {
+               /*
+                * If the pool is suspended we need to wait until it
+                * is resumed.  Note that it's possible that the pool
+                * has become active after this thread has tried to
+                * obtain a tx.  If that's the case then tx_lasttried_txg
+                * would not have been set.
+                */
+               txg_wait_synced(dp, spa_last_synced_txg(spa) + 1);
+       } else if (tx->tx_needassign_txh) {
+               dnode_t *dn = tx->tx_needassign_txh->txh_dnode;
+
+               mutex_enter(&dn->dn_mtx);
+               while (dn->dn_assigned_txg == tx->tx_lasttried_txg - 1)
+                       cv_wait(&dn->dn_notxholds, &dn->dn_mtx);
+               mutex_exit(&dn->dn_mtx);
+               tx->tx_needassign_txh = NULL;
+       } else {
+               /*
+                * A dnode is assigned to the quiescing txg.  Wait for its
+                * transaction to complete.
+                */
+               txg_wait_open(tx->tx_pool, tx->tx_lasttried_txg + 1);
+       }
+
+       spa_tx_assign_add_nsecs(spa, gethrtime() - before);
+}
+
+void
+dmu_tx_willuse_space(dmu_tx_t *tx, int64_t delta)
+{
+#ifdef DEBUG_DMU_TX
+       if (tx->tx_dir == NULL || delta == 0)
+               return;
+
+       if (delta > 0) {
+               ASSERT3U(refcount_count(&tx->tx_space_written) + delta, <=,
+                   tx->tx_space_towrite);
+               (void) refcount_add_many(&tx->tx_space_written, delta, NULL);
+       } else {
+               (void) refcount_add_many(&tx->tx_space_freed, -delta, NULL);
+       }
+#endif
+}
+
+void
+dmu_tx_commit(dmu_tx_t *tx)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg != 0);
+
+       /*
+        * Go through the transaction's hold list and remove holds on
+        * associated dnodes, notifying waiters if no holds remain.
+        */
+       while ((txh = list_head(&tx->tx_holds))) {
+               dnode_t *dn = txh->txh_dnode;
+
+               list_remove(&tx->tx_holds, txh);
+               kmem_free(txh, sizeof (dmu_tx_hold_t));
+               if (dn == NULL)
+                       continue;
+               mutex_enter(&dn->dn_mtx);
+               ASSERT3U(dn->dn_assigned_txg, ==, tx->tx_txg);
+
+               if (refcount_remove(&dn->dn_tx_holds, tx) == 0) {
+                       dn->dn_assigned_txg = 0;
+                       cv_broadcast(&dn->dn_notxholds);
+               }
+               mutex_exit(&dn->dn_mtx);
+               dnode_rele(dn, tx);
+       }
+
+       if (tx->tx_tempreserve_cookie)
+               dsl_dir_tempreserve_clear(tx->tx_tempreserve_cookie, tx);
+
+       if (!list_is_empty(&tx->tx_callbacks))
+               txg_register_callbacks(&tx->tx_txgh, &tx->tx_callbacks);
+
+       if (tx->tx_anyobj == FALSE)
+               txg_rele_to_sync(&tx->tx_txgh);
+
+       list_destroy(&tx->tx_callbacks);
+       list_destroy(&tx->tx_holds);
+#ifdef DEBUG_DMU_TX
+       dprintf("towrite=%llu written=%llu tofree=%llu freed=%llu\n",
+           tx->tx_space_towrite, refcount_count(&tx->tx_space_written),
+           tx->tx_space_tofree, refcount_count(&tx->tx_space_freed));
+       refcount_destroy_many(&tx->tx_space_written,
+           refcount_count(&tx->tx_space_written));
+       refcount_destroy_many(&tx->tx_space_freed,
+           refcount_count(&tx->tx_space_freed));
+#endif
+       kmem_free(tx, sizeof (dmu_tx_t));
+}
+
+void
+dmu_tx_abort(dmu_tx_t *tx)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+
+       while ((txh = list_head(&tx->tx_holds))) {
+               dnode_t *dn = txh->txh_dnode;
+
+               list_remove(&tx->tx_holds, txh);
+               kmem_free(txh, sizeof (dmu_tx_hold_t));
+               if (dn != NULL)
+                       dnode_rele(dn, tx);
+       }
+
+       /*
+        * Call any registered callbacks with an error code.
+        */
+       if (!list_is_empty(&tx->tx_callbacks))
+               dmu_tx_do_callbacks(&tx->tx_callbacks, ECANCELED);
+
+       list_destroy(&tx->tx_callbacks);
+       list_destroy(&tx->tx_holds);
+#ifdef DEBUG_DMU_TX
+       refcount_destroy_many(&tx->tx_space_written,
+           refcount_count(&tx->tx_space_written));
+       refcount_destroy_many(&tx->tx_space_freed,
+           refcount_count(&tx->tx_space_freed));
+#endif
+       kmem_free(tx, sizeof (dmu_tx_t));
+}
+
+uint64_t
+dmu_tx_get_txg(dmu_tx_t *tx)
+{
+       ASSERT(tx->tx_txg != 0);
+       return (tx->tx_txg);
+}
+
+dsl_pool_t *
+dmu_tx_pool(dmu_tx_t *tx)
+{
+       ASSERT(tx->tx_pool != NULL);
+       return (tx->tx_pool);
+}
+
+void
+dmu_tx_callback_register(dmu_tx_t *tx, dmu_tx_callback_func_t *func, void *data)
+{
+       dmu_tx_callback_t *dcb;
+
+       dcb = kmem_alloc(sizeof (dmu_tx_callback_t), KM_SLEEP);
+
+       dcb->dcb_func = func;
+       dcb->dcb_data = data;
+
+       list_insert_tail(&tx->tx_callbacks, dcb);
+}
+
+/*
+ * Call all the commit callbacks on a list, with a given error code.
+ */
+void
+dmu_tx_do_callbacks(list_t *cb_list, int error)
+{
+       dmu_tx_callback_t *dcb;
+
+       while ((dcb = list_head(cb_list))) {
+               list_remove(cb_list, dcb);
+               dcb->dcb_func(dcb->dcb_data, error);
+               kmem_free(dcb, sizeof (dmu_tx_callback_t));
+       }
+}
+
+/*
+ * Interface to hold a bunch of attributes.
+ * used for creating new files.
+ * attrsize is the total size of all attributes
+ * to be added during object creation
+ *
+ * For updating/adding a single attribute dmu_tx_hold_sa() should be used.
+ */
+
+/*
+ * hold necessary attribute name for attribute registration.
+ * should be a very rare case where this is needed.  If it does
+ * happen it would only happen on the first write to the file system.
+ */
+static void
+dmu_tx_sa_registration_hold(sa_os_t *sa, dmu_tx_t *tx)
+{
+       int i;
+
+       if (!sa->sa_need_attr_registration)
+               return;
+
+       for (i = 0; i != sa->sa_num_attrs; i++) {
+               if (!sa->sa_attr_table[i].sa_registered) {
+                       if (sa->sa_reg_attr_obj)
+                               dmu_tx_hold_zap(tx, sa->sa_reg_attr_obj,
+                                   B_TRUE, sa->sa_attr_table[i].sa_name);
+                       else
+                               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT,
+                                   B_TRUE, sa->sa_attr_table[i].sa_name);
+               }
+       }
+}
+
+
+void
+dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object)
+{
+       dnode_t *dn;
+       dmu_tx_hold_t *txh;
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset, object,
+           THT_SPILL, 0, 0);
+       if (txh == NULL)
+               return;
+
+       dn = txh->txh_dnode;
+
+       if (dn == NULL)
+               return;
+
+       /* If blkptr doesn't exist then add space to towrite */
+       if (!(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR)) {
+               txh->txh_space_towrite += SPA_OLD_MAXBLOCKSIZE;
+       } else {
+               blkptr_t *bp;
+
+               bp = &dn->dn_phys->dn_spill;
+               if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
+                   bp, bp->blk_birth))
+                       txh->txh_space_tooverwrite += SPA_OLD_MAXBLOCKSIZE;
+               else
+                       txh->txh_space_towrite += SPA_OLD_MAXBLOCKSIZE;
+               if (!BP_IS_HOLE(bp))
+                       txh->txh_space_tounref += SPA_OLD_MAXBLOCKSIZE;
+       }
+}
+
+void
+dmu_tx_hold_sa_create(dmu_tx_t *tx, int attrsize)
+{
+       sa_os_t *sa = tx->tx_objset->os_sa;
+
+       dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+
+       if (tx->tx_objset->os_sa->sa_master_obj == 0)
+               return;
+
+       if (tx->tx_objset->os_sa->sa_layout_attr_obj)
+               dmu_tx_hold_zap(tx, sa->sa_layout_attr_obj, B_TRUE, NULL);
+       else {
+               dmu_tx_hold_zap(tx, sa->sa_master_obj, B_TRUE, SA_LAYOUTS);
+               dmu_tx_hold_zap(tx, sa->sa_master_obj, B_TRUE, SA_REGISTRY);
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, B_TRUE, NULL);
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, B_TRUE, NULL);
+       }
+
+       dmu_tx_sa_registration_hold(sa, tx);
+
+       if (attrsize <= DN_MAX_BONUSLEN && !sa->sa_force_spill)
+               return;
+
+       (void) dmu_tx_hold_object_impl(tx, tx->tx_objset, DMU_NEW_OBJECT,
+           THT_SPILL, 0, 0);
+}
+
+/*
+ * Hold SA attribute
+ *
+ * dmu_tx_hold_sa(dmu_tx_t *tx, sa_handle_t *, attribute, add, size)
+ *
+ * variable_size is the total size of all variable sized attributes
+ * passed to this function.  It is not the total size of all
+ * variable size attributes that *may* exist on this object.
+ */
+void
+dmu_tx_hold_sa(dmu_tx_t *tx, sa_handle_t *hdl, boolean_t may_grow)
+{
+       uint64_t object;
+       sa_os_t *sa = tx->tx_objset->os_sa;
+
+       ASSERT(hdl != NULL);
+
+       object = sa_handle_object(hdl);
+
+       dmu_tx_hold_bonus(tx, object);
+
+       if (tx->tx_objset->os_sa->sa_master_obj == 0)
+               return;
+
+       if (tx->tx_objset->os_sa->sa_reg_attr_obj == 0 ||
+           tx->tx_objset->os_sa->sa_layout_attr_obj == 0) {
+               dmu_tx_hold_zap(tx, sa->sa_master_obj, B_TRUE, SA_LAYOUTS);
+               dmu_tx_hold_zap(tx, sa->sa_master_obj, B_TRUE, SA_REGISTRY);
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, B_TRUE, NULL);
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, B_TRUE, NULL);
+       }
+
+       dmu_tx_sa_registration_hold(sa, tx);
+
+       if (may_grow && tx->tx_objset->os_sa->sa_layout_attr_obj)
+               dmu_tx_hold_zap(tx, sa->sa_layout_attr_obj, B_TRUE, NULL);
+
+       if (sa->sa_force_spill || may_grow || hdl->sa_spill) {
+               ASSERT(tx->tx_txg == 0);
+               dmu_tx_hold_spill(tx, object);
+       } else {
+               dmu_buf_impl_t *db = (dmu_buf_impl_t *)hdl->sa_bonus;
+               dnode_t *dn;
+
+               DB_DNODE_ENTER(db);
+               dn = DB_DNODE(db);
+               if (dn->dn_have_spill) {
+                       ASSERT(tx->tx_txg == 0);
+                       dmu_tx_hold_spill(tx, object);
+               }
+               DB_DNODE_EXIT(db);
+       }
+}
+
+void
+dmu_tx_init(void)
+{
+       dmu_tx_ksp = kstat_create("zfs", 0, "dmu_tx", "misc",
+           KSTAT_TYPE_NAMED, sizeof (dmu_tx_stats) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+
+       if (dmu_tx_ksp != NULL) {
+               dmu_tx_ksp->ks_data = &dmu_tx_stats;
+               kstat_install(dmu_tx_ksp);
+       }
+}
+
+void
+dmu_tx_fini(void)
+{
+       if (dmu_tx_ksp != NULL) {
+               kstat_delete(dmu_tx_ksp);
+               dmu_tx_ksp = NULL;
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dmu_tx_create);
+EXPORT_SYMBOL(dmu_tx_hold_write);
+EXPORT_SYMBOL(dmu_tx_hold_free);
+EXPORT_SYMBOL(dmu_tx_hold_zap);
+EXPORT_SYMBOL(dmu_tx_hold_bonus);
+EXPORT_SYMBOL(dmu_tx_abort);
+EXPORT_SYMBOL(dmu_tx_assign);
+EXPORT_SYMBOL(dmu_tx_wait);
+EXPORT_SYMBOL(dmu_tx_commit);
+EXPORT_SYMBOL(dmu_tx_get_txg);
+EXPORT_SYMBOL(dmu_tx_callback_register);
+EXPORT_SYMBOL(dmu_tx_do_callbacks);
+EXPORT_SYMBOL(dmu_tx_hold_spill);
+EXPORT_SYMBOL(dmu_tx_hold_sa_create);
+EXPORT_SYMBOL(dmu_tx_hold_sa);
+#endif
diff --git a/zfs/module/zfs/dmu_zfetch.c b/zfs/module/zfs/dmu_zfetch.c
new file mode 100644 (file)
index 0000000..8ff2f05
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dnode.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_zfetch.h>
+#include <sys/dmu.h>
+#include <sys/dbuf.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.
+ */
+
+int zfs_prefetch_disable = 0;
+
+/* 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) */
+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;
+} 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 },
+};
+
+#define        ZFETCHSTAT_INCR(stat, val) \
+       atomic_add_64(&zfetch_stats.stat.value.ui64, (val));
+
+#define        ZFETCHSTAT_BUMP(stat)           ZFETCHSTAT_INCR(stat, 1);
+
+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);
+
+       if (zfetch_ksp != NULL) {
+               zfetch_ksp->ks_data = &zfetch_stats;
+               kstat_install(zfetch_ksp);
+       }
+}
+
+void
+zfetch_fini(void)
+{
+       if (zfetch_ksp != NULL) {
+               kstat_delete(zfetch_ksp);
+               zfetch_ksp = NULL;
+       }
+}
+
+/*
+ * This takes a pointer to a zfetch structure and a dnode.  It performs the
+ * necessary setup for the zfetch structure, grokking data from the
+ * associated dnode.
+ */
+void
+dmu_zfetch_init(zfetch_t *zf, dnode_t *dno)
+{
+       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));
+
+       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)
+{
+       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);
+}
+
+/*
+ * 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.
+ */
+void
+dmu_zfetch_rele(zfetch_t *zf)
+{
+       zstream_t       *zs;
+       zstream_t       *zs_next;
+
+       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));
+       }
+       list_destroy(&zf->zf_stream);
+       rw_destroy(&zf->zf_rwlock);
+
+       zf->zf_dnode = NULL;
+}
+
+/*
+ * 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.
+ */
+static int
+dmu_zfetch_stream_insert(zfetch_t *zf, zstream_t *zs)
+{
+       zstream_t       *zs_walk;
+       zstream_t       *zs_next;
+
+       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;
+       }
+
+       if (zs) {
+               dmu_zfetch_stream_remove(zf, zs);
+               mutex_destroy(&zs->zst_lock);
+               bzero(zs, sizeof (zstream_t));
+       } else {
+               zf->zf_alloc_fail++;
+       }
+       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);
+
+       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);
+}
+
+/*
+ * This is the prefetch entry point.  It calls all of the other dmu_zfetch
+ * routines to create, delete, find, or operate upon prefetch streams.
+ */
+void
+dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched)
+{
+       zstream_t       zst;
+       zstream_t       *newstream;
+       boolean_t       fetched;
+       int             inserted;
+       unsigned int    blkshft;
+       uint64_t        blksz;
+
+       if (zfs_prefetch_disable)
+               return;
+
+       /* files that aren't ln2 blocksz are only one block -- nothing to do */
+       if (!zf->zf_dnode->dn_datablkshift)
+               return;
+
+       /* convert offset and size, into blockid and nblocks */
+       blkshft = zf->zf_dnode->dn_datablkshift;
+       blksz = (1 << blkshft);
+
+       bzero(&zst, sizeof (zstream_t));
+       zst.zst_offset = offset >> blkshft;
+       zst.zst_len = (P2ROUNDUP(offset + size, blksz) -
+           P2ALIGN(offset, blksz)) >> blkshft;
+
+       fetched = dmu_zfetch_find(zf, &zst, prefetched);
+       if (fetched) {
+               ZFETCHSTAT_BUMP(zfetchstat_hits);
+       } else {
+               ZFETCHSTAT_BUMP(zfetchstat_misses);
+               if ((fetched = dmu_zfetch_colinear(zf, &zst))) {
+                       ZFETCHSTAT_BUMP(zfetchstat_colinear_hits);
+               } else {
+                       ZFETCHSTAT_BUMP(zfetchstat_colinear_misses);
+               }
+       }
+
+       if (!fetched) {
+               newstream = dmu_zfetch_stream_reclaim(zf);
+
+               /*
+                * we still couldn't find a stream, drop the lock, and allocate
+                * one if possible.  Otherwise, give up and go home.
+                */
+               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);
+               }
+
+               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();
+
+               mutex_init(&newstream->zst_lock, NULL, MUTEX_DEFAULT, NULL);
+
+               rw_enter(&zf->zf_rwlock, RW_WRITER);
+               inserted = dmu_zfetch_stream_insert(zf, newstream);
+               rw_exit(&zf->zf_rwlock);
+
+               if (!inserted) {
+                       mutex_destroy(&newstream->zst_lock);
+                       kmem_free(newstream, sizeof (zstream_t));
+               }
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_prefetch_disable, int, 0644);
+MODULE_PARM_DESC(zfs_prefetch_disable, "Disable all ZFS prefetching");
+
+module_param(zfetch_max_streams, uint, 0644);
+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_array_rd_sz, ulong, 0644);
+MODULE_PARM_DESC(zfetch_array_rd_sz, "Number of bytes in a array_read");
+#endif
diff --git a/zfs/module/zfs/dnode.c b/zfs/module/zfs/dnode.c
new file mode 100644 (file)
index 0000000..2858bbf
--- /dev/null
@@ -0,0 +1,2044 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/dmu_zfetch.h>
+#include <sys/range_tree.h>
+#include <sys/trace_dnode.h>
+
+static kmem_cache_t *dnode_cache;
+/*
+ * Define DNODE_STATS to turn on statistic gathering. By default, it is only
+ * turned on when DEBUG is also defined.
+ */
+#ifdef DEBUG
+#define        DNODE_STATS
+#endif /* DEBUG */
+
+#ifdef DNODE_STATS
+#define        DNODE_STAT_ADD(stat)                    ((stat)++)
+#else
+#define        DNODE_STAT_ADD(stat)                    /* nothing */
+#endif /* DNODE_STATS */
+
+ASSERTV(static dnode_phys_t dnode_phys_zero);
+
+int zfs_default_bs = SPA_MINBLOCKSHIFT;
+int zfs_default_ibs = DN_MAX_INDBLKSHIFT;
+
+#ifdef _KERNEL
+static kmem_cbrc_t dnode_move(void *, void *, size_t, void *);
+#endif /* _KERNEL */
+
+static int
+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);
+       }
+
+       if (d1->db_blkid < d2->db_blkid) {
+               return (-1);
+       }
+       if (d1->db_blkid > d2->db_blkid) {
+               return (1);
+       }
+
+       if (d1->db_state == DB_SEARCH) {
+               ASSERT3S(d2->db_state, !=, DB_SEARCH);
+               return (-1);
+       } else if (d2->db_state == DB_SEARCH) {
+               ASSERT3S(d1->db_state, !=, DB_SEARCH);
+               return (1);
+       }
+
+       if ((uintptr_t)d1 < (uintptr_t)d2) {
+               return (-1);
+       }
+       if ((uintptr_t)d1 > (uintptr_t)d2) {
+               return (1);
+       }
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+dnode_cons(void *arg, void *unused, int kmflag)
+{
+       dnode_t *dn = arg;
+       int i;
+
+       rw_init(&dn->dn_struct_rwlock, NULL, RW_DEFAULT, 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);
+
+       /*
+        * Every dbuf has a reference, and dropping a tracked reference is
+        * O(number of references), so don't track dn_holds.
+        */
+       refcount_create_untracked(&dn->dn_holds);
+       refcount_create(&dn->dn_tx_holds);
+       list_link_init(&dn->dn_link);
+
+       bzero(&dn->dn_next_nblkptr[0], sizeof (dn->dn_next_nblkptr));
+       bzero(&dn->dn_next_nlevels[0], sizeof (dn->dn_next_nlevels));
+       bzero(&dn->dn_next_indblkshift[0], sizeof (dn->dn_next_indblkshift));
+       bzero(&dn->dn_next_bonustype[0], sizeof (dn->dn_next_bonustype));
+       bzero(&dn->dn_rm_spillblk[0], sizeof (dn->dn_rm_spillblk));
+       bzero(&dn->dn_next_bonuslen[0], sizeof (dn->dn_next_bonuslen));
+       bzero(&dn->dn_next_blksz[0], sizeof (dn->dn_next_blksz));
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               list_link_init(&dn->dn_dirty_link[i]);
+               dn->dn_free_ranges[i] = NULL;
+               list_create(&dn->dn_dirty_records[i],
+                   sizeof (dbuf_dirty_record_t),
+                   offsetof(dbuf_dirty_record_t, dr_dirty_node));
+       }
+
+       dn->dn_allocated_txg = 0;
+       dn->dn_free_txg = 0;
+       dn->dn_assigned_txg = 0;
+       dn->dn_dirtyctx = 0;
+       dn->dn_dirtyctx_firstset = NULL;
+       dn->dn_bonus = NULL;
+       dn->dn_have_spill = B_FALSE;
+       dn->dn_zio = NULL;
+       dn->dn_oldused = 0;
+       dn->dn_oldflags = 0;
+       dn->dn_olduid = 0;
+       dn->dn_oldgid = 0;
+       dn->dn_newuid = 0;
+       dn->dn_newgid = 0;
+       dn->dn_id_flags = 0;
+
+       dn->dn_dbufs_count = 0;
+       dn->dn_unlisted_l0_blkid = 0;
+       avl_create(&dn->dn_dbufs, dbuf_compare, sizeof (dmu_buf_impl_t),
+           offsetof(dmu_buf_impl_t, db_link));
+
+       dn->dn_moved = 0;
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+dnode_dest(void *arg, void *unused)
+{
+       int i;
+       dnode_t *dn = arg;
+
+       rw_destroy(&dn->dn_struct_rwlock);
+       mutex_destroy(&dn->dn_mtx);
+       mutex_destroy(&dn->dn_dbufs_mtx);
+       cv_destroy(&dn->dn_notxholds);
+       refcount_destroy(&dn->dn_holds);
+       refcount_destroy(&dn->dn_tx_holds);
+       ASSERT(!list_link_active(&dn->dn_link));
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               ASSERT(!list_link_active(&dn->dn_dirty_link[i]));
+               ASSERT3P(dn->dn_free_ranges[i], ==, NULL);
+               list_destroy(&dn->dn_dirty_records[i]);
+               ASSERT0(dn->dn_next_nblkptr[i]);
+               ASSERT0(dn->dn_next_nlevels[i]);
+               ASSERT0(dn->dn_next_indblkshift[i]);
+               ASSERT0(dn->dn_next_bonustype[i]);
+               ASSERT0(dn->dn_rm_spillblk[i]);
+               ASSERT0(dn->dn_next_bonuslen[i]);
+               ASSERT0(dn->dn_next_blksz[i]);
+       }
+
+       ASSERT0(dn->dn_allocated_txg);
+       ASSERT0(dn->dn_free_txg);
+       ASSERT0(dn->dn_assigned_txg);
+       ASSERT0(dn->dn_dirtyctx);
+       ASSERT3P(dn->dn_dirtyctx_firstset, ==, NULL);
+       ASSERT3P(dn->dn_bonus, ==, NULL);
+       ASSERT(!dn->dn_have_spill);
+       ASSERT3P(dn->dn_zio, ==, NULL);
+       ASSERT0(dn->dn_oldused);
+       ASSERT0(dn->dn_oldflags);
+       ASSERT0(dn->dn_olduid);
+       ASSERT0(dn->dn_oldgid);
+       ASSERT0(dn->dn_newuid);
+       ASSERT0(dn->dn_newgid);
+       ASSERT0(dn->dn_id_flags);
+
+       ASSERT0(dn->dn_dbufs_count);
+       ASSERT0(dn->dn_unlisted_l0_blkid);
+       avl_destroy(&dn->dn_dbufs);
+}
+
+void
+dnode_init(void)
+{
+       ASSERT(dnode_cache == NULL);
+       dnode_cache = kmem_cache_create("dnode_t", sizeof (dnode_t),
+           0, dnode_cons, dnode_dest, NULL, NULL, NULL, 0);
+       kmem_cache_set_move(dnode_cache, dnode_move);
+}
+
+void
+dnode_fini(void)
+{
+       kmem_cache_destroy(dnode_cache);
+       dnode_cache = NULL;
+}
+
+
+#ifdef ZFS_DEBUG
+void
+dnode_verify(dnode_t *dn)
+{
+       int drop_struct_lock = FALSE;
+
+       ASSERT(dn->dn_phys);
+       ASSERT(dn->dn_objset);
+       ASSERT(dn->dn_handle->dnh_dnode == dn);
+
+       ASSERT(DMU_OT_IS_VALID(dn->dn_phys->dn_type));
+
+       if (!(zfs_flags & ZFS_DEBUG_DNODE_VERIFY))
+               return;
+
+       if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+               drop_struct_lock = TRUE;
+       }
+       if (dn->dn_phys->dn_type != DMU_OT_NONE || dn->dn_allocated_txg != 0) {
+               int i;
+               ASSERT3U(dn->dn_indblkshift, <=, SPA_MAXBLOCKSHIFT);
+               if (dn->dn_datablkshift) {
+                       ASSERT3U(dn->dn_datablkshift, >=, SPA_MINBLOCKSHIFT);
+                       ASSERT3U(dn->dn_datablkshift, <=, SPA_MAXBLOCKSHIFT);
+                       ASSERT3U(1<<dn->dn_datablkshift, ==, dn->dn_datablksz);
+               }
+               ASSERT3U(dn->dn_nlevels, <=, 30);
+               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_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);
+               for (i = 0; i < TXG_SIZE; i++) {
+                       ASSERT3U(dn->dn_next_nlevels[i], <=, dn->dn_nlevels);
+               }
+       }
+       if (dn->dn_phys->dn_type != DMU_OT_NONE)
+               ASSERT3U(dn->dn_phys->dn_nlevels, <=, dn->dn_nlevels);
+       ASSERT(DMU_OBJECT_IS_SPECIAL(dn->dn_object) || dn->dn_dbuf != NULL);
+       if (dn->dn_dbuf != NULL) {
+               ASSERT3P(dn->dn_phys, ==,
+                   (dnode_phys_t *)dn->dn_dbuf->db.db_data +
+                   (dn->dn_object % (dn->dn_dbuf->db.db_size >> DNODE_SHIFT)));
+       }
+       if (drop_struct_lock)
+               rw_exit(&dn->dn_struct_rwlock);
+}
+#endif
+
+void
+dnode_byteswap(dnode_phys_t *dnp)
+{
+       uint64_t *buf64 = (void*)&dnp->dn_blkptr;
+       int i;
+
+       if (dnp->dn_type == DMU_OT_NONE) {
+               bzero(dnp, sizeof (dnode_phys_t));
+               return;
+       }
+
+       dnp->dn_datablkszsec = BSWAP_16(dnp->dn_datablkszsec);
+       dnp->dn_bonuslen = BSWAP_16(dnp->dn_bonuslen);
+       dnp->dn_maxblkid = BSWAP_64(dnp->dn_maxblkid);
+       dnp->dn_used = BSWAP_64(dnp->dn_used);
+
+       /*
+        * dn_nblkptr is only one byte, so it's OK to read it in either
+        * byte order.  We can't read dn_bouslen.
+        */
+       ASSERT(dnp->dn_indblkshift <= SPA_MAXBLOCKSHIFT);
+       ASSERT(dnp->dn_nblkptr <= DN_MAX_NBLKPTR);
+       for (i = 0; i < dnp->dn_nblkptr * sizeof (blkptr_t)/8; i++)
+               buf64[i] = BSWAP_64(buf64[i]);
+
+       /*
+        * OK to check dn_bonuslen for zero, because it won't matter if
+        * we have the wrong byte order.  This is necessary because the
+        * dnode dnode is smaller than a regular dnode.
+        */
+       if (dnp->dn_bonuslen != 0) {
+               /*
+                * Note that the bonus length calculated here may be
+                * longer than the actual bonus buffer.  This is because
+                * we always put the bonus buffer after the last block
+                * pointer (instead of packing it against the end of the
+                * dnode buffer).
+                */
+               int off = (dnp->dn_nblkptr-1) * sizeof (blkptr_t);
+               size_t len = DN_MAX_BONUSLEN - off;
+               dmu_object_byteswap_t byteswap;
+               ASSERT(DMU_OT_IS_VALID(dnp->dn_bonustype));
+               byteswap = DMU_OT_BYTESWAP(dnp->dn_bonustype);
+               dmu_ot_byteswap[byteswap].ob_func(dnp->dn_bonus + off, len);
+       }
+
+       /* Swap SPILL block if we have one */
+       if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR)
+               byteswap_uint64_array(&dnp->dn_spill, sizeof (blkptr_t));
+
+}
+
+void
+dnode_buf_byteswap(void *vbuf, size_t size)
+{
+       dnode_phys_t *buf = vbuf;
+       int i;
+
+       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++;
+       }
+}
+
+void
+dnode_setbonuslen(dnode_t *dn, int newsize, dmu_tx_t *tx)
+{
+       ASSERT3U(refcount_count(&dn->dn_holds), >=, 1);
+
+       dnode_setdirty(dn, tx);
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       ASSERT3U(newsize, <=, DN_MAX_BONUSLEN -
+           (dn->dn_nblkptr-1) * sizeof (blkptr_t));
+       dn->dn_bonuslen = newsize;
+       if (newsize == 0)
+               dn->dn_next_bonuslen[tx->tx_txg & TXG_MASK] = DN_ZERO_BONUSLEN;
+       else
+               dn->dn_next_bonuslen[tx->tx_txg & TXG_MASK] = dn->dn_bonuslen;
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+void
+dnode_setbonus_type(dnode_t *dn, dmu_object_type_t newtype, dmu_tx_t *tx)
+{
+       ASSERT3U(refcount_count(&dn->dn_holds), >=, 1);
+       dnode_setdirty(dn, tx);
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       dn->dn_bonustype = newtype;
+       dn->dn_next_bonustype[tx->tx_txg & TXG_MASK] = dn->dn_bonustype;
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+void
+dnode_rm_spill(dnode_t *dn, dmu_tx_t *tx)
+{
+       ASSERT3U(refcount_count(&dn->dn_holds), >=, 1);
+       ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock));
+       dnode_setdirty(dn, tx);
+       dn->dn_rm_spillblk[tx->tx_txg&TXG_MASK] = DN_KILL_SPILLBLK;
+       dn->dn_have_spill = B_FALSE;
+}
+
+static void
+dnode_setdblksz(dnode_t *dn, int size)
+{
+       ASSERT0(P2PHASE(size, SPA_MINBLOCKSIZE));
+       ASSERT3U(size, <=, SPA_MAXBLOCKSIZE);
+       ASSERT3U(size, >=, SPA_MINBLOCKSIZE);
+       ASSERT3U(size >> SPA_MINBLOCKSHIFT, <,
+           1<<(sizeof (dn->dn_phys->dn_datablkszsec) * 8));
+       dn->dn_datablksz = size;
+       dn->dn_datablkszsec = size >> SPA_MINBLOCKSHIFT;
+       dn->dn_datablkshift = ISP2(size) ? highbit64(size - 1) : 0;
+}
+
+static dnode_t *
+dnode_create(objset_t *os, dnode_phys_t *dnp, dmu_buf_impl_t *db,
+    uint64_t object, dnode_handle_t *dnh)
+{
+       dnode_t *dn;
+
+       dn = kmem_cache_alloc(dnode_cache, KM_SLEEP);
+       ASSERT(!POINTER_IS_VALID(dn->dn_objset));
+       dn->dn_moved = 0;
+
+       /*
+        * Defer setting dn_objset until the dnode is ready to be a candidate
+        * for the dnode_move() callback.
+        */
+       dn->dn_object = object;
+       dn->dn_dbuf = db;
+       dn->dn_handle = dnh;
+       dn->dn_phys = dnp;
+
+       if (dnp->dn_datablkszsec) {
+               dnode_setdblksz(dn, dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
+       } else {
+               dn->dn_datablksz = 0;
+               dn->dn_datablkszsec = 0;
+               dn->dn_datablkshift = 0;
+       }
+       dn->dn_indblkshift = dnp->dn_indblkshift;
+       dn->dn_nlevels = dnp->dn_nlevels;
+       dn->dn_type = dnp->dn_type;
+       dn->dn_nblkptr = dnp->dn_nblkptr;
+       dn->dn_checksum = dnp->dn_checksum;
+       dn->dn_compress = dnp->dn_compress;
+       dn->dn_bonustype = dnp->dn_bonustype;
+       dn->dn_bonuslen = dnp->dn_bonuslen;
+       dn->dn_maxblkid = dnp->dn_maxblkid;
+       dn->dn_have_spill = ((dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0);
+       dn->dn_id_flags = 0;
+
+       dmu_zfetch_init(&dn->dn_zfetch, dn);
+
+       ASSERT(DMU_OT_IS_VALID(dn->dn_phys->dn_type));
+
+       mutex_enter(&os->os_lock);
+       if (dnh->dnh_dnode != NULL) {
+               /* Lost the allocation race. */
+               mutex_exit(&os->os_lock);
+               kmem_cache_free(dnode_cache, dn);
+               return (dnh->dnh_dnode);
+       }
+
+       /*
+        * Exclude special dnodes from os_dnodes so an empty os_dnodes
+        * signifies that the special dnodes have no references from
+        * their children (the entries in os_dnodes).  This allows
+        * dnode_destroy() to easily determine if the last child has
+        * been removed and then complete eviction of the objset.
+        */
+       if (!DMU_OBJECT_IS_SPECIAL(object))
+               list_insert_head(&os->os_dnodes, dn);
+       membar_producer();
+
+       /*
+        * Everything else must be valid before assigning dn_objset
+        * makes the dnode eligible for dnode_move().
+        */
+       dn->dn_objset = os;
+
+       dnh->dnh_dnode = dn;
+       mutex_exit(&os->os_lock);
+
+       arc_space_consume(sizeof (dnode_t), ARC_SPACE_OTHER);
+       return (dn);
+}
+
+/*
+ * Caller must be holding the dnode handle, which is released upon return.
+ */
+static void
+dnode_destroy(dnode_t *dn)
+{
+       objset_t *os = dn->dn_objset;
+       boolean_t complete_os_eviction = B_FALSE;
+
+       ASSERT((dn->dn_id_flags & DN_ID_NEW_EXIST) == 0);
+
+       mutex_enter(&os->os_lock);
+       POINTER_INVALIDATE(&dn->dn_objset);
+       if (!DMU_OBJECT_IS_SPECIAL(dn->dn_object)) {
+               list_remove(&os->os_dnodes, dn);
+               complete_os_eviction =
+                   list_is_empty(&os->os_dnodes) &&
+                   list_link_active(&os->os_evicting_node);
+       }
+       mutex_exit(&os->os_lock);
+
+       /* the dnode can no longer move, so we can release the handle */
+       zrl_remove(&dn->dn_handle->dnh_zrlock);
+
+       dn->dn_allocated_txg = 0;
+       dn->dn_free_txg = 0;
+       dn->dn_assigned_txg = 0;
+
+       dn->dn_dirtyctx = 0;
+       if (dn->dn_dirtyctx_firstset != NULL) {
+               kmem_free(dn->dn_dirtyctx_firstset, 1);
+               dn->dn_dirtyctx_firstset = NULL;
+       }
+       if (dn->dn_bonus != NULL) {
+               mutex_enter(&dn->dn_bonus->db_mtx);
+               dbuf_evict(dn->dn_bonus);
+               dn->dn_bonus = NULL;
+       }
+       dn->dn_zio = NULL;
+
+       dn->dn_have_spill = B_FALSE;
+       dn->dn_oldused = 0;
+       dn->dn_oldflags = 0;
+       dn->dn_olduid = 0;
+       dn->dn_oldgid = 0;
+       dn->dn_newuid = 0;
+       dn->dn_newgid = 0;
+       dn->dn_id_flags = 0;
+       dn->dn_unlisted_l0_blkid = 0;
+
+       dmu_zfetch_rele(&dn->dn_zfetch);
+       kmem_cache_free(dnode_cache, dn);
+       arc_space_return(sizeof (dnode_t), ARC_SPACE_OTHER);
+
+       if (complete_os_eviction)
+               dmu_objset_evict_done(os);
+}
+
+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)
+{
+       int i;
+
+       ASSERT3U(blocksize, <=,
+           spa_maxblocksize(dmu_objset_spa(dn->dn_objset)));
+       if (blocksize == 0)
+               blocksize = 1 << zfs_default_bs;
+       else
+               blocksize = P2ROUNDUP(blocksize, SPA_MINBLOCKSIZE);
+
+       if (ibs == 0)
+               ibs = zfs_default_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);
+
+       ASSERT(dn->dn_type == DMU_OT_NONE);
+       ASSERT(bcmp(dn->dn_phys, &dnode_phys_zero, sizeof (dnode_phys_t)) == 0);
+       ASSERT(dn->dn_phys->dn_type == DMU_OT_NONE);
+       ASSERT(ot != DMU_OT_NONE);
+       ASSERT(DMU_OT_IS_VALID(ot));
+       ASSERT((bonustype == DMU_OT_NONE && bonuslen == 0) ||
+           (bonustype == DMU_OT_SA && bonuslen == 0) ||
+           (bonustype != DMU_OT_NONE && bonuslen != 0));
+       ASSERT(DMU_OT_IS_VALID(bonustype));
+       ASSERT3U(bonuslen, <=, DN_MAX_BONUSLEN);
+       ASSERT(dn->dn_type == DMU_OT_NONE);
+       ASSERT0(dn->dn_maxblkid);
+       ASSERT0(dn->dn_allocated_txg);
+       ASSERT0(dn->dn_assigned_txg);
+       ASSERT(refcount_is_zero(&dn->dn_tx_holds));
+       ASSERT3U(refcount_count(&dn->dn_holds), <=, 1);
+       ASSERT(avl_is_empty(&dn->dn_dbufs));
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               ASSERT0(dn->dn_next_nblkptr[i]);
+               ASSERT0(dn->dn_next_nlevels[i]);
+               ASSERT0(dn->dn_next_indblkshift[i]);
+               ASSERT0(dn->dn_next_bonuslen[i]);
+               ASSERT0(dn->dn_next_bonustype[i]);
+               ASSERT0(dn->dn_rm_spillblk[i]);
+               ASSERT0(dn->dn_next_blksz[i]);
+               ASSERT(!list_link_active(&dn->dn_dirty_link[i]));
+               ASSERT3P(list_head(&dn->dn_dirty_records[i]), ==, NULL);
+               ASSERT3P(dn->dn_free_ranges[i], ==, NULL);
+       }
+
+       dn->dn_type = ot;
+       dnode_setdblksz(dn, blocksize);
+       dn->dn_indblkshift = ibs;
+       dn->dn_nlevels = 1;
+       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);
+       dn->dn_bonustype = bonustype;
+       dn->dn_bonuslen = bonuslen;
+       dn->dn_checksum = ZIO_CHECKSUM_INHERIT;
+       dn->dn_compress = ZIO_COMPRESS_INHERIT;
+       dn->dn_dirtyctx = 0;
+
+       dn->dn_free_txg = 0;
+       if (dn->dn_dirtyctx_firstset) {
+               kmem_free(dn->dn_dirtyctx_firstset, 1);
+               dn->dn_dirtyctx_firstset = NULL;
+       }
+
+       dn->dn_allocated_txg = tx->tx_txg;
+       dn->dn_id_flags = 0;
+
+       dnode_setdirty(dn, tx);
+       dn->dn_next_indblkshift[tx->tx_txg & TXG_MASK] = ibs;
+       dn->dn_next_bonuslen[tx->tx_txg & TXG_MASK] = dn->dn_bonuslen;
+       dn->dn_next_bonustype[tx->tx_txg & TXG_MASK] = dn->dn_bonustype;
+       dn->dn_next_blksz[tx->tx_txg & TXG_MASK] = dn->dn_datablksz;
+}
+
+void
+dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
+    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
+       int nblkptr;
+
+       ASSERT3U(blocksize, >=, SPA_MINBLOCKSIZE);
+       ASSERT3U(blocksize, <=,
+           spa_maxblocksize(dmu_objset_spa(dn->dn_objset)));
+       ASSERT0(blocksize % SPA_MINBLOCKSIZE);
+       ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx));
+       ASSERT(tx->tx_txg != 0);
+       ASSERT((bonustype == DMU_OT_NONE && bonuslen == 0) ||
+           (bonustype != DMU_OT_NONE && bonuslen != 0) ||
+           (bonustype == DMU_OT_SA && bonuslen == 0));
+       ASSERT(DMU_OT_IS_VALID(bonustype));
+       ASSERT3U(bonuslen, <=, DN_MAX_BONUSLEN);
+
+       /* clean up any unreferenced dbufs */
+       dnode_evict_dbufs(dn);
+
+       dn->dn_id_flags = 0;
+
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       dnode_setdirty(dn, tx);
+       if (dn->dn_datablksz != blocksize) {
+               /* change blocksize */
+               ASSERT(dn->dn_maxblkid == 0 &&
+                   (BP_IS_HOLE(&dn->dn_phys->dn_blkptr[0]) ||
+                   dnode_block_freed(dn, 0)));
+               dnode_setdblksz(dn, blocksize);
+               dn->dn_next_blksz[tx->tx_txg&TXG_MASK] = blocksize;
+       }
+       if (dn->dn_bonuslen != bonuslen)
+               dn->dn_next_bonuslen[tx->tx_txg&TXG_MASK] = bonuslen;
+
+       if (bonustype == DMU_OT_SA) /* Maximize bonus space for SA */
+               nblkptr = 1;
+       else
+               nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
+       if (dn->dn_bonustype != bonustype)
+               dn->dn_next_bonustype[tx->tx_txg&TXG_MASK] = bonustype;
+       if (dn->dn_nblkptr != nblkptr)
+               dn->dn_next_nblkptr[tx->tx_txg&TXG_MASK] = nblkptr;
+       if (dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
+               dbuf_rm_spill(dn, tx);
+               dnode_rm_spill(dn, tx);
+       }
+       rw_exit(&dn->dn_struct_rwlock);
+
+       /* change type */
+       dn->dn_type = ot;
+
+       /* change bonus size and type */
+       mutex_enter(&dn->dn_mtx);
+       dn->dn_bonustype = bonustype;
+       dn->dn_bonuslen = bonuslen;
+       dn->dn_nblkptr = nblkptr;
+       dn->dn_checksum = ZIO_CHECKSUM_INHERIT;
+       dn->dn_compress = ZIO_COMPRESS_INHERIT;
+       ASSERT3U(dn->dn_nblkptr, <=, DN_MAX_NBLKPTR);
+
+       /* 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);
+               ASSERT(dn->dn_bonuslen <= dn->dn_bonus->db.db_size);
+       }
+
+       dn->dn_allocated_txg = tx->tx_txg;
+       mutex_exit(&dn->dn_mtx);
+}
+
+#ifdef _KERNEL
+#ifdef DNODE_STATS
+static struct {
+       uint64_t dms_dnode_invalid;
+       uint64_t dms_dnode_recheck1;
+       uint64_t dms_dnode_recheck2;
+       uint64_t dms_dnode_special;
+       uint64_t dms_dnode_handle;
+       uint64_t dms_dnode_rwlock;
+       uint64_t dms_dnode_active;
+} dnode_move_stats;
+#endif /* DNODE_STATS */
+
+static void
+dnode_move_impl(dnode_t *odn, dnode_t *ndn)
+{
+       int i;
+
+       ASSERT(!RW_LOCK_HELD(&odn->dn_struct_rwlock));
+       ASSERT(MUTEX_NOT_HELD(&odn->dn_mtx));
+       ASSERT(MUTEX_NOT_HELD(&odn->dn_dbufs_mtx));
+       ASSERT(!RW_LOCK_HELD(&odn->dn_zfetch.zf_rwlock));
+
+       /* Copy fields. */
+       ndn->dn_objset = odn->dn_objset;
+       ndn->dn_object = odn->dn_object;
+       ndn->dn_dbuf = odn->dn_dbuf;
+       ndn->dn_handle = odn->dn_handle;
+       ndn->dn_phys = odn->dn_phys;
+       ndn->dn_type = odn->dn_type;
+       ndn->dn_bonuslen = odn->dn_bonuslen;
+       ndn->dn_bonustype = odn->dn_bonustype;
+       ndn->dn_nblkptr = odn->dn_nblkptr;
+       ndn->dn_checksum = odn->dn_checksum;
+       ndn->dn_compress = odn->dn_compress;
+       ndn->dn_nlevels = odn->dn_nlevels;
+       ndn->dn_indblkshift = odn->dn_indblkshift;
+       ndn->dn_datablkshift = odn->dn_datablkshift;
+       ndn->dn_datablkszsec = odn->dn_datablkszsec;
+       ndn->dn_datablksz = odn->dn_datablksz;
+       ndn->dn_maxblkid = odn->dn_maxblkid;
+       bcopy(&odn->dn_next_nblkptr[0], &ndn->dn_next_nblkptr[0],
+           sizeof (odn->dn_next_nblkptr));
+       bcopy(&odn->dn_next_nlevels[0], &ndn->dn_next_nlevels[0],
+           sizeof (odn->dn_next_nlevels));
+       bcopy(&odn->dn_next_indblkshift[0], &ndn->dn_next_indblkshift[0],
+           sizeof (odn->dn_next_indblkshift));
+       bcopy(&odn->dn_next_bonustype[0], &ndn->dn_next_bonustype[0],
+           sizeof (odn->dn_next_bonustype));
+       bcopy(&odn->dn_rm_spillblk[0], &ndn->dn_rm_spillblk[0],
+           sizeof (odn->dn_rm_spillblk));
+       bcopy(&odn->dn_next_bonuslen[0], &ndn->dn_next_bonuslen[0],
+           sizeof (odn->dn_next_bonuslen));
+       bcopy(&odn->dn_next_blksz[0], &ndn->dn_next_blksz[0],
+           sizeof (odn->dn_next_blksz));
+       for (i = 0; i < TXG_SIZE; i++) {
+               list_move_tail(&ndn->dn_dirty_records[i],
+                   &odn->dn_dirty_records[i]);
+       }
+       bcopy(&odn->dn_free_ranges[0], &ndn->dn_free_ranges[0],
+           sizeof (odn->dn_free_ranges));
+       ndn->dn_allocated_txg = odn->dn_allocated_txg;
+       ndn->dn_free_txg = odn->dn_free_txg;
+       ndn->dn_assigned_txg = odn->dn_assigned_txg;
+       ndn->dn_dirtyctx = odn->dn_dirtyctx;
+       ndn->dn_dirtyctx_firstset = odn->dn_dirtyctx_firstset;
+       ASSERT(refcount_count(&odn->dn_tx_holds) == 0);
+       refcount_transfer(&ndn->dn_holds, &odn->dn_holds);
+       ASSERT(avl_is_empty(&ndn->dn_dbufs));
+       avl_swap(&ndn->dn_dbufs, &odn->dn_dbufs);
+       ndn->dn_dbufs_count = odn->dn_dbufs_count;
+       ndn->dn_unlisted_l0_blkid = odn->dn_unlisted_l0_blkid;
+       ndn->dn_bonus = odn->dn_bonus;
+       ndn->dn_have_spill = odn->dn_have_spill;
+       ndn->dn_zio = odn->dn_zio;
+       ndn->dn_oldused = odn->dn_oldused;
+       ndn->dn_oldflags = odn->dn_oldflags;
+       ndn->dn_olduid = odn->dn_olduid;
+       ndn->dn_oldgid = odn->dn_oldgid;
+       ndn->dn_newuid = odn->dn_newuid;
+       ndn->dn_newgid = odn->dn_newgid;
+       ndn->dn_id_flags = odn->dn_id_flags;
+       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
+        * every descendant dbuf as well as the bonus dbuf.
+        */
+       ASSERT(ndn->dn_handle->dnh_dnode == odn);
+       ndn->dn_handle->dnh_dnode = ndn;
+       if (ndn->dn_zfetch.zf_dnode == odn) {
+               ndn->dn_zfetch.zf_dnode = ndn;
+       }
+
+       /*
+        * Invalidate the original dnode by clearing all of its back pointers.
+        */
+       odn->dn_dbuf = NULL;
+       odn->dn_handle = NULL;
+       avl_create(&odn->dn_dbufs, dbuf_compare, sizeof (dmu_buf_impl_t),
+           offsetof(dmu_buf_impl_t, db_link));
+       odn->dn_dbufs_count = 0;
+       odn->dn_unlisted_l0_blkid = 0;
+       odn->dn_bonus = NULL;
+       odn->dn_zfetch.zf_dnode = NULL;
+
+       /*
+        * Set the low bit of the objset pointer to ensure that dnode_move()
+        * recognizes the dnode as invalid in any subsequent callback.
+        */
+       POINTER_INVALIDATE(&odn->dn_objset);
+
+       /*
+        * Satisfy the destructor.
+        */
+       for (i = 0; i < TXG_SIZE; i++) {
+               list_create(&odn->dn_dirty_records[i],
+                   sizeof (dbuf_dirty_record_t),
+                   offsetof(dbuf_dirty_record_t, dr_dirty_node));
+               odn->dn_free_ranges[i] = NULL;
+               odn->dn_next_nlevels[i] = 0;
+               odn->dn_next_indblkshift[i] = 0;
+               odn->dn_next_bonustype[i] = 0;
+               odn->dn_rm_spillblk[i] = 0;
+               odn->dn_next_bonuslen[i] = 0;
+               odn->dn_next_blksz[i] = 0;
+       }
+       odn->dn_allocated_txg = 0;
+       odn->dn_free_txg = 0;
+       odn->dn_assigned_txg = 0;
+       odn->dn_dirtyctx = 0;
+       odn->dn_dirtyctx_firstset = NULL;
+       odn->dn_have_spill = B_FALSE;
+       odn->dn_zio = NULL;
+       odn->dn_oldused = 0;
+       odn->dn_oldflags = 0;
+       odn->dn_olduid = 0;
+       odn->dn_oldgid = 0;
+       odn->dn_newuid = 0;
+       odn->dn_newgid = 0;
+       odn->dn_id_flags = 0;
+
+       /*
+        * Mark the dnode.
+        */
+       ndn->dn_moved = 1;
+       odn->dn_moved = (uint8_t)-1;
+}
+
+/*ARGSUSED*/
+static kmem_cbrc_t
+dnode_move(void *buf, void *newbuf, size_t size, void *arg)
+{
+       dnode_t *odn = buf, *ndn = newbuf;
+       objset_t *os;
+       int64_t refcount;
+       uint32_t dbufs;
+
+       /*
+        * The dnode is on the objset's list of known dnodes if the objset
+        * pointer is valid. We set the low bit of the objset pointer when
+        * freeing the dnode to invalidate it, and the memory patterns written
+        * by kmem (baddcafe and deadbeef) set at least one of the two low bits.
+        * A newly created dnode sets the objset pointer last of all to indicate
+        * that the dnode is known and in a valid state to be moved by this
+        * function.
+        */
+       os = odn->dn_objset;
+       if (!POINTER_IS_VALID(os)) {
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_invalid);
+               return (KMEM_CBRC_DONT_KNOW);
+       }
+
+       /*
+        * Ensure that the objset does not go away during the move.
+        */
+       rw_enter(&os_lock, RW_WRITER);
+       if (os != odn->dn_objset) {
+               rw_exit(&os_lock);
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_recheck1);
+               return (KMEM_CBRC_DONT_KNOW);
+       }
+
+       /*
+        * If the dnode is still valid, then so is the objset. We know that no
+        * valid objset can be freed while we hold os_lock, so we can safely
+        * ensure that the objset remains in use.
+        */
+       mutex_enter(&os->os_lock);
+
+       /*
+        * Recheck the objset pointer in case the dnode was removed just before
+        * acquiring the lock.
+        */
+       if (os != odn->dn_objset) {
+               mutex_exit(&os->os_lock);
+               rw_exit(&os_lock);
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_recheck2);
+               return (KMEM_CBRC_DONT_KNOW);
+       }
+
+       /*
+        * At this point we know that as long as we hold os->os_lock, the dnode
+        * cannot be freed and fields within the dnode can be safely accessed.
+        * The objset listing this dnode cannot go away as long as this dnode is
+        * on its list.
+        */
+       rw_exit(&os_lock);
+       if (DMU_OBJECT_IS_SPECIAL(odn->dn_object)) {
+               mutex_exit(&os->os_lock);
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_special);
+               return (KMEM_CBRC_NO);
+       }
+       ASSERT(odn->dn_dbuf != NULL); /* only "special" dnodes have no parent */
+
+       /*
+        * Lock the dnode handle to prevent the dnode from obtaining any new
+        * holds. This also prevents the descendant dbufs and the bonus dbuf
+        * from accessing the dnode, so that we can discount their holds. The
+        * handle is safe to access because we know that while the dnode cannot
+        * go away, neither can its handle. Once we hold dnh_zrlock, we can
+        * safely move any dnode referenced only by dbufs.
+        */
+       if (!zrl_tryenter(&odn->dn_handle->dnh_zrlock)) {
+               mutex_exit(&os->os_lock);
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_handle);
+               return (KMEM_CBRC_LATER);
+       }
+
+       /*
+        * Ensure a consistent view of the dnode's holds and the dnode's dbufs.
+        * We need to guarantee that there is a hold for every dbuf in order to
+        * determine whether the dnode is actively referenced. Falsely matching
+        * a dbuf to an active hold would lead to an unsafe move. It's possible
+        * that a thread already having an active dnode hold is about to add a
+        * dbuf, and we can't compare hold and dbuf counts while the add is in
+        * progress.
+        */
+       if (!rw_tryenter(&odn->dn_struct_rwlock, RW_WRITER)) {
+               zrl_exit(&odn->dn_handle->dnh_zrlock);
+               mutex_exit(&os->os_lock);
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_rwlock);
+               return (KMEM_CBRC_LATER);
+       }
+
+       /*
+        * A dbuf may be removed (evicted) without an active dnode hold. In that
+        * case, the dbuf count is decremented under the handle lock before the
+        * dbuf's hold is released. This order ensures that if we count the hold
+        * after the dbuf is removed but before its hold is released, we will
+        * treat the unmatched hold as active and exit safely. If we count the
+        * hold before the dbuf is removed, the hold is discounted, and the
+        * removal is blocked until the move completes.
+        */
+       refcount = refcount_count(&odn->dn_holds);
+       ASSERT(refcount >= 0);
+       dbufs = odn->dn_dbufs_count;
+
+       /* We can't have more dbufs than dnode holds. */
+       ASSERT3U(dbufs, <=, refcount);
+       DTRACE_PROBE3(dnode__move, dnode_t *, odn, int64_t, refcount,
+           uint32_t, dbufs);
+
+       if (refcount > dbufs) {
+               rw_exit(&odn->dn_struct_rwlock);
+               zrl_exit(&odn->dn_handle->dnh_zrlock);
+               mutex_exit(&os->os_lock);
+               DNODE_STAT_ADD(dnode_move_stats.dms_dnode_active);
+               return (KMEM_CBRC_LATER);
+       }
+
+       rw_exit(&odn->dn_struct_rwlock);
+
+       /*
+        * At this point we know that anyone with a hold on the dnode is not
+        * actively referencing it. The dnode is known and in a valid state to
+        * move. We're holding the locks needed to execute the critical section.
+        */
+       dnode_move_impl(odn, ndn);
+
+       list_link_replace(&odn->dn_link, &ndn->dn_link);
+       /* If the dnode was safe to move, the refcount cannot have changed. */
+       ASSERT(refcount == refcount_count(&ndn->dn_holds));
+       ASSERT(dbufs == ndn->dn_dbufs_count);
+       zrl_exit(&ndn->dn_handle->dnh_zrlock); /* handle has moved */
+       mutex_exit(&os->os_lock);
+
+       return (KMEM_CBRC_YES);
+}
+#endif /* _KERNEL */
+
+void
+dnode_special_close(dnode_handle_t *dnh)
+{
+       dnode_t *dn = dnh->dnh_dnode;
+
+       /*
+        * Wait for final references to the dnode to clear.  This can
+        * only happen if the arc is asyncronously evicting state that
+        * has a hold on this dnode while we are trying to evict this
+        * dnode.
+        */
+       while (refcount_count(&dn->dn_holds) > 0)
+               delay(1);
+       ASSERT(dn->dn_dbuf == NULL ||
+           dmu_buf_get_user(&dn->dn_dbuf->db) == NULL);
+       zrl_add(&dnh->dnh_zrlock);
+       dnode_destroy(dn); /* implicit zrl_remove() */
+       zrl_destroy(&dnh->dnh_zrlock);
+       dnh->dnh_dnode = NULL;
+}
+
+void
+dnode_special_open(objset_t *os, dnode_phys_t *dnp, uint64_t object,
+    dnode_handle_t *dnh)
+{
+       dnode_t *dn;
+
+       dn = dnode_create(os, dnp, NULL, object, dnh);
+       zrl_init(&dnh->dnh_zrlock);
+       DNODE_VERIFY(dn);
+}
+
+static void
+dnode_buf_pageout(void *dbu)
+{
+       dnode_children_t *children_dnodes = dbu;
+       int i;
+
+       for (i = 0; i < children_dnodes->dnc_count; i++) {
+               dnode_handle_t *dnh = &children_dnodes->dnc_children[i];
+               dnode_t *dn;
+
+               /*
+                * The dnode handle lock guards against the dnode moving to
+                * another valid address, so there is no need here to guard
+                * against changes to or from NULL.
+                */
+               if (dnh->dnh_dnode == NULL) {
+                       zrl_destroy(&dnh->dnh_zrlock);
+                       continue;
+               }
+
+               zrl_add(&dnh->dnh_zrlock);
+               dn = dnh->dnh_dnode;
+               /*
+                * If there are holds on this dnode, then there should
+                * be holds on the dnode's containing dbuf as well; thus
+                * it wouldn't be eligible for eviction and this function
+                * would not have been called.
+                */
+               ASSERT(refcount_is_zero(&dn->dn_holds));
+               ASSERT(refcount_is_zero(&dn->dn_tx_holds));
+
+               dnode_destroy(dn); /* implicit zrl_remove() */
+               zrl_destroy(&dnh->dnh_zrlock);
+               dnh->dnh_dnode = NULL;
+       }
+       kmem_free(children_dnodes, sizeof (dnode_children_t) +
+           children_dnodes->dnc_count * sizeof (dnode_handle_t));
+}
+
+/*
+ * errors:
+ * EINVAL - invalid object number.
+ * EIO - i/o error.
+ * succeeds even for free dnodes.
+ */
+int
+dnode_hold_impl(objset_t *os, uint64_t object, int flag,
+    void *tag, dnode_t **dnp)
+{
+       int epb, idx, err;
+       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_handle_t *dnh;
+
+       /*
+        * 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
+        * which may require us to read from the root filesystem while
+        * holding some (not all) of the locks as writer.
+        */
+       ASSERT(spa_config_held(os->os_spa, SCL_ALL, RW_WRITER) == 0 ||
+           (spa_is_root(os->os_spa) &&
+           spa_config_held(os->os_spa, SCL_STATE, RW_WRITER)));
+
+       if (object == DMU_USERUSED_OBJECT || object == DMU_GROUPUSED_OBJECT) {
+               dn = (object == DMU_USERUSED_OBJECT) ?
+                   DMU_USERUSED_DNODE(os) : DMU_GROUPUSED_DNODE(os);
+               if (dn == NULL)
+                       return (SET_ERROR(ENOENT));
+               type = dn->dn_type;
+               if ((flag & DNODE_MUST_BE_ALLOCATED) && type == DMU_OT_NONE)
+                       return (SET_ERROR(ENOENT));
+               if ((flag & DNODE_MUST_BE_FREE) && type != DMU_OT_NONE)
+                       return (SET_ERROR(EEXIST));
+               DNODE_VERIFY(dn);
+               (void) refcount_add(&dn->dn_holds, tag);
+               *dnp = dn;
+               return (0);
+       }
+
+       if (object == 0 || object >= DN_MAX_OBJECT)
+               return (SET_ERROR(EINVAL));
+
+       mdn = DMU_META_DNODE(os);
+       ASSERT(mdn->dn_object == DMU_META_DNODE_OBJECT);
+
+       DNODE_VERIFY(mdn);
+
+       if (!RW_WRITE_HELD(&mdn->dn_struct_rwlock)) {
+               rw_enter(&mdn->dn_struct_rwlock, RW_READER);
+               drop_struct_lock = TRUE;
+       }
+
+       blk = dbuf_whichblock(mdn, object * sizeof (dnode_phys_t));
+
+       db = dbuf_hold(mdn, blk, FTAG);
+       if (drop_struct_lock)
+               rw_exit(&mdn->dn_struct_rwlock);
+       if (db == NULL)
+               return (SET_ERROR(EIO));
+       err = dbuf_read(db, NULL, DB_RF_CANFAIL);
+       if (err) {
+               dbuf_rele(db, FTAG);
+               return (err);
+       }
+
+       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);
+               children_dnodes->dnc_count = epb;
+               dnh = &children_dnodes->dnc_children[0];
+               for (i = 0; i < epb; i++) {
+                       zrl_init(&dnh[i].dnh_zrlock);
+               }
+               dmu_buf_init_user(&children_dnodes->dnc_dbu,
+                   dnode_buf_pageout, NULL);
+               winner = dmu_buf_set_user(&db->db, &children_dnodes->dnc_dbu);
+               if (winner != NULL) {
+
+                       for (i = 0; i < epb; i++) {
+                               zrl_destroy(&dnh[i].dnh_zrlock);
+                       }
+
+                       kmem_free(children_dnodes, sizeof (dnode_children_t) +
+                           epb * sizeof (dnode_handle_t));
+                       children_dnodes = winner;
+               }
+       }
+       ASSERT(children_dnodes->dnc_count == epb);
+
+       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);
+       }
+
+       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)))) {
+               mutex_exit(&dn->dn_mtx);
+               zrl_remove(&dnh->dnh_zrlock);
+               dbuf_rele(db, FTAG);
+               return (type == DMU_OT_NONE ? ENOENT : EEXIST);
+       }
+       if (refcount_add(&dn->dn_holds, tag) == 1)
+               dbuf_add_ref(db, dnh);
+       mutex_exit(&dn->dn_mtx);
+
+       /* Now we can rely on the hold to prevent the dnode from moving. */
+       zrl_remove(&dnh->dnh_zrlock);
+
+       DNODE_VERIFY(dn);
+       ASSERT3P(dn->dn_dbuf, ==, db);
+       ASSERT3U(dn->dn_object, ==, object);
+       dbuf_rele(db, FTAG);
+
+       *dnp = dn;
+       return (0);
+}
+
+/*
+ * Return held dnode if the object is allocated, NULL if not.
+ */
+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));
+}
+
+/*
+ * Can only add a reference if there is already at least one
+ * reference on the dnode.  Returns FALSE if unable to add a
+ * new reference.
+ */
+boolean_t
+dnode_add_ref(dnode_t *dn, void *tag)
+{
+       mutex_enter(&dn->dn_mtx);
+       if (refcount_is_zero(&dn->dn_holds)) {
+               mutex_exit(&dn->dn_mtx);
+               return (FALSE);
+       }
+       VERIFY(1 < refcount_add(&dn->dn_holds, tag));
+       mutex_exit(&dn->dn_mtx);
+       return (TRUE);
+}
+
+void
+dnode_rele(dnode_t *dn, void *tag)
+{
+       mutex_enter(&dn->dn_mtx);
+       dnode_rele_and_unlock(dn, tag);
+}
+
+void
+dnode_rele_and_unlock(dnode_t *dn, void *tag)
+{
+       uint64_t refs;
+       /* Get while the hold prevents the dnode from moving. */
+       dmu_buf_impl_t *db = dn->dn_dbuf;
+       dnode_handle_t *dnh = dn->dn_handle;
+
+       refs = refcount_remove(&dn->dn_holds, tag);
+       mutex_exit(&dn->dn_mtx);
+
+       /*
+        * It's unsafe to release the last hold on a dnode by dnode_rele() or
+        * indirectly by dbuf_rele() while relying on the dnode handle to
+        * prevent the dnode from moving, since releasing the last hold could
+        * result in the dnode's parent dbuf evicting its dnode handles. For
+        * that reason anyone calling dnode_rele() or dbuf_rele() without some
+        * other direct or indirect hold on the dnode must first drop the dnode
+        * handle.
+        */
+       ASSERT(refs > 0 || dnh->dnh_zrlock.zr_owner != curthread);
+
+       /* NOTE: the DNODE_DNODE does not have a dn_dbuf */
+       if (refs == 0 && db != NULL) {
+               /*
+                * Another thread could add a hold to the dnode handle in
+                * dnode_hold_impl() while holding the parent dbuf. Since the
+                * hold on the parent dbuf prevents the handle from being
+                * destroyed, the hold on the handle is OK. We can't yet assert
+                * that the handle has zero references, but that will be
+                * asserted anyway when the handle gets destroyed.
+                */
+               dbuf_rele(db, dnh);
+       }
+}
+
+void
+dnode_setdirty(dnode_t *dn, dmu_tx_t *tx)
+{
+       objset_t *os = dn->dn_objset;
+       uint64_t txg = tx->tx_txg;
+
+       if (DMU_OBJECT_IS_SPECIAL(dn->dn_object)) {
+               dsl_dataset_dirty(os->os_dsl_dataset, tx);
+               return;
+       }
+
+       DNODE_VERIFY(dn);
+
+#ifdef ZFS_DEBUG
+       mutex_enter(&dn->dn_mtx);
+       ASSERT(dn->dn_phys->dn_type || dn->dn_allocated_txg);
+       ASSERT(dn->dn_free_txg == 0 || dn->dn_free_txg >= txg);
+       mutex_exit(&dn->dn_mtx);
+#endif
+
+       /*
+        * Determine old uid/gid when necessary
+        */
+       dmu_objset_userquota_get_ids(dn, B_TRUE, tx);
+
+       mutex_enter(&os->os_lock);
+
+       /*
+        * If we are already marked dirty, we're done.
+        */
+       if (list_link_active(&dn->dn_dirty_link[txg & TXG_MASK])) {
+               mutex_exit(&os->os_lock);
+               return;
+       }
+
+       ASSERT(!refcount_is_zero(&dn->dn_holds) ||
+           !avl_is_empty(&dn->dn_dbufs));
+       ASSERT(dn->dn_datablksz != 0);
+       ASSERT0(dn->dn_next_bonuslen[txg&TXG_MASK]);
+       ASSERT0(dn->dn_next_blksz[txg&TXG_MASK]);
+       ASSERT0(dn->dn_next_bonustype[txg&TXG_MASK]);
+
+       dprintf_ds(os->os_dsl_dataset, "obj=%llu txg=%llu\n",
+           dn->dn_object, txg);
+
+       if (dn->dn_free_txg > 0 && dn->dn_free_txg <= txg) {
+               list_insert_tail(&os->os_free_dnodes[txg&TXG_MASK], dn);
+       } else {
+               list_insert_tail(&os->os_dirty_dnodes[txg&TXG_MASK], dn);
+       }
+
+       mutex_exit(&os->os_lock);
+
+       /*
+        * The dnode maintains a hold on its containing dbuf as
+        * long as there are holds on it.  Each instantiated child
+        * dbuf maintains a hold on the dnode.  When the last child
+        * drops its hold, the dnode will drop its hold on the
+        * containing dbuf. We add a "dirty hold" here so that the
+        * dnode will hang around after we finish processing its
+        * children.
+        */
+       VERIFY(dnode_add_ref(dn, (void *)(uintptr_t)tx->tx_txg));
+
+       (void) dbuf_dirty(dn->dn_dbuf, tx);
+
+       dsl_dataset_dirty(os->os_dsl_dataset, tx);
+}
+
+void
+dnode_free(dnode_t *dn, dmu_tx_t *tx)
+{
+       int txgoff = tx->tx_txg & TXG_MASK;
+
+       dprintf("dn=%p txg=%llu\n", dn, tx->tx_txg);
+
+       /* we should be the only holder... hopefully */
+       /* ASSERT3U(refcount_count(&dn->dn_holds), ==, 1); */
+
+       mutex_enter(&dn->dn_mtx);
+       if (dn->dn_type == DMU_OT_NONE || dn->dn_free_txg) {
+               mutex_exit(&dn->dn_mtx);
+               return;
+       }
+       dn->dn_free_txg = tx->tx_txg;
+       mutex_exit(&dn->dn_mtx);
+
+       /*
+        * If the dnode is already dirty, it needs to be moved from
+        * the dirty list to the free list.
+        */
+       mutex_enter(&dn->dn_objset->os_lock);
+       if (list_link_active(&dn->dn_dirty_link[txgoff])) {
+               list_remove(&dn->dn_objset->os_dirty_dnodes[txgoff], dn);
+               list_insert_tail(&dn->dn_objset->os_free_dnodes[txgoff], dn);
+               mutex_exit(&dn->dn_objset->os_lock);
+       } else {
+               mutex_exit(&dn->dn_objset->os_lock);
+               dnode_setdirty(dn, tx);
+       }
+}
+
+/*
+ * Try to change the block size for the indicated dnode.  This can only
+ * succeed if there are no blocks allocated or dirty beyond first block
+ */
+int
+dnode_set_blksz(dnode_t *dn, uint64_t size, int ibs, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db;
+       int err;
+
+       ASSERT3U(size, <=, spa_maxblocksize(dmu_objset_spa(dn->dn_objset)));
+       if (size == 0)
+               size = SPA_MINBLOCKSIZE;
+       else
+               size = P2ROUNDUP(size, SPA_MINBLOCKSIZE);
+
+       if (ibs == dn->dn_indblkshift)
+               ibs = 0;
+
+       if (size >> SPA_MINBLOCKSHIFT == dn->dn_datablkszsec && ibs == 0)
+               return (0);
+
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+
+       /* Check for any allocated blocks beyond the first */
+       if (dn->dn_maxblkid != 0)
+               goto fail;
+
+       mutex_enter(&dn->dn_dbufs_mtx);
+       for (db = avl_first(&dn->dn_dbufs); db != NULL;
+           db = AVL_NEXT(&dn->dn_dbufs, db)) {
+               if (db->db_blkid != 0 && db->db_blkid != DMU_BONUS_BLKID &&
+                   db->db_blkid != DMU_SPILL_BLKID) {
+                       mutex_exit(&dn->dn_dbufs_mtx);
+                       goto fail;
+               }
+       }
+       mutex_exit(&dn->dn_dbufs_mtx);
+
+       if (ibs && dn->dn_nlevels != 1)
+               goto fail;
+
+       /* resize the old block */
+       err = dbuf_hold_impl(dn, 0, 0, TRUE, FTAG, &db);
+       if (err == 0)
+               dbuf_new_size(db, size, tx);
+       else if (err != ENOENT)
+               goto fail;
+
+       dnode_setdblksz(dn, size);
+       dnode_setdirty(dn, tx);
+       dn->dn_next_blksz[tx->tx_txg&TXG_MASK] = size;
+       if (ibs) {
+               dn->dn_indblkshift = ibs;
+               dn->dn_next_indblkshift[tx->tx_txg&TXG_MASK] = ibs;
+       }
+       /* rele after we have fixed the blocksize in the dnode */
+       if (db)
+               dbuf_rele(db, FTAG);
+
+       rw_exit(&dn->dn_struct_rwlock);
+       return (0);
+
+fail:
+       rw_exit(&dn->dn_struct_rwlock);
+       return (SET_ERROR(ENOTSUP));
+}
+
+/* read-holding callers must not rely on the lock being continuously held */
+void
+dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t have_read)
+{
+       uint64_t txgoff = tx->tx_txg & TXG_MASK;
+       int epbs, new_nlevels;
+       uint64_t sz;
+
+       ASSERT(blkid != DMU_BONUS_BLKID);
+
+       ASSERT(have_read ?
+           RW_READ_HELD(&dn->dn_struct_rwlock) :
+           RW_WRITE_HELD(&dn->dn_struct_rwlock));
+
+       /*
+        * if we have a read-lock, check to see if we need to do any work
+        * before upgrading to a write-lock.
+        */
+       if (have_read) {
+               if (blkid <= dn->dn_maxblkid)
+                       return;
+
+               if (!rw_tryupgrade(&dn->dn_struct_rwlock)) {
+                       rw_exit(&dn->dn_struct_rwlock);
+                       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+               }
+       }
+
+       if (blkid <= dn->dn_maxblkid)
+               goto out;
+
+       dn->dn_maxblkid = blkid;
+
+       /*
+        * Compute the number of levels necessary to support the new maxblkid.
+        */
+       new_nlevels = 1;
+       epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+       for (sz = dn->dn_nblkptr;
+           sz <= blkid && sz >= dn->dn_nblkptr; sz <<= epbs)
+               new_nlevels++;
+
+       if (new_nlevels > dn->dn_nlevels) {
+               int old_nlevels = dn->dn_nlevels;
+               dmu_buf_impl_t *db;
+               list_t *list;
+               dbuf_dirty_record_t *new, *dr, *dr_next;
+
+               dn->dn_nlevels = new_nlevels;
+
+               ASSERT3U(new_nlevels, >, dn->dn_next_nlevels[txgoff]);
+               dn->dn_next_nlevels[txgoff] = new_nlevels;
+
+               /* dirty the left indirects */
+               db = dbuf_hold_level(dn, old_nlevels, 0, FTAG);
+               ASSERT(db != NULL);
+               new = dbuf_dirty(db, tx);
+               dbuf_rele(db, FTAG);
+
+               /* transfer the dirty records to the new indirect */
+               mutex_enter(&dn->dn_mtx);
+               mutex_enter(&new->dt.di.dr_mtx);
+               list = &dn->dn_dirty_records[txgoff];
+               for (dr = list_head(list); dr; dr = dr_next) {
+                       dr_next = list_next(&dn->dn_dirty_records[txgoff], dr);
+                       if (dr->dr_dbuf->db_level != new_nlevels-1 &&
+                           dr->dr_dbuf->db_blkid != DMU_BONUS_BLKID &&
+                           dr->dr_dbuf->db_blkid != DMU_SPILL_BLKID) {
+                               ASSERT(dr->dr_dbuf->db_level == old_nlevels-1);
+                               list_remove(&dn->dn_dirty_records[txgoff], dr);
+                               list_insert_tail(&new->dt.di.dr_children, dr);
+                               dr->dr_parent = new;
+                       }
+               }
+               mutex_exit(&new->dt.di.dr_mtx);
+               mutex_exit(&dn->dn_mtx);
+       }
+
+out:
+       if (have_read)
+               rw_downgrade(&dn->dn_struct_rwlock);
+}
+
+static void
+dnode_dirty_l1(dnode_t *dn, uint64_t l1blkid, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = dbuf_hold_level(dn, 1, l1blkid, FTAG);
+       if (db != NULL) {
+               dmu_buf_will_dirty(&db->db, tx);
+               dbuf_rele(db, FTAG);
+       }
+}
+
+void
+dnode_free_range(dnode_t *dn, uint64_t off, uint64_t len, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db;
+       uint64_t blkoff, blkid, nblks;
+       int blksz, blkshift, head, tail;
+       int trunc = FALSE;
+       int epbs;
+
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       blksz = dn->dn_datablksz;
+       blkshift = dn->dn_datablkshift;
+       epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+       if (len == DMU_OBJECT_END) {
+               len = UINT64_MAX - off;
+               trunc = TRUE;
+       }
+
+       /*
+        * First, block align the region to free:
+        */
+       if (ISP2(blksz)) {
+               head = P2NPHASE(off, blksz);
+               blkoff = P2PHASE(off, blksz);
+               if ((off >> blkshift) > dn->dn_maxblkid)
+                       goto out;
+       } else {
+               ASSERT(dn->dn_maxblkid == 0);
+               if (off == 0 && len >= blksz) {
+                       /*
+                        * Freeing the whole block; fast-track this request.
+                        * Note that we won't dirty any indirect blocks,
+                        * which is fine because we will be freeing the entire
+                        * file and thus all indirect blocks will be freed
+                        * by free_children().
+                        */
+                       blkid = 0;
+                       nblks = 1;
+                       goto done;
+               } else if (off >= blksz) {
+                       /* Freeing past end-of-data */
+                       goto out;
+               } else {
+                       /* Freeing part of the block. */
+                       head = blksz - off;
+                       ASSERT3U(head, >, 0);
+               }
+               blkoff = off;
+       }
+       /* zero out any partial block data at the start of the range */
+       if (head) {
+               ASSERT3U(blkoff + head, ==, blksz);
+               if (len < head)
+                       head = len;
+               if (dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, off), TRUE,
+                   FTAG, &db) == 0) {
+                       caddr_t data;
+
+                       /* don't dirty if it isn't on disk and isn't dirty */
+                       if (db->db_last_dirty ||
+                           (db->db_blkptr && !BP_IS_HOLE(db->db_blkptr))) {
+                               rw_exit(&dn->dn_struct_rwlock);
+                               dmu_buf_will_dirty(&db->db, tx);
+                               rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+                               data = db->db.db_data;
+                               bzero(data + blkoff, head);
+                       }
+                       dbuf_rele(db, FTAG);
+               }
+               off += head;
+               len -= head;
+       }
+
+       /* If the range was less than one block, we're done */
+       if (len == 0)
+               goto out;
+
+       /* If the remaining range is past end of file, we're done */
+       if ((off >> blkshift) > dn->dn_maxblkid)
+               goto out;
+
+       ASSERT(ISP2(blksz));
+       if (trunc)
+               tail = 0;
+       else
+               tail = P2PHASE(len, blksz);
+
+       ASSERT0(P2PHASE(off, blksz));
+       /* zero out any partial block data at the end of the range */
+       if (tail) {
+               if (len < tail)
+                       tail = len;
+               if (dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, off+len),
+                   TRUE, 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))) {
+                               rw_exit(&dn->dn_struct_rwlock);
+                               dmu_buf_will_dirty(&db->db, tx);
+                               rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+                               bzero(db->db.db_data, tail);
+                       }
+                       dbuf_rele(db, FTAG);
+               }
+               len -= tail;
+       }
+
+       /* If the range did not include a full block, we are done */
+       if (len == 0)
+               goto out;
+
+       ASSERT(IS_P2ALIGNED(off, blksz));
+       ASSERT(trunc || IS_P2ALIGNED(len, blksz));
+       blkid = off >> blkshift;
+       nblks = len >> blkshift;
+       if (trunc)
+               nblks += 1;
+
+       /*
+        * Dirty all the indirect blocks in this range.  Note that only
+        * the first and last indirect blocks can actually be written
+        * (if they were partially freed) -- they must be dirtied, even if
+        * they do not exist on disk yet.  The interior blocks will
+        * be freed by free_children(), so they will not actually be written.
+        * Even though these interior blocks will not be written, we
+        * dirty them for two reasons:
+        *
+        *  - It ensures that the indirect blocks remain in memory until
+        *    syncing context.  (They have already been prefetched by
+        *    dmu_tx_hold_free(), so we don't have to worry about reading
+        *    them serially here.)
+        *
+        *  - The dirty space accounting will put pressure on the txg sync
+        *    mechanism to begin syncing, and to delay transactions if there
+        *    is a large amount of freeing.  Even though these indirect
+        *    blocks will not be written, we could need to write the same
+        *    amount of space if we copy the freed BPs into deadlists.
+        */
+       if (dn->dn_nlevels > 1) {
+               uint64_t first, last, i, ibyte;
+               int shift, err;
+
+               first = blkid >> epbs;
+               dnode_dirty_l1(dn, first, tx);
+               if (trunc)
+                       last = dn->dn_maxblkid >> epbs;
+               else
+                       last = (blkid + nblks - 1) >> epbs;
+               if (last != first)
+                       dnode_dirty_l1(dn, last, tx);
+
+               shift = dn->dn_datablkshift + dn->dn_indblkshift -
+                   SPA_BLKPTRSHIFT;
+               for (i = first + 1; i < last; i++) {
+                       /*
+                        * Set i to the blockid of the next non-hole
+                        * level-1 indirect block at or after i.  Note
+                        * that dnode_next_offset() operates in terms of
+                        * level-0-equivalent bytes.
+                        */
+                       ibyte = i << shift;
+                       err = dnode_next_offset(dn, DNODE_FIND_HAVELOCK,
+                           &ibyte, 2, 1, 0);
+                       i = ibyte >> shift;
+                       if (i >= last)
+                               break;
+
+                       /*
+                        * Normally we should not see an error, either
+                        * from dnode_next_offset() or dbuf_hold_level()
+                        * (except for ESRCH from dnode_next_offset).
+                        * If there is an i/o error, then when we read
+                        * this block in syncing context, it will use
+                        * ZIO_FLAG_MUSTSUCCEED, and thus hang/panic according
+                        * to the "failmode" property.  dnode_next_offset()
+                        * doesn't have a flag to indicate MUSTSUCCEED.
+                        */
+                       if (err != 0)
+                               break;
+
+                       dnode_dirty_l1(dn, i, tx);
+               }
+       }
+
+done:
+       /*
+        * Add this range to the dnode range list.
+        * We will finish up this free operation in the syncing phase.
+        */
+       mutex_enter(&dn->dn_mtx);
+       {
+       int txgoff = tx->tx_txg & TXG_MASK;
+       if (dn->dn_free_ranges[txgoff] == NULL) {
+               dn->dn_free_ranges[txgoff] =
+                   range_tree_create(NULL, NULL, &dn->dn_mtx);
+       }
+       range_tree_clear(dn->dn_free_ranges[txgoff], blkid, nblks);
+       range_tree_add(dn->dn_free_ranges[txgoff], blkid, nblks);
+       }
+       dprintf_dnode(dn, "blkid=%llu nblks=%llu txg=%llu\n",
+           blkid, nblks, tx->tx_txg);
+       mutex_exit(&dn->dn_mtx);
+
+       dbuf_free_range(dn, blkid, blkid + nblks - 1, tx);
+       dnode_setdirty(dn, tx);
+out:
+
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+static boolean_t
+dnode_spill_freed(dnode_t *dn)
+{
+       int i;
+
+       mutex_enter(&dn->dn_mtx);
+       for (i = 0; i < TXG_SIZE; i++) {
+               if (dn->dn_rm_spillblk[i] == DN_KILL_SPILLBLK)
+                       break;
+       }
+       mutex_exit(&dn->dn_mtx);
+       return (i < TXG_SIZE);
+}
+
+/* return TRUE if this blkid was freed in a recent txg, or FALSE if it wasn't */
+uint64_t
+dnode_block_freed(dnode_t *dn, uint64_t blkid)
+{
+       void *dp = spa_get_dsl(dn->dn_objset->os_spa);
+       int i;
+
+       if (blkid == DMU_BONUS_BLKID)
+               return (FALSE);
+
+       /*
+        * If we're in the process of opening the pool, dp will not be
+        * set yet, but there shouldn't be anything dirty.
+        */
+       if (dp == NULL)
+               return (FALSE);
+
+       if (dn->dn_free_txg)
+               return (TRUE);
+
+       if (blkid == DMU_SPILL_BLKID)
+               return (dnode_spill_freed(dn));
+
+       mutex_enter(&dn->dn_mtx);
+       for (i = 0; i < TXG_SIZE; i++) {
+               if (dn->dn_free_ranges[i] != NULL &&
+                   range_tree_contains(dn->dn_free_ranges[i], blkid, 1))
+                       break;
+       }
+       mutex_exit(&dn->dn_mtx);
+       return (i < TXG_SIZE);
+}
+
+/* call from syncing context when we actually write/free space for this dnode */
+void
+dnode_diduse_space(dnode_t *dn, int64_t delta)
+{
+       uint64_t space;
+       dprintf_dnode(dn, "dn=%p dnp=%p used=%llu delta=%lld\n",
+           dn, dn->dn_phys,
+           (u_longlong_t)dn->dn_phys->dn_used,
+           (longlong_t)delta);
+
+       mutex_enter(&dn->dn_mtx);
+       space = DN_USED_BYTES(dn->dn_phys);
+       if (delta > 0) {
+               ASSERT3U(space + delta, >=, space); /* no overflow */
+       } else {
+               ASSERT3U(space, >=, -delta); /* no underflow */
+       }
+       space += delta;
+       if (spa_version(dn->dn_objset->os_spa) < SPA_VERSION_DNODE_BYTES) {
+               ASSERT((dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES) == 0);
+               ASSERT0(P2PHASE(space, 1<<DEV_BSHIFT));
+               dn->dn_phys->dn_used = space >> DEV_BSHIFT;
+       } else {
+               dn->dn_phys->dn_used = space;
+               dn->dn_phys->dn_flags |= DNODE_FLAG_USED_BYTES;
+       }
+       mutex_exit(&dn->dn_mtx);
+}
+
+/*
+ * Call when we think we're going to write/free space in open context to track
+ * the amount of memory in use by the currently open txg.
+ */
+void
+dnode_willuse_space(dnode_t *dn, int64_t space, dmu_tx_t *tx)
+{
+       objset_t *os = dn->dn_objset;
+       dsl_dataset_t *ds = os->os_dsl_dataset;
+       int64_t aspace = spa_get_asize(os->os_spa, space);
+
+       if (ds != NULL) {
+               dsl_dir_willuse_space(ds->ds_dir, aspace, tx);
+               dsl_pool_dirty_space(dmu_tx_pool(tx), space, tx);
+       }
+
+       dmu_tx_willuse_space(tx, aspace);
+}
+
+/*
+ * Scans a block at the indicated "level" looking for a hole or data,
+ * depending on 'flags'.
+ *
+ * If level > 0, then we are scanning an indirect block looking at its
+ * pointers.  If level == 0, then we are looking at a block of dnodes.
+ *
+ * If we don't find what we are looking for in the block, we return ESRCH.
+ * Otherwise, return with *offset pointing to the beginning (if searching
+ * forwards) or end (if searching backwards) of the range covered by the
+ * block pointer we matched on (or dnode).
+ *
+ * The basic search algorithm used below by dnode_next_offset() is to
+ * use this function to search up the block tree (widen the search) until
+ * we find something (i.e., we don't return ESRCH) and then search back
+ * down the tree (narrow the search) until we reach our original search
+ * level.
+ */
+static int
+dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
+       int lvl, uint64_t blkfill, uint64_t txg)
+{
+       dmu_buf_impl_t *db = NULL;
+       void *data = NULL;
+       uint64_t epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+       uint64_t epb = 1ULL << epbs;
+       uint64_t minfill, maxfill;
+       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);
+
+       if (lvl == dn->dn_phys->dn_nlevels) {
+               error = 0;
+               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);
+               if (error) {
+                       if (error != ENOENT)
+                               return (error);
+                       if (hole)
+                               return (0);
+                       /*
+                        * This can only happen when we are searching up
+                        * the block tree for data.  We don't really need to
+                        * adjust the offset, as we will just end up looking
+                        * at the pointer to this block in its parent, and its
+                        * going to be unallocated, so we will skip over it.
+                        */
+                       return (SET_ERROR(ESRCH));
+               }
+               error = dbuf_read(db, NULL, DB_RF_CANFAIL | DB_RF_HAVESTRUCT);
+               if (error) {
+                       dbuf_rele(db, FTAG);
+                       return (error);
+               }
+               data = db->db.db_data;
+       }
+
+
+       if (db != NULL && txg != 0 && (db->db_blkptr == NULL ||
+           db->db_blkptr->blk_birth <= txg ||
+           BP_IS_HOLE(db->db_blkptr))) {
+               /*
+                * This can only happen when we are searching up the tree
+                * and these conditions mean that we need to keep climbing.
+                */
+               error = SET_ERROR(ESRCH);
+       } else if (lvl == 0) {
+               dnode_phys_t *dnp = data;
+               span = DNODE_SHIFT;
+               ASSERT(dn->dn_type == DMU_OT_DNODE);
+
+               for (i = (*offset >> span) & (blkfill - 1);
+                   i >= 0 && i < blkfill; i += inc) {
+                       if ((dnp[i].dn_type == DMU_OT_NONE) == hole)
+                               break;
+                       *offset += (1ULL << span) * inc;
+               }
+               if (i < 0 || i == blkfill)
+                       error = SET_ERROR(ESRCH);
+       } else {
+               blkptr_t *bp = data;
+               uint64_t start = *offset;
+               span = (lvl - 1) * epbs + dn->dn_datablkshift;
+               minfill = 0;
+               maxfill = blkfill << ((lvl - 1) * epbs);
+
+               if (hole)
+                       maxfill--;
+               else
+                       minfill++;
+
+               *offset = *offset >> span;
+               for (i = BF64_GET(*offset, 0, epbs);
+                   i >= 0 && i < epb; i += inc) {
+                       if (BP_GET_FILL(&bp[i]) >= minfill &&
+                           BP_GET_FILL(&bp[i]) <= maxfill &&
+                           (hole || bp[i].blk_birth > txg))
+                               break;
+                       if (inc > 0 || *offset > 0)
+                               *offset += inc;
+               }
+               *offset = *offset << span;
+               if (inc < 0) {
+                       /* traversing backwards; position offset at the end */
+                       ASSERT3U(*offset, <=, start);
+                       *offset = MIN(*offset + (1ULL << span) - 1, start);
+               } else if (*offset < start) {
+                       *offset = start;
+               }
+               if (i < 0 || i >= epb)
+                       error = SET_ERROR(ESRCH);
+       }
+
+       if (db)
+               dbuf_rele(db, FTAG);
+
+       return (error);
+}
+
+/*
+ * Find the next hole, data, or sparse region at or after *offset.
+ * The value 'blkfill' tells us how many items we expect to find
+ * in an L0 data block; this value is 1 for normal objects,
+ * DNODES_PER_BLOCK for the meta dnode, and some fraction of
+ * DNODES_PER_BLOCK when searching for sparse regions thereof.
+ *
+ * Examples:
+ *
+ * dnode_next_offset(dn, flags, offset, 1, 1, 0);
+ *     Finds the next/previous hole/data in a file.
+ *     Used in dmu_offset_next().
+ *
+ * dnode_next_offset(mdn, flags, offset, 0, DNODES_PER_BLOCK, txg);
+ *     Finds the next free/allocated dnode an objset's meta-dnode.
+ *     Only finds objects that have new contents since txg (ie.
+ *     bonus buffer changes and content removal are ignored).
+ *     Used in dmu_object_next().
+ *
+ * dnode_next_offset(mdn, DNODE_FIND_HOLE, offset, 2, DNODES_PER_BLOCK >> 2, 0);
+ *     Finds the next L2 meta-dnode bp that's at most 1/4 full.
+ *     Used in dmu_object_alloc().
+ */
+int
+dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset,
+    int minlvl, uint64_t blkfill, uint64_t txg)
+{
+       uint64_t initial_offset = *offset;
+       int lvl, maxlvl;
+       int error = 0;
+
+       if (!(flags & DNODE_FIND_HAVELOCK))
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+
+       if (dn->dn_phys->dn_nlevels == 0) {
+               error = SET_ERROR(ESRCH);
+               goto out;
+       }
+
+       if (dn->dn_datablkshift == 0) {
+               if (*offset < dn->dn_datablksz) {
+                       if (flags & DNODE_FIND_HOLE)
+                               *offset = dn->dn_datablksz;
+               } else {
+                       error = SET_ERROR(ESRCH);
+               }
+               goto out;
+       }
+
+       maxlvl = dn->dn_phys->dn_nlevels;
+
+       for (lvl = minlvl; lvl <= maxlvl; lvl++) {
+               error = dnode_next_offset_level(dn,
+                   flags, offset, lvl, blkfill, txg);
+               if (error != ESRCH)
+                       break;
+       }
+
+       while (error == 0 && --lvl >= minlvl) {
+               error = dnode_next_offset_level(dn,
+                   flags, offset, lvl, blkfill, txg);
+       }
+
+       /*
+        * There's always a "virtual hole" at the end of the object, even
+        * if all BP's which physically exist are non-holes.
+        */
+       if ((flags & DNODE_FIND_HOLE) && error == ESRCH && txg == 0 &&
+           minlvl == 1 && blkfill == 1 && !(flags & DNODE_FIND_BACKWARDS)) {
+               error = 0;
+       }
+
+       if (error == 0 && (flags & DNODE_FIND_BACKWARDS ?
+           initial_offset < *offset : initial_offset > *offset))
+               error = SET_ERROR(ESRCH);
+out:
+       if (!(flags & DNODE_FIND_HAVELOCK))
+               rw_exit(&dn->dn_struct_rwlock);
+
+       return (error);
+}
diff --git a/zfs/module/zfs/dnode_sync.c b/zfs/module/zfs/dnode_sync.c
new file mode 100644 (file)
index 0000000..df5c8e4
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/spa.h>
+#include <sys/range_tree.h>
+#include <sys/zfeature.h>
+
+static void
+dnode_increase_indirection(dnode_t *dn, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db;
+       int txgoff = tx->tx_txg & TXG_MASK;
+       int nblkptr = dn->dn_phys->dn_nblkptr;
+       int old_toplvl = dn->dn_phys->dn_nlevels - 1;
+       int new_level = dn->dn_next_nlevels[txgoff];
+       int i;
+
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+
+       /* this dnode can't be paged out because it's dirty */
+       ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE);
+       ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock));
+       ASSERT(new_level > 1 && dn->dn_phys->dn_nlevels > 0);
+
+       db = dbuf_hold_level(dn, dn->dn_phys->dn_nlevels, 0, FTAG);
+       ASSERT(db != NULL);
+
+       dn->dn_phys->dn_nlevels = new_level;
+       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);
+       }
+
+       /* set dbuf's parent pointers to new indirect buf */
+       for (i = 0; i < nblkptr; i++) {
+               dmu_buf_impl_t *child =
+                   dbuf_find(dn->dn_objset, dn->dn_object, old_toplvl, i);
+
+               if (child == NULL)
+                       continue;
+#ifdef DEBUG
+               DB_DNODE_ENTER(child);
+               ASSERT3P(DB_DNODE(child), ==, dn);
+               DB_DNODE_EXIT(child);
+#endif /* DEBUG */
+               if (child->db_parent && child->db_parent != dn->dn_dbuf) {
+                       ASSERT(child->db_parent->db_level == db->db_level);
+                       ASSERT(child->db_blkptr !=
+                           &dn->dn_phys->dn_blkptr[child->db_blkid]);
+                       mutex_exit(&child->db_mtx);
+                       continue;
+               }
+               ASSERT(child->db_parent == NULL ||
+                   child->db_parent == dn->dn_dbuf);
+
+               child->db_parent = db;
+               dbuf_add_ref(db, child);
+               if (db->db.db_data)
+                       child->db_blkptr = (blkptr_t *)db->db.db_data + i;
+               else
+                       child->db_blkptr = NULL;
+               dprintf_dbuf_bp(child, child->db_blkptr,
+                   "changed db_blkptr to new indirect %s", "");
+
+               mutex_exit(&child->db_mtx);
+       }
+
+       bzero(dn->dn_phys->dn_blkptr, sizeof (blkptr_t) * nblkptr);
+
+       dbuf_rele(db, FTAG);
+
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+static void
+free_blocks(dnode_t *dn, blkptr_t *bp, int num, dmu_tx_t *tx)
+{
+       dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
+       uint64_t bytesfreed = 0;
+       int i;
+
+       dprintf("ds=%p obj=%llx num=%d\n", ds, dn->dn_object, num);
+
+       for (i = 0; i < num; i++, bp++) {
+               uint64_t lsize, lvl;
+               dmu_object_type_t type;
+
+               if (BP_IS_HOLE(bp))
+                       continue;
+
+               bytesfreed += dsl_dataset_block_kill(ds, bp, tx, B_FALSE);
+               ASSERT3U(bytesfreed, <=, DN_USED_BYTES(dn->dn_phys));
+
+               /*
+                * Save some useful information on the holes being
+                * punched, including logical size, type, and indirection
+                * level. Retaining birth time enables detection of when
+                * holes are punched for reducing the number of free
+                * records transmitted during a zfs send.
+                */
+
+               lsize = BP_GET_LSIZE(bp);
+               type = BP_GET_TYPE(bp);
+               lvl = BP_GET_LEVEL(bp);
+
+               bzero(bp, sizeof (blkptr_t));
+
+               if (spa_feature_is_active(dn->dn_objset->os_spa,
+                   SPA_FEATURE_HOLE_BIRTH)) {
+                       BP_SET_LSIZE(bp, lsize);
+                       BP_SET_TYPE(bp, type);
+                       BP_SET_LEVEL(bp, lvl);
+                       BP_SET_BIRTH(bp, dmu_tx_get_txg(tx), 0);
+               }
+       }
+       dnode_diduse_space(dn, -bytesfreed);
+}
+
+#ifdef ZFS_DEBUG
+static void
+free_verify(dmu_buf_impl_t *db, uint64_t start, uint64_t end, dmu_tx_t *tx)
+{
+       int off, num;
+       int i, err, epbs;
+       uint64_t txg = tx->tx_txg;
+       dnode_t *dn;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+       off = start - (db->db_blkid * 1<<epbs);
+       num = end - start + 1;
+
+       ASSERT3U(off, >=, 0);
+       ASSERT3U(num, >=, 0);
+       ASSERT3U(db->db_level, >, 0);
+       ASSERT3U(db->db.db_size, ==, 1 << dn->dn_phys->dn_indblkshift);
+       ASSERT3U(off+num, <=, db->db.db_size >> SPA_BLKPTRSHIFT);
+       ASSERT(db->db_blkptr != NULL);
+
+       for (i = off; i < off+num; i++) {
+               uint64_t *buf;
+               dmu_buf_impl_t *child;
+               dbuf_dirty_record_t *dr;
+               int j;
+
+               ASSERT(db->db_level == 1);
+
+               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);
+               rw_exit(&dn->dn_struct_rwlock);
+               if (err == ENOENT)
+                       continue;
+               ASSERT(err == 0);
+               ASSERT(child->db_level == 0);
+               dr = child->db_last_dirty;
+               while (dr && dr->dr_txg > txg)
+                       dr = dr->dr_next;
+               ASSERT(dr == NULL || dr->dr_txg == txg);
+
+               /* data_old better be zeroed */
+               if (dr) {
+                       buf = dr->dt.dl.dr_data->b_data;
+                       for (j = 0; j < child->db.db_size >> 3; j++) {
+                               if (buf[j] != 0) {
+                                       panic("freed data not zero: "
+                                           "child=%p i=%d off=%d num=%d\n",
+                                           (void *)child, i, off, num);
+                               }
+                       }
+               }
+
+               /*
+                * db_data better be zeroed unless it's dirty in a
+                * future txg.
+                */
+               mutex_enter(&child->db_mtx);
+               buf = child->db.db_data;
+               if (buf != NULL && child->db_state != DB_FILL &&
+                   child->db_last_dirty == NULL) {
+                       for (j = 0; j < child->db.db_size >> 3; j++) {
+                               if (buf[j] != 0) {
+                                       panic("freed data not zero: "
+                                           "child=%p i=%d off=%d num=%d\n",
+                                           (void *)child, i, off, num);
+                               }
+                       }
+               }
+               mutex_exit(&child->db_mtx);
+
+               dbuf_rele(child, FTAG);
+       }
+       DB_DNODE_EXIT(db);
+}
+#endif
+
+static void
+free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks,
+    dmu_tx_t *tx)
+{
+       dnode_t *dn;
+       blkptr_t *bp;
+       dmu_buf_impl_t *subdb;
+       uint64_t start, end, dbstart, dbend, i;
+       int epbs, shift;
+
+       /*
+        * There is a small possibility that this block will not be cached:
+        *   1 - if level > 1 and there are no children with level <= 1
+        *   2 - if this block was evicted since we read it from
+        *       dmu_tx_hold_free().
+        */
+       if (db->db_state != DB_CACHED)
+               (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED);
+
+       dbuf_release_bp(db);
+       bp = db->db.db_data;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+       shift = (db->db_level - 1) * epbs;
+       dbstart = db->db_blkid << epbs;
+       start = blkid >> shift;
+       if (dbstart < start) {
+               bp += start - dbstart;
+       } else {
+               start = dbstart;
+       }
+       dbend = ((db->db_blkid + 1) << epbs) - 1;
+       end = (blkid + nblks - 1) >> shift;
+       if (dbend <= end)
+               end = dbend;
+
+       ASSERT3U(start, <=, end);
+
+       if (db->db_level == 1) {
+               FREE_VERIFY(db, start, end, tx);
+               free_blocks(dn, bp, end-start+1, tx);
+       } else {
+               for (i = start; i <= end; i++, bp++) {
+                       if (BP_IS_HOLE(bp))
+                               continue;
+                       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+                       VERIFY0(dbuf_hold_impl(dn, db->db_level - 1,
+                           i, B_TRUE, FTAG, &subdb));
+                       rw_exit(&dn->dn_struct_rwlock);
+                       ASSERT3P(bp, ==, subdb->db_blkptr);
+
+                       free_children(subdb, blkid, nblks, tx);
+                       dbuf_rele(subdb, FTAG);
+               }
+       }
+
+       /* If this whole block is free, free ourself too. */
+       for (i = 0, bp = db->db.db_data; i < 1 << epbs; i++, bp++) {
+               if (!BP_IS_HOLE(bp))
+                       break;
+       }
+       if (i == 1 << epbs) {
+               /* didn't find any non-holes */
+               bzero(db->db.db_data, db->db.db_size);
+               free_blocks(dn, db->db_blkptr, 1, tx);
+       } else {
+               /*
+                * Partial block free; must be marked dirty so that it
+                * will be written out.
+                */
+               ASSERT(db->db_dirtycnt > 0);
+       }
+
+       DB_DNODE_EXIT(db);
+       arc_buf_freeze(db->db_buf);
+}
+
+/*
+ * Traverse the indicated range of the provided file
+ * and "free" all the blocks contained there.
+ */
+static void
+dnode_sync_free_range_impl(dnode_t *dn, uint64_t blkid, uint64_t nblks,
+    dmu_tx_t *tx)
+{
+       blkptr_t *bp = dn->dn_phys->dn_blkptr;
+       int dnlevel = dn->dn_phys->dn_nlevels;
+       boolean_t trunc = B_FALSE;
+
+       if (blkid > dn->dn_phys->dn_maxblkid)
+               return;
+
+       ASSERT(dn->dn_phys->dn_maxblkid < UINT64_MAX);
+       if (blkid + nblks > dn->dn_phys->dn_maxblkid) {
+               nblks = dn->dn_phys->dn_maxblkid - blkid + 1;
+               trunc = B_TRUE;
+       }
+
+       /* There are no indirect blocks in the object */
+       if (dnlevel == 1) {
+               if (blkid >= dn->dn_phys->dn_nblkptr) {
+                       /* this range was never made persistent */
+                       return;
+               }
+               ASSERT3U(blkid + nblks, <=, dn->dn_phys->dn_nblkptr);
+               free_blocks(dn, bp + blkid, nblks, tx);
+       } else {
+               int shift = (dnlevel - 1) *
+                   (dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT);
+               int start = blkid >> shift;
+               int end = (blkid + nblks - 1) >> shift;
+               dmu_buf_impl_t *db;
+               int i;
+
+               ASSERT(start < dn->dn_phys->dn_nblkptr);
+               bp += start;
+               for (i = start; i <= end; i++, bp++) {
+                       if (BP_IS_HOLE(bp))
+                               continue;
+                       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+                       VERIFY0(dbuf_hold_impl(dn, dnlevel - 1, i,
+                           TRUE, FTAG, &db));
+                       rw_exit(&dn->dn_struct_rwlock);
+
+                       free_children(db, blkid, nblks, tx);
+                       dbuf_rele(db, FTAG);
+               }
+       }
+
+       if (trunc) {
+               ASSERTV(uint64_t off);
+               dn->dn_phys->dn_maxblkid = blkid == 0 ? 0 : blkid - 1;
+
+               ASSERTV(off = (dn->dn_phys->dn_maxblkid + 1) *
+                   (dn->dn_phys->dn_datablkszsec << SPA_MINBLOCKSHIFT));
+               ASSERT(off < dn->dn_phys->dn_maxblkid ||
+                   dn->dn_phys->dn_maxblkid == 0 ||
+                   dnode_next_offset(dn, 0, &off, 1, 1, 0) != 0);
+       }
+}
+
+typedef struct dnode_sync_free_range_arg {
+       dnode_t *dsfra_dnode;
+       dmu_tx_t *dsfra_tx;
+} dnode_sync_free_range_arg_t;
+
+static void
+dnode_sync_free_range(void *arg, uint64_t blkid, uint64_t nblks)
+{
+       dnode_sync_free_range_arg_t *dsfra = arg;
+       dnode_t *dn = dsfra->dsfra_dnode;
+
+       mutex_exit(&dn->dn_mtx);
+       dnode_sync_free_range_impl(dn, blkid, nblks, dsfra->dsfra_tx);
+       mutex_enter(&dn->dn_mtx);
+}
+
+/*
+ * Try to kick all the dnode's dbufs out of the cache...
+ */
+void
+dnode_evict_dbufs(dnode_t *dn)
+{
+       dmu_buf_impl_t *db_marker;
+       dmu_buf_impl_t *db, *db_next;
+
+       db_marker = kmem_alloc(sizeof (dmu_buf_impl_t), KM_SLEEP);
+
+       mutex_enter(&dn->dn_dbufs_mtx);
+       for (db = avl_first(&dn->dn_dbufs); db != NULL; db = db_next) {
+
+#ifdef DEBUG
+               DB_DNODE_ENTER(db);
+               ASSERT3P(DB_DNODE(db), ==, dn);
+               DB_DNODE_EXIT(db);
+#endif /* DEBUG */
+
+               mutex_enter(&db->db_mtx);
+               if (db->db_state != DB_EVICTING &&
+                   refcount_is_zero(&db->db_holds)) {
+                       db_marker->db_level = db->db_level;
+                       db_marker->db_blkid = db->db_blkid;
+                       db_marker->db_state = DB_SEARCH;
+                       avl_insert_here(&dn->dn_dbufs, db_marker, db,
+                           AVL_BEFORE);
+
+                       dbuf_clear(db);
+
+                       db_next = AVL_NEXT(&dn->dn_dbufs, db_marker);
+                       avl_remove(&dn->dn_dbufs, db_marker);
+               } else {
+                       db->db_pending_evict = TRUE;
+                       mutex_exit(&db->db_mtx);
+                       db_next = AVL_NEXT(&dn->dn_dbufs, db);
+               }
+       }
+       mutex_exit(&dn->dn_dbufs_mtx);
+
+       kmem_free(db_marker, sizeof (dmu_buf_impl_t));
+
+       dnode_evict_bonus(dn);
+}
+
+void
+dnode_evict_bonus(dnode_t *dn)
+{
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       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);
+                       dn->dn_bonus = NULL;
+               } else {
+                       dn->dn_bonus->db_pending_evict = TRUE;
+               }
+       }
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+static void
+dnode_undirty_dbufs(list_t *list)
+{
+       dbuf_dirty_record_t *dr;
+
+       while ((dr = list_head(list))) {
+               dmu_buf_impl_t *db = dr->dr_dbuf;
+               uint64_t txg = dr->dr_txg;
+
+               if (db->db_level != 0)
+                       dnode_undirty_dbufs(&dr->dt.di.dr_children);
+
+               mutex_enter(&db->db_mtx);
+               /* XXX - use dbuf_undirty()? */
+               list_remove(list, dr);
+               ASSERT(db->db_last_dirty == dr);
+               db->db_last_dirty = NULL;
+               db->db_dirtycnt -= 1;
+               if (db->db_level == 0) {
+                       ASSERT(db->db_blkid == DMU_BONUS_BLKID ||
+                           dr->dt.dl.dr_data == db->db_buf);
+                       dbuf_unoverride(dr);
+               } else {
+                       mutex_destroy(&dr->dt.di.dr_mtx);
+                       list_destroy(&dr->dt.di.dr_children);
+               }
+               kmem_free(dr, sizeof (dbuf_dirty_record_t));
+               dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg);
+       }
+}
+
+static void
+dnode_sync_free(dnode_t *dn, dmu_tx_t *tx)
+{
+       int txgoff = tx->tx_txg & TXG_MASK;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       /*
+        * Our contents should have been freed in dnode_sync() by the
+        * free range record inserted by the caller of dnode_free().
+        */
+       ASSERT0(DN_USED_BYTES(dn->dn_phys));
+       ASSERT(BP_IS_HOLE(dn->dn_phys->dn_blkptr));
+
+       dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]);
+       dnode_evict_dbufs(dn);
+
+       /*
+        * XXX - It would be nice to assert this, but we may still
+        * have residual holds from async evictions from the arc...
+        *
+        * zfs_obj_to_path() also depends on this being
+        * commented out.
+        *
+        * ASSERT3U(refcount_count(&dn->dn_holds), ==, 1);
+        */
+
+       /* Undirty next bits */
+       dn->dn_next_nlevels[txgoff] = 0;
+       dn->dn_next_indblkshift[txgoff] = 0;
+       dn->dn_next_blksz[txgoff] = 0;
+
+       /* ASSERT(blkptrs are zero); */
+       ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE);
+       ASSERT(dn->dn_type != DMU_OT_NONE);
+
+       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));
+
+       mutex_enter(&dn->dn_mtx);
+       dn->dn_type = DMU_OT_NONE;
+       dn->dn_maxblkid = 0;
+       dn->dn_allocated_txg = 0;
+       dn->dn_free_txg = 0;
+       dn->dn_have_spill = B_FALSE;
+       mutex_exit(&dn->dn_mtx);
+
+       ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT);
+
+       dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg);
+       /*
+        * Now that we've released our hold, the dnode may
+        * be evicted, so we musn't access it.
+        */
+}
+
+/*
+ * Write out the dnode's dirty buffers.
+ */
+void
+dnode_sync(dnode_t *dn, dmu_tx_t *tx)
+{
+       dnode_phys_t *dnp = dn->dn_phys;
+       int txgoff = tx->tx_txg & TXG_MASK;
+       list_t *list = &dn->dn_dirty_records[txgoff];
+       boolean_t kill_spill = B_FALSE;
+       boolean_t freeing_dnode;
+       ASSERTV(static const dnode_phys_t zerodn = { 0 });
+
+       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);
+       DNODE_VERIFY(dn);
+
+       ASSERT(dn->dn_dbuf == NULL || arc_released(dn->dn_dbuf->db_buf));
+
+       if (dmu_objset_userused_enabled(dn->dn_objset) &&
+           !DMU_OBJECT_IS_SPECIAL(dn->dn_object)) {
+               mutex_enter(&dn->dn_mtx);
+               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;
+               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));
+       }
+
+       mutex_enter(&dn->dn_mtx);
+       if (dn->dn_allocated_txg == tx->tx_txg) {
+               /* The dnode is newly allocated or reallocated */
+               if (dnp->dn_type == DMU_OT_NONE) {
+                       /* this is a first alloc, not a realloc */
+                       dnp->dn_nlevels = 1;
+                       dnp->dn_nblkptr = dn->dn_nblkptr;
+               }
+
+               dnp->dn_type = dn->dn_type;
+               dnp->dn_bonustype = dn->dn_bonustype;
+               dnp->dn_bonuslen = dn->dn_bonuslen;
+       }
+       ASSERT(dnp->dn_nlevels > 1 ||
+           BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
+           BP_IS_EMBEDDED(&dnp->dn_blkptr[0]) ||
+           BP_GET_LSIZE(&dnp->dn_blkptr[0]) ==
+           dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
+       ASSERT(dnp->dn_nlevels < 2 ||
+           BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
+           BP_GET_LSIZE(&dnp->dn_blkptr[0]) == 1 << dnp->dn_indblkshift);
+
+       if (dn->dn_next_type[txgoff] != 0) {
+               dnp->dn_type = dn->dn_type;
+               dn->dn_next_type[txgoff] = 0;
+       }
+
+       if (dn->dn_next_blksz[txgoff] != 0) {
+               ASSERT(P2PHASE(dn->dn_next_blksz[txgoff],
+                   SPA_MINBLOCKSIZE) == 0);
+               ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
+                   dn->dn_maxblkid == 0 || list_head(list) != NULL ||
+                   dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT ==
+                   dnp->dn_datablkszsec ||
+                   range_tree_space(dn->dn_free_ranges[txgoff]) != 0);
+               dnp->dn_datablkszsec =
+                   dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT;
+               dn->dn_next_blksz[txgoff] = 0;
+       }
+
+       if (dn->dn_next_bonuslen[txgoff] != 0) {
+               if (dn->dn_next_bonuslen[txgoff] == DN_ZERO_BONUSLEN)
+                       dnp->dn_bonuslen = 0;
+               else
+                       dnp->dn_bonuslen = dn->dn_next_bonuslen[txgoff];
+               ASSERT(dnp->dn_bonuslen <= DN_MAX_BONUSLEN);
+               dn->dn_next_bonuslen[txgoff] = 0;
+       }
+
+       if (dn->dn_next_bonustype[txgoff] != 0) {
+               ASSERT(DMU_OT_IS_VALID(dn->dn_next_bonustype[txgoff]));
+               dnp->dn_bonustype = dn->dn_next_bonustype[txgoff];
+               dn->dn_next_bonustype[txgoff] = 0;
+       }
+
+       freeing_dnode = dn->dn_free_txg > 0 && dn->dn_free_txg <= tx->tx_txg;
+
+       /*
+        * Remove the spill block if we have been explicitly asked to
+        * remove it, or if the object is being removed.
+        */
+       if (dn->dn_rm_spillblk[txgoff] || freeing_dnode) {
+               if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR)
+                       kill_spill = B_TRUE;
+               dn->dn_rm_spillblk[txgoff] = 0;
+       }
+
+       if (dn->dn_next_indblkshift[txgoff] != 0) {
+               ASSERT(dnp->dn_nlevels == 1);
+               dnp->dn_indblkshift = dn->dn_next_indblkshift[txgoff];
+               dn->dn_next_indblkshift[txgoff] = 0;
+       }
+
+       /*
+        * Just take the live (open-context) values for checksum and compress.
+        * Strictly speaking it's a future leak, but nothing bad happens if we
+        * start using the new checksum or compress algorithm a little early.
+        */
+       dnp->dn_checksum = dn->dn_checksum;
+       dnp->dn_compress = dn->dn_compress;
+
+       mutex_exit(&dn->dn_mtx);
+
+       if (kill_spill) {
+               free_blocks(dn, &dn->dn_phys->dn_spill, 1, tx);
+               mutex_enter(&dn->dn_mtx);
+               dnp->dn_flags &= ~DNODE_FLAG_SPILL_BLKPTR;
+               mutex_exit(&dn->dn_mtx);
+       }
+
+       /* process all the "freed" ranges in the file */
+       if (dn->dn_free_ranges[txgoff] != NULL) {
+               dnode_sync_free_range_arg_t dsfra;
+               dsfra.dsfra_dnode = dn;
+               dsfra.dsfra_tx = tx;
+               mutex_enter(&dn->dn_mtx);
+               range_tree_vacate(dn->dn_free_ranges[txgoff],
+                   dnode_sync_free_range, &dsfra);
+               range_tree_destroy(dn->dn_free_ranges[txgoff]);
+               dn->dn_free_ranges[txgoff] = NULL;
+               mutex_exit(&dn->dn_mtx);
+       }
+
+       if (freeing_dnode) {
+               dnode_sync_free(dn, tx);
+               return;
+       }
+
+       if (dn->dn_next_nlevels[txgoff]) {
+               dnode_increase_indirection(dn, tx);
+               dn->dn_next_nlevels[txgoff] = 0;
+       }
+
+       if (dn->dn_next_nblkptr[txgoff]) {
+               /* this should only happen on a realloc */
+               ASSERT(dn->dn_allocated_txg == tx->tx_txg);
+               if (dn->dn_next_nblkptr[txgoff] > dnp->dn_nblkptr) {
+                       /* zero the new blkptrs we are gaining */
+                       bzero(dnp->dn_blkptr + dnp->dn_nblkptr,
+                           sizeof (blkptr_t) *
+                           (dn->dn_next_nblkptr[txgoff] - dnp->dn_nblkptr));
+#ifdef ZFS_DEBUG
+               } else {
+                       int i;
+                       ASSERT(dn->dn_next_nblkptr[txgoff] < dnp->dn_nblkptr);
+                       /* the blkptrs we are losing better be unallocated */
+                       for (i = 0; i < dnp->dn_nblkptr; i++) {
+                               if (i >= dn->dn_next_nblkptr[txgoff])
+                                       ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[i]));
+                       }
+#endif
+               }
+               mutex_enter(&dn->dn_mtx);
+               dnp->dn_nblkptr = dn->dn_next_nblkptr[txgoff];
+               dn->dn_next_nblkptr[txgoff] = 0;
+               mutex_exit(&dn->dn_mtx);
+       }
+
+       dbuf_sync_list(list, dn->dn_phys->dn_nlevels - 1, tx);
+
+       if (!DMU_OBJECT_IS_SPECIAL(dn->dn_object)) {
+               ASSERT3P(list_head(list), ==, NULL);
+               dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg);
+       }
+
+       /*
+        * Although we have dropped our reference to the dnode, it
+        * can't be evicted until its written, and we haven't yet
+        * initiated the IO for the dnode's dbuf.
+        */
+}
diff --git a/zfs/module/zfs/dsl_bookmark.c b/zfs/module/zfs/dsl_bookmark.c
new file mode 100644 (file)
index 0000000..447a3a2
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * 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) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/arc.h>
+#include <sys/zap.h>
+#include <sys/zfeature.h>
+#include <sys/spa.h>
+#include <sys/dsl_bookmark.h>
+#include <zfs_namecheck.h>
+
+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 *hashp;
+
+       if (strlen(fullname) >= MAXNAMELEN)
+               return (SET_ERROR(ENAMETOOLONG));
+       hashp = strchr(fullname, '#');
+       if (hashp == NULL)
+               return (SET_ERROR(EINVAL));
+
+       *shortnamep = hashp + 1;
+       if (zfs_component_namecheck(*shortnamep, NULL, NULL))
+               return (SET_ERROR(EINVAL));
+       (void) strlcpy(buf, fullname, hashp - fullname + 1);
+       return (dsl_dataset_hold(dp, buf, tag, dsp));
+}
+
+/*
+ * Returns ESRCH if bookmark is not found.
+ */
+static int
+dsl_dataset_bmark_lookup(dsl_dataset_t *ds, const char *shortname,
+    zfs_bookmark_phys_t *bmark_phys)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       uint64_t bmark_zapobj = ds->ds_bookmarks;
+       matchtype_t mt;
+       int err;
+
+       if (bmark_zapobj == 0)
+               return (SET_ERROR(ESRCH));
+
+       if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
+               mt = MT_FIRST;
+       else
+               mt = MT_EXACT;
+
+       err = zap_lookup_norm(mos, bmark_zapobj, shortname, sizeof (uint64_t),
+           sizeof (*bmark_phys) / sizeof (uint64_t), bmark_phys, mt,
+           NULL, 0, NULL);
+
+       return (err == ENOENT ? ESRCH : err);
+}
+
+/*
+ * If later_ds is non-NULL, this will return EXDEV if the the specified bookmark
+ * does not represents an earlier point in later_ds's timeline.
+ *
+ * Returns ENOENT if the dataset containing the bookmark does not exist.
+ * Returns ESRCH if the dataset exists but the bookmark was not found in it.
+ */
+int
+dsl_bookmark_lookup(dsl_pool_t *dp, const char *fullname,
+    dsl_dataset_t *later_ds, zfs_bookmark_phys_t *bmp)
+{
+       char *shortname;
+       dsl_dataset_t *ds;
+       int error;
+
+       error = dsl_bookmark_hold_ds(dp, fullname, &ds, FTAG, &shortname);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_bmark_lookup(ds, shortname, bmp);
+       if (error == 0 && later_ds != NULL) {
+               if (!dsl_dataset_is_before(later_ds, ds, bmp->zbm_creation_txg))
+                       error = SET_ERROR(EXDEV);
+       }
+       dsl_dataset_rele(ds, FTAG);
+       return (error);
+}
+
+typedef struct dsl_bookmark_create_arg {
+       nvlist_t *dbca_bmarks;
+       nvlist_t *dbca_errors;
+} dsl_bookmark_create_arg_t;
+
+static int
+dsl_bookmark_create_check_impl(dsl_dataset_t *snapds, const char *bookmark_name,
+    dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *bmark_fs;
+       char *shortname;
+       int error;
+       zfs_bookmark_phys_t bmark_phys;
+
+       if (!snapds->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       error = dsl_bookmark_hold_ds(dp, bookmark_name,
+           &bmark_fs, FTAG, &shortname);
+       if (error != 0)
+               return (error);
+
+       if (!dsl_dataset_is_before(bmark_fs, snapds, 0)) {
+               dsl_dataset_rele(bmark_fs, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       error = dsl_dataset_bmark_lookup(bmark_fs, shortname,
+           &bmark_phys);
+       dsl_dataset_rele(bmark_fs, FTAG);
+       if (error == 0)
+               return (SET_ERROR(EEXIST));
+       if (error == ESRCH)
+               return (0);
+       return (error);
+}
+
+static int
+dsl_bookmark_create_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_bookmark_create_arg_t *dbca = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       int rv = 0;
+       nvpair_t *pair;
+
+       if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS))
+               return (SET_ERROR(ENOTSUP));
+
+       for (pair = nvlist_next_nvpair(dbca->dbca_bmarks, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(dbca->dbca_bmarks, pair)) {
+               dsl_dataset_t *snapds;
+               int error;
+
+               /* note: validity of nvlist checked by ioctl layer */
+               error = dsl_dataset_hold(dp, fnvpair_value_string(pair),
+                   FTAG, &snapds);
+               if (error == 0) {
+                       error = dsl_bookmark_create_check_impl(snapds,
+                           nvpair_name(pair), tx);
+                       dsl_dataset_rele(snapds, FTAG);
+               }
+               if (error != 0) {
+                       fnvlist_add_int32(dbca->dbca_errors,
+                           nvpair_name(pair), error);
+                       rv = error;
+               }
+       }
+
+       return (rv);
+}
+
+static void
+dsl_bookmark_create_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_bookmark_create_arg_t *dbca = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       nvpair_t *pair;
+
+       ASSERT(spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS));
+
+       for (pair = nvlist_next_nvpair(dbca->dbca_bmarks, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(dbca->dbca_bmarks, pair)) {
+               dsl_dataset_t *snapds, *bmark_fs;
+               zfs_bookmark_phys_t bmark_phys;
+               char *shortname;
+
+               VERIFY0(dsl_dataset_hold(dp, fnvpair_value_string(pair),
+                   FTAG, &snapds));
+               VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
+                   &bmark_fs, FTAG, &shortname));
+               if (bmark_fs->ds_bookmarks == 0) {
+                       bmark_fs->ds_bookmarks =
+                           zap_create_norm(mos, U8_TEXTPREP_TOUPPER,
+                           DMU_OTN_ZAP_METADATA, DMU_OT_NONE, 0, tx);
+                       spa_feature_incr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);
+
+                       dsl_dataset_zapify(bmark_fs, tx);
+                       VERIFY0(zap_add(mos, bmark_fs->ds_object,
+                           DS_FIELD_BOOKMARK_NAMES,
+                           sizeof (bmark_fs->ds_bookmarks), 1,
+                           &bmark_fs->ds_bookmarks, tx));
+               }
+
+               bmark_phys.zbm_guid = dsl_dataset_phys(snapds)->ds_guid;
+               bmark_phys.zbm_creation_txg =
+                   dsl_dataset_phys(snapds)->ds_creation_txg;
+               bmark_phys.zbm_creation_time =
+                   dsl_dataset_phys(snapds)->ds_creation_time;
+
+               VERIFY0(zap_add(mos, bmark_fs->ds_bookmarks,
+                   shortname, sizeof (uint64_t),
+                   sizeof (zfs_bookmark_phys_t) / sizeof (uint64_t),
+                   &bmark_phys, tx));
+
+               spa_history_log_internal_ds(bmark_fs, "bookmark", tx,
+                   "name=%s creation_txg=%llu target_snap=%llu",
+                   shortname,
+                   (longlong_t)bmark_phys.zbm_creation_txg,
+                   (longlong_t)snapds->ds_object);
+
+               dsl_dataset_rele(bmark_fs, FTAG);
+               dsl_dataset_rele(snapds, FTAG);
+       }
+}
+
+/*
+ * The bookmarks must all be in the same pool.
+ */
+int
+dsl_bookmark_create(nvlist_t *bmarks, nvlist_t *errors)
+{
+       nvpair_t *pair;
+       dsl_bookmark_create_arg_t dbca;
+
+       pair = nvlist_next_nvpair(bmarks, NULL);
+       if (pair == NULL)
+               return (0);
+
+       dbca.dbca_bmarks = bmarks;
+       dbca.dbca_errors = errors;
+
+       return (dsl_sync_task(nvpair_name(pair), dsl_bookmark_create_check,
+           dsl_bookmark_create_sync, &dbca,
+           fnvlist_num_pairs(bmarks), ZFS_SPACE_CHECK_NORMAL));
+}
+
+int
+dsl_get_bookmarks_impl(dsl_dataset_t *ds, nvlist_t *props, nvlist_t *outnvl)
+{
+       int err = 0;
+       zap_cursor_t zc;
+       zap_attribute_t attr;
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+
+       uint64_t bmark_zapobj = ds->ds_bookmarks;
+       if (bmark_zapobj == 0)
+               return (0);
+
+       for (zap_cursor_init(&zc, dp->dp_meta_objset, bmark_zapobj);
+           zap_cursor_retrieve(&zc, &attr) == 0;
+           zap_cursor_advance(&zc)) {
+               nvlist_t *out_props;
+               char *bmark_name = attr.za_name;
+               zfs_bookmark_phys_t bmark_phys;
+
+               err = dsl_dataset_bmark_lookup(ds, bmark_name, &bmark_phys);
+               ASSERT3U(err, !=, ENOENT);
+               if (err != 0)
+                       break;
+
+               out_props = fnvlist_alloc();
+               if (nvlist_exists(props,
+                   zfs_prop_to_name(ZFS_PROP_GUID))) {
+                       dsl_prop_nvlist_add_uint64(out_props,
+                           ZFS_PROP_GUID, bmark_phys.zbm_guid);
+               }
+               if (nvlist_exists(props,
+                   zfs_prop_to_name(ZFS_PROP_CREATETXG))) {
+                       dsl_prop_nvlist_add_uint64(out_props,
+                           ZFS_PROP_CREATETXG, bmark_phys.zbm_creation_txg);
+               }
+               if (nvlist_exists(props,
+                   zfs_prop_to_name(ZFS_PROP_CREATION))) {
+                       dsl_prop_nvlist_add_uint64(out_props,
+                           ZFS_PROP_CREATION, bmark_phys.zbm_creation_time);
+               }
+
+               fnvlist_add_nvlist(outnvl, bmark_name, out_props);
+               fnvlist_free(out_props);
+       }
+       zap_cursor_fini(&zc);
+       return (err);
+}
+
+/*
+ * Retrieve the bookmarks that exist in the specified dataset, and the
+ * requested properties of each bookmark.
+ *
+ * The "props" nvlist specifies which properties are requested.
+ * See lzc_get_bookmarks() for the list of valid properties.
+ */
+int
+dsl_get_bookmarks(const char *dsname, nvlist_t *props, nvlist_t *outnvl)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int err;
+
+       err = dsl_pool_hold(dsname, FTAG, &dp);
+       if (err != 0)
+               return (err);
+       err = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+       if (err != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (err);
+       }
+
+       err = dsl_get_bookmarks_impl(ds, props, outnvl);
+
+       dsl_dataset_rele(ds, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (err);
+}
+
+typedef struct dsl_bookmark_destroy_arg {
+       nvlist_t *dbda_bmarks;
+       nvlist_t *dbda_success;
+       nvlist_t *dbda_errors;
+} dsl_bookmark_destroy_arg_t;
+
+static int
+dsl_dataset_bookmark_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       uint64_t bmark_zapobj = ds->ds_bookmarks;
+       matchtype_t mt;
+
+       if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
+               mt = MT_FIRST;
+       else
+               mt = MT_EXACT;
+
+       return (zap_remove_norm(mos, bmark_zapobj, name, mt, tx));
+}
+
+static int
+dsl_bookmark_destroy_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_bookmark_destroy_arg_t *dbda = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       int rv = 0;
+       nvpair_t *pair;
+
+       if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS))
+               return (0);
+
+       for (pair = nvlist_next_nvpair(dbda->dbda_bmarks, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_bmarks, pair)) {
+               const char *fullname = nvpair_name(pair);
+               dsl_dataset_t *ds;
+               zfs_bookmark_phys_t bm;
+               int error;
+               char *shortname;
+
+               error = dsl_bookmark_hold_ds(dp, fullname, &ds,
+                   FTAG, &shortname);
+               if (error == ENOENT) {
+                       /* ignore it; the bookmark is "already destroyed" */
+                       continue;
+               }
+               if (error == 0) {
+                       error = dsl_dataset_bmark_lookup(ds, shortname, &bm);
+                       dsl_dataset_rele(ds, FTAG);
+                       if (error == ESRCH) {
+                               /*
+                                * ignore it; the bookmark is
+                                * "already destroyed"
+                                */
+                               continue;
+                       }
+               }
+               if (error == 0) {
+                       fnvlist_add_boolean(dbda->dbda_success, fullname);
+               } else {
+                       fnvlist_add_int32(dbda->dbda_errors, fullname, error);
+                       rv = error;
+               }
+       }
+       return (rv);
+}
+
+static void
+dsl_bookmark_destroy_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_bookmark_destroy_arg_t *dbda = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       nvpair_t *pair;
+
+       for (pair = nvlist_next_nvpair(dbda->dbda_success, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_success, pair)) {
+               dsl_dataset_t *ds;
+               char *shortname;
+               uint64_t zap_cnt;
+
+               VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
+                   &ds, FTAG, &shortname));
+               VERIFY0(dsl_dataset_bookmark_remove(ds, shortname, tx));
+
+               /*
+                * If all of this dataset's bookmarks have been destroyed,
+                * free the zap object and decrement the feature's use count.
+                */
+               VERIFY0(zap_count(mos, ds->ds_bookmarks,
+                   &zap_cnt));
+               if (zap_cnt == 0) {
+                       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+                       VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx));
+                       ds->ds_bookmarks = 0;
+                       spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);
+                       VERIFY0(zap_remove(mos, ds->ds_object,
+                           DS_FIELD_BOOKMARK_NAMES, tx));
+               }
+
+               spa_history_log_internal_ds(ds, "remove bookmark", tx,
+                   "name=%s", shortname);
+
+               dsl_dataset_rele(ds, FTAG);
+       }
+}
+
+/*
+ * The bookmarks must all be in the same pool.
+ */
+int
+dsl_bookmark_destroy(nvlist_t *bmarks, nvlist_t *errors)
+{
+       int rv;
+       dsl_bookmark_destroy_arg_t dbda;
+       nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL);
+       if (pair == NULL)
+               return (0);
+
+       dbda.dbda_bmarks = bmarks;
+       dbda.dbda_errors = errors;
+       dbda.dbda_success = fnvlist_alloc();
+
+       rv = dsl_sync_task(nvpair_name(pair), dsl_bookmark_destroy_check,
+           dsl_bookmark_destroy_sync, &dbda, fnvlist_num_pairs(bmarks),
+           ZFS_SPACE_CHECK_RESERVED);
+       fnvlist_free(dbda.dbda_success);
+       return (rv);
+}
diff --git a/zfs/module/zfs/dsl_dataset.c b/zfs/module/zfs/dsl_dataset.c
new file mode 100644 (file)
index 0000000..9bbb6fa
--- /dev/null
@@ -0,0 +1,3428 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 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.
+ */
+
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/arc.h>
+#include <sys/zio.h>
+#include <sys/zap.h>
+#include <sys/zfeature.h>
+#include <sys/unique.h>
+#include <sys/zfs_context.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/spa.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_onexit.h>
+#include <sys/zvol.h>
+#include <sys/dsl_scan.h>
+#include <sys/dsl_deadlist.h>
+#include <sys/dsl_destroy.h>
+#include <sys/dsl_userhold.h>
+#include <sys/dsl_bookmark.h>
+
+/*
+ * The SPA supports block sizes up to 16MB.  However, very large blocks
+ * can have an impact on i/o latency (e.g. tying up a spinning disk for
+ * ~300ms), 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.
+ */
+int zfs_max_recordsize = 1 * 1024 * 1024;
+
+#define        SWITCH64(x, y) \
+       { \
+               uint64_t __tmp = (x); \
+               (x) = (y); \
+               (y) = __tmp; \
+       }
+
+#define        DS_REF_MAX      (1ULL << 62)
+
+extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
+
+/*
+ * 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
+ * partially accounted for in our ancestors.
+ */
+static int64_t
+parent_delta(dsl_dataset_t *ds, int64_t delta)
+{
+       dsl_dataset_phys_t *ds_phys;
+       uint64_t old_bytes, new_bytes;
+
+       if (ds->ds_reserved == 0)
+               return (delta);
+
+       ds_phys = dsl_dataset_phys(ds);
+       old_bytes = MAX(ds_phys->ds_unique_bytes, ds->ds_reserved);
+       new_bytes = MAX(ds_phys->ds_unique_bytes + delta, ds->ds_reserved);
+
+       ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta));
+       return (new_bytes - old_bytes);
+}
+
+void
+dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       int used, compressed, uncompressed;
+       int64_t delta;
+
+       used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
+       compressed = BP_GET_PSIZE(bp);
+       uncompressed = BP_GET_UCSIZE(bp);
+
+       dprintf_bp(bp, "ds=%p", ds);
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       /* It could have been compressed away to nothing */
+       if (BP_IS_HOLE(bp))
+               return;
+       ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE);
+       ASSERT(DMU_OT_IS_VALID(BP_GET_TYPE(bp)));
+       if (ds == NULL) {
+               dsl_pool_mos_diduse_space(tx->tx_pool,
+                   used, compressed, uncompressed);
+               return;
+       }
+
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       mutex_enter(&ds->ds_lock);
+       delta = parent_delta(ds, used);
+       dsl_dataset_phys(ds)->ds_referenced_bytes += used;
+       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;
+       mutex_exit(&ds->ds_lock);
+       dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
+           compressed, uncompressed, tx);
+       dsl_dir_transfer_space(ds->ds_dir, used - delta,
+           DD_USED_REFRSRV, DD_USED_HEAD, tx);
+}
+
+int
+dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
+    boolean_t async)
+{
+       int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
+       int compressed = BP_GET_PSIZE(bp);
+       int uncompressed = BP_GET_UCSIZE(bp);
+
+       if (BP_IS_HOLE(bp))
+               return (0);
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(bp->blk_birth <= tx->tx_txg);
+
+       if (ds == NULL) {
+               dsl_free(tx->tx_pool, tx->tx_txg, bp);
+               dsl_pool_mos_diduse_space(tx->tx_pool,
+                   -used, -compressed, -uncompressed);
+               return (used);
+       }
+       ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool);
+
+       ASSERT(!ds->ds_is_snapshot);
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+
+       if (bp->blk_birth > dsl_dataset_phys(ds)->ds_prev_snap_txg) {
+               int64_t delta;
+
+               dprintf_bp(bp, "freeing ds=%llu", ds->ds_object);
+               dsl_free(tx->tx_pool, tx->tx_txg, bp);
+
+               mutex_enter(&ds->ds_lock);
+               ASSERT(dsl_dataset_phys(ds)->ds_unique_bytes >= used ||
+                   !DS_UNIQUE_IS_ACCURATE(ds));
+               delta = parent_delta(ds, -used);
+               dsl_dataset_phys(ds)->ds_unique_bytes -= used;
+               mutex_exit(&ds->ds_lock);
+               dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD,
+                   delta, -compressed, -uncompressed, tx);
+               dsl_dir_transfer_space(ds->ds_dir, -used - delta,
+                   DD_USED_REFRSRV, DD_USED_HEAD, tx);
+       } else {
+               dprintf_bp(bp, "putting on dead list: %s", "");
+               if (async) {
+                       /*
+                        * We are here as part of zio's write done callback,
+                        * which means we're a zio interrupt thread.  We can't
+                        * call dsl_deadlist_insert() now because it may block
+                        * waiting for I/O.  Instead, put bp on the deferred
+                        * queue and let dsl_pool_sync() finish the job.
+                        */
+                       bplist_append(&ds->ds_pending_deadlist, bp);
+               } else {
+                       dsl_deadlist_insert(&ds->ds_deadlist, bp, tx);
+               }
+               ASSERT3U(ds->ds_prev->ds_object, ==,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj);
+               ASSERT(dsl_dataset_phys(ds->ds_prev)->ds_num_children > 0);
+               /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */
+               if (dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj ==
+                   ds->ds_object && bp->blk_birth >
+                   dsl_dataset_phys(ds->ds_prev)->ds_prev_snap_txg) {
+                       dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
+                       mutex_enter(&ds->ds_prev->ds_lock);
+                       dsl_dataset_phys(ds->ds_prev)->ds_unique_bytes += used;
+                       mutex_exit(&ds->ds_prev->ds_lock);
+               }
+               if (bp->blk_birth > ds->ds_dir->dd_origin_txg) {
+                       dsl_dir_transfer_space(ds->ds_dir, used,
+                           DD_USED_HEAD, DD_USED_SNAP, tx);
+               }
+       }
+       mutex_enter(&ds->ds_lock);
+       ASSERT3U(dsl_dataset_phys(ds)->ds_referenced_bytes, >=, used);
+       dsl_dataset_phys(ds)->ds_referenced_bytes -= used;
+       ASSERT3U(dsl_dataset_phys(ds)->ds_compressed_bytes, >=, compressed);
+       dsl_dataset_phys(ds)->ds_compressed_bytes -= compressed;
+       ASSERT3U(dsl_dataset_phys(ds)->ds_uncompressed_bytes, >=, uncompressed);
+       dsl_dataset_phys(ds)->ds_uncompressed_bytes -= uncompressed;
+       mutex_exit(&ds->ds_lock);
+
+       return (used);
+}
+
+uint64_t
+dsl_dataset_prev_snap_txg(dsl_dataset_t *ds)
+{
+       uint64_t trysnap = 0;
+
+       if (ds == NULL)
+               return (0);
+       /*
+        * The snapshot creation could fail, but that would cause an
+        * incorrect FALSE return, which would only result in an
+        * overestimation of the amount of space that an operation would
+        * consume, which is OK.
+        *
+        * There's also a small window where we could miss a pending
+        * snapshot, because we could set the sync task in the quiescing
+        * phase.  So this should only be used as a guess.
+        */
+       if (ds->ds_trysnap_txg >
+           spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa))
+               trysnap = ds->ds_trysnap_txg;
+       return (MAX(dsl_dataset_phys(ds)->ds_prev_snap_txg, trysnap));
+}
+
+boolean_t
+dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp,
+    uint64_t blk_birth)
+{
+       if (blk_birth <= dsl_dataset_prev_snap_txg(ds) ||
+           (bp != NULL && BP_IS_HOLE(bp)))
+               return (B_FALSE);
+
+       ddt_prefetch(dsl_dataset_get_spa(ds), bp);
+
+       return (B_TRUE);
+}
+
+static void
+dsl_dataset_evict(void *dbu)
+{
+       dsl_dataset_t *ds = dbu;
+
+       ASSERT(ds->ds_owner == NULL);
+
+       ds->ds_dbuf = NULL;
+
+       unique_remove(ds->ds_fsid_guid);
+
+       if (ds->ds_objset != NULL)
+               dmu_objset_evict(ds->ds_objset);
+
+       if (ds->ds_prev) {
+               dsl_dataset_rele(ds->ds_prev, ds);
+               ds->ds_prev = NULL;
+       }
+
+       bplist_destroy(&ds->ds_pending_deadlist);
+       if (ds->ds_deadlist.dl_os != NULL)
+               dsl_deadlist_close(&ds->ds_deadlist);
+       if (ds->ds_dir)
+               dsl_dir_async_rele(ds->ds_dir, ds);
+
+       ASSERT(!list_link_active(&ds->ds_synced_link));
+
+       mutex_destroy(&ds->ds_lock);
+       mutex_destroy(&ds->ds_opening_lock);
+       mutex_destroy(&ds->ds_sendstream_lock);
+       refcount_destroy(&ds->ds_longholds);
+
+       kmem_free(ds, sizeof (dsl_dataset_t));
+}
+
+int
+dsl_dataset_get_snapname(dsl_dataset_t *ds)
+{
+       dsl_dataset_phys_t *headphys;
+       int err;
+       dmu_buf_t *headdbuf;
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       objset_t *mos = dp->dp_meta_objset;
+
+       if (ds->ds_snapname[0])
+               return (0);
+       if (dsl_dataset_phys(ds)->ds_next_snap_obj == 0)
+               return (0);
+
+       err = dmu_bonus_hold(mos, dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj,
+           FTAG, &headdbuf);
+       if (err != 0)
+               return (err);
+       headphys = headdbuf->db_data;
+       err = zap_value_search(dp->dp_meta_objset,
+           headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname);
+       if (err != 0 && zfs_recover == B_TRUE) {
+               err = 0;
+               (void) snprintf(ds->ds_snapname, sizeof (ds->ds_snapname),
+                   "SNAPOBJ=%llu-ERR=%d",
+                   (unsigned long long)ds->ds_object, err);
+       }
+       dmu_buf_rele(headdbuf, FTAG);
+       return (err);
+}
+
+int
+dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       uint64_t snapobj = dsl_dataset_phys(ds)->ds_snapnames_zapobj;
+       matchtype_t mt;
+       int err;
+
+       if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
+               mt = MT_FIRST;
+       else
+               mt = MT_EXACT;
+
+       err = zap_lookup_norm(mos, snapobj, name, 8, 1,
+           value, mt, NULL, 0, NULL);
+       if (err == ENOTSUP && mt == MT_FIRST)
+               err = zap_lookup(mos, snapobj, name, 8, 1, value);
+       return (err);
+}
+
+int
+dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx,
+    boolean_t adj_cnt)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       uint64_t snapobj = dsl_dataset_phys(ds)->ds_snapnames_zapobj;
+       matchtype_t mt;
+       int err;
+
+       dsl_dir_snap_cmtime_update(ds->ds_dir);
+
+       if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
+               mt = MT_FIRST;
+       else
+               mt = MT_EXACT;
+
+       err = zap_remove_norm(mos, snapobj, name, mt, tx);
+       if (err == ENOTSUP && mt == MT_FIRST)
+               err = zap_remove(mos, snapobj, name, tx);
+
+       if (err == 0 && adj_cnt)
+               dsl_fs_ss_count_adjust(ds->ds_dir, -1,
+                   DD_FIELD_SNAPSHOT_COUNT, tx);
+
+       return (err);
+}
+
+boolean_t
+dsl_dataset_try_add_ref(dsl_pool_t *dp, dsl_dataset_t *ds, void *tag)
+{
+       dmu_buf_t *dbuf = ds->ds_dbuf;
+       boolean_t result = B_FALSE;
+
+       if (dbuf != NULL && dmu_buf_try_add_ref(dbuf, dp->dp_meta_objset,
+           ds->ds_object, DMU_BONUS_BLKID, tag)) {
+
+               if (ds == dmu_buf_get_user(dbuf))
+                       result = B_TRUE;
+               else
+                       dmu_buf_rele(dbuf, tag);
+       }
+
+       return (result);
+}
+
+int
+dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
+    dsl_dataset_t **dsp)
+{
+       objset_t *mos = dp->dp_meta_objset;
+       dmu_buf_t *dbuf;
+       dsl_dataset_t *ds;
+       int err;
+       dmu_object_info_t doi;
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       err = dmu_bonus_hold(mos, dsobj, tag, &dbuf);
+       if (err != 0)
+               return (err);
+
+       /* Make sure dsobj has the correct object type. */
+       dmu_object_info_from_db(dbuf, &doi);
+       if (doi.doi_bonus_type != DMU_OT_DSL_DATASET) {
+               dmu_buf_rele(dbuf, tag);
+               return (SET_ERROR(EINVAL));
+       }
+
+       ds = dmu_buf_get_user(dbuf);
+       if (ds == NULL) {
+               dsl_dataset_t *winner = NULL;
+
+               ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
+               ds->ds_dbuf = dbuf;
+               ds->ds_object = dsobj;
+               ds->ds_is_snapshot = dsl_dataset_phys(ds)->ds_num_children != 0;
+               list_link_init(&ds->ds_synced_link);
+
+               mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
+               mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
+               mutex_init(&ds->ds_sendstream_lock, NULL, MUTEX_DEFAULT, NULL);
+               refcount_create(&ds->ds_longholds);
+
+               bplist_create(&ds->ds_pending_deadlist);
+               dsl_deadlist_open(&ds->ds_deadlist,
+                   mos, dsl_dataset_phys(ds)->ds_deadlist_obj);
+
+               list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t),
+                   offsetof(dmu_sendarg_t, dsa_link));
+
+               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;
+                       }
+               }
+
+               if (err == 0) {
+                       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);
+                       mutex_destroy(&ds->ds_sendstream_lock);
+                       refcount_destroy(&ds->ds_longholds);
+                       bplist_destroy(&ds->ds_pending_deadlist);
+                       dsl_deadlist_close(&ds->ds_deadlist);
+                       kmem_free(ds, sizeof (dsl_dataset_t));
+                       dmu_buf_rele(dbuf, tag);
+                       return (err);
+               }
+
+               if (!ds->ds_is_snapshot) {
+                       ds->ds_snapname[0] = '\0';
+                       if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
+                               err = dsl_dataset_hold_obj(dp,
+                                   dsl_dataset_phys(ds)->ds_prev_snap_obj,
+                                   ds, &ds->ds_prev);
+                       }
+                       if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
+                               int zaperr = zap_lookup(mos, ds->ds_object,
+                                   DS_FIELD_BOOKMARK_NAMES,
+                                   sizeof (ds->ds_bookmarks), 1,
+                                   &ds->ds_bookmarks);
+                               if (zaperr != ENOENT)
+                                       VERIFY0(zaperr);
+                       }
+               } else {
+                       if (zfs_flags & ZFS_DEBUG_SNAPNAMES)
+                               err = dsl_dataset_get_snapname(ds);
+                       if (err == 0 &&
+                           dsl_dataset_phys(ds)->ds_userrefs_obj != 0) {
+                               err = zap_count(
+                                   ds->ds_dir->dd_pool->dp_meta_objset,
+                                   dsl_dataset_phys(ds)->ds_userrefs_obj,
+                                   &ds->ds_userrefs);
+                       }
+               }
+
+               if (err == 0 && !ds->ds_is_snapshot) {
+                       err = dsl_prop_get_int_ds(ds,
+                           zfs_prop_to_name(ZFS_PROP_REFRESERVATION),
+                           &ds->ds_reserved);
+                       if (err == 0) {
+                               err = dsl_prop_get_int_ds(ds,
+                                   zfs_prop_to_name(ZFS_PROP_REFQUOTA),
+                                   &ds->ds_quota);
+                       }
+               } else {
+                       ds->ds_reserved = ds->ds_quota = 0;
+               }
+
+               dmu_buf_init_user(&ds->ds_dbu, dsl_dataset_evict, &ds->ds_dbuf);
+               if (err == 0)
+                       winner = dmu_buf_set_user_ie(dbuf, &ds->ds_dbu);
+
+               if (err != 0 || winner != NULL) {
+                       bplist_destroy(&ds->ds_pending_deadlist);
+                       dsl_deadlist_close(&ds->ds_deadlist);
+                       if (ds->ds_prev)
+                               dsl_dataset_rele(ds->ds_prev, ds);
+                       dsl_dir_rele(ds->ds_dir, ds);
+                       mutex_destroy(&ds->ds_lock);
+                       mutex_destroy(&ds->ds_opening_lock);
+                       mutex_destroy(&ds->ds_sendstream_lock);
+                       refcount_destroy(&ds->ds_longholds);
+                       kmem_free(ds, sizeof (dsl_dataset_t));
+                       if (err != 0) {
+                               dmu_buf_rele(dbuf, tag);
+                               return (err);
+                       }
+                       ds = winner;
+               } else {
+                       ds->ds_fsid_guid =
+                           unique_insert(dsl_dataset_phys(ds)->ds_fsid_guid);
+               }
+       }
+       ASSERT3P(ds->ds_dbuf, ==, dbuf);
+       ASSERT3P(dsl_dataset_phys(ds), ==, dbuf->db_data);
+       ASSERT(dsl_dataset_phys(ds)->ds_prev_snap_obj != 0 ||
+           spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN ||
+           dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap);
+       *dsp = ds;
+       return (0);
+}
+
+int
+dsl_dataset_hold(dsl_pool_t *dp, const char *name,
+    void *tag, dsl_dataset_t **dsp)
+{
+       dsl_dir_t *dd;
+       const char *snapname;
+       uint64_t obj;
+       int err = 0;
+
+       err = dsl_dir_hold(dp, name, FTAG, &dd, &snapname);
+       if (err != 0)
+               return (err);
+
+       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);
+       else
+               err = SET_ERROR(ENOENT);
+
+       /* we may be looking for a snapshot */
+       if (err == 0 && snapname != NULL) {
+               dsl_dataset_t *ds;
+
+               if (*snapname++ != '@') {
+                       dsl_dataset_rele(*dsp, 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);
+               if (err == 0)
+                       err = dsl_dataset_hold_obj(dp, obj, tag, &ds);
+               dsl_dataset_rele(*dsp, 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;
+               }
+       }
+
+       dsl_dir_rele(dd, FTAG);
+       return (err);
+}
+
+int
+dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj,
+    void *tag, dsl_dataset_t **dsp)
+{
+       int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp);
+       if (err != 0)
+               return (err);
+       if (!dsl_dataset_tryown(*dsp, tag)) {
+               dsl_dataset_rele(*dsp, tag);
+               *dsp = NULL;
+               return (SET_ERROR(EBUSY));
+       }
+       return (0);
+}
+
+int
+dsl_dataset_own(dsl_pool_t *dp, const char *name,
+    void *tag, dsl_dataset_t **dsp)
+{
+       int err = dsl_dataset_hold(dp, name, tag, dsp);
+       if (err != 0)
+               return (err);
+       if (!dsl_dataset_tryown(*dsp, tag)) {
+               dsl_dataset_rele(*dsp, tag);
+               return (SET_ERROR(EBUSY));
+       }
+       return (0);
+}
+
+/*
+ * See the comment above dsl_pool_hold() for details.  In summary, a long
+ * hold is used to prevent destruction of a dataset while the pool hold
+ * is dropped, allowing other concurrent operations (e.g. spa_sync()).
+ *
+ * The dataset and pool must be held when this function is called.  After it
+ * is called, the pool hold may be released while the dataset is still held
+ * and accessed.
+ */
+void
+dsl_dataset_long_hold(dsl_dataset_t *ds, void *tag)
+{
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
+       (void) refcount_add(&ds->ds_longholds, tag);
+}
+
+void
+dsl_dataset_long_rele(dsl_dataset_t *ds, void *tag)
+{
+       (void) refcount_remove(&ds->ds_longholds, tag);
+}
+
+/* Return B_TRUE if there are any long holds on this dataset. */
+boolean_t
+dsl_dataset_long_held(dsl_dataset_t *ds)
+{
+       return (!refcount_is_zero(&ds->ds_longholds));
+}
+
+void
+dsl_dataset_name(dsl_dataset_t *ds, char *name)
+{
+       if (ds == NULL) {
+               (void) strcpy(name, "mos");
+       } else {
+               dsl_dir_name(ds->ds_dir, name);
+               VERIFY0(dsl_dataset_get_snapname(ds));
+               if (ds->ds_snapname[0]) {
+                       (void) strcat(name, "@");
+                       /*
+                        * 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);
+                               mutex_exit(&ds->ds_lock);
+                       } else {
+                               (void) strcat(name, ds->ds_snapname);
+                       }
+               }
+       }
+}
+
+int
+dsl_dataset_namelen(dsl_dataset_t *ds)
+{
+       int len;
+       VERIFY0(dsl_dataset_get_snapname(ds));
+       mutex_enter(&ds->ds_lock);
+       len = strlen(ds->ds_snapname);
+       /* add '@' if ds is a snap */
+       if (len > 0)
+               len++;
+       len += dsl_dir_namelen(ds->ds_dir);
+       mutex_exit(&ds->ds_lock);
+       return (len);
+}
+
+void
+dsl_dataset_rele(dsl_dataset_t *ds, void *tag)
+{
+       dmu_buf_rele(ds->ds_dbuf, tag);
+}
+
+void
+dsl_dataset_disown(dsl_dataset_t *ds, void *tag)
+{
+       ASSERT3P(ds->ds_owner, ==, tag);
+       ASSERT(ds->ds_dbuf != NULL);
+
+       mutex_enter(&ds->ds_lock);
+       ds->ds_owner = NULL;
+       mutex_exit(&ds->ds_lock);
+       dsl_dataset_long_rele(ds, tag);
+       dsl_dataset_rele(ds, tag);
+}
+
+boolean_t
+dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
+{
+       boolean_t gotit = FALSE;
+
+       mutex_enter(&ds->ds_lock);
+       if (ds->ds_owner == NULL && !DS_IS_INCONSISTENT(ds)) {
+               ds->ds_owner = tag;
+               dsl_dataset_long_hold(ds, tag);
+               gotit = TRUE;
+       }
+       mutex_exit(&ds->ds_lock);
+       return (gotit);
+}
+
+uint64_t
+dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
+    uint64_t flags, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dd->dd_pool;
+       dmu_buf_t *dbuf;
+       dsl_dataset_phys_t *dsphys;
+       uint64_t dsobj;
+       objset_t *mos = dp->dp_meta_objset;
+
+       if (origin == NULL)
+               origin = dp->dp_origin_snap;
+
+       ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp);
+       ASSERT(origin == NULL || dsl_dataset_phys(origin)->ds_num_children > 0);
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(dsl_dir_phys(dd)->dd_head_dataset_obj == 0);
+
+       dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
+           DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
+       VERIFY0(dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
+       dmu_buf_will_dirty(dbuf, tx);
+       dsphys = dbuf->db_data;
+       bzero(dsphys, sizeof (dsl_dataset_phys_t));
+       dsphys->ds_dir_obj = dd->dd_object;
+       dsphys->ds_flags = flags;
+       dsphys->ds_fsid_guid = unique_create();
+       (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
+           sizeof (dsphys->ds_guid));
+       dsphys->ds_snapnames_zapobj =
+           zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP,
+           DMU_OT_NONE, 0, tx);
+       dsphys->ds_creation_time = gethrestime_sec();
+       dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg;
+
+       if (origin == NULL) {
+               dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx);
+       } else {
+               dsl_dataset_t *ohds; /* head of the origin snapshot */
+
+               dsphys->ds_prev_snap_obj = origin->ds_object;
+               dsphys->ds_prev_snap_txg =
+                   dsl_dataset_phys(origin)->ds_creation_txg;
+               dsphys->ds_referenced_bytes =
+                   dsl_dataset_phys(origin)->ds_referenced_bytes;
+               dsphys->ds_compressed_bytes =
+                   dsl_dataset_phys(origin)->ds_compressed_bytes;
+               dsphys->ds_uncompressed_bytes =
+                   dsl_dataset_phys(origin)->ds_uncompressed_bytes;
+               dsphys->ds_bp = dsl_dataset_phys(origin)->ds_bp;
+
+               /*
+                * Inherit flags that describe the dataset's contents
+                * (INCONSISTENT) or properties (Case Insensitive).
+                */
+               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);
+
+               dmu_buf_will_dirty(origin->ds_dbuf, tx);
+               dsl_dataset_phys(origin)->ds_num_children++;
+
+               VERIFY0(dsl_dataset_hold_obj(dp,
+                   dsl_dir_phys(origin->ds_dir)->dd_head_dataset_obj,
+                   FTAG, &ohds));
+               dsphys->ds_deadlist_obj = dsl_deadlist_clone(&ohds->ds_deadlist,
+                   dsphys->ds_prev_snap_txg, dsphys->ds_prev_snap_obj, tx);
+               dsl_dataset_rele(ohds, FTAG);
+
+               if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) {
+                       if (dsl_dataset_phys(origin)->ds_next_clones_obj == 0) {
+                               dsl_dataset_phys(origin)->ds_next_clones_obj =
+                                   zap_create(mos,
+                                   DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx);
+                       }
+                       VERIFY0(zap_add_int(mos,
+                           dsl_dataset_phys(origin)->ds_next_clones_obj,
+                           dsobj, tx));
+               }
+
+               dmu_buf_will_dirty(dd->dd_dbuf, tx);
+               dsl_dir_phys(dd)->dd_origin_obj = origin->ds_object;
+               if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
+                       if (dsl_dir_phys(origin->ds_dir)->dd_clones == 0) {
+                               dmu_buf_will_dirty(origin->ds_dir->dd_dbuf, tx);
+                               dsl_dir_phys(origin->ds_dir)->dd_clones =
+                                   zap_create(mos,
+                                   DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx);
+                       }
+                       VERIFY0(zap_add_int(mos,
+                           dsl_dir_phys(origin->ds_dir)->dd_clones,
+                           dsobj, tx));
+               }
+       }
+
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE)
+               dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
+
+       dmu_buf_rele(dbuf, FTAG);
+
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+       dsl_dir_phys(dd)->dd_head_dataset_obj = dsobj;
+
+       return (dsobj);
+}
+
+static void
+dsl_dataset_zero_zil(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       objset_t *os;
+
+       VERIFY0(dmu_objset_from_ds(ds, &os));
+       bzero(&os->os_zil_header, sizeof (os->os_zil_header));
+       dsl_dataset_dirty(ds, tx);
+}
+
+uint64_t
+dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname,
+    dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = pdd->dd_pool;
+       uint64_t dsobj, ddobj;
+       dsl_dir_t *dd;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(lastname[0] != '@');
+
+       ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx);
+       VERIFY0(dsl_dir_hold_obj(dp, ddobj, lastname, FTAG, &dd));
+
+       dsobj = dsl_dataset_create_sync_dd(dd, origin,
+           flags & ~DS_CREATE_FLAG_NODIRTY, tx);
+
+       dsl_deleg_set_create_perms(dd, tx, cr);
+
+       /*
+        * Since we're creating a new node we know it's a leaf, so we can
+        * initialize the counts if the limit feature is active.
+        */
+       if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_FS_SS_LIMIT)) {
+               uint64_t cnt = 0;
+               objset_t *os = dd->dd_pool->dp_meta_objset;
+
+               dsl_dir_zapify(dd, tx);
+               VERIFY0(zap_add(os, dd->dd_object, DD_FIELD_FILESYSTEM_COUNT,
+                   sizeof (cnt), 1, &cnt, tx));
+               VERIFY0(zap_add(os, dd->dd_object, DD_FIELD_SNAPSHOT_COUNT,
+                   sizeof (cnt), 1, &cnt, tx));
+       }
+
+       dsl_dir_rele(dd, FTAG);
+
+       /*
+        * If we are creating a clone, make sure we zero out any stale
+        * data from the origin snapshots zil header.
+        */
+       if (origin != NULL && !(flags & DS_CREATE_FLAG_NODIRTY)) {
+               dsl_dataset_t *ds;
+
+               VERIFY0(dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
+               dsl_dataset_zero_zil(ds, tx);
+               dsl_dataset_rele(ds, FTAG);
+       }
+
+       return (dsobj);
+}
+
+/*
+ * The unique space in the head dataset can be calculated by subtracting
+ * the space used in the most recent snapshot, that is still being used
+ * in this file system, from the space currently in use.  To figure out
+ * the space in the most recent snapshot still in use, we need to take
+ * the total space used in the snapshot and subtract out the space that
+ * has been freed up since the snapshot was taken.
+ */
+void
+dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds)
+{
+       uint64_t mrs_used;
+       uint64_t dlused, dlcomp, dluncomp;
+
+       ASSERT(!ds->ds_is_snapshot);
+
+       if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0)
+               mrs_used = dsl_dataset_phys(ds->ds_prev)->ds_referenced_bytes;
+       else
+               mrs_used = 0;
+
+       dsl_deadlist_space(&ds->ds_deadlist, &dlused, &dlcomp, &dluncomp);
+
+       ASSERT3U(dlused, <=, mrs_used);
+       dsl_dataset_phys(ds)->ds_unique_bytes =
+           dsl_dataset_phys(ds)->ds_referenced_bytes - (mrs_used - dlused);
+
+       if (spa_version(ds->ds_dir->dd_pool->dp_spa) >=
+           SPA_VERSION_UNIQUE_ACCURATE)
+               dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
+}
+
+void
+dsl_dataset_remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj,
+    dmu_tx_t *tx)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       int err;
+       ASSERTV(uint64_t count);
+
+       ASSERT(dsl_dataset_phys(ds)->ds_num_children >= 2);
+       err = zap_remove_int(mos, dsl_dataset_phys(ds)->ds_next_clones_obj,
+           obj, tx);
+       /*
+        * The err should not be ENOENT, but a bug in a previous version
+        * of the code could cause upgrade_clones_cb() to not set
+        * ds_next_snap_obj when it should, leading to a missing entry.
+        * If we knew that the pool was created after
+        * SPA_VERSION_NEXT_CLONES, we could assert that it isn't
+        * ENOENT.  However, at least we can check that we don't have
+        * too many entries in the next_clones_obj even after failing to
+        * remove this one.
+        */
+       if (err != ENOENT)
+               VERIFY0(err);
+       ASSERT0(zap_count(mos, dsl_dataset_phys(ds)->ds_next_clones_obj,
+           &count));
+       ASSERT3U(count, <=, dsl_dataset_phys(ds)->ds_num_children - 2);
+}
+
+
+blkptr_t *
+dsl_dataset_get_blkptr(dsl_dataset_t *ds)
+{
+       return (&dsl_dataset_phys(ds)->ds_bp);
+}
+
+void
+dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx)
+{
+       ASSERT(dmu_tx_is_syncing(tx));
+       /* If it's the meta-objset, set dp_meta_rootbp */
+       if (ds == NULL) {
+               tx->tx_pool->dp_meta_rootbp = *bp;
+       } else {
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               dsl_dataset_phys(ds)->ds_bp = *bp;
+       }
+}
+
+spa_t *
+dsl_dataset_get_spa(dsl_dataset_t *ds)
+{
+       return (ds->ds_dir->dd_pool->dp_spa);
+}
+
+void
+dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp;
+
+       if (ds == NULL) /* this is the meta-objset */
+               return;
+
+       ASSERT(ds->ds_objset != NULL);
+
+       if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0)
+               panic("dirtying snapshot!");
+
+       dp = ds->ds_dir->dd_pool;
+
+       if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg)) {
+               /* up the hold count until we can be written out */
+               dmu_buf_add_ref(ds->ds_dbuf, ds);
+       }
+}
+
+boolean_t
+dsl_dataset_is_dirty(dsl_dataset_t *ds)
+{
+       int t;
+
+       for (t = 0; t < TXG_SIZE; t++) {
+               if (txg_list_member(&ds->ds_dir->dd_pool->dp_dirty_datasets,
+                   ds, t))
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+static int
+dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       uint64_t asize;
+
+       if (!dmu_tx_is_syncing(tx))
+               return (0);
+
+       /*
+        * If there's an fs-only reservation, any blocks that might become
+        * owned by the snapshot dataset must be accommodated by space
+        * outside of the reservation.
+        */
+       ASSERT(ds->ds_reserved == 0 || DS_UNIQUE_IS_ACCURATE(ds));
+       asize = MIN(dsl_dataset_phys(ds)->ds_unique_bytes, ds->ds_reserved);
+       if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
+               return (SET_ERROR(ENOSPC));
+
+       /*
+        * Propagate any reserved space for this snapshot to other
+        * snapshot checks in this sync group.
+        */
+       if (asize > 0)
+               dsl_dir_willuse_space(ds->ds_dir, asize, tx);
+
+       return (0);
+}
+
+typedef struct dsl_dataset_snapshot_arg {
+       nvlist_t *ddsa_snaps;
+       nvlist_t *ddsa_props;
+       nvlist_t *ddsa_errors;
+       cred_t *ddsa_cr;
+} dsl_dataset_snapshot_arg_t;
+
+int
+dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
+    dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr)
+{
+       int error;
+       uint64_t value;
+
+       ds->ds_trysnap_txg = tx->tx_txg;
+
+       if (!dmu_tx_is_syncing(tx))
+               return (0);
+
+       /*
+        * We don't allow multiple snapshots of the same txg.  If there
+        * is already one, try again.
+        */
+       if (dsl_dataset_phys(ds)->ds_prev_snap_txg >= tx->tx_txg)
+               return (SET_ERROR(EAGAIN));
+
+       /*
+        * Check for conflicting snapshot name.
+        */
+       error = dsl_dataset_snap_lookup(ds, snapname, &value);
+       if (error == 0)
+               return (SET_ERROR(EEXIST));
+       if (error != ENOENT)
+               return (error);
+
+       /*
+        * We don't allow taking snapshots of inconsistent datasets, such as
+        * those into which we are currently receiving.  However, if we are
+        * creating this snapshot as part of a receive, this check will be
+        * executed atomically with respect to the completion of the receive
+        * itself but prior to the clearing of DS_FLAG_INCONSISTENT; in this
+        * case we ignore this, knowing it will be fixed up for us shortly in
+        * dmu_recv_end_sync().
+        */
+       if (!recv && DS_IS_INCONSISTENT(ds))
+               return (SET_ERROR(EBUSY));
+
+       /*
+        * Skip the check for temporary snapshots or if we have already checked
+        * the counts in dsl_dataset_snapshot_check. This means we really only
+        * check the count here when we're receiving a stream.
+        */
+       if (cnt != 0 && cr != NULL) {
+               error = dsl_fs_ss_limit_check(ds->ds_dir, cnt,
+                   ZFS_PROP_SNAPSHOT_LIMIT, NULL, cr);
+               if (error != 0)
+                       return (error);
+       }
+
+       error = dsl_dataset_snapshot_reserve_space(ds, tx);
+       if (error != 0)
+               return (error);
+
+       return (0);
+}
+
+static int
+dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_snapshot_arg_t *ddsa = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvpair_t *pair;
+       int rv = 0;
+
+       /*
+        * Pre-compute how many total new snapshots will be created for each
+        * level in the tree and below. This is needed for validating the
+        * snapshot limit when either taking a recursive snapshot or when
+        * taking multiple snapshots.
+        *
+        * The problem is that the counts are not actually adjusted when
+        * we are checking, only when we finally sync. For a single snapshot,
+        * this is easy, the count will increase by 1 at each node up the tree,
+        * but its more complicated for the recursive/multiple snapshot case.
+        *
+        * The dsl_fs_ss_limit_check function does recursively check the count
+        * at each level up the tree but since it is validating each snapshot
+        * independently we need to be sure that we are validating the complete
+        * count for the entire set of snapshots. We do this by rolling up the
+        * counts for each component of the name into an nvlist and then
+        * checking each of those cases with the aggregated count.
+        *
+        * This approach properly handles not only the recursive snapshot
+        * case (where we get all of those on the ddsa_snaps list) but also
+        * the sibling case (e.g. snapshot a/b and a/c so that we will also
+        * validate the limit on 'a' using a count of 2).
+        *
+        * We validate the snapshot names in the third loop and only report
+        * name errors once.
+        */
+       if (dmu_tx_is_syncing(tx)) {
+               char *nm;
+               nvlist_t *cnt_track = NULL;
+               cnt_track = fnvlist_alloc();
+
+               nm = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+               /* Rollup aggregated counts into the cnt_track list */
+               for (pair = nvlist_next_nvpair(ddsa->ddsa_snaps, NULL);
+                   pair != NULL;
+                   pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) {
+                       char *pdelim;
+                       uint64_t val;
+
+                       (void) strlcpy(nm, nvpair_name(pair), MAXPATHLEN);
+                       pdelim = strchr(nm, '@');
+                       if (pdelim == NULL)
+                               continue;
+                       *pdelim = '\0';
+
+                       do {
+                               if (nvlist_lookup_uint64(cnt_track, nm,
+                                   &val) == 0) {
+                                       /* update existing entry */
+                                       fnvlist_add_uint64(cnt_track, nm,
+                                           val + 1);
+                               } else {
+                                       /* add to list */
+                                       fnvlist_add_uint64(cnt_track, nm, 1);
+                               }
+
+                               pdelim = strrchr(nm, '/');
+                               if (pdelim != NULL)
+                                       *pdelim = '\0';
+                       } while (pdelim != NULL);
+               }
+
+               kmem_free(nm, MAXPATHLEN);
+
+               /* Check aggregated counts at each level */
+               for (pair = nvlist_next_nvpair(cnt_track, NULL);
+                   pair != NULL; pair = nvlist_next_nvpair(cnt_track, pair)) {
+                       int error = 0;
+                       char *name;
+                       uint64_t cnt = 0;
+                       dsl_dataset_t *ds;
+
+                       name = nvpair_name(pair);
+                       cnt = fnvpair_value_uint64(pair);
+                       ASSERT(cnt > 0);
+
+                       error = dsl_dataset_hold(dp, name, FTAG, &ds);
+                       if (error == 0) {
+                               error = dsl_fs_ss_limit_check(ds->ds_dir, cnt,
+                                   ZFS_PROP_SNAPSHOT_LIMIT, NULL,
+                                   ddsa->ddsa_cr);
+                               dsl_dataset_rele(ds, FTAG);
+                       }
+
+                       if (error != 0) {
+                               if (ddsa->ddsa_errors != NULL)
+                                       fnvlist_add_int32(ddsa->ddsa_errors,
+                                           name, error);
+                               rv = error;
+                               /* only report one error for this check */
+                               break;
+                       }
+               }
+               nvlist_free(cnt_track);
+       }
+
+       for (pair = nvlist_next_nvpair(ddsa->ddsa_snaps, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) {
+               int error = 0;
+               dsl_dataset_t *ds;
+               char *name, *atp;
+               char dsname[MAXNAMELEN];
+
+               name = nvpair_name(pair);
+               if (strlen(name) >= MAXNAMELEN)
+                       error = SET_ERROR(ENAMETOOLONG);
+               if (error == 0) {
+                       atp = strchr(name, '@');
+                       if (atp == NULL)
+                               error = SET_ERROR(EINVAL);
+                       if (error == 0)
+                               (void) strlcpy(dsname, name, atp - name + 1);
+               }
+               if (error == 0)
+                       error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+               if (error == 0) {
+                       /* passing 0/NULL skips dsl_fs_ss_limit_check */
+                       error = dsl_dataset_snapshot_check_impl(ds,
+                           atp + 1, tx, B_FALSE, 0, NULL);
+                       dsl_dataset_rele(ds, FTAG);
+               }
+
+               if (error != 0) {
+                       if (ddsa->ddsa_errors != NULL) {
+                               fnvlist_add_int32(ddsa->ddsa_errors,
+                                   name, error);
+                       }
+                       rv = error;
+               }
+       }
+
+       return (rv);
+}
+
+void
+dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
+    dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       dmu_buf_t *dbuf;
+       dsl_dataset_phys_t *dsphys;
+       uint64_t dsobj, crtxg;
+       objset_t *mos = dp->dp_meta_objset;
+       ASSERTV(static zil_header_t zero_zil);
+       ASSERTV(objset_t *os);
+
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+
+       /*
+        * If we are on an old pool, the zil must not be active, in which
+        * case it will be zeroed.  Usually zil_suspend() accomplishes this.
+        */
+       ASSERT(spa_version(dmu_tx_pool(tx)->dp_spa) >= SPA_VERSION_FAST_SNAP ||
+           dmu_objset_from_ds(ds, &os) != 0 ||
+           bcmp(&os->os_phys->os_zil_header, &zero_zil,
+           sizeof (zero_zil)) == 0);
+
+       dsl_fs_ss_count_adjust(ds->ds_dir, 1, DD_FIELD_SNAPSHOT_COUNT, tx);
+
+       /*
+        * The origin's ds_creation_txg has to be < TXG_INITIAL
+        */
+       if (strcmp(snapname, ORIGIN_DIR_NAME) == 0)
+               crtxg = 1;
+       else
+               crtxg = tx->tx_txg;
+
+       dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0,
+           DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx);
+       VERIFY0(dmu_bonus_hold(mos, dsobj, FTAG, &dbuf));
+       dmu_buf_will_dirty(dbuf, tx);
+       dsphys = dbuf->db_data;
+       bzero(dsphys, sizeof (dsl_dataset_phys_t));
+       dsphys->ds_dir_obj = ds->ds_dir->dd_object;
+       dsphys->ds_fsid_guid = unique_create();
+       (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
+           sizeof (dsphys->ds_guid));
+       dsphys->ds_prev_snap_obj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
+       dsphys->ds_prev_snap_txg = dsl_dataset_phys(ds)->ds_prev_snap_txg;
+       dsphys->ds_next_snap_obj = ds->ds_object;
+       dsphys->ds_num_children = 1;
+       dsphys->ds_creation_time = gethrestime_sec();
+       dsphys->ds_creation_txg = crtxg;
+       dsphys->ds_deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj;
+       dsphys->ds_referenced_bytes = dsl_dataset_phys(ds)->ds_referenced_bytes;
+       dsphys->ds_compressed_bytes = dsl_dataset_phys(ds)->ds_compressed_bytes;
+       dsphys->ds_uncompressed_bytes =
+           dsl_dataset_phys(ds)->ds_uncompressed_bytes;
+       dsphys->ds_flags = dsl_dataset_phys(ds)->ds_flags;
+       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);
+
+       ASSERT3U(ds->ds_prev != 0, ==,
+           dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
+       if (ds->ds_prev) {
+               uint64_t next_clones_obj =
+                   dsl_dataset_phys(ds->ds_prev)->ds_next_clones_obj;
+               ASSERT(dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj ==
+                   ds->ds_object ||
+                   dsl_dataset_phys(ds->ds_prev)->ds_num_children > 1);
+               if (dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj ==
+                   ds->ds_object) {
+                       dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
+                       ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==,
+                           dsl_dataset_phys(ds->ds_prev)->ds_creation_txg);
+                       dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj = dsobj;
+               } else if (next_clones_obj != 0) {
+                       dsl_dataset_remove_from_next_clones(ds->ds_prev,
+                           dsphys->ds_next_snap_obj, tx);
+                       VERIFY0(zap_add_int(mos,
+                           next_clones_obj, dsobj, tx));
+               }
+       }
+
+       /*
+        * If we have a reference-reservation on this dataset, we will
+        * need to increase the amount of refreservation being charged
+        * since our unique space is going to zero.
+        */
+       if (ds->ds_reserved) {
+               int64_t delta;
+               ASSERT(DS_UNIQUE_IS_ACCURATE(ds));
+               delta = MIN(dsl_dataset_phys(ds)->ds_unique_bytes,
+                   ds->ds_reserved);
+               dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV,
+                   delta, 0, 0, tx);
+       }
+
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_deadlist_obj =
+           dsl_deadlist_clone(&ds->ds_deadlist, UINT64_MAX,
+           dsl_dataset_phys(ds)->ds_prev_snap_obj, tx);
+       dsl_deadlist_close(&ds->ds_deadlist);
+       dsl_deadlist_open(&ds->ds_deadlist, mos,
+           dsl_dataset_phys(ds)->ds_deadlist_obj);
+       dsl_deadlist_add_key(&ds->ds_deadlist,
+           dsl_dataset_phys(ds)->ds_prev_snap_txg, tx);
+
+       ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, <, tx->tx_txg);
+       dsl_dataset_phys(ds)->ds_prev_snap_obj = dsobj;
+       dsl_dataset_phys(ds)->ds_prev_snap_txg = crtxg;
+       dsl_dataset_phys(ds)->ds_unique_bytes = 0;
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE)
+               dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
+
+       VERIFY0(zap_add(mos, dsl_dataset_phys(ds)->ds_snapnames_zapobj,
+           snapname, 8, 1, &dsobj, tx));
+
+       if (ds->ds_prev)
+               dsl_dataset_rele(ds->ds_prev, ds);
+       VERIFY0(dsl_dataset_hold_obj(dp,
+           dsl_dataset_phys(ds)->ds_prev_snap_obj, ds, &ds->ds_prev));
+
+       dsl_scan_ds_snapshotted(ds, tx);
+
+       dsl_dir_snap_cmtime_update(ds->ds_dir);
+
+       spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
+}
+
+static void
+dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_snapshot_arg_t *ddsa = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvpair_t *pair;
+
+       for (pair = nvlist_next_nvpair(ddsa->ddsa_snaps, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) {
+               dsl_dataset_t *ds;
+               char *name, *atp;
+               char dsname[MAXNAMELEN];
+
+               name = nvpair_name(pair);
+               atp = strchr(name, '@');
+               (void) strlcpy(dsname, name, atp - name + 1);
+               VERIFY0(dsl_dataset_hold(dp, dsname, FTAG, &ds));
+
+               dsl_dataset_snapshot_sync_impl(ds, atp + 1, tx);
+               if (ddsa->ddsa_props != NULL) {
+                       dsl_props_set_sync_impl(ds->ds_prev,
+                           ZPROP_SRC_LOCAL, ddsa->ddsa_props, tx);
+               }
+               zvol_create_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
+               dsl_dataset_rele(ds, FTAG);
+       }
+}
+
+/*
+ * The snapshots must all be in the same pool.
+ * All-or-nothing: if there are any failures, nothing will be modified.
+ */
+int
+dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
+{
+       dsl_dataset_snapshot_arg_t ddsa;
+       nvpair_t *pair;
+       boolean_t needsuspend;
+       int error;
+       spa_t *spa;
+       char *firstname;
+       nvlist_t *suspended = NULL;
+
+       pair = nvlist_next_nvpair(snaps, NULL);
+       if (pair == NULL)
+               return (0);
+       firstname = nvpair_name(pair);
+
+       error = spa_open(firstname, &spa, FTAG);
+       if (error != 0)
+               return (error);
+       needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
+       spa_close(spa, FTAG);
+
+       if (needsuspend) {
+               suspended = fnvlist_alloc();
+               for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
+                   pair = nvlist_next_nvpair(snaps, pair)) {
+                       char fsname[MAXNAMELEN];
+                       char *snapname = nvpair_name(pair);
+                       char *atp;
+                       void *cookie;
+
+                       atp = strchr(snapname, '@');
+                       if (atp == NULL) {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+                       (void) strlcpy(fsname, snapname, atp - snapname + 1);
+
+                       error = zil_suspend(fsname, &cookie);
+                       if (error != 0)
+                               break;
+                       fnvlist_add_uint64(suspended, fsname,
+                           (uintptr_t)cookie);
+               }
+       }
+
+       ddsa.ddsa_snaps = snaps;
+       ddsa.ddsa_props = props;
+       ddsa.ddsa_errors = errors;
+       ddsa.ddsa_cr = CRED();
+
+       if (error == 0) {
+               error = dsl_sync_task(firstname, dsl_dataset_snapshot_check,
+                   dsl_dataset_snapshot_sync, &ddsa,
+                   fnvlist_num_pairs(snaps) * 3, ZFS_SPACE_CHECK_NORMAL);
+       }
+
+       if (suspended != NULL) {
+               for (pair = nvlist_next_nvpair(suspended, NULL); pair != NULL;
+                   pair = nvlist_next_nvpair(suspended, pair)) {
+                       zil_resume((void *)(uintptr_t)
+                           fnvpair_value_uint64(pair));
+               }
+               fnvlist_free(suspended);
+       }
+
+       return (error);
+}
+
+typedef struct dsl_dataset_snapshot_tmp_arg {
+       const char *ddsta_fsname;
+       const char *ddsta_snapname;
+       minor_t ddsta_cleanup_minor;
+       const char *ddsta_htag;
+} dsl_dataset_snapshot_tmp_arg_t;
+
+static int
+dsl_dataset_snapshot_tmp_check(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;
+       int error;
+
+       error = dsl_dataset_hold(dp, ddsta->ddsta_fsname, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       /* NULL cred means no limit check for tmp snapshot */
+       error = dsl_dataset_snapshot_check_impl(ds, ddsta->ddsta_snapname,
+           tx, B_FALSE, 0, NULL);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       if (spa_version(dp->dp_spa) < SPA_VERSION_USERREFS) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(ENOTSUP));
+       }
+       error = dsl_dataset_user_hold_check_one(NULL, ddsta->ddsta_htag,
+           B_TRUE, tx);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+static void
+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;
+
+       VERIFY0(dsl_dataset_hold(dp, ddsta->ddsta_fsname, FTAG, &ds));
+
+       dsl_dataset_snapshot_sync_impl(ds, ddsta->ddsta_snapname, tx);
+       dsl_dataset_user_hold_sync_one(ds->ds_prev, ddsta->ddsta_htag,
+           ddsta->ddsta_cleanup_minor, gethrestime_sec(), tx);
+       dsl_destroy_snapshot_sync_impl(ds->ds_prev, B_TRUE, tx);
+
+       dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
+    minor_t cleanup_minor, const char *htag)
+{
+       dsl_dataset_snapshot_tmp_arg_t ddsta;
+       int error;
+       spa_t *spa;
+       boolean_t needsuspend;
+       void *cookie;
+
+       ddsta.ddsta_fsname = fsname;
+       ddsta.ddsta_snapname = snapname;
+       ddsta.ddsta_cleanup_minor = cleanup_minor;
+       ddsta.ddsta_htag = htag;
+
+       error = spa_open(fsname, &spa, FTAG);
+       if (error != 0)
+               return (error);
+       needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
+       spa_close(spa, FTAG);
+
+       if (needsuspend) {
+               error = zil_suspend(fsname, &cookie);
+               if (error != 0)
+                       return (error);
+       }
+
+       error = dsl_sync_task(fsname, dsl_dataset_snapshot_tmp_check,
+           dsl_dataset_snapshot_tmp_sync, &ddsta, 3, ZFS_SPACE_CHECK_RESERVED);
+
+       if (needsuspend)
+               zil_resume(cookie);
+       return (error);
+}
+
+
+void
+dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
+{
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(ds->ds_objset != NULL);
+       ASSERT(dsl_dataset_phys(ds)->ds_next_snap_obj == 0);
+
+       /*
+        * in case we had to change ds_fsid_guid when we opened it,
+        * sync it out now.
+        */
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_fsid_guid = ds->ds_fsid_guid;
+
+       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;
+       }
+}
+
+static void
+get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
+{
+       uint64_t count = 0;
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       nvlist_t *propval = fnvlist_alloc();
+       nvlist_t *val = fnvlist_alloc();
+
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
+
+       /*
+        * There may be missing entries in ds_next_clones_obj
+        * due to a bug in a previous version of the code.
+        * Only trust it if it has the right number of entries.
+        */
+       if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) {
+               VERIFY0(zap_count(mos, dsl_dataset_phys(ds)->ds_next_clones_obj,
+                   &count));
+       }
+       if (count != dsl_dataset_phys(ds)->ds_num_children - 1)
+               goto fail;
+       for (zap_cursor_init(&zc, mos,
+           dsl_dataset_phys(ds)->ds_next_clones_obj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               dsl_dataset_t *clone;
+               char buf[ZFS_MAXNAMELEN];
+               VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
+                   za.za_first_integer, FTAG, &clone));
+               dsl_dir_name(clone->ds_dir, buf);
+               fnvlist_add_boolean(val, buf);
+               dsl_dataset_rele(clone, FTAG);
+       }
+       zap_cursor_fini(&zc);
+       fnvlist_add_nvlist(propval, ZPROP_VALUE, val);
+       fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), propval);
+fail:
+       nvlist_free(val);
+       nvlist_free(propval);
+}
+
+void
+dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
+{
+       uint64_t refd, avail, uobjs, aobjs, ratio;
+       ASSERTV(dsl_pool_t *dp = ds->ds_dir->dd_pool);
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 :
+           (dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 /
+           dsl_dataset_phys(ds)->ds_compressed_bytes);
+
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALREFERENCED,
+           dsl_dataset_phys(ds)->ds_uncompressed_bytes);
+
+       if (ds->ds_is_snapshot) {
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
+                   dsl_dataset_phys(ds)->ds_unique_bytes);
+               get_clones_stat(ds, nv);
+       } else {
+               dsl_dir_stats(ds->ds_dir, nv);
+       }
+
+       dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd);
+
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION,
+           dsl_dataset_phys(ds)->ds_creation_time);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG,
+           dsl_dataset_phys(ds)->ds_creation_txg);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA,
+           ds->ds_quota);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION,
+           ds->ds_reserved);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID,
+           dsl_dataset_phys(ds)->ds_guid);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE,
+           dsl_dataset_phys(ds)->ds_unique_bytes);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID,
+           ds->ds_object);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS,
+           ds->ds_userrefs);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY,
+           DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
+
+       if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
+               uint64_t written, comp, uncomp;
+               dsl_pool_t *dp = ds->ds_dir->dd_pool;
+               dsl_dataset_t *prev;
+               int err;
+
+               err = dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
+               if (err == 0) {
+                       err = dsl_dataset_space_written(prev, ds, &written,
+                           &comp, &uncomp);
+                       dsl_dataset_rele(prev, FTAG);
+                       if (err == 0) {
+                               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
+                                   written);
+                       }
+               }
+       }
+
+}
+
+void
+dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       ASSERT(dsl_pool_config_held(dp));
+
+       stat->dds_creation_txg = dsl_dataset_phys(ds)->ds_creation_txg;
+       stat->dds_inconsistent =
+           dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT;
+       stat->dds_guid = dsl_dataset_phys(ds)->ds_guid;
+       stat->dds_origin[0] = '\0';
+       if (ds->ds_is_snapshot) {
+               stat->dds_is_snapshot = B_TRUE;
+               stat->dds_num_clones =
+                   dsl_dataset_phys(ds)->ds_num_children - 1;
+       } else {
+               stat->dds_is_snapshot = B_FALSE;
+               stat->dds_num_clones = 0;
+
+               if (dsl_dir_is_clone(ds->ds_dir)) {
+                       dsl_dataset_t *ods;
+
+                       VERIFY0(dsl_dataset_hold_obj(dp,
+                           dsl_dir_phys(ds->ds_dir)->dd_origin_obj,
+                           FTAG, &ods));
+                       dsl_dataset_name(ods, stat->dds_origin);
+                       dsl_dataset_rele(ods, FTAG);
+               }
+       }
+}
+
+uint64_t
+dsl_dataset_fsid_guid(dsl_dataset_t *ds)
+{
+       return (ds->ds_fsid_guid);
+}
+
+void
+dsl_dataset_space(dsl_dataset_t *ds,
+    uint64_t *refdbytesp, uint64_t *availbytesp,
+    uint64_t *usedobjsp, uint64_t *availobjsp)
+{
+       *refdbytesp = dsl_dataset_phys(ds)->ds_referenced_bytes;
+       *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE);
+       if (ds->ds_reserved > dsl_dataset_phys(ds)->ds_unique_bytes)
+               *availbytesp +=
+                   ds->ds_reserved - dsl_dataset_phys(ds)->ds_unique_bytes;
+       if (ds->ds_quota != 0) {
+               /*
+                * Adjust available bytes according to refquota
+                */
+               if (*refdbytesp < ds->ds_quota)
+                       *availbytesp = MIN(*availbytesp,
+                           ds->ds_quota - *refdbytesp);
+               else
+                       *availbytesp = 0;
+       }
+       *usedobjsp = BP_GET_FILL(&dsl_dataset_phys(ds)->ds_bp);
+       *availobjsp = DN_MAX_OBJECT - *usedobjsp;
+}
+
+boolean_t
+dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap)
+{
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
+       if (snap == NULL)
+               return (B_FALSE);
+       if (dsl_dataset_phys(ds)->ds_bp.blk_birth >
+           dsl_dataset_phys(snap)->ds_creation_txg) {
+               objset_t *os, *os_snap;
+               /*
+                * It may be that only the ZIL differs, because it was
+                * reset in the head.  Don't count that as being
+                * modified.
+                */
+               if (dmu_objset_from_ds(ds, &os) != 0)
+                       return (B_TRUE);
+               if (dmu_objset_from_ds(snap, &os_snap) != 0)
+                       return (B_TRUE);
+               return (bcmp(&os->os_phys->os_meta_dnode,
+                   &os_snap->os_phys->os_meta_dnode,
+                   sizeof (os->os_phys->os_meta_dnode)) != 0);
+       }
+       return (B_FALSE);
+}
+
+typedef struct dsl_dataset_rename_snapshot_arg {
+       const char *ddrsa_fsname;
+       const char *ddrsa_oldsnapname;
+       const char *ddrsa_newsnapname;
+       boolean_t ddrsa_recursive;
+       dmu_tx_t *ddrsa_tx;
+} dsl_dataset_rename_snapshot_arg_t;
+
+/* ARGSUSED */
+static int
+dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp,
+    dsl_dataset_t *hds, void *arg)
+{
+       dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
+       int error;
+       uint64_t val;
+
+       error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_oldsnapname, &val);
+       if (error != 0) {
+               /* ignore nonexistent snapshots */
+               return (error == ENOENT ? 0 : error);
+       }
+
+       /* new name should not exist */
+       error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_newsnapname, &val);
+       if (error == 0)
+               error = SET_ERROR(EEXIST);
+       else if (error == ENOENT)
+               error = 0;
+
+       /* dataset name + 1 for the "@" + the new snapshot name must fit */
+       if (dsl_dir_namelen(hds->ds_dir) + 1 +
+           strlen(ddrsa->ddrsa_newsnapname) >= MAXNAMELEN)
+               error = SET_ERROR(ENAMETOOLONG);
+
+       return (error);
+}
+
+static int
+dsl_dataset_rename_snapshot_check(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;
+       int error;
+
+       error = dsl_dataset_hold(dp, ddrsa->ddrsa_fsname, FTAG, &hds);
+       if (error != 0)
+               return (error);
+
+       if (ddrsa->ddrsa_recursive) {
+               error = dmu_objset_find_dp(dp, hds->ds_dir->dd_object,
+                   dsl_dataset_rename_snapshot_check_impl, ddrsa,
+                   DS_FIND_CHILDREN);
+       } else {
+               error = dsl_dataset_rename_snapshot_check_impl(dp, hds, ddrsa);
+       }
+       dsl_dataset_rele(hds, FTAG);
+       return (error);
+}
+
+static int
+dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
+    dsl_dataset_t *hds, void *arg)
+{
+       dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
+       dsl_dataset_t *ds;
+       uint64_t val;
+       dmu_tx_t *tx = ddrsa->ddrsa_tx;
+       int error;
+
+       error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_oldsnapname, &val);
+       ASSERT(error == 0 || error == ENOENT);
+       if (error == ENOENT) {
+               /* ignore nonexistent snapshots */
+               return (0);
+       }
+
+       VERIFY0(dsl_dataset_hold_obj(dp, val, FTAG, &ds));
+
+       /* log before we change the name */
+       spa_history_log_internal_ds(ds, "rename", tx,
+           "-> @%s", ddrsa->ddrsa_newsnapname);
+
+       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);
+       mutex_exit(&ds->ds_lock);
+       VERIFY0(zap_add(dp->dp_meta_objset,
+           dsl_dataset_phys(hds)->ds_snapnames_zapobj,
+           ds->ds_snapname, 8, 1, &ds->ds_object, tx));
+       zvol_rename_minors(dp->dp_spa, ddrsa->ddrsa_oldsnapname,
+           ddrsa->ddrsa_newsnapname, B_TRUE);
+
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+static void
+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;
+
+       VERIFY0(dsl_dataset_hold(dp, ddrsa->ddrsa_fsname, FTAG, &hds));
+       ddrsa->ddrsa_tx = tx;
+       if (ddrsa->ddrsa_recursive) {
+               VERIFY0(dmu_objset_find_dp(dp, hds->ds_dir->dd_object,
+                   dsl_dataset_rename_snapshot_sync_impl, ddrsa,
+                   DS_FIND_CHILDREN));
+       } else {
+               VERIFY0(dsl_dataset_rename_snapshot_sync_impl(dp, hds, ddrsa));
+       }
+       dsl_dataset_rele(hds, FTAG);
+}
+
+int
+dsl_dataset_rename_snapshot(const char *fsname,
+    const char *oldsnapname, const char *newsnapname, boolean_t recursive)
+{
+       dsl_dataset_rename_snapshot_arg_t ddrsa;
+
+       ddrsa.ddrsa_fsname = fsname;
+       ddrsa.ddrsa_oldsnapname = oldsnapname;
+       ddrsa.ddrsa_newsnapname = newsnapname;
+       ddrsa.ddrsa_recursive = recursive;
+
+       return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
+           dsl_dataset_rename_snapshot_sync, &ddrsa,
+           1, ZFS_SPACE_CHECK_RESERVED));
+}
+
+/*
+ * If we're doing an ownership handoff, we need to make sure that there is
+ * 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.
+ */
+static int
+dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
+{
+       boolean_t held;
+
+       if (!dmu_tx_is_syncing(tx))
+               return (0);
+
+       if (owner != NULL) {
+               VERIFY3P(ds->ds_owner, ==, owner);
+               dsl_dataset_long_rele(ds, owner);
+       }
+
+       held = dsl_dataset_long_held(ds);
+
+       if (owner != NULL)
+               dsl_dataset_long_hold(ds, owner);
+
+       if (held)
+               return (SET_ERROR(EBUSY));
+
+       return (0);
+}
+
+typedef struct dsl_dataset_rollback_arg {
+       const char *ddra_fsname;
+       void *ddra_owner;
+       nvlist_t *ddra_result;
+} dsl_dataset_rollback_arg_t;
+
+static int
+dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_rollback_arg_t *ddra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       int64_t unused_refres_delta;
+       int error;
+       nvpair_t *pair;
+       nvlist_t *proprequest, *bookmarks;
+
+       error = dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       /* must not be a snapshot */
+       if (ds->ds_is_snapshot) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /* must have a most recent snapshot */
+       if (dsl_dataset_phys(ds)->ds_prev_snap_txg < TXG_INITIAL) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /* must not have any bookmarks after the most recent snapshot */
+       proprequest = fnvlist_alloc();
+       fnvlist_add_boolean(proprequest, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+       bookmarks = fnvlist_alloc();
+       error = dsl_get_bookmarks_impl(ds, proprequest, bookmarks);
+       fnvlist_free(proprequest);
+       if (error != 0)
+               return (error);
+       for (pair = nvlist_next_nvpair(bookmarks, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(bookmarks, pair)) {
+               nvlist_t *valuenv =
+                   fnvlist_lookup_nvlist(fnvpair_value_nvlist(pair),
+                   zfs_prop_to_name(ZFS_PROP_CREATETXG));
+               uint64_t createtxg = fnvlist_lookup_uint64(valuenv, "value");
+               if (createtxg > dsl_dataset_phys(ds)->ds_prev_snap_txg) {
+                       fnvlist_free(bookmarks);
+                       dsl_dataset_rele(ds, FTAG);
+                       return (SET_ERROR(EEXIST));
+               }
+       }
+       fnvlist_free(bookmarks);
+
+       error = dsl_dataset_handoff_check(ds, ddra->ddra_owner, tx);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       /*
+        * Check if the snap we are rolling back to uses more than
+        * the refquota.
+        */
+       if (ds->ds_quota != 0 &&
+           dsl_dataset_phys(ds->ds_prev)->ds_referenced_bytes > ds->ds_quota) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EDQUOT));
+       }
+
+       /*
+        * When we do the clone swap, we will temporarily use more space
+        * due to the refreservation (the head will no longer have any
+        * unique space, so the entire amount of the refreservation will need
+        * to be free).  We will immediately destroy the clone, freeing
+        * this space, but the freeing happens over many txg's.
+        */
+       unused_refres_delta = (int64_t)MIN(ds->ds_reserved,
+           dsl_dataset_phys(ds)->ds_unique_bytes);
+
+       if (unused_refres_delta > 0 &&
+           unused_refres_delta >
+           dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(ENOSPC));
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+static void
+dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_rollback_arg_t *ddra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds, *clone;
+       uint64_t cloneobj;
+       char namebuf[ZFS_MAXNAMELEN];
+
+       VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds));
+
+       dsl_dataset_name(ds->ds_prev, namebuf);
+       fnvlist_add_string(ddra->ddra_result, "target", namebuf);
+
+       cloneobj = dsl_dataset_create_sync(ds->ds_dir, "%rollback",
+           ds->ds_prev, DS_CREATE_FLAG_NODIRTY, kcred, tx);
+
+       VERIFY0(dsl_dataset_hold_obj(dp, cloneobj, FTAG, &clone));
+
+       dsl_dataset_clone_swap_sync_impl(clone, ds, tx);
+       dsl_dataset_zero_zil(ds, tx);
+
+       dsl_destroy_head_sync_impl(clone, tx);
+
+       dsl_dataset_rele(clone, FTAG);
+       dsl_dataset_rele(ds, FTAG);
+}
+
+/*
+ * Rolls back the given filesystem or volume to the most recent snapshot.
+ * The name of the most recent snapshot will be returned under key "target"
+ * in the result nvlist.
+ *
+ * If owner != NULL:
+ * - The existing dataset MUST be owned by the specified owner at entry
+ * - Upon return, dataset will still be held by the same owner, whether we
+ *   succeed or not.
+ *
+ * This mode is required any time the existing filesystem is mounted.  See
+ * notes above zfs_suspend_fs() for further details.
+ */
+int
+dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result)
+{
+       dsl_dataset_rollback_arg_t ddra;
+
+       ddra.ddra_fsname = fsname;
+       ddra.ddra_owner = owner;
+       ddra.ddra_result = result;
+
+       return (dsl_sync_task(fsname, dsl_dataset_rollback_check,
+           dsl_dataset_rollback_sync, &ddra,
+           1, ZFS_SPACE_CHECK_RESERVED));
+}
+
+struct promotenode {
+       list_node_t link;
+       dsl_dataset_t *ds;
+};
+
+typedef struct dsl_dataset_promote_arg {
+       const char *ddpa_clonename;
+       dsl_dataset_t *ddpa_clone;
+       list_t shared_snaps, origin_snaps, clone_snaps;
+       dsl_dataset_t *origin_origin; /* origin of the origin */
+       uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
+       char *err_ds;
+       cred_t *cr;
+} dsl_dataset_promote_arg_t;
+
+static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep);
+static int promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp,
+    void *tag);
+static void promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag);
+
+static int
+dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_promote_arg_t *ddpa = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *hds;
+       struct promotenode *snap;
+       dsl_dataset_t *origin_ds;
+       int err;
+       uint64_t unused;
+       uint64_t ss_mv_cnt;
+       size_t max_snap_len;
+
+       err = promote_hold(ddpa, dp, FTAG);
+       if (err != 0)
+               return (err);
+
+       hds = ddpa->ddpa_clone;
+       max_snap_len = MAXNAMELEN - strlen(ddpa->ddpa_clonename) - 1;
+
+       if (dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE) {
+               promote_rele(ddpa, FTAG);
+               return (SET_ERROR(EXDEV));
+       }
+
+       /*
+        * Compute and check the amount of space to transfer.  Since this is
+        * so expensive, don't do the preliminary check.
+        */
+       if (!dmu_tx_is_syncing(tx)) {
+               promote_rele(ddpa, FTAG);
+               return (0);
+       }
+
+       snap = list_head(&ddpa->shared_snaps);
+       origin_ds = snap->ds;
+
+       /* compute origin's new unique space */
+       snap = list_tail(&ddpa->clone_snaps);
+       ASSERT3U(dsl_dataset_phys(snap->ds)->ds_prev_snap_obj, ==,
+           origin_ds->ds_object);
+       dsl_deadlist_space_range(&snap->ds->ds_deadlist,
+           dsl_dataset_phys(origin_ds)->ds_prev_snap_txg, UINT64_MAX,
+           &ddpa->unique, &unused, &unused);
+
+       /*
+        * Walk the snapshots that we are moving
+        *
+        * Compute space to transfer.  Consider the incremental changes
+        * to used by each snapshot:
+        * (my used) = (prev's used) + (blocks born) - (blocks killed)
+        * So each snapshot gave birth to:
+        * (blocks born) = (my used) - (prev's used) + (blocks killed)
+        * So a sequence would look like:
+        * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0)
+        * Which simplifies to:
+        * uN + kN + kN-1 + ... + k1 + k0
+        * Note however, if we stop before we reach the ORIGIN we get:
+        * uN + kN + kN-1 + ... + kM - uM-1
+        */
+       ss_mv_cnt = 0;
+       ddpa->used = dsl_dataset_phys(origin_ds)->ds_referenced_bytes;
+       ddpa->comp = dsl_dataset_phys(origin_ds)->ds_compressed_bytes;
+       ddpa->uncomp = dsl_dataset_phys(origin_ds)->ds_uncompressed_bytes;
+       for (snap = list_head(&ddpa->shared_snaps); snap;
+           snap = list_next(&ddpa->shared_snaps, snap)) {
+               uint64_t val, dlused, dlcomp, dluncomp;
+               dsl_dataset_t *ds = snap->ds;
+
+               ss_mv_cnt++;
+
+               /*
+                * If there are long holds, we won't be able to evict
+                * the objset.
+                */
+               if (dsl_dataset_long_held(ds)) {
+                       err = SET_ERROR(EBUSY);
+                       goto out;
+               }
+
+               /* Check that the snapshot name does not conflict */
+               VERIFY0(dsl_dataset_get_snapname(ds));
+               if (strlen(ds->ds_snapname) >= max_snap_len) {
+                       err = SET_ERROR(ENAMETOOLONG);
+                       goto out;
+               }
+               err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val);
+               if (err == 0) {
+                       (void) strcpy(ddpa->err_ds, snap->ds->ds_snapname);
+                       err = SET_ERROR(EEXIST);
+                       goto out;
+               }
+               if (err != ENOENT)
+                       goto out;
+
+               /* The very first snapshot does not have a deadlist */
+               if (dsl_dataset_phys(ds)->ds_prev_snap_obj == 0)
+                       continue;
+
+               dsl_deadlist_space(&ds->ds_deadlist,
+                   &dlused, &dlcomp, &dluncomp);
+               ddpa->used += dlused;
+               ddpa->comp += dlcomp;
+               ddpa->uncomp += dluncomp;
+       }
+
+       /*
+        * If we are a clone of a clone then we never reached ORIGIN,
+        * so we need to subtract out the clone origin's used space.
+        */
+       if (ddpa->origin_origin) {
+               ddpa->used -=
+                   dsl_dataset_phys(ddpa->origin_origin)->ds_referenced_bytes;
+               ddpa->comp -=
+                   dsl_dataset_phys(ddpa->origin_origin)->ds_compressed_bytes;
+               ddpa->uncomp -=
+                   dsl_dataset_phys(ddpa->origin_origin)->
+                   ds_uncompressed_bytes;
+       }
+
+       /* Check that there is enough space and limit headroom here */
+       err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir,
+           0, ss_mv_cnt, ddpa->used, ddpa->cr);
+       if (err != 0)
+               goto out;
+
+       /*
+        * Compute the amounts of space that will be used by snapshots
+        * after the promotion (for both origin and clone).  For each,
+        * it is the amount of space that will be on all of their
+        * deadlists (that was not born before their new origin).
+        */
+       if (dsl_dir_phys(hds->ds_dir)->dd_flags & DD_FLAG_USED_BREAKDOWN) {
+               uint64_t space;
+
+               /*
+                * Note, typically this will not be a clone of a clone,
+                * so dd_origin_txg will be < TXG_INITIAL, so
+                * these snaplist_space() -> dsl_deadlist_space_range()
+                * calls will be fast because they do not have to
+                * iterate over all bps.
+                */
+               snap = list_head(&ddpa->origin_snaps);
+               err = snaplist_space(&ddpa->shared_snaps,
+                   snap->ds->ds_dir->dd_origin_txg, &ddpa->cloneusedsnap);
+               if (err != 0)
+                       goto out;
+
+               err = snaplist_space(&ddpa->clone_snaps,
+                   snap->ds->ds_dir->dd_origin_txg, &space);
+               if (err != 0)
+                       goto out;
+               ddpa->cloneusedsnap += space;
+       }
+       if (dsl_dir_phys(origin_ds->ds_dir)->dd_flags &
+           DD_FLAG_USED_BREAKDOWN) {
+               err = snaplist_space(&ddpa->origin_snaps,
+                   dsl_dataset_phys(origin_ds)->ds_creation_txg,
+                   &ddpa->originusedsnap);
+               if (err != 0)
+                       goto out;
+       }
+
+out:
+       promote_rele(ddpa, FTAG);
+       return (err);
+}
+
+static void
+dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_promote_arg_t *ddpa = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *hds;
+       struct promotenode *snap;
+       dsl_dataset_t *origin_ds;
+       dsl_dataset_t *origin_head;
+       dsl_dir_t *dd;
+       dsl_dir_t *odd = NULL;
+       uint64_t oldnext_obj;
+       int64_t delta;
+
+       VERIFY0(promote_hold(ddpa, dp, FTAG));
+       hds = ddpa->ddpa_clone;
+
+       ASSERT0(dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE);
+
+       snap = list_head(&ddpa->shared_snaps);
+       origin_ds = snap->ds;
+       dd = hds->ds_dir;
+
+       snap = list_head(&ddpa->origin_snaps);
+       origin_head = snap->ds;
+
+       /*
+        * We need to explicitly open odd, since origin_ds's dd will be
+        * changing.
+        */
+       VERIFY0(dsl_dir_hold_obj(dp, origin_ds->ds_dir->dd_object,
+           NULL, FTAG, &odd));
+
+       /* change origin's next snap */
+       dmu_buf_will_dirty(origin_ds->ds_dbuf, tx);
+       oldnext_obj = dsl_dataset_phys(origin_ds)->ds_next_snap_obj;
+       snap = list_tail(&ddpa->clone_snaps);
+       ASSERT3U(dsl_dataset_phys(snap->ds)->ds_prev_snap_obj, ==,
+           origin_ds->ds_object);
+       dsl_dataset_phys(origin_ds)->ds_next_snap_obj = snap->ds->ds_object;
+
+       /* change the origin's next clone */
+       if (dsl_dataset_phys(origin_ds)->ds_next_clones_obj) {
+               dsl_dataset_remove_from_next_clones(origin_ds,
+                   snap->ds->ds_object, tx);
+               VERIFY0(zap_add_int(dp->dp_meta_objset,
+                   dsl_dataset_phys(origin_ds)->ds_next_clones_obj,
+                   oldnext_obj, tx));
+       }
+
+       /* change origin */
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+       ASSERT3U(dsl_dir_phys(dd)->dd_origin_obj, ==, origin_ds->ds_object);
+       dsl_dir_phys(dd)->dd_origin_obj = dsl_dir_phys(odd)->dd_origin_obj;
+       dd->dd_origin_txg = origin_head->ds_dir->dd_origin_txg;
+       dmu_buf_will_dirty(odd->dd_dbuf, tx);
+       dsl_dir_phys(odd)->dd_origin_obj = origin_ds->ds_object;
+       origin_head->ds_dir->dd_origin_txg =
+           dsl_dataset_phys(origin_ds)->ds_creation_txg;
+
+       /* change dd_clone entries */
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
+               VERIFY0(zap_remove_int(dp->dp_meta_objset,
+                   dsl_dir_phys(odd)->dd_clones, hds->ds_object, tx));
+               VERIFY0(zap_add_int(dp->dp_meta_objset,
+                   dsl_dir_phys(ddpa->origin_origin->ds_dir)->dd_clones,
+                   hds->ds_object, tx));
+
+               VERIFY0(zap_remove_int(dp->dp_meta_objset,
+                   dsl_dir_phys(ddpa->origin_origin->ds_dir)->dd_clones,
+                   origin_head->ds_object, tx));
+               if (dsl_dir_phys(dd)->dd_clones == 0) {
+                       dsl_dir_phys(dd)->dd_clones =
+                           zap_create(dp->dp_meta_objset, DMU_OT_DSL_CLONES,
+                           DMU_OT_NONE, 0, tx);
+               }
+               VERIFY0(zap_add_int(dp->dp_meta_objset,
+                   dsl_dir_phys(dd)->dd_clones, origin_head->ds_object, tx));
+       }
+
+       /* move snapshots to this dir */
+       for (snap = list_head(&ddpa->shared_snaps); snap;
+           snap = list_next(&ddpa->shared_snaps, snap)) {
+               dsl_dataset_t *ds = snap->ds;
+
+               /*
+                * Property callbacks are registered to a particular
+                * dsl_dir.  Since ours is changing, evict the objset
+                * so that they will be unregistered from the old dsl_dir.
+                */
+               if (ds->ds_objset) {
+                       dmu_objset_evict(ds->ds_objset);
+                       ds->ds_objset = NULL;
+               }
+
+               /* move snap name entry */
+               VERIFY0(dsl_dataset_get_snapname(ds));
+               VERIFY0(dsl_dataset_snap_remove(origin_head,
+                   ds->ds_snapname, tx, B_TRUE));
+               VERIFY0(zap_add(dp->dp_meta_objset,
+                   dsl_dataset_phys(hds)->ds_snapnames_zapobj, ds->ds_snapname,
+                   8, 1, &ds->ds_object, tx));
+               dsl_fs_ss_count_adjust(hds->ds_dir, 1,
+                   DD_FIELD_SNAPSHOT_COUNT, tx);
+
+               /* change containing dsl_dir */
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               ASSERT3U(dsl_dataset_phys(ds)->ds_dir_obj, ==, odd->dd_object);
+               dsl_dataset_phys(ds)->ds_dir_obj = dd->dd_object;
+               ASSERT3P(ds->ds_dir, ==, odd);
+               dsl_dir_rele(ds->ds_dir, ds);
+               VERIFY0(dsl_dir_hold_obj(dp, dd->dd_object,
+                   NULL, ds, &ds->ds_dir));
+
+               /* move any clone references */
+               if (dsl_dataset_phys(ds)->ds_next_clones_obj &&
+                   spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
+                       zap_cursor_t zc;
+                       zap_attribute_t za;
+
+                       for (zap_cursor_init(&zc, dp->dp_meta_objset,
+                           dsl_dataset_phys(ds)->ds_next_clones_obj);
+                           zap_cursor_retrieve(&zc, &za) == 0;
+                           zap_cursor_advance(&zc)) {
+                               dsl_dataset_t *cnds;
+                               uint64_t o;
+
+                               if (za.za_first_integer == oldnext_obj) {
+                                       /*
+                                        * We've already moved the
+                                        * origin's reference.
+                                        */
+                                       continue;
+                               }
+
+                               VERIFY0(dsl_dataset_hold_obj(dp,
+                                   za.za_first_integer, FTAG, &cnds));
+                               o = dsl_dir_phys(cnds->ds_dir)->
+                                   dd_head_dataset_obj;
+
+                               VERIFY0(zap_remove_int(dp->dp_meta_objset,
+                                   dsl_dir_phys(odd)->dd_clones, o, tx));
+                               VERIFY0(zap_add_int(dp->dp_meta_objset,
+                                   dsl_dir_phys(dd)->dd_clones, o, tx));
+                               dsl_dataset_rele(cnds, FTAG);
+                       }
+                       zap_cursor_fini(&zc);
+               }
+
+               ASSERT(!dsl_prop_hascb(ds));
+       }
+
+       /*
+        * Change space accounting.
+        * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either
+        * both be valid, or both be 0 (resulting in delta == 0).  This
+        * is true for each of {clone,origin} independently.
+        */
+
+       delta = ddpa->cloneusedsnap -
+           dsl_dir_phys(dd)->dd_used_breakdown[DD_USED_SNAP];
+       ASSERT3S(delta, >=, 0);
+       ASSERT3U(ddpa->used, >=, delta);
+       dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx);
+       dsl_dir_diduse_space(dd, DD_USED_HEAD,
+           ddpa->used - delta, ddpa->comp, ddpa->uncomp, tx);
+
+       delta = ddpa->originusedsnap -
+           dsl_dir_phys(odd)->dd_used_breakdown[DD_USED_SNAP];
+       ASSERT3S(delta, <=, 0);
+       ASSERT3U(ddpa->used, >=, -delta);
+       dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx);
+       dsl_dir_diduse_space(odd, DD_USED_HEAD,
+           -ddpa->used - delta, -ddpa->comp, -ddpa->uncomp, tx);
+
+       dsl_dataset_phys(origin_ds)->ds_unique_bytes = ddpa->unique;
+
+       /* log history record */
+       spa_history_log_internal_ds(hds, "promote", tx, "");
+
+       dsl_dir_rele(odd, FTAG);
+       promote_rele(ddpa, FTAG);
+}
+
+/*
+ * Make a list of dsl_dataset_t's for the snapshots between first_obj
+ * (exclusive) and last_obj (inclusive).  The list will be in reverse
+ * order (last_obj will be the list_head()).  If first_obj == 0, do all
+ * snapshots back to this dataset's origin.
+ */
+static int
+snaplist_make(dsl_pool_t *dp,
+    uint64_t first_obj, uint64_t last_obj, list_t *l, void *tag)
+{
+       uint64_t obj = last_obj;
+
+       list_create(l, sizeof (struct promotenode),
+           offsetof(struct promotenode, link));
+
+       while (obj != first_obj) {
+               dsl_dataset_t *ds;
+               struct promotenode *snap;
+               int err;
+
+               err = dsl_dataset_hold_obj(dp, obj, tag, &ds);
+               ASSERT(err != ENOENT);
+               if (err != 0)
+                       return (err);
+
+               if (first_obj == 0)
+                       first_obj = dsl_dir_phys(ds->ds_dir)->dd_origin_obj;
+
+               snap = kmem_alloc(sizeof (*snap), KM_SLEEP);
+               snap->ds = ds;
+               list_insert_tail(l, snap);
+               obj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
+       }
+
+       return (0);
+}
+
+static int
+snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep)
+{
+       struct promotenode *snap;
+
+       *spacep = 0;
+       for (snap = list_head(l); snap; snap = list_next(l, snap)) {
+               uint64_t used, comp, uncomp;
+               dsl_deadlist_space_range(&snap->ds->ds_deadlist,
+                   mintxg, UINT64_MAX, &used, &comp, &uncomp);
+               *spacep += used;
+       }
+       return (0);
+}
+
+static void
+snaplist_destroy(list_t *l, void *tag)
+{
+       struct promotenode *snap;
+
+       if (l == NULL || !list_link_active(&l->list_head))
+               return;
+
+       while ((snap = list_tail(l)) != NULL) {
+               list_remove(l, snap);
+               dsl_dataset_rele(snap->ds, tag);
+               kmem_free(snap, sizeof (*snap));
+       }
+       list_destroy(l);
+}
+
+static int
+promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp, void *tag)
+{
+       int error;
+       dsl_dir_t *dd;
+       struct promotenode *snap;
+
+       error = dsl_dataset_hold(dp, ddpa->ddpa_clonename, tag,
+           &ddpa->ddpa_clone);
+       if (error != 0)
+               return (error);
+       dd = ddpa->ddpa_clone->ds_dir;
+
+       if (ddpa->ddpa_clone->ds_is_snapshot ||
+           !dsl_dir_is_clone(dd)) {
+               dsl_dataset_rele(ddpa->ddpa_clone, tag);
+               return (SET_ERROR(EINVAL));
+       }
+
+       error = snaplist_make(dp, 0, dsl_dir_phys(dd)->dd_origin_obj,
+           &ddpa->shared_snaps, tag);
+       if (error != 0)
+               goto out;
+
+       error = snaplist_make(dp, 0, ddpa->ddpa_clone->ds_object,
+           &ddpa->clone_snaps, tag);
+       if (error != 0)
+               goto out;
+
+       snap = list_head(&ddpa->shared_snaps);
+       ASSERT3U(snap->ds->ds_object, ==, dsl_dir_phys(dd)->dd_origin_obj);
+       error = snaplist_make(dp, dsl_dir_phys(dd)->dd_origin_obj,
+           dsl_dir_phys(snap->ds->ds_dir)->dd_head_dataset_obj,
+           &ddpa->origin_snaps, tag);
+       if (error != 0)
+               goto out;
+
+       if (dsl_dir_phys(snap->ds->ds_dir)->dd_origin_obj != 0) {
+               error = dsl_dataset_hold_obj(dp,
+                   dsl_dir_phys(snap->ds->ds_dir)->dd_origin_obj,
+                   tag, &ddpa->origin_origin);
+               if (error != 0)
+                       goto out;
+       }
+out:
+       if (error != 0)
+               promote_rele(ddpa, tag);
+       return (error);
+}
+
+static void
+promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag)
+{
+       snaplist_destroy(&ddpa->shared_snaps, tag);
+       snaplist_destroy(&ddpa->clone_snaps, tag);
+       snaplist_destroy(&ddpa->origin_snaps, tag);
+       if (ddpa->origin_origin != NULL)
+               dsl_dataset_rele(ddpa->origin_origin, tag);
+       dsl_dataset_rele(ddpa->ddpa_clone, 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.)
+ */
+int
+dsl_dataset_promote(const char *name, char *conflsnap)
+{
+       dsl_dataset_promote_arg_t ddpa = { 0 };
+       uint64_t numsnaps;
+       int error;
+       objset_t *os;
+
+       /*
+        * We will modify space proportional to the number of
+        * snapshots.  Compute numsnaps.
+        */
+       error = dmu_objset_hold(name, FTAG, &os);
+       if (error != 0)
+               return (error);
+       error = zap_count(dmu_objset_pool(os)->dp_meta_objset,
+           dsl_dataset_phys(dmu_objset_ds(os))->ds_snapnames_zapobj,
+           &numsnaps);
+       dmu_objset_rele(os, FTAG);
+       if (error != 0)
+               return (error);
+
+       ddpa.ddpa_clonename = name;
+       ddpa.err_ds = conflsnap;
+       ddpa.cr = CRED();
+
+       return (dsl_sync_task(name, dsl_dataset_promote_check,
+           dsl_dataset_promote_sync, &ddpa,
+           2 + numsnaps, ZFS_SPACE_CHECK_RESERVED));
+}
+
+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)
+{
+       int64_t unused_refres_delta;
+
+       /* they should both be heads */
+       if (clone->ds_is_snapshot ||
+           origin_head->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       /* if we are not forcing, the branch point should be just before them */
+       if (!force && clone->ds_prev != origin_head->ds_prev)
+               return (SET_ERROR(EINVAL));
+
+       /* clone should be the clone (unless they are unrelated) */
+       if (clone->ds_prev != NULL &&
+           clone->ds_prev != clone->ds_dir->dd_pool->dp_origin_snap &&
+           origin_head->ds_dir != clone->ds_prev->ds_dir)
+               return (SET_ERROR(EINVAL));
+
+       /* the clone should be a child of the origin */
+       if (clone->ds_dir->dd_parent != origin_head->ds_dir)
+               return (SET_ERROR(EINVAL));
+
+       /* origin_head shouldn't be modified unless 'force' */
+       if (!force &&
+           dsl_dataset_modified_since_snap(origin_head, origin_head->ds_prev))
+               return (SET_ERROR(ETXTBSY));
+
+       /* origin_head should have no long holds (e.g. is not mounted) */
+       if (dsl_dataset_handoff_check(origin_head, owner, tx))
+               return (SET_ERROR(EBUSY));
+
+       /* check amount of any unconsumed refreservation */
+       unused_refres_delta =
+           (int64_t)MIN(origin_head->ds_reserved,
+           dsl_dataset_phys(origin_head)->ds_unique_bytes) -
+           (int64_t)MIN(origin_head->ds_reserved,
+           dsl_dataset_phys(clone)->ds_unique_bytes);
+
+       if (unused_refres_delta > 0 &&
+           unused_refres_delta >
+           dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
+               return (SET_ERROR(ENOSPC));
+
+       /* clone can't be over the head's refquota */
+       if (origin_head->ds_quota != 0 &&
+           dsl_dataset_phys(clone)->ds_referenced_bytes >
+           origin_head->ds_quota)
+               return (SET_ERROR(EDQUOT));
+
+       return (0);
+}
+
+void
+dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
+    dsl_dataset_t *origin_head, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       int64_t unused_refres_delta;
+
+       ASSERT(clone->ds_reserved == 0);
+       ASSERT(origin_head->ds_quota == 0 ||
+           dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
+       ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
+
+       dmu_buf_will_dirty(clone->ds_dbuf, tx);
+       dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
+
+       if (clone->ds_objset != NULL) {
+               dmu_objset_evict(clone->ds_objset);
+               clone->ds_objset = NULL;
+       }
+
+       if (origin_head->ds_objset != NULL) {
+               dmu_objset_evict(origin_head->ds_objset);
+               origin_head->ds_objset = NULL;
+       }
+
+       unused_refres_delta =
+           (int64_t)MIN(origin_head->ds_reserved,
+           dsl_dataset_phys(origin_head)->ds_unique_bytes) -
+           (int64_t)MIN(origin_head->ds_reserved,
+           dsl_dataset_phys(clone)->ds_unique_bytes);
+
+       /*
+        * Reset origin's unique bytes, if it exists.
+        */
+       if (clone->ds_prev) {
+               dsl_dataset_t *origin = clone->ds_prev;
+               uint64_t comp, uncomp;
+
+               dmu_buf_will_dirty(origin->ds_dbuf, tx);
+               dsl_deadlist_space_range(&clone->ds_deadlist,
+                   dsl_dataset_phys(origin)->ds_prev_snap_txg, UINT64_MAX,
+                   &dsl_dataset_phys(origin)->ds_unique_bytes, &comp, &uncomp);
+       }
+
+       /* swap blkptrs */
+       {
+               blkptr_t tmp;
+               tmp = dsl_dataset_phys(origin_head)->ds_bp;
+               dsl_dataset_phys(origin_head)->ds_bp =
+                   dsl_dataset_phys(clone)->ds_bp;
+               dsl_dataset_phys(clone)->ds_bp = tmp;
+       }
+
+       /* set dd_*_bytes */
+       {
+               int64_t dused, dcomp, duncomp;
+               uint64_t cdl_used, cdl_comp, cdl_uncomp;
+               uint64_t odl_used, odl_comp, odl_uncomp;
+
+               ASSERT3U(dsl_dir_phys(clone->ds_dir)->
+                   dd_used_breakdown[DD_USED_SNAP], ==, 0);
+
+               dsl_deadlist_space(&clone->ds_deadlist,
+                   &cdl_used, &cdl_comp, &cdl_uncomp);
+               dsl_deadlist_space(&origin_head->ds_deadlist,
+                   &odl_used, &odl_comp, &odl_uncomp);
+
+               dused = dsl_dataset_phys(clone)->ds_referenced_bytes +
+                   cdl_used -
+                   (dsl_dataset_phys(origin_head)->ds_referenced_bytes +
+                   odl_used);
+               dcomp = dsl_dataset_phys(clone)->ds_compressed_bytes +
+                   cdl_comp -
+                   (dsl_dataset_phys(origin_head)->ds_compressed_bytes +
+                   odl_comp);
+               duncomp = dsl_dataset_phys(clone)->ds_uncompressed_bytes +
+                   cdl_uncomp -
+                   (dsl_dataset_phys(origin_head)->ds_uncompressed_bytes +
+                   odl_uncomp);
+
+               dsl_dir_diduse_space(origin_head->ds_dir, DD_USED_HEAD,
+                   dused, dcomp, duncomp, tx);
+               dsl_dir_diduse_space(clone->ds_dir, DD_USED_HEAD,
+                   -dused, -dcomp, -duncomp, tx);
+
+               /*
+                * The difference in the space used by snapshots is the
+                * difference in snapshot space due to the head's
+                * deadlist (since that's the only thing that's
+                * changing that affects the snapused).
+                */
+               dsl_deadlist_space_range(&clone->ds_deadlist,
+                   origin_head->ds_dir->dd_origin_txg, UINT64_MAX,
+                   &cdl_used, &cdl_comp, &cdl_uncomp);
+               dsl_deadlist_space_range(&origin_head->ds_deadlist,
+                   origin_head->ds_dir->dd_origin_txg, UINT64_MAX,
+                   &odl_used, &odl_comp, &odl_uncomp);
+               dsl_dir_transfer_space(origin_head->ds_dir, cdl_used - odl_used,
+                   DD_USED_HEAD, DD_USED_SNAP, tx);
+       }
+
+       /* swap ds_*_bytes */
+       SWITCH64(dsl_dataset_phys(origin_head)->ds_referenced_bytes,
+           dsl_dataset_phys(clone)->ds_referenced_bytes);
+       SWITCH64(dsl_dataset_phys(origin_head)->ds_compressed_bytes,
+           dsl_dataset_phys(clone)->ds_compressed_bytes);
+       SWITCH64(dsl_dataset_phys(origin_head)->ds_uncompressed_bytes,
+           dsl_dataset_phys(clone)->ds_uncompressed_bytes);
+       SWITCH64(dsl_dataset_phys(origin_head)->ds_unique_bytes,
+           dsl_dataset_phys(clone)->ds_unique_bytes);
+
+       /* apply any parent delta for change in unconsumed refreservation */
+       dsl_dir_diduse_space(origin_head->ds_dir, DD_USED_REFRSRV,
+           unused_refres_delta, 0, 0, tx);
+
+       /*
+        * Swap deadlists.
+        */
+       dsl_deadlist_close(&clone->ds_deadlist);
+       dsl_deadlist_close(&origin_head->ds_deadlist);
+       SWITCH64(dsl_dataset_phys(origin_head)->ds_deadlist_obj,
+           dsl_dataset_phys(clone)->ds_deadlist_obj);
+       dsl_deadlist_open(&clone->ds_deadlist, dp->dp_meta_objset,
+           dsl_dataset_phys(clone)->ds_deadlist_obj);
+       dsl_deadlist_open(&origin_head->ds_deadlist, dp->dp_meta_objset,
+           dsl_dataset_phys(origin_head)->ds_deadlist_obj);
+
+       dsl_scan_ds_clone_swapped(origin_head, clone, tx);
+
+       spa_history_log_internal_ds(clone, "clone swap", tx,
+           "parent=%s", origin_head->ds_dir->dd_myname);
+}
+
+/*
+ * Given a pool name and a dataset object number in that pool,
+ * return the name of that dataset.
+ */
+int
+dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int error;
+
+       error = dsl_pool_hold(pname, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds);
+       if (error == 0) {
+               dsl_dataset_name(ds, buf);
+               dsl_dataset_rele(ds, FTAG);
+       }
+       dsl_pool_rele(dp, FTAG);
+
+       return (error);
+}
+
+int
+dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota,
+    uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv)
+{
+       int error = 0;
+
+       ASSERT3S(asize, >, 0);
+
+       /*
+        * *ref_rsrv is the portion of asize that will come from any
+        * unconsumed refreservation space.
+        */
+       *ref_rsrv = 0;
+
+       mutex_enter(&ds->ds_lock);
+       /*
+        * Make a space adjustment for reserved bytes.
+        */
+       if (ds->ds_reserved > dsl_dataset_phys(ds)->ds_unique_bytes) {
+               ASSERT3U(*used, >=,
+                   ds->ds_reserved - dsl_dataset_phys(ds)->ds_unique_bytes);
+               *used -=
+                   (ds->ds_reserved - dsl_dataset_phys(ds)->ds_unique_bytes);
+               *ref_rsrv =
+                   asize - MIN(asize, parent_delta(ds, asize + inflight));
+       }
+
+       if (!check_quota || ds->ds_quota == 0) {
+               mutex_exit(&ds->ds_lock);
+               return (0);
+       }
+       /*
+        * If they are requesting more space, and our current estimate
+        * is over quota, they get to try again unless the actual
+        * on-disk is over quota and there are no pending changes (which
+        * may free up space for us).
+        */
+       if (dsl_dataset_phys(ds)->ds_referenced_bytes + inflight >=
+           ds->ds_quota) {
+               if (inflight > 0 ||
+                   dsl_dataset_phys(ds)->ds_referenced_bytes < ds->ds_quota)
+                       error = SET_ERROR(ERESTART);
+               else
+                       error = SET_ERROR(EDQUOT);
+       }
+       mutex_exit(&ds->ds_lock);
+
+       return (error);
+}
+
+typedef struct dsl_dataset_set_qr_arg {
+       const char *ddsqra_name;
+       zprop_source_t ddsqra_source;
+       uint64_t ddsqra_value;
+} dsl_dataset_set_qr_arg_t;
+
+
+/* ARGSUSED */
+static int
+dsl_dataset_set_refquota_check(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;
+       int error;
+       uint64_t newval;
+
+       if (spa_version(dp->dp_spa) < SPA_VERSION_REFQUOTA)
+               return (SET_ERROR(ENOTSUP));
+
+       error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       if (ds->ds_is_snapshot) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       error = dsl_prop_predict(ds->ds_dir,
+           zfs_prop_to_name(ZFS_PROP_REFQUOTA),
+           ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       if (newval == 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (0);
+       }
+
+       if (newval < dsl_dataset_phys(ds)->ds_referenced_bytes ||
+           newval < ds->ds_reserved) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(ENOSPC));
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+static void
+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;
+       uint64_t newval;
+
+       VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds));
+
+       dsl_prop_set_sync_impl(ds,
+           zfs_prop_to_name(ZFS_PROP_REFQUOTA),
+           ddsqra->ddsqra_source, sizeof (ddsqra->ddsqra_value), 1,
+           &ddsqra->ddsqra_value, tx);
+
+       VERIFY0(dsl_prop_get_int_ds(ds,
+           zfs_prop_to_name(ZFS_PROP_REFQUOTA), &newval));
+
+       if (ds->ds_quota != newval) {
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               ds->ds_quota = newval;
+       }
+       dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_dataset_set_refquota(const char *dsname, zprop_source_t source,
+    uint64_t refquota)
+{
+       dsl_dataset_set_qr_arg_t ddsqra;
+
+       ddsqra.ddsqra_name = dsname;
+       ddsqra.ddsqra_source = source;
+       ddsqra.ddsqra_value = refquota;
+
+       return (dsl_sync_task(dsname, dsl_dataset_set_refquota_check,
+           dsl_dataset_set_refquota_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+static int
+dsl_dataset_set_refreservation_check(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;
+       int error;
+       uint64_t newval, unique;
+
+       if (spa_version(dp->dp_spa) < SPA_VERSION_REFRESERVATION)
+               return (SET_ERROR(ENOTSUP));
+
+       error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       if (ds->ds_is_snapshot) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       error = dsl_prop_predict(ds->ds_dir,
+           zfs_prop_to_name(ZFS_PROP_REFRESERVATION),
+           ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       /*
+        * If we are doing the preliminary check in open context, the
+        * space estimates may be inaccurate.
+        */
+       if (!dmu_tx_is_syncing(tx)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (0);
+       }
+
+       mutex_enter(&ds->ds_lock);
+       if (!DS_UNIQUE_IS_ACCURATE(ds))
+               dsl_dataset_recalc_head_uniq(ds);
+       unique = dsl_dataset_phys(ds)->ds_unique_bytes;
+       mutex_exit(&ds->ds_lock);
+
+       if (MAX(unique, newval) > MAX(unique, ds->ds_reserved)) {
+               uint64_t delta = MAX(unique, newval) -
+                   MAX(unique, ds->ds_reserved);
+
+               if (delta >
+                   dsl_dir_space_available(ds->ds_dir, NULL, 0, B_TRUE) ||
+                   (ds->ds_quota > 0 && newval > ds->ds_quota)) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (SET_ERROR(ENOSPC));
+               }
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+void
+dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds,
+    zprop_source_t source, uint64_t value, dmu_tx_t *tx)
+{
+       uint64_t newval;
+       uint64_t unique;
+       int64_t delta;
+
+       dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_REFRESERVATION),
+           source, sizeof (value), 1, &value, tx);
+
+       VERIFY0(dsl_prop_get_int_ds(ds,
+           zfs_prop_to_name(ZFS_PROP_REFRESERVATION), &newval));
+
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       mutex_enter(&ds->ds_dir->dd_lock);
+       mutex_enter(&ds->ds_lock);
+       ASSERT(DS_UNIQUE_IS_ACCURATE(ds));
+       unique = dsl_dataset_phys(ds)->ds_unique_bytes;
+       delta = MAX(0, (int64_t)(newval - unique)) -
+           MAX(0, (int64_t)(ds->ds_reserved - unique));
+       ds->ds_reserved = newval;
+       mutex_exit(&ds->ds_lock);
+
+       dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx);
+       mutex_exit(&ds->ds_dir->dd_lock);
+}
+
+static void
+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;
+
+       VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds));
+       dsl_dataset_set_refreservation_sync_impl(ds,
+           ddsqra->ddsqra_source, ddsqra->ddsqra_value, tx);
+       dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_dataset_set_refreservation(const char *dsname, zprop_source_t source,
+    uint64_t refreservation)
+{
+       dsl_dataset_set_qr_arg_t ddsqra;
+
+       ddsqra.ddsqra_name = dsname;
+       ddsqra.ddsqra_source = source;
+       ddsqra.ddsqra_value = refreservation;
+
+       return (dsl_sync_task(dsname, dsl_dataset_set_refreservation_check,
+           dsl_dataset_set_refreservation_sync, &ddsqra,
+           0, ZFS_SPACE_CHECK_NONE));
+}
+
+/*
+ * Return (in *usedp) the amount of space written in new that is not
+ * present in oldsnap.  New may be a snapshot or the head.  Old must be
+ * a snapshot before new, in new's filesystem (or its origin).  If not then
+ * fail and return EINVAL.
+ *
+ * The written space is calculated by considering two components:  First, we
+ * ignore any freed space, and calculate the written as new's used space
+ * minus old's used space.  Next, we add in the amount of space that was freed
+ * between the two snapshots, thus reducing new's used space relative to old's.
+ * Specifically, this is the space that was born before old->ds_creation_txg,
+ * and freed before new (ie. on new's deadlist or a previous deadlist).
+ *
+ * space freed                         [---------------------]
+ * snapshots                       ---O-------O--------O-------O------
+ *                                         oldsnap            new
+ */
+int
+dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+       int err = 0;
+       uint64_t snapobj;
+       dsl_pool_t *dp = new->ds_dir->dd_pool;
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       *usedp = 0;
+       *usedp += dsl_dataset_phys(new)->ds_referenced_bytes;
+       *usedp -= dsl_dataset_phys(oldsnap)->ds_referenced_bytes;
+
+       *compp = 0;
+       *compp += dsl_dataset_phys(new)->ds_compressed_bytes;
+       *compp -= dsl_dataset_phys(oldsnap)->ds_compressed_bytes;
+
+       *uncompp = 0;
+       *uncompp += dsl_dataset_phys(new)->ds_uncompressed_bytes;
+       *uncompp -= dsl_dataset_phys(oldsnap)->ds_uncompressed_bytes;
+
+       snapobj = new->ds_object;
+       while (snapobj != oldsnap->ds_object) {
+               dsl_dataset_t *snap;
+               uint64_t used, comp, uncomp;
+
+               if (snapobj == new->ds_object) {
+                       snap = new;
+               } else {
+                       err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap);
+                       if (err != 0)
+                               break;
+               }
+
+               if (dsl_dataset_phys(snap)->ds_prev_snap_txg ==
+                   dsl_dataset_phys(oldsnap)->ds_creation_txg) {
+                       /*
+                        * The blocks in the deadlist can not be born after
+                        * ds_prev_snap_txg, so get the whole deadlist space,
+                        * which is more efficient (especially for old-format
+                        * deadlists).  Unfortunately the deadlist code
+                        * doesn't have enough information to make this
+                        * optimization itself.
+                        */
+                       dsl_deadlist_space(&snap->ds_deadlist,
+                           &used, &comp, &uncomp);
+               } else {
+                       dsl_deadlist_space_range(&snap->ds_deadlist,
+                           0, dsl_dataset_phys(oldsnap)->ds_creation_txg,
+                           &used, &comp, &uncomp);
+               }
+               *usedp += used;
+               *compp += comp;
+               *uncompp += uncomp;
+
+               /*
+                * If we get to the beginning of the chain of snapshots
+                * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap
+                * was not a snapshot of/before new.
+                */
+               snapobj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+               if (snap != new)
+                       dsl_dataset_rele(snap, FTAG);
+               if (snapobj == 0) {
+                       err = SET_ERROR(EINVAL);
+                       break;
+               }
+
+       }
+       return (err);
+}
+
+/*
+ * Return (in *usedp) the amount of space that will be reclaimed if firstsnap,
+ * lastsnap, and all snapshots in between are deleted.
+ *
+ * blocks that would be freed            [---------------------------]
+ * snapshots                       ---O-------O--------O-------O--------O
+ *                                        firstsnap        lastsnap
+ *
+ * This is the set of blocks that were born after the snap before firstsnap,
+ * (birth > firstsnap->prev_snap_txg) and died before the snap after the
+ * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist).
+ * We calculate this by iterating over the relevant deadlists (from the snap
+ * after lastsnap, backward to the snap after firstsnap), summing up the
+ * space on the deadlist that was born after the snap before firstsnap.
+ */
+int
+dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
+    dsl_dataset_t *lastsnap,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+       int err = 0;
+       uint64_t snapobj;
+       dsl_pool_t *dp = firstsnap->ds_dir->dd_pool;
+
+       ASSERT(firstsnap->ds_is_snapshot);
+       ASSERT(lastsnap->ds_is_snapshot);
+
+       /*
+        * Check that the snapshots are in the same dsl_dir, and firstsnap
+        * is before lastsnap.
+        */
+       if (firstsnap->ds_dir != lastsnap->ds_dir ||
+           dsl_dataset_phys(firstsnap)->ds_creation_txg >
+           dsl_dataset_phys(lastsnap)->ds_creation_txg)
+               return (SET_ERROR(EINVAL));
+
+       *usedp = *compp = *uncompp = 0;
+
+       snapobj = dsl_dataset_phys(lastsnap)->ds_next_snap_obj;
+       while (snapobj != firstsnap->ds_object) {
+               dsl_dataset_t *ds;
+               uint64_t used, comp, uncomp;
+
+               err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds);
+               if (err != 0)
+                       break;
+
+               dsl_deadlist_space_range(&ds->ds_deadlist,
+                   dsl_dataset_phys(firstsnap)->ds_prev_snap_txg, UINT64_MAX,
+                   &used, &comp, &uncomp);
+               *usedp += used;
+               *compp += comp;
+               *uncompp += uncomp;
+
+               snapobj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
+               ASSERT3U(snapobj, !=, 0);
+               dsl_dataset_rele(ds, FTAG);
+       }
+       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
+ * 'earlier' is before 'later'.  Or 'earlier' could be the origin of
+ * 'later's filesystem.  Or 'earlier' could be an older snapshot in the origin's
+ * filesystem.  Or 'earlier' could be the origin's origin.
+ *
+ * If non-zero, earlier_txg is used instead of earlier's ds_creation_txg.
+ */
+boolean_t
+dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
+       uint64_t earlier_txg)
+{
+       dsl_pool_t *dp = later->ds_dir->dd_pool;
+       int error;
+       boolean_t ret;
+       dsl_dataset_t *origin;
+
+       ASSERT(dsl_pool_config_held(dp));
+       ASSERT(earlier->ds_is_snapshot || earlier_txg != 0);
+
+       if (earlier_txg == 0)
+               earlier_txg = dsl_dataset_phys(earlier)->ds_creation_txg;
+
+       if (later->ds_is_snapshot &&
+           earlier_txg >= dsl_dataset_phys(later)->ds_creation_txg)
+               return (B_FALSE);
+
+       if (later->ds_dir == earlier->ds_dir)
+               return (B_TRUE);
+       if (!dsl_dir_is_clone(later->ds_dir))
+               return (B_FALSE);
+
+       if (dsl_dir_phys(later->ds_dir)->dd_origin_obj == earlier->ds_object)
+               return (B_TRUE);
+       error = dsl_dataset_hold_obj(dp,
+           dsl_dir_phys(later->ds_dir)->dd_origin_obj, FTAG, &origin);
+       if (error != 0)
+               return (B_FALSE);
+       ret = dsl_dataset_is_before(origin, earlier, earlier_txg);
+       dsl_dataset_rele(origin, FTAG);
+       return (ret);
+}
+
+
+void
+dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+#if defined(_LP64)
+module_param(zfs_max_recordsize, int, 0644);
+MODULE_PARM_DESC(zfs_max_recordsize, "Max allowed record size");
+#else
+/* Limited to 1M on 32-bit platforms due to lack of virtual address space */
+module_param(zfs_max_recordsize, int, 0444);
+MODULE_PARM_DESC(zfs_max_recordsize, "Max allowed record size");
+#endif
+
+EXPORT_SYMBOL(dsl_dataset_hold);
+EXPORT_SYMBOL(dsl_dataset_hold_obj);
+EXPORT_SYMBOL(dsl_dataset_own);
+EXPORT_SYMBOL(dsl_dataset_own_obj);
+EXPORT_SYMBOL(dsl_dataset_name);
+EXPORT_SYMBOL(dsl_dataset_rele);
+EXPORT_SYMBOL(dsl_dataset_disown);
+EXPORT_SYMBOL(dsl_dataset_tryown);
+EXPORT_SYMBOL(dsl_dataset_create_sync);
+EXPORT_SYMBOL(dsl_dataset_create_sync_dd);
+EXPORT_SYMBOL(dsl_dataset_snapshot_check);
+EXPORT_SYMBOL(dsl_dataset_snapshot_sync);
+EXPORT_SYMBOL(dsl_dataset_promote);
+EXPORT_SYMBOL(dsl_dataset_user_hold);
+EXPORT_SYMBOL(dsl_dataset_user_release);
+EXPORT_SYMBOL(dsl_dataset_get_holds);
+EXPORT_SYMBOL(dsl_dataset_get_blkptr);
+EXPORT_SYMBOL(dsl_dataset_set_blkptr);
+EXPORT_SYMBOL(dsl_dataset_get_spa);
+EXPORT_SYMBOL(dsl_dataset_modified_since_snap);
+EXPORT_SYMBOL(dsl_dataset_space_written);
+EXPORT_SYMBOL(dsl_dataset_space_wouldfree);
+EXPORT_SYMBOL(dsl_dataset_sync);
+EXPORT_SYMBOL(dsl_dataset_block_born);
+EXPORT_SYMBOL(dsl_dataset_block_kill);
+EXPORT_SYMBOL(dsl_dataset_block_freeable);
+EXPORT_SYMBOL(dsl_dataset_prev_snap_txg);
+EXPORT_SYMBOL(dsl_dataset_dirty);
+EXPORT_SYMBOL(dsl_dataset_stats);
+EXPORT_SYMBOL(dsl_dataset_fast_stat);
+EXPORT_SYMBOL(dsl_dataset_space);
+EXPORT_SYMBOL(dsl_dataset_fsid_guid);
+EXPORT_SYMBOL(dsl_dsobj_to_dsname);
+EXPORT_SYMBOL(dsl_dataset_check_quota);
+EXPORT_SYMBOL(dsl_dataset_clone_swap_check_impl);
+EXPORT_SYMBOL(dsl_dataset_clone_swap_sync_impl);
+#endif
diff --git a/zfs/module/zfs/dsl_deadlist.c b/zfs/module/zfs/dsl_deadlist.c
new file mode 100644 (file)
index 0000000..8da77eb
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/dsl_dataset.h>
+#include <sys/dmu.h>
+#include <sys/refcount.h>
+#include <sys/zap.h>
+#include <sys/zfs_context.h>
+#include <sys/dsl_pool.h>
+
+/*
+ * Deadlist concurrency:
+ *
+ * Deadlists can only be modified from the syncing thread.
+ *
+ * Except for dsl_deadlist_insert(), it can only be modified with the
+ * dp_config_rwlock held with RW_WRITER.
+ *
+ * The accessors (dsl_deadlist_space() and dsl_deadlist_space_range()) can
+ * be called concurrently, from open context, with the dl_config_rwlock held
+ * with RW_READER.
+ *
+ * Therefore, we only need to provide locking between dsl_deadlist_insert() and
+ * the accessors, protecting:
+ *     dl_phys->dl_used,comp,uncomp
+ *     and protecting the dl_tree from being loaded.
+ * The locking is provided by dl_lock.  Note that locking on the bpobj_t
+ * provides its own locking, and dl_oldfmt is immutable.
+ */
+
+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;
+
+       if (dle1->dle_mintxg < dle2->dle_mintxg)
+               return (-1);
+       else if (dle1->dle_mintxg > dle2->dle_mintxg)
+               return (+1);
+       else
+               return (0);
+}
+
+static void
+dsl_deadlist_load_tree(dsl_deadlist_t *dl)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+
+       ASSERT(!dl->dl_oldfmt);
+       if (dl->dl_havetree)
+               return;
+
+       avl_create(&dl->dl_tree, dsl_deadlist_compare,
+           sizeof (dsl_deadlist_entry_t),
+           offsetof(dsl_deadlist_entry_t, dle_node));
+       for (zap_cursor_init(&zc, dl->dl_os, dl->dl_object);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               dsl_deadlist_entry_t *dle;
+
+               dle = kmem_alloc(sizeof (*dle), KM_SLEEP);
+               dle->dle_mintxg = strtonum(za.za_name, NULL);
+               VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os,
+                   za.za_first_integer));
+               avl_add(&dl->dl_tree, dle);
+       }
+       zap_cursor_fini(&zc);
+       dl->dl_havetree = B_TRUE;
+}
+
+void
+dsl_deadlist_open(dsl_deadlist_t *dl, objset_t *os, uint64_t object)
+{
+       dmu_object_info_t doi;
+
+       mutex_init(&dl->dl_lock, NULL, MUTEX_DEFAULT, NULL);
+       dl->dl_os = os;
+       dl->dl_object = object;
+       VERIFY3U(0, ==, dmu_bonus_hold(os, object, dl, &dl->dl_dbuf));
+       dmu_object_info_from_db(dl->dl_dbuf, &doi);
+       if (doi.doi_type == DMU_OT_BPOBJ) {
+               dmu_buf_rele(dl->dl_dbuf, dl);
+               dl->dl_dbuf = NULL;
+               dl->dl_oldfmt = B_TRUE;
+               VERIFY3U(0, ==, bpobj_open(&dl->dl_bpobj, os, object));
+               return;
+       }
+
+       dl->dl_oldfmt = B_FALSE;
+       dl->dl_phys = dl->dl_dbuf->db_data;
+       dl->dl_havetree = B_FALSE;
+}
+
+void
+dsl_deadlist_close(dsl_deadlist_t *dl)
+{
+       void *cookie = NULL;
+       dsl_deadlist_entry_t *dle;
+
+       dl->dl_os = NULL;
+
+       if (dl->dl_oldfmt) {
+               dl->dl_oldfmt = B_FALSE;
+               bpobj_close(&dl->dl_bpobj);
+               return;
+       }
+
+       if (dl->dl_havetree) {
+               while ((dle = avl_destroy_nodes(&dl->dl_tree, &cookie))
+                   != NULL) {
+                       bpobj_close(&dle->dle_bpobj);
+                       kmem_free(dle, sizeof (*dle));
+               }
+               avl_destroy(&dl->dl_tree);
+       }
+       dmu_buf_rele(dl->dl_dbuf, dl);
+       mutex_destroy(&dl->dl_lock);
+       dl->dl_dbuf = NULL;
+       dl->dl_phys = NULL;
+}
+
+uint64_t
+dsl_deadlist_alloc(objset_t *os, dmu_tx_t *tx)
+{
+       if (spa_version(dmu_objset_spa(os)) < SPA_VERSION_DEADLISTS)
+               return (bpobj_alloc(os, SPA_OLD_MAXBLOCKSIZE, tx));
+       return (zap_create(os, DMU_OT_DEADLIST, DMU_OT_DEADLIST_HDR,
+           sizeof (dsl_deadlist_phys_t), tx));
+}
+
+void
+dsl_deadlist_free(objset_t *os, uint64_t dlobj, dmu_tx_t *tx)
+{
+       dmu_object_info_t doi;
+       zap_cursor_t zc;
+       zap_attribute_t za;
+
+       VERIFY3U(0, ==, dmu_object_info(os, dlobj, &doi));
+       if (doi.doi_type == DMU_OT_BPOBJ) {
+               bpobj_free(os, dlobj, tx);
+               return;
+       }
+
+       for (zap_cursor_init(&zc, os, dlobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               uint64_t obj = za.za_first_integer;
+               if (obj == dmu_objset_pool(os)->dp_empty_bpobj)
+                       bpobj_decr_empty(os, tx);
+               else
+                       bpobj_free(os, obj, tx);
+       }
+       zap_cursor_fini(&zc);
+       VERIFY3U(0, ==, dmu_object_free(os, dlobj, tx));
+}
+
+static void
+dle_enqueue(dsl_deadlist_t *dl, dsl_deadlist_entry_t *dle,
+    const blkptr_t *bp, dmu_tx_t *tx)
+{
+       if (dle->dle_bpobj.bpo_object ==
+           dmu_objset_pool(dl->dl_os)->dp_empty_bpobj) {
+               uint64_t obj = bpobj_alloc(dl->dl_os, SPA_OLD_MAXBLOCKSIZE, tx);
+               bpobj_close(&dle->dle_bpobj);
+               bpobj_decr_empty(dl->dl_os, tx);
+               VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os, obj));
+               VERIFY3U(0, ==, zap_update_int_key(dl->dl_os, dl->dl_object,
+                   dle->dle_mintxg, obj, tx));
+       }
+       bpobj_enqueue(&dle->dle_bpobj, bp, tx);
+}
+
+static void
+dle_enqueue_subobj(dsl_deadlist_t *dl, dsl_deadlist_entry_t *dle,
+    uint64_t obj, dmu_tx_t *tx)
+{
+       if (dle->dle_bpobj.bpo_object !=
+           dmu_objset_pool(dl->dl_os)->dp_empty_bpobj) {
+               bpobj_enqueue_subobj(&dle->dle_bpobj, obj, tx);
+       } else {
+               bpobj_close(&dle->dle_bpobj);
+               bpobj_decr_empty(dl->dl_os, tx);
+               VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os, obj));
+               VERIFY3U(0, ==, zap_update_int_key(dl->dl_os, dl->dl_object,
+                   dle->dle_mintxg, obj, tx));
+       }
+}
+
+void
+dsl_deadlist_insert(dsl_deadlist_t *dl, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       dsl_deadlist_entry_t dle_tofind;
+       dsl_deadlist_entry_t *dle;
+       avl_index_t where;
+
+       if (dl->dl_oldfmt) {
+               bpobj_enqueue(&dl->dl_bpobj, bp, tx);
+               return;
+       }
+
+       dsl_deadlist_load_tree(dl);
+
+       dmu_buf_will_dirty(dl->dl_dbuf, tx);
+       mutex_enter(&dl->dl_lock);
+       dl->dl_phys->dl_used +=
+           bp_get_dsize_sync(dmu_objset_spa(dl->dl_os), bp);
+       dl->dl_phys->dl_comp += BP_GET_PSIZE(bp);
+       dl->dl_phys->dl_uncomp += BP_GET_UCSIZE(bp);
+       mutex_exit(&dl->dl_lock);
+
+       dle_tofind.dle_mintxg = bp->blk_birth;
+       dle = avl_find(&dl->dl_tree, &dle_tofind, &where);
+       if (dle == NULL)
+               dle = avl_nearest(&dl->dl_tree, where, AVL_BEFORE);
+       else
+               dle = AVL_PREV(&dl->dl_tree, dle);
+       dle_enqueue(dl, dle, bp, tx);
+}
+
+/*
+ * Insert new key in deadlist, which must be > all current entries.
+ * mintxg is not inclusive.
+ */
+void
+dsl_deadlist_add_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx)
+{
+       uint64_t obj;
+       dsl_deadlist_entry_t *dle;
+
+       if (dl->dl_oldfmt)
+               return;
+
+       dsl_deadlist_load_tree(dl);
+
+       dle = kmem_alloc(sizeof (*dle), KM_SLEEP);
+       dle->dle_mintxg = mintxg;
+       obj = bpobj_alloc_empty(dl->dl_os, SPA_OLD_MAXBLOCKSIZE, tx);
+       VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os, obj));
+       avl_add(&dl->dl_tree, dle);
+
+       VERIFY3U(0, ==, zap_add_int_key(dl->dl_os, dl->dl_object,
+           mintxg, obj, tx));
+}
+
+/*
+ * Remove this key, merging its entries into the previous key.
+ */
+void
+dsl_deadlist_remove_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx)
+{
+       dsl_deadlist_entry_t dle_tofind;
+       dsl_deadlist_entry_t *dle, *dle_prev;
+
+       if (dl->dl_oldfmt)
+               return;
+
+       dsl_deadlist_load_tree(dl);
+
+       dle_tofind.dle_mintxg = mintxg;
+       dle = avl_find(&dl->dl_tree, &dle_tofind, NULL);
+       dle_prev = AVL_PREV(&dl->dl_tree, dle);
+
+       dle_enqueue_subobj(dl, dle_prev, dle->dle_bpobj.bpo_object, tx);
+
+       avl_remove(&dl->dl_tree, dle);
+       bpobj_close(&dle->dle_bpobj);
+       kmem_free(dle, sizeof (*dle));
+
+       VERIFY3U(0, ==, zap_remove_int(dl->dl_os, dl->dl_object, mintxg, tx));
+}
+
+/*
+ * Walk ds's snapshots to regenerate generate ZAP & AVL.
+ */
+static void
+dsl_deadlist_regenerate(objset_t *os, uint64_t dlobj,
+    uint64_t mrs_obj, dmu_tx_t *tx)
+{
+       dsl_deadlist_t dl;
+       dsl_pool_t *dp = dmu_objset_pool(os);
+
+       dsl_deadlist_open(&dl, os, dlobj);
+       if (dl.dl_oldfmt) {
+               dsl_deadlist_close(&dl);
+               return;
+       }
+
+       while (mrs_obj != 0) {
+               dsl_dataset_t *ds;
+               VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, mrs_obj, FTAG, &ds));
+               dsl_deadlist_add_key(&dl,
+                   dsl_dataset_phys(ds)->ds_prev_snap_txg, tx);
+               mrs_obj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
+               dsl_dataset_rele(ds, FTAG);
+       }
+       dsl_deadlist_close(&dl);
+}
+
+uint64_t
+dsl_deadlist_clone(dsl_deadlist_t *dl, uint64_t maxtxg,
+    uint64_t mrs_obj, dmu_tx_t *tx)
+{
+       dsl_deadlist_entry_t *dle;
+       uint64_t newobj;
+
+       newobj = dsl_deadlist_alloc(dl->dl_os, tx);
+
+       if (dl->dl_oldfmt) {
+               dsl_deadlist_regenerate(dl->dl_os, newobj, mrs_obj, tx);
+               return (newobj);
+       }
+
+       dsl_deadlist_load_tree(dl);
+
+       for (dle = avl_first(&dl->dl_tree); dle;
+           dle = AVL_NEXT(&dl->dl_tree, dle)) {
+               uint64_t obj;
+
+               if (dle->dle_mintxg >= maxtxg)
+                       break;
+
+               obj = bpobj_alloc_empty(dl->dl_os, SPA_OLD_MAXBLOCKSIZE, tx);
+               VERIFY3U(0, ==, zap_add_int_key(dl->dl_os, newobj,
+                   dle->dle_mintxg, obj, tx));
+       }
+       return (newobj);
+}
+
+void
+dsl_deadlist_space(dsl_deadlist_t *dl,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+       if (dl->dl_oldfmt) {
+               VERIFY3U(0, ==, bpobj_space(&dl->dl_bpobj,
+                   usedp, compp, uncompp));
+               return;
+       }
+
+       mutex_enter(&dl->dl_lock);
+       *usedp = dl->dl_phys->dl_used;
+       *compp = dl->dl_phys->dl_comp;
+       *uncompp = dl->dl_phys->dl_uncomp;
+       mutex_exit(&dl->dl_lock);
+}
+
+/*
+ * return space used in the range (mintxg, maxtxg].
+ * Includes maxtxg, does not include mintxg.
+ * mintxg and maxtxg must both be keys in the deadlist (unless maxtxg is
+ * larger than any bp in the deadlist (eg. UINT64_MAX)).
+ */
+void
+dsl_deadlist_space_range(dsl_deadlist_t *dl, uint64_t mintxg, uint64_t maxtxg,
+    uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+       dsl_deadlist_entry_t *dle;
+       dsl_deadlist_entry_t dle_tofind;
+       avl_index_t where;
+
+       if (dl->dl_oldfmt) {
+               VERIFY3U(0, ==, bpobj_space_range(&dl->dl_bpobj,
+                   mintxg, maxtxg, usedp, compp, uncompp));
+               return;
+       }
+
+       *usedp = *compp = *uncompp = 0;
+
+       mutex_enter(&dl->dl_lock);
+       dsl_deadlist_load_tree(dl);
+       dle_tofind.dle_mintxg = mintxg;
+       dle = avl_find(&dl->dl_tree, &dle_tofind, &where);
+       /*
+        * If we don't find this mintxg, there shouldn't be anything
+        * after it either.
+        */
+       ASSERT(dle != NULL ||
+           avl_nearest(&dl->dl_tree, where, AVL_AFTER) == NULL);
+
+       for (; dle && dle->dle_mintxg < maxtxg;
+           dle = AVL_NEXT(&dl->dl_tree, dle)) {
+               uint64_t used, comp, uncomp;
+
+               VERIFY3U(0, ==, bpobj_space(&dle->dle_bpobj,
+                   &used, &comp, &uncomp));
+
+               *usedp += used;
+               *compp += comp;
+               *uncompp += uncomp;
+       }
+       mutex_exit(&dl->dl_lock);
+}
+
+static void
+dsl_deadlist_insert_bpobj(dsl_deadlist_t *dl, uint64_t obj, uint64_t birth,
+    dmu_tx_t *tx)
+{
+       dsl_deadlist_entry_t dle_tofind;
+       dsl_deadlist_entry_t *dle;
+       avl_index_t where;
+       uint64_t used, comp, uncomp;
+       bpobj_t bpo;
+
+       VERIFY3U(0, ==, bpobj_open(&bpo, dl->dl_os, obj));
+       VERIFY3U(0, ==, bpobj_space(&bpo, &used, &comp, &uncomp));
+       bpobj_close(&bpo);
+
+       dsl_deadlist_load_tree(dl);
+
+       dmu_buf_will_dirty(dl->dl_dbuf, tx);
+       mutex_enter(&dl->dl_lock);
+       dl->dl_phys->dl_used += used;
+       dl->dl_phys->dl_comp += comp;
+       dl->dl_phys->dl_uncomp += uncomp;
+       mutex_exit(&dl->dl_lock);
+
+       dle_tofind.dle_mintxg = birth;
+       dle = avl_find(&dl->dl_tree, &dle_tofind, &where);
+       if (dle == NULL)
+               dle = avl_nearest(&dl->dl_tree, where, AVL_BEFORE);
+       dle_enqueue_subobj(dl, dle, obj, tx);
+}
+
+static int
+dsl_deadlist_insert_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       dsl_deadlist_t *dl = arg;
+       dsl_deadlist_insert(dl, bp, tx);
+       return (0);
+}
+
+/*
+ * Merge the deadlist pointed to by 'obj' into dl.  obj will be left as
+ * an empty deadlist.
+ */
+void
+dsl_deadlist_merge(dsl_deadlist_t *dl, uint64_t obj, dmu_tx_t *tx)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       dmu_buf_t *bonus;
+       dsl_deadlist_phys_t *dlp;
+       dmu_object_info_t doi;
+
+       VERIFY3U(0, ==, dmu_object_info(dl->dl_os, obj, &doi));
+       if (doi.doi_type == DMU_OT_BPOBJ) {
+               bpobj_t bpo;
+               VERIFY3U(0, ==, bpobj_open(&bpo, dl->dl_os, obj));
+               VERIFY3U(0, ==, bpobj_iterate(&bpo,
+                   dsl_deadlist_insert_cb, dl, tx));
+               bpobj_close(&bpo);
+               return;
+       }
+
+       for (zap_cursor_init(&zc, dl->dl_os, obj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               uint64_t mintxg = strtonum(za.za_name, NULL);
+               dsl_deadlist_insert_bpobj(dl, za.za_first_integer, mintxg, tx);
+               VERIFY3U(0, ==, zap_remove_int(dl->dl_os, obj, mintxg, tx));
+       }
+       zap_cursor_fini(&zc);
+
+       VERIFY3U(0, ==, dmu_bonus_hold(dl->dl_os, obj, FTAG, &bonus));
+       dlp = bonus->db_data;
+       dmu_buf_will_dirty(bonus, tx);
+       bzero(dlp, sizeof (*dlp));
+       dmu_buf_rele(bonus, FTAG);
+}
+
+/*
+ * Remove entries on dl that are >= mintxg, and put them on the bpobj.
+ */
+void
+dsl_deadlist_move_bpobj(dsl_deadlist_t *dl, bpobj_t *bpo, uint64_t mintxg,
+    dmu_tx_t *tx)
+{
+       dsl_deadlist_entry_t dle_tofind;
+       dsl_deadlist_entry_t *dle;
+       avl_index_t where;
+
+       ASSERT(!dl->dl_oldfmt);
+       dmu_buf_will_dirty(dl->dl_dbuf, tx);
+       dsl_deadlist_load_tree(dl);
+
+       dle_tofind.dle_mintxg = mintxg;
+       dle = avl_find(&dl->dl_tree, &dle_tofind, &where);
+       if (dle == NULL)
+               dle = avl_nearest(&dl->dl_tree, where, AVL_AFTER);
+       while (dle) {
+               uint64_t used, comp, uncomp;
+               dsl_deadlist_entry_t *dle_next;
+
+               bpobj_enqueue_subobj(bpo, dle->dle_bpobj.bpo_object, tx);
+
+               VERIFY3U(0, ==, bpobj_space(&dle->dle_bpobj,
+                   &used, &comp, &uncomp));
+               mutex_enter(&dl->dl_lock);
+               ASSERT3U(dl->dl_phys->dl_used, >=, used);
+               ASSERT3U(dl->dl_phys->dl_comp, >=, comp);
+               ASSERT3U(dl->dl_phys->dl_uncomp, >=, uncomp);
+               dl->dl_phys->dl_used -= used;
+               dl->dl_phys->dl_comp -= comp;
+               dl->dl_phys->dl_uncomp -= uncomp;
+               mutex_exit(&dl->dl_lock);
+
+               VERIFY3U(0, ==, zap_remove_int(dl->dl_os, dl->dl_object,
+                   dle->dle_mintxg, tx));
+
+               dle_next = AVL_NEXT(&dl->dl_tree, dle);
+               avl_remove(&dl->dl_tree, dle);
+               bpobj_close(&dle->dle_bpobj);
+               kmem_free(dle, sizeof (*dle));
+               dle = dle_next;
+       }
+}
diff --git a/zfs/module/zfs/dsl_deleg.c b/zfs/module/zfs/dsl_deleg.c
new file mode 100644 (file)
index 0000000..952422b
--- /dev/null
@@ -0,0 +1,775 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * DSL permissions are stored in a two level zap attribute
+ * mechanism.   The first level identifies the "class" of
+ * entry.  The class is identified by the first 2 letters of
+ * the attribute.  The second letter "l" or "d" identifies whether
+ * it is a local or descendent permission.  The first letter
+ * identifies the type of entry.
+ *
+ * ul$<id>    identifies permissions granted locally for this userid.
+ * ud$<id>    identifies permissions granted on descendent datasets for
+ *            this userid.
+ * Ul$<id>    identifies permission sets granted locally for this userid.
+ * Ud$<id>    identifies permission sets granted on descendent datasets for
+ *            this userid.
+ * gl$<id>    identifies permissions granted locally for this groupid.
+ * gd$<id>    identifies permissions granted on descendent datasets for
+ *            this groupid.
+ * Gl$<id>    identifies permission sets granted locally for this groupid.
+ * Gd$<id>    identifies permission sets granted on descendent datasets for
+ *            this groupid.
+ * el$        identifies permissions granted locally for everyone.
+ * ed$        identifies permissions granted on descendent datasets
+ *            for everyone.
+ * El$        identifies permission sets granted locally for everyone.
+ * Ed$        identifies permission sets granted to descendent datasets for
+ *            everyone.
+ * c-$        identifies permission to create at dataset creation time.
+ * C-$        identifies permission sets to grant locally at dataset creation
+ *            time.
+ * s-$@<name> permissions defined in specified set @<name>
+ * S-$@<name> Sets defined in named set @<name>
+ *
+ * Each of the above entities points to another zap attribute that contains one
+ * attribute for each allowed permission, such as create, destroy,...
+ * All of the "upper" case class types will specify permission set names
+ * rather than permissions.
+ *
+ * Basically it looks something like this:
+ * ul$12 -> ZAP OBJ -> permissions...
+ *
+ * The ZAP OBJ is referred to as the jump object.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dsl_deleg.h>
+#include <sys/spa.h>
+#include <sys/zap.h>
+#include <sys/fs/zfs.h>
+#include <sys/cred.h>
+#include <sys/sunddi.h>
+
+#include "zfs_deleg.h"
+
+/*
+ * Validate that user is allowed to delegate specified permissions.
+ *
+ * In order to delegate "create" you must have "create"
+ * and "allow".
+ */
+int
+dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
+{
+       nvpair_t *whopair = NULL;
+       int error;
+
+       if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
+               return (error);
+
+       while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
+               nvlist_t *perms;
+               nvpair_t *permpair = NULL;
+
+               VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
+
+               while ((permpair = nvlist_next_nvpair(perms, permpair))) {
+                       const char *perm = nvpair_name(permpair);
+
+                       if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
+                               return (SET_ERROR(EPERM));
+
+                       if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
+                               return (error);
+               }
+       }
+       return (0);
+}
+
+/*
+ * Validate that user is allowed to unallow specified permissions.  They
+ * must have the 'allow' permission, and even then can only unallow
+ * perms for their uid.
+ */
+int
+dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
+{
+       nvpair_t *whopair = NULL;
+       int error;
+       char idstr[32];
+
+       if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
+               return (error);
+
+       (void) snprintf(idstr, sizeof (idstr), "%lld",
+           (longlong_t)crgetuid(cr));
+
+       while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
+               zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
+
+               if (type != ZFS_DELEG_USER &&
+                   type != ZFS_DELEG_USER_SETS)
+                       return (SET_ERROR(EPERM));
+
+               if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
+                       return (SET_ERROR(EPERM));
+       }
+       return (0);
+}
+
+typedef struct dsl_deleg_arg {
+       const char *dda_name;
+       nvlist_t *dda_nvlist;
+} dsl_deleg_arg_t;
+
+static void
+dsl_deleg_set_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_deleg_arg_t *dda = arg;
+       dsl_dir_t *dd;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       nvpair_t *whopair = NULL;
+       uint64_t zapobj;
+
+       VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
+
+       zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
+       if (zapobj == 0) {
+               dmu_buf_will_dirty(dd->dd_dbuf, tx);
+               zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
+                   DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
+       }
+
+       while ((whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair))) {
+               const char *whokey = nvpair_name(whopair);
+               nvlist_t *perms;
+               nvpair_t *permpair = NULL;
+               uint64_t jumpobj;
+
+               perms = fnvpair_value_nvlist(whopair);
+
+               if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
+                       jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS,
+                           zapobj, whokey, tx);
+               }
+
+               while ((permpair = nvlist_next_nvpair(perms, permpair))) {
+                       const char *perm = nvpair_name(permpair);
+                       uint64_t n = 0;
+
+                       VERIFY(zap_update(mos, jumpobj,
+                           perm, 8, 1, &n, tx) == 0);
+                       spa_history_log_internal_dd(dd, "permission update", tx,
+                           "%s %s", whokey, perm);
+               }
+       }
+       dsl_dir_rele(dd, FTAG);
+}
+
+static void
+dsl_deleg_unset_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_deleg_arg_t *dda = arg;
+       dsl_dir_t *dd;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       nvpair_t *whopair = NULL;
+       uint64_t zapobj;
+
+       VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
+       zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
+       if (zapobj == 0) {
+               dsl_dir_rele(dd, FTAG);
+               return;
+       }
+
+       while ((whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair))) {
+               const char *whokey = nvpair_name(whopair);
+               nvlist_t *perms;
+               nvpair_t *permpair = NULL;
+               uint64_t jumpobj;
+
+               if (nvpair_value_nvlist(whopair, &perms) != 0) {
+                       if (zap_lookup(mos, zapobj, whokey, 8,
+                           1, &jumpobj) == 0) {
+                               (void) zap_remove(mos, zapobj, whokey, tx);
+                               VERIFY(0 == zap_destroy(mos, jumpobj, tx));
+                       }
+                       spa_history_log_internal_dd(dd, "permission who remove",
+                           tx, "%s", whokey);
+                       continue;
+               }
+
+               if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
+                       continue;
+
+               while ((permpair = nvlist_next_nvpair(perms, permpair))) {
+                       const char *perm = nvpair_name(permpair);
+                       uint64_t n = 0;
+
+                       (void) zap_remove(mos, jumpobj, perm, tx);
+                       if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
+                               (void) zap_remove(mos, zapobj,
+                                   whokey, tx);
+                               VERIFY(0 == zap_destroy(mos,
+                                   jumpobj, tx));
+                       }
+                       spa_history_log_internal_dd(dd, "permission remove", tx,
+                           "%s %s", whokey, perm);
+               }
+       }
+       dsl_dir_rele(dd, FTAG);
+}
+
+static int
+dsl_deleg_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_deleg_arg_t *dda = arg;
+       dsl_dir_t *dd;
+       int error;
+
+       if (spa_version(dmu_tx_pool(tx)->dp_spa) <
+           SPA_VERSION_DELEGATED_PERMS) {
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       error = dsl_dir_hold(dmu_tx_pool(tx), dda->dda_name, FTAG, &dd, NULL);
+       if (error == 0)
+               dsl_dir_rele(dd, FTAG);
+       return (error);
+}
+
+int
+dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
+{
+       dsl_deleg_arg_t dda;
+
+       /* nvp must already have been verified to be valid */
+
+       dda.dda_name = ddname;
+       dda.dda_nvlist = nvp;
+
+       return (dsl_sync_task(ddname, dsl_deleg_check,
+           unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
+           &dda, fnvlist_num_pairs(nvp), ZFS_SPACE_CHECK_RESERVED));
+}
+
+/*
+ * Find all 'allow' permissions from a given point and then continue
+ * traversing up to the root.
+ *
+ * This function constructs an nvlist of nvlists.
+ * each setpoint is an nvlist composed of an nvlist of an nvlist
+ * of the individual * users/groups/everyone/create
+ * permissions.
+ *
+ * The nvlist will look like this.
+ *
+ * { source fsname -> { whokeys { permissions,...}, ...}}
+ *
+ * The fsname nvpairs will be arranged in a bottom up order.  For example,
+ * if we have the following structure a/b/c then the nvpairs for the fsnames
+ * will be ordered a/b/c, a/b, a.
+ */
+int
+dsl_deleg_get(const char *ddname, nvlist_t **nvp)
+{
+       dsl_dir_t *dd, *startdd;
+       dsl_pool_t *dp;
+       int error;
+       objset_t *mos;
+       zap_cursor_t *basezc, *zc;
+       zap_attribute_t *baseza, *za;
+       char *source;
+
+       error = dsl_pool_hold(ddname, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       dp = startdd->dd_pool;
+       mos = dp->dp_meta_objset;
+
+       zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
+       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);
+       VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
+               nvlist_t *sp_nvp;
+               uint64_t n;
+
+               if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
+                   zap_count(mos,
+                   dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
+                       continue;
+
+               sp_nvp = fnvlist_alloc();
+               for (zap_cursor_init(basezc, mos,
+                   dsl_dir_phys(dd)->dd_deleg_zapobj);
+                   zap_cursor_retrieve(basezc, baseza) == 0;
+                   zap_cursor_advance(basezc)) {
+                       nvlist_t *perms_nvp;
+
+                       ASSERT(baseza->za_integer_length == 8);
+                       ASSERT(baseza->za_num_integers == 1);
+
+                       perms_nvp = fnvlist_alloc();
+                       for (zap_cursor_init(zc, mos, baseza->za_first_integer);
+                           zap_cursor_retrieve(zc, za) == 0;
+                           zap_cursor_advance(zc)) {
+                               fnvlist_add_boolean(perms_nvp, za->za_name);
+                       }
+                       zap_cursor_fini(zc);
+                       fnvlist_add_nvlist(sp_nvp, baseza->za_name, perms_nvp);
+                       fnvlist_free(perms_nvp);
+               }
+
+               zap_cursor_fini(basezc);
+
+               dsl_dir_name(dd, source);
+               fnvlist_add_nvlist(*nvp, source, sp_nvp);
+               nvlist_free(sp_nvp);
+       }
+
+       kmem_free(source, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
+       kmem_free(baseza, sizeof (zap_attribute_t));
+       kmem_free(basezc, sizeof (zap_cursor_t));
+       kmem_free(za, sizeof (zap_attribute_t));
+       kmem_free(zc, sizeof (zap_cursor_t));
+
+       dsl_dir_rele(startdd, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (0);
+}
+
+/*
+ * Routines for dsl_deleg_access() -- access checking.
+ */
+typedef struct perm_set {
+       avl_node_t      p_node;
+       boolean_t       p_matched;
+       char            p_setname[ZFS_MAX_DELEG_NAME];
+} perm_set_t;
+
+static int
+perm_set_compare(const void *arg1, const void *arg2)
+{
+       const perm_set_t *node1 = arg1;
+       const perm_set_t *node2 = arg2;
+       int val;
+
+       val = strcmp(node1->p_setname, node2->p_setname);
+       if (val == 0)
+               return (0);
+       return (val > 0 ? 1 : -1);
+}
+
+/*
+ * Determine whether a specified permission exists.
+ *
+ * First the base attribute has to be retrieved.  i.e. ul$12
+ * Once the base object has been retrieved the actual permission
+ * is lookup up in the zap object the base object points to.
+ *
+ * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
+ * there is no perm in that jumpobj.
+ */
+static int
+dsl_check_access(objset_t *mos, uint64_t zapobj,
+    char type, char checkflag, void *valp, const char *perm)
+{
+       int error;
+       uint64_t jumpobj, zero;
+       char whokey[ZFS_MAX_DELEG_NAME];
+
+       zfs_deleg_whokey(whokey, type, checkflag, valp);
+       error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
+       if (error == 0) {
+               error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
+               if (error == ENOENT)
+                       error = SET_ERROR(EPERM);
+       }
+       return (error);
+}
+
+/*
+ * check a specified user/group for a requested permission
+ */
+static int
+dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
+    int checkflag, cred_t *cr)
+{
+       const   gid_t *gids;
+       int     ngids;
+       int     i;
+       uint64_t id;
+
+       /* check for user */
+       id = crgetuid(cr);
+       if (dsl_check_access(mos, zapobj,
+           ZFS_DELEG_USER, checkflag, &id, perm) == 0)
+               return (0);
+
+       /* check for users primary group */
+       id = crgetgid(cr);
+       if (dsl_check_access(mos, zapobj,
+           ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
+               return (0);
+
+       /* check for everyone entry */
+       id = -1;
+       if (dsl_check_access(mos, zapobj,
+           ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
+               return (0);
+
+       /* check each supplemental group user is a member of */
+       ngids = crgetngroups(cr);
+       gids = crgetgroups(cr);
+       for (i = 0; i != ngids; i++) {
+               id = gids[i];
+               if (dsl_check_access(mos, zapobj,
+                   ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
+                       return (0);
+       }
+
+       return (SET_ERROR(EPERM));
+}
+
+/*
+ * Iterate over the sets specified in the specified zapobj
+ * and load them into the permsets avl tree.
+ */
+static int
+dsl_load_sets(objset_t *mos, uint64_t zapobj,
+    char type, char checkflag, void *valp, avl_tree_t *avl)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       perm_set_t *permnode;
+       avl_index_t idx;
+       uint64_t jumpobj;
+       int error;
+       char whokey[ZFS_MAX_DELEG_NAME];
+
+       zfs_deleg_whokey(whokey, type, checkflag, valp);
+
+       error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
+       if (error != 0)
+               return (error);
+
+       for (zap_cursor_init(&zc, mos, jumpobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
+               (void) strlcpy(permnode->p_setname, za.za_name,
+                   sizeof (permnode->p_setname));
+               permnode->p_matched = B_FALSE;
+
+               if (avl_find(avl, permnode, &idx) == NULL) {
+                       avl_insert(avl, permnode, idx);
+               } else {
+                       kmem_free(permnode, sizeof (perm_set_t));
+               }
+       }
+       zap_cursor_fini(&zc);
+       return (0);
+}
+
+/*
+ * Load all permissions user based on cred belongs to.
+ */
+static void
+dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
+    char checkflag, cred_t *cr)
+{
+       const   gid_t *gids;
+       int     ngids, i;
+       uint64_t id;
+
+       id = crgetuid(cr);
+       (void) dsl_load_sets(mos, zapobj,
+           ZFS_DELEG_USER_SETS, checkflag, &id, avl);
+
+       id = crgetgid(cr);
+       (void) dsl_load_sets(mos, zapobj,
+           ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
+
+       (void) dsl_load_sets(mos, zapobj,
+           ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
+
+       ngids = crgetngroups(cr);
+       gids = crgetgroups(cr);
+       for (i = 0; i != ngids; i++) {
+               id = gids[i];
+               (void) dsl_load_sets(mos, zapobj,
+                   ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
+       }
+}
+
+/*
+ * Check if user has requested permission.
+ */
+int
+dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
+{
+       dsl_dir_t *dd;
+       dsl_pool_t *dp;
+       void *cookie;
+       int     error;
+       char    checkflag;
+       objset_t *mos;
+       avl_tree_t permsets;
+       perm_set_t *setnode;
+
+       dp = ds->ds_dir->dd_pool;
+       mos = dp->dp_meta_objset;
+
+       if (dsl_delegation_on(mos) == B_FALSE)
+               return (SET_ERROR(ECANCELED));
+
+       if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
+           SPA_VERSION_DELEGATED_PERMS)
+               return (SET_ERROR(EPERM));
+
+       if (ds->ds_is_snapshot) {
+               /*
+                * Snapshots are treated as descendents only,
+                * local permissions do not apply.
+                */
+               checkflag = ZFS_DELEG_DESCENDENT;
+       } else {
+               checkflag = ZFS_DELEG_LOCAL;
+       }
+
+       avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
+           offsetof(perm_set_t, p_node));
+
+       ASSERT(dsl_pool_config_held(dp));
+       for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
+           checkflag = ZFS_DELEG_DESCENDENT) {
+               uint64_t zapobj;
+               boolean_t expanded;
+
+               /*
+                * If not in global zone then make sure
+                * the zoned property is set
+                */
+               if (!INGLOBALZONE(curproc)) {
+                       uint64_t zoned;
+
+                       if (dsl_prop_get_dd(dd,
+                           zfs_prop_to_name(ZFS_PROP_ZONED),
+                           8, 1, &zoned, NULL, B_FALSE) != 0)
+                               break;
+                       if (!zoned)
+                               break;
+               }
+               zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
+
+               if (zapobj == 0)
+                       continue;
+
+               dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
+again:
+               expanded = B_FALSE;
+               for (setnode = avl_first(&permsets); setnode;
+                   setnode = AVL_NEXT(&permsets, setnode)) {
+                       if (setnode->p_matched == B_TRUE)
+                               continue;
+
+                       /* See if this set directly grants this permission */
+                       error = dsl_check_access(mos, zapobj,
+                           ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm);
+                       if (error == 0)
+                               goto success;
+                       if (error == EPERM)
+                               setnode->p_matched = B_TRUE;
+
+                       /* See if this set includes other sets */
+                       error = dsl_load_sets(mos, zapobj,
+                           ZFS_DELEG_NAMED_SET_SETS, 0,
+                           setnode->p_setname, &permsets);
+                       if (error == 0)
+                               setnode->p_matched = expanded = B_TRUE;
+               }
+               /*
+                * If we expanded any sets, that will define more sets,
+                * which we need to check.
+                */
+               if (expanded)
+                       goto again;
+
+               error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
+               if (error == 0)
+                       goto success;
+       }
+       error = SET_ERROR(EPERM);
+success:
+
+       cookie = NULL;
+       while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
+               kmem_free(setnode, sizeof (perm_set_t));
+
+       return (error);
+}
+
+int
+dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int error;
+
+       error = dsl_pool_hold(dsname, FTAG, &dp);
+       if (error != 0)
+               return (error);
+       error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+       if (error == 0) {
+               error = dsl_deleg_access_impl(ds, perm, cr);
+               dsl_dataset_rele(ds, FTAG);
+       }
+       dsl_pool_rele(dp, FTAG);
+
+       return (error);
+}
+
+/*
+ * Other routines.
+ */
+
+static void
+copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
+    boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
+{
+       objset_t *mos = dd->dd_pool->dp_meta_objset;
+       uint64_t jumpobj, pjumpobj;
+       uint64_t zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       char whokey[ZFS_MAX_DELEG_NAME];
+
+       zfs_deleg_whokey(whokey,
+           dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
+           ZFS_DELEG_LOCAL, NULL);
+       if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
+               return;
+
+       if (zapobj == 0) {
+               dmu_buf_will_dirty(dd->dd_dbuf, tx);
+               zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
+                   DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
+       }
+
+       zfs_deleg_whokey(whokey,
+           dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
+           ZFS_DELEG_LOCAL, &uid);
+       if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
+               jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
+               VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
+       }
+
+       for (zap_cursor_init(&zc, mos, pjumpobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               uint64_t zero = 0;
+               ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
+
+               VERIFY(zap_update(mos, jumpobj, za.za_name,
+                   8, 1, &zero, tx) == 0);
+       }
+       zap_cursor_fini(&zc);
+}
+
+/*
+ * set all create time permission on new dataset.
+ */
+void
+dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
+{
+       dsl_dir_t *dd;
+       uint64_t uid = crgetuid(cr);
+
+       if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
+           SPA_VERSION_DELEGATED_PERMS)
+               return;
+
+       for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
+               uint64_t pzapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
+
+               if (pzapobj == 0)
+                       continue;
+
+               copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
+               copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
+       }
+}
+
+int
+dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+
+       if (zapobj == 0)
+               return (0);
+
+       for (zap_cursor_init(&zc, mos, zapobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
+               VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx));
+       }
+       zap_cursor_fini(&zc);
+       VERIFY(0 == zap_destroy(mos, zapobj, tx));
+       return (0);
+}
+
+boolean_t
+dsl_delegation_on(objset_t *os)
+{
+       return (!!spa_delegation(os->os_spa));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_deleg_get);
+EXPORT_SYMBOL(dsl_deleg_set);
+#endif
diff --git a/zfs/module/zfs/dsl_destroy.c b/zfs/module/zfs/dsl_destroy.c
new file mode 100644 (file)
index 0000000..34d076e
--- /dev/null
@@ -0,0 +1,990 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dsl_userhold.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dir.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_scan.h>
+#include <sys/dmu_objset.h>
+#include <sys/zap.h>
+#include <sys/zfeature.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/dsl_deleg.h>
+#include <sys/dmu_impl.h>
+#include <sys/zvol.h>
+
+typedef struct dmu_snapshots_destroy_arg {
+       nvlist_t *dsda_snaps;
+       nvlist_t *dsda_successful_snaps;
+       boolean_t dsda_defer;
+       nvlist_t *dsda_errlist;
+} dmu_snapshots_destroy_arg_t;
+
+int
+dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
+{
+       if (!ds->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       if (dsl_dataset_long_held(ds))
+               return (SET_ERROR(EBUSY));
+
+       /*
+        * Only allow deferred destroy on pools that support it.
+        * NOTE: deferred destroy is only supported on snapshots.
+        */
+       if (defer) {
+               if (spa_version(ds->ds_dir->dd_pool->dp_spa) <
+                   SPA_VERSION_USERREFS)
+                       return (SET_ERROR(ENOTSUP));
+               return (0);
+       }
+
+       /*
+        * If this snapshot has an elevated user reference count,
+        * we can't destroy it yet.
+        */
+       if (ds->ds_userrefs > 0)
+               return (SET_ERROR(EBUSY));
+
+       /*
+        * Can't delete a branch point.
+        */
+       if (dsl_dataset_phys(ds)->ds_num_children > 1)
+               return (SET_ERROR(EEXIST));
+
+       return (0);
+}
+
+static int
+dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx)
+{
+       dmu_snapshots_destroy_arg_t *dsda = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvpair_t *pair;
+       int error = 0;
+
+       if (!dmu_tx_is_syncing(tx))
+               return (0);
+
+       for (pair = nvlist_next_nvpair(dsda->dsda_snaps, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(dsda->dsda_snaps, pair)) {
+               dsl_dataset_t *ds;
+
+               error = dsl_dataset_hold(dp, nvpair_name(pair),
+                   FTAG, &ds);
+
+               /*
+                * If the snapshot does not exist, silently ignore it
+                * (it's "already destroyed").
+                */
+               if (error == ENOENT)
+                       continue;
+
+               if (error == 0) {
+                       error = dsl_destroy_snapshot_check_impl(ds,
+                           dsda->dsda_defer);
+                       dsl_dataset_rele(ds, FTAG);
+               }
+
+               if (error == 0) {
+                       fnvlist_add_boolean(dsda->dsda_successful_snaps,
+                           nvpair_name(pair));
+               } else {
+                       fnvlist_add_int32(dsda->dsda_errlist,
+                           nvpair_name(pair), error);
+               }
+       }
+
+       pair = nvlist_next_nvpair(dsda->dsda_errlist, NULL);
+       if (pair != NULL)
+               return (fnvpair_value_int32(pair));
+
+       return (0);
+}
+
+struct process_old_arg {
+       dsl_dataset_t *ds;
+       dsl_dataset_t *ds_prev;
+       boolean_t after_branch_point;
+       zio_t *pio;
+       uint64_t used, comp, uncomp;
+};
+
+static int
+process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       struct process_old_arg *poa = arg;
+       dsl_pool_t *dp = poa->ds->ds_dir->dd_pool;
+
+       ASSERT(!BP_IS_HOLE(bp));
+
+       if (bp->blk_birth <= dsl_dataset_phys(poa->ds)->ds_prev_snap_txg) {
+               dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx);
+               if (poa->ds_prev && !poa->after_branch_point &&
+                   bp->blk_birth >
+                   dsl_dataset_phys(poa->ds_prev)->ds_prev_snap_txg) {
+                       dsl_dataset_phys(poa->ds_prev)->ds_unique_bytes +=
+                           bp_get_dsize_sync(dp->dp_spa, bp);
+               }
+       } else {
+               poa->used += bp_get_dsize_sync(dp->dp_spa, bp);
+               poa->comp += BP_GET_PSIZE(bp);
+               poa->uncomp += BP_GET_UCSIZE(bp);
+               dsl_free_sync(poa->pio, dp, tx->tx_txg, bp);
+       }
+       return (0);
+}
+
+static void
+process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev,
+    dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx)
+{
+       struct process_old_arg poa = { 0 };
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       objset_t *mos = dp->dp_meta_objset;
+       uint64_t deadlist_obj;
+
+       ASSERT(ds->ds_deadlist.dl_oldfmt);
+       ASSERT(ds_next->ds_deadlist.dl_oldfmt);
+
+       poa.ds = ds;
+       poa.ds_prev = ds_prev;
+       poa.after_branch_point = after_branch_point;
+       poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
+       VERIFY0(bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj,
+           process_old_cb, &poa, tx));
+       VERIFY0(zio_wait(poa.pio));
+       ASSERT3U(poa.used, ==, dsl_dataset_phys(ds)->ds_unique_bytes);
+
+       /* change snapused */
+       dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP,
+           -poa.used, -poa.comp, -poa.uncomp, tx);
+
+       /* swap next's deadlist to our deadlist */
+       dsl_deadlist_close(&ds->ds_deadlist);
+       dsl_deadlist_close(&ds_next->ds_deadlist);
+       deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj;
+       dsl_dataset_phys(ds)->ds_deadlist_obj =
+           dsl_dataset_phys(ds_next)->ds_deadlist_obj;
+       dsl_dataset_phys(ds_next)->ds_deadlist_obj = deadlist_obj;
+       dsl_deadlist_open(&ds->ds_deadlist, mos,
+           dsl_dataset_phys(ds)->ds_deadlist_obj);
+       dsl_deadlist_open(&ds_next->ds_deadlist, mos,
+           dsl_dataset_phys(ds_next)->ds_deadlist_obj);
+}
+
+static void
+dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       zap_cursor_t *zc;
+       zap_attribute_t *za;
+
+       /*
+        * If it is the old version, dd_clones doesn't exist so we can't
+        * find the clones, but dsl_deadlist_remove_key() is a no-op so it
+        * doesn't matter.
+        */
+       if (dsl_dir_phys(ds->ds_dir)->dd_clones == 0)
+               return;
+
+       zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
+       za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+
+       for (zap_cursor_init(zc, mos, dsl_dir_phys(ds->ds_dir)->dd_clones);
+           zap_cursor_retrieve(zc, za) == 0;
+           zap_cursor_advance(zc)) {
+               dsl_dataset_t *clone;
+
+               VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
+                   za->za_first_integer, FTAG, &clone));
+               if (clone->ds_dir->dd_origin_txg > mintxg) {
+                       dsl_deadlist_remove_key(&clone->ds_deadlist,
+                           mintxg, tx);
+                       dsl_dataset_remove_clones_key(clone, mintxg, tx);
+               }
+               dsl_dataset_rele(clone, FTAG);
+       }
+       zap_cursor_fini(zc);
+
+       kmem_free(za, sizeof (zap_attribute_t));
+       kmem_free(zc, sizeof (zap_cursor_t));
+}
+
+void
+dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
+{
+       int after_branch_point = FALSE;
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       objset_t *mos = dp->dp_meta_objset;
+       dsl_dataset_t *ds_prev = NULL;
+       uint64_t obj, old_unique, used = 0, comp = 0, uncomp = 0;
+       dsl_dataset_t *ds_next, *ds_head, *hds;
+
+
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+       ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg);
+       ASSERT(refcount_is_zero(&ds->ds_longholds));
+
+       if (defer &&
+           (ds->ds_userrefs > 0 ||
+           dsl_dataset_phys(ds)->ds_num_children > 1)) {
+               ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY;
+               spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
+               return;
+       }
+
+       ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1);
+
+       /* We need to log before removing it from the namespace. */
+       spa_history_log_internal_ds(ds, "destroy", tx, "");
+
+       dsl_scan_ds_destroyed(ds, 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);
+       }
+       if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
+               ASSERT3P(ds->ds_prev, ==, NULL);
+               VERIFY0(dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev));
+               after_branch_point =
+                   (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj);
+
+               dmu_buf_will_dirty(ds_prev->ds_dbuf, tx);
+               if (after_branch_point &&
+                   dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) {
+                       dsl_dataset_remove_from_next_clones(ds_prev, obj, tx);
+                       if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) {
+                               VERIFY0(zap_add_int(mos,
+                                   dsl_dataset_phys(ds_prev)->
+                                   ds_next_clones_obj,
+                                   dsl_dataset_phys(ds)->ds_next_snap_obj,
+                                   tx));
+                       }
+               }
+               if (!after_branch_point) {
+                       dsl_dataset_phys(ds_prev)->ds_next_snap_obj =
+                           dsl_dataset_phys(ds)->ds_next_snap_obj;
+               }
+       }
+
+       VERIFY0(dsl_dataset_hold_obj(dp,
+           dsl_dataset_phys(ds)->ds_next_snap_obj, FTAG, &ds_next));
+       ASSERT3U(dsl_dataset_phys(ds_next)->ds_prev_snap_obj, ==, obj);
+
+       old_unique = dsl_dataset_phys(ds_next)->ds_unique_bytes;
+
+       dmu_buf_will_dirty(ds_next->ds_dbuf, tx);
+       dsl_dataset_phys(ds_next)->ds_prev_snap_obj =
+           dsl_dataset_phys(ds)->ds_prev_snap_obj;
+       dsl_dataset_phys(ds_next)->ds_prev_snap_txg =
+           dsl_dataset_phys(ds)->ds_prev_snap_txg;
+       ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==,
+           ds_prev ? dsl_dataset_phys(ds_prev)->ds_creation_txg : 0);
+
+       if (ds_next->ds_deadlist.dl_oldfmt) {
+               process_old_deadlist(ds, ds_prev, ds_next,
+                   after_branch_point, tx);
+       } else {
+               /* Adjust prev's unique space. */
+               if (ds_prev && !after_branch_point) {
+                       dsl_deadlist_space_range(&ds_next->ds_deadlist,
+                           dsl_dataset_phys(ds_prev)->ds_prev_snap_txg,
+                           dsl_dataset_phys(ds)->ds_prev_snap_txg,
+                           &used, &comp, &uncomp);
+                       dsl_dataset_phys(ds_prev)->ds_unique_bytes += used;
+               }
+
+               /* Adjust snapused. */
+               dsl_deadlist_space_range(&ds_next->ds_deadlist,
+                   dsl_dataset_phys(ds)->ds_prev_snap_txg, UINT64_MAX,
+                   &used, &comp, &uncomp);
+               dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP,
+                   -used, -comp, -uncomp, tx);
+
+               /* Move blocks to be freed to pool's free list. */
+               dsl_deadlist_move_bpobj(&ds_next->ds_deadlist,
+                   &dp->dp_free_bpobj, dsl_dataset_phys(ds)->ds_prev_snap_txg,
+                   tx);
+               dsl_dir_diduse_space(tx->tx_pool->dp_free_dir,
+                   DD_USED_HEAD, used, comp, uncomp, tx);
+
+               /* Merge our deadlist into next's and free it. */
+               dsl_deadlist_merge(&ds_next->ds_deadlist,
+                   dsl_dataset_phys(ds)->ds_deadlist_obj, tx);
+       }
+       dsl_deadlist_close(&ds->ds_deadlist);
+       dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx);
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_deadlist_obj = 0;
+
+       /* Collapse range in clone heads */
+       dsl_dataset_remove_clones_key(ds,
+           dsl_dataset_phys(ds)->ds_creation_txg, tx);
+
+       if (ds_next->ds_is_snapshot) {
+               dsl_dataset_t *ds_nextnext;
+
+               /*
+                * Update next's unique to include blocks which
+                * were previously shared by only this snapshot
+                * and it.  Those blocks will be born after the
+                * prev snap and before this snap, and will have
+                * died after the next snap and before the one
+                * after that (ie. be on the snap after next's
+                * deadlist).
+                */
+               VERIFY0(dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(ds_next)->ds_next_snap_obj,
+                   FTAG, &ds_nextnext));
+               dsl_deadlist_space_range(&ds_nextnext->ds_deadlist,
+                   dsl_dataset_phys(ds)->ds_prev_snap_txg,
+                   dsl_dataset_phys(ds)->ds_creation_txg,
+                   &used, &comp, &uncomp);
+               dsl_dataset_phys(ds_next)->ds_unique_bytes += used;
+               dsl_dataset_rele(ds_nextnext, FTAG);
+               ASSERT3P(ds_next->ds_prev, ==, NULL);
+
+               /* Collapse range in this head. */
+               VERIFY0(dsl_dataset_hold_obj(dp,
+                   dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &hds));
+               dsl_deadlist_remove_key(&hds->ds_deadlist,
+                   dsl_dataset_phys(ds)->ds_creation_txg, tx);
+               dsl_dataset_rele(hds, FTAG);
+
+       } else {
+               ASSERT3P(ds_next->ds_prev, ==, ds);
+               dsl_dataset_rele(ds_next->ds_prev, ds_next);
+               ds_next->ds_prev = NULL;
+               if (ds_prev) {
+                       VERIFY0(dsl_dataset_hold_obj(dp,
+                           dsl_dataset_phys(ds)->ds_prev_snap_obj,
+                           ds_next, &ds_next->ds_prev));
+               }
+
+               dsl_dataset_recalc_head_uniq(ds_next);
+
+               /*
+                * Reduce the amount of our unconsumed refreservation
+                * being charged to our parent by the amount of
+                * new unique data we have gained.
+                */
+               if (old_unique < ds_next->ds_reserved) {
+                       int64_t mrsdelta;
+                       uint64_t new_unique =
+                           dsl_dataset_phys(ds_next)->ds_unique_bytes;
+
+                       ASSERT(old_unique <= new_unique);
+                       mrsdelta = MIN(new_unique - old_unique,
+                           ds_next->ds_reserved - old_unique);
+                       dsl_dir_diduse_space(ds->ds_dir,
+                           DD_USED_REFRSRV, -mrsdelta, 0, 0, tx);
+               }
+       }
+       dsl_dataset_rele(ds_next, FTAG);
+
+       /*
+        * This must be done after the dsl_traverse(), because it will
+        * re-open the objset.
+        */
+       if (ds->ds_objset) {
+               dmu_objset_evict(ds->ds_objset);
+               ds->ds_objset = NULL;
+       }
+
+       /* remove from snapshot namespace */
+       ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0);
+       VERIFY0(dsl_dataset_hold_obj(dp,
+           dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &ds_head));
+       VERIFY0(dsl_dataset_get_snapname(ds));
+#ifdef ZFS_DEBUG
+       {
+               uint64_t val;
+               int err;
+
+               err = dsl_dataset_snap_lookup(ds_head,
+                   ds->ds_snapname, &val);
+               ASSERT0(err);
+               ASSERT3U(val, ==, obj);
+       }
+#endif
+       VERIFY0(dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx, B_TRUE));
+       dsl_dataset_rele(ds_head, FTAG);
+
+       if (ds_prev != NULL)
+               dsl_dataset_rele(ds_prev, FTAG);
+
+       spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
+
+       if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) {
+               ASSERTV(uint64_t count);
+               ASSERT0(zap_count(mos,
+                   dsl_dataset_phys(ds)->ds_next_clones_obj, &count) &&
+                   count == 0);
+               VERIFY0(dmu_object_free(mos,
+                   dsl_dataset_phys(ds)->ds_next_clones_obj, tx));
+       }
+       if (dsl_dataset_phys(ds)->ds_props_obj != 0)
+               VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_props_obj,
+                   tx));
+       if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0)
+               VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_userrefs_obj,
+                   tx));
+       dsl_dir_rele(ds->ds_dir, ds);
+       ds->ds_dir = NULL;
+       dmu_object_free_zapified(mos, obj, tx);
+}
+
+static void
+dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx)
+{
+       dmu_snapshots_destroy_arg_t *dsda = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvpair_t *pair;
+
+       for (pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, NULL);
+           pair != NULL;
+           pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, pair)) {
+               dsl_dataset_t *ds;
+
+               VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
+
+               dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx);
+               zvol_remove_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
+               dsl_dataset_rele(ds, FTAG);
+       }
+}
+
+/*
+ * The semantics of this function are described in the comment above
+ * lzc_destroy_snaps().  To summarize:
+ *
+ * The snapshots must all be in the same pool.
+ *
+ * Snapshots that don't exist will be silently ignored (considered to be
+ * "already deleted").
+ *
+ * On success, all snaps will be destroyed and this will return 0.
+ * On failure, no snaps will be destroyed, the errlist will be filled in,
+ * and this will return an errno.
+ */
+int
+dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer,
+    nvlist_t *errlist)
+{
+       dmu_snapshots_destroy_arg_t dsda;
+       int error;
+       nvpair_t *pair;
+
+       pair = nvlist_next_nvpair(snaps, NULL);
+       if (pair == NULL)
+               return (0);
+
+       dsda.dsda_snaps = snaps;
+       VERIFY0(nvlist_alloc(&dsda.dsda_successful_snaps,
+           NV_UNIQUE_NAME, KM_SLEEP));
+       dsda.dsda_defer = defer;
+       dsda.dsda_errlist = errlist;
+
+       error = dsl_sync_task(nvpair_name(pair),
+           dsl_destroy_snapshot_check, dsl_destroy_snapshot_sync,
+           &dsda, 0, ZFS_SPACE_CHECK_NONE);
+       fnvlist_free(dsda.dsda_successful_snaps);
+
+       return (error);
+}
+
+int
+dsl_destroy_snapshot(const char *name, boolean_t defer)
+{
+       int error;
+       nvlist_t *nvl = fnvlist_alloc();
+       nvlist_t *errlist = fnvlist_alloc();
+
+       fnvlist_add_boolean(nvl, name);
+       error = dsl_destroy_snapshots_nvl(nvl, defer, errlist);
+       fnvlist_free(errlist);
+       fnvlist_free(nvl);
+       return (error);
+}
+
+struct killarg {
+       dsl_dataset_t *ds;
+       dmu_tx_t *tx;
+};
+
+/* ARGSUSED */
+static int
+kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       struct killarg *ka = arg;
+       dmu_tx_t *tx = ka->tx;
+
+       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+               return (0);
+
+       if (zb->zb_level == ZB_ZIL_LEVEL) {
+               ASSERT(zilog != NULL);
+               /*
+                * It's a block in the intent log.  It has no
+                * accounting, so just free it.
+                */
+               dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp);
+       } else {
+               ASSERT(zilog == NULL);
+               ASSERT3U(bp->blk_birth, >,
+                   dsl_dataset_phys(ka->ds)->ds_prev_snap_txg);
+               (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE);
+       }
+
+       return (0);
+}
+
+static void
+old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       struct killarg ka;
+
+       /*
+        * Free everything that we point to (that's born after
+        * the previous snapshot, if we are a clone)
+        *
+        * NB: this should be very quick, because we already
+        * freed all the objects in open context.
+        */
+       ka.ds = ds;
+       ka.tx = tx;
+       VERIFY0(traverse_dataset(ds,
+           dsl_dataset_phys(ds)->ds_prev_snap_txg, TRAVERSE_POST,
+           kill_blkptr, &ka));
+       ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) ||
+           dsl_dataset_phys(ds)->ds_unique_bytes == 0);
+}
+
+typedef struct dsl_destroy_head_arg {
+       const char *ddha_name;
+} dsl_destroy_head_arg_t;
+
+int
+dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds)
+{
+       int error;
+       uint64_t count;
+       objset_t *mos;
+
+       ASSERT(!ds->ds_is_snapshot);
+       if (ds->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       if (refcount_count(&ds->ds_longholds) != expected_holds)
+               return (SET_ERROR(EBUSY));
+
+       mos = ds->ds_dir->dd_pool->dp_meta_objset;
+
+       /*
+        * Can't delete a head dataset if there are snapshots of it.
+        * (Except if the only snapshots are from the branch we cloned
+        * from.)
+        */
+       if (ds->ds_prev != NULL &&
+           dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj == ds->ds_object)
+               return (SET_ERROR(EBUSY));
+
+       /*
+        * Can't delete if there are children of this fs.
+        */
+       error = zap_count(mos,
+           dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &count);
+       if (error != 0)
+               return (error);
+       if (count != 0)
+               return (SET_ERROR(EEXIST));
+
+       if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev) &&
+           dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 &&
+           ds->ds_prev->ds_userrefs == 0) {
+               /* We need to remove the origin snapshot as well. */
+               if (!refcount_is_zero(&ds->ds_prev->ds_longholds))
+                       return (SET_ERROR(EBUSY));
+       }
+       return (0);
+}
+
+static int
+dsl_destroy_head_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_destroy_head_arg_t *ddha = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       int error;
+
+       error = dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       error = dsl_destroy_head_check_impl(ds, 0);
+       dsl_dataset_rele(ds, FTAG);
+       return (error);
+}
+
+static void
+dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx)
+{
+       dsl_dir_t *dd;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       dd_used_t t;
+
+       ASSERT(RRW_WRITE_HELD(&dmu_tx_pool(tx)->dp_config_rwlock));
+
+       VERIFY0(dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd));
+
+       ASSERT0(dsl_dir_phys(dd)->dd_head_dataset_obj);
+
+       /*
+        * Decrement the filesystem count for all parent filesystems.
+        *
+        * When we receive an incremental stream into a filesystem that already
+        * exists, a temporary clone is created.  We never count this temporary
+        * clone, whose name begins with a '%'.
+        */
+       if (dd->dd_myname[0] != '%' && dd->dd_parent != NULL)
+               dsl_fs_ss_count_adjust(dd->dd_parent, -1,
+                   DD_FIELD_FILESYSTEM_COUNT, tx);
+
+       /*
+        * Remove our reservation. The impl() routine avoids setting the
+        * actual property, which would require the (already destroyed) ds.
+        */
+       dsl_dir_set_reservation_sync_impl(dd, 0, tx);
+
+       ASSERT0(dsl_dir_phys(dd)->dd_used_bytes);
+       ASSERT0(dsl_dir_phys(dd)->dd_reserved);
+       for (t = 0; t < DD_USED_NUM; t++)
+               ASSERT0(dsl_dir_phys(dd)->dd_used_breakdown[t]);
+
+       VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_child_dir_zapobj, tx));
+       VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_props_zapobj, tx));
+       VERIFY0(dsl_deleg_destroy(mos, dsl_dir_phys(dd)->dd_deleg_zapobj, tx));
+       VERIFY0(zap_remove(mos,
+           dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj,
+           dd->dd_myname, tx));
+
+       dsl_dir_rele(dd, FTAG);
+       dmu_object_free_zapified(mos, ddobj, tx);
+}
+
+void
+dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       uint64_t obj, ddobj, prevobj = 0;
+       boolean_t rmorigin;
+       objset_t *os;
+
+       ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1);
+       ASSERT(ds->ds_prev == NULL ||
+           dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj != ds->ds_object);
+       ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg);
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+
+       /* We need to log before removing it from the namespace. */
+       spa_history_log_internal_ds(ds, "destroy", tx, "");
+
+       rmorigin = (dsl_dir_is_clone(ds->ds_dir) &&
+           DS_IS_DEFER_DESTROY(ds->ds_prev) &&
+           dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 &&
+           ds->ds_prev->ds_userrefs == 0);
+
+       /* Remove our reservation. */
+       if (ds->ds_reserved != 0) {
+               dsl_dataset_set_refreservation_sync_impl(ds,
+                   (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED),
+                   0, tx);
+               ASSERT0(ds->ds_reserved);
+       }
+
+       if (ds->ds_large_blocks)
+               spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
+
+       dsl_scan_ds_destroyed(ds, tx);
+
+       obj = ds->ds_object;
+
+       if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
+               /* This is a clone */
+               ASSERT(ds->ds_prev != NULL);
+               ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj, !=,
+                   obj);
+               ASSERT0(dsl_dataset_phys(ds)->ds_next_snap_obj);
+
+               dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
+               if (dsl_dataset_phys(ds->ds_prev)->ds_next_clones_obj != 0) {
+                       dsl_dataset_remove_from_next_clones(ds->ds_prev,
+                           obj, tx);
+               }
+
+               ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_num_children, >, 1);
+               dsl_dataset_phys(ds->ds_prev)->ds_num_children--;
+       }
+
+       /*
+        * Destroy the deadlist.  Unless it's a clone, the
+        * deadlist should be empty.  (If it's a clone, it's
+        * safe to ignore the deadlist contents.)
+        */
+       dsl_deadlist_close(&ds->ds_deadlist);
+       dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx);
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_deadlist_obj = 0;
+
+       VERIFY0(dmu_objset_from_ds(ds, &os));
+
+       if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) {
+               old_synchronous_dataset_destroy(ds, tx);
+       } else {
+               /*
+                * Move the bptree into the pool's list of trees to
+                * clean up and update space accounting information.
+                */
+               uint64_t used, comp, uncomp;
+
+               zil_destroy_sync(dmu_objset_zil(os), tx);
+
+               if (!spa_feature_is_active(dp->dp_spa,
+                   SPA_FEATURE_ASYNC_DESTROY)) {
+                       dsl_scan_t *scn = dp->dp_scan;
+                       spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY,
+                           tx);
+                       dp->dp_bptree_obj = bptree_alloc(mos, tx);
+                       VERIFY0(zap_add(mos,
+                           DMU_POOL_DIRECTORY_OBJECT,
+                           DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1,
+                           &dp->dp_bptree_obj, tx));
+                       ASSERT(!scn->scn_async_destroying);
+                       scn->scn_async_destroying = B_TRUE;
+               }
+
+               used = dsl_dir_phys(ds->ds_dir)->dd_used_bytes;
+               comp = dsl_dir_phys(ds->ds_dir)->dd_compressed_bytes;
+               uncomp = dsl_dir_phys(ds->ds_dir)->dd_uncompressed_bytes;
+
+               ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) ||
+                   dsl_dataset_phys(ds)->ds_unique_bytes == used);
+
+               bptree_add(mos, dp->dp_bptree_obj,
+                   &dsl_dataset_phys(ds)->ds_bp,
+                   dsl_dataset_phys(ds)->ds_prev_snap_txg,
+                   used, comp, uncomp, tx);
+               dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD,
+                   -used, -comp, -uncomp, tx);
+               dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD,
+                   used, comp, uncomp, tx);
+       }
+
+       if (ds->ds_prev != NULL) {
+               if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) {
+                       VERIFY0(zap_remove_int(mos,
+                           dsl_dir_phys(ds->ds_prev->ds_dir)->dd_clones,
+                           ds->ds_object, tx));
+               }
+               prevobj = ds->ds_prev->ds_object;
+               dsl_dataset_rele(ds->ds_prev, ds);
+               ds->ds_prev = NULL;
+       }
+
+       /*
+        * This must be done after the dsl_traverse(), because it will
+        * re-open the objset.
+        */
+       if (ds->ds_objset) {
+               dmu_objset_evict(ds->ds_objset);
+               ds->ds_objset = NULL;
+       }
+
+       /* Erase the link in the dir */
+       dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx);
+       dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj = 0;
+       ddobj = ds->ds_dir->dd_object;
+       ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0);
+       VERIFY0(zap_destroy(mos,
+           dsl_dataset_phys(ds)->ds_snapnames_zapobj, tx));
+
+       if (ds->ds_bookmarks != 0) {
+               VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx));
+               spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);
+       }
+
+       spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
+
+       ASSERT0(dsl_dataset_phys(ds)->ds_next_clones_obj);
+       ASSERT0(dsl_dataset_phys(ds)->ds_props_obj);
+       ASSERT0(dsl_dataset_phys(ds)->ds_userrefs_obj);
+       dsl_dir_rele(ds->ds_dir, ds);
+       ds->ds_dir = NULL;
+       dmu_object_free_zapified(mos, obj, tx);
+
+       dsl_dir_destroy_sync(ddobj, tx);
+
+       if (rmorigin) {
+               dsl_dataset_t *prev;
+               VERIFY0(dsl_dataset_hold_obj(dp, prevobj, FTAG, &prev));
+               dsl_destroy_snapshot_sync_impl(prev, B_FALSE, tx);
+               dsl_dataset_rele(prev, FTAG);
+       }
+}
+
+static void
+dsl_destroy_head_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_destroy_head_arg_t *ddha = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+
+       VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds));
+       dsl_destroy_head_sync_impl(ds, tx);
+       zvol_remove_minors(dp->dp_spa, ddha->ddha_name, B_TRUE);
+       dsl_dataset_rele(ds, FTAG);
+}
+
+static void
+dsl_destroy_head_begin_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_destroy_head_arg_t *ddha = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+
+       VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds));
+
+       /* Mark it as inconsistent on-disk, in case we crash */
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT;
+
+       spa_history_log_internal_ds(ds, "destroy begin", tx, "");
+       dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_destroy_head(const char *name)
+{
+       dsl_destroy_head_arg_t ddha;
+       int error;
+       spa_t *spa;
+       boolean_t isenabled;
+
+#ifdef _KERNEL
+       zfs_destroy_unmount_origin(name);
+#endif
+
+       error = spa_open(name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+       isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY);
+       spa_close(spa, FTAG);
+
+       ddha.ddha_name = name;
+
+       if (!isenabled) {
+               objset_t *os;
+
+               error = dsl_sync_task(name, dsl_destroy_head_check,
+                   dsl_destroy_head_begin_sync, &ddha,
+                   0, ZFS_SPACE_CHECK_NONE);
+               if (error != 0)
+                       return (error);
+
+               /*
+                * Head deletion is processed in one txg on old pools;
+                * remove the objects from open context so that the txg sync
+                * is not too long.
+                */
+               error = dmu_objset_own(name, DMU_OST_ANY, B_FALSE, FTAG, &os);
+               if (error == 0) {
+                       uint64_t obj;
+                       uint64_t prev_snap_txg =
+                           dsl_dataset_phys(dmu_objset_ds(os))->
+                           ds_prev_snap_txg;
+                       for (obj = 0; error == 0;
+                           error = dmu_object_next(os, &obj, FALSE,
+                           prev_snap_txg))
+                               (void) dmu_free_long_object(os, obj);
+                       /* sync out all frees */
+                       txg_wait_synced(dmu_objset_pool(os), 0);
+                       dmu_objset_disown(os, FTAG);
+               }
+       }
+
+       return (dsl_sync_task(name, dsl_destroy_head_check,
+           dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+/*
+ * Note, this function is used as the callback for dmu_objset_find().  We
+ * always return 0 so that we will continue to find and process
+ * inconsistent datasets, even if we encounter an error trying to
+ * process one of them.
+ */
+/* ARGSUSED */
+int
+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));
+               dmu_objset_rele(os, FTAG);
+               if (inconsistent)
+                       (void) dsl_destroy_head(dsname);
+       }
+       return (0);
+}
+
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_destroy_head);
+EXPORT_SYMBOL(dsl_destroy_head_sync_impl);
+EXPORT_SYMBOL(dsl_dataset_user_hold_check_one);
+EXPORT_SYMBOL(dsl_destroy_snapshot_sync_impl);
+EXPORT_SYMBOL(dsl_destroy_inconsistent);
+EXPORT_SYMBOL(dsl_dataset_user_release_tmp);
+EXPORT_SYMBOL(dsl_destroy_head_check_impl);
+#endif
diff --git a/zfs/module/zfs/dsl_dir.c b/zfs/module/zfs/dsl_dir.c
new file mode 100644 (file)
index 0000000..762e2e5
--- /dev/null
@@ -0,0 +1,2009 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Martin Matuska. All rights reserved.
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dsl_deleg.h>
+#include <sys/dmu_impl.h>
+#include <sys/spa.h>
+#include <sys/metaslab.h>
+#include <sys/zap.h>
+#include <sys/zio.h>
+#include <sys/arc.h>
+#include <sys/sunddi.h>
+#include <sys/zfeature.h>
+#include <sys/policy.h>
+#include <sys/zfs_znode.h>
+#include <sys/zvol.h>
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+
+/*
+ * Filesystem and Snapshot Limits
+ * ------------------------------
+ *
+ * These limits are used to restrict the number of filesystems and/or snapshots
+ * that can be created at a given level in the tree or below. A typical
+ * use-case is with a delegated dataset where the administrator wants to ensure
+ * that a user within the zone is not creating too many additional filesystems
+ * or snapshots, even though they're not exceeding their space quota.
+ *
+ * The filesystem and snapshot counts are stored as extensible properties. This
+ * capability is controlled by a feature flag and must be enabled to be used.
+ * Once enabled, the feature is not active until the first limit is set. At
+ * that point, future operations to create/destroy filesystems or snapshots
+ * will validate and update the counts.
+ *
+ * Because the count properties will not exist before the feature is active,
+ * the counts are updated when a limit is first set on an uninitialized
+ * dsl_dir node in the tree (The filesystem/snapshot count on a node includes
+ * all of the nested filesystems/snapshots. Thus, a new leaf node has a
+ * filesystem count of 0 and a snapshot count of 0. Non-existent filesystem and
+ * snapshot count properties on a node indicate uninitialized counts on that
+ * node.) When first setting a limit on an uninitialized node, the code starts
+ * at the filesystem with the new limit and descends into all sub-filesystems
+ * to add the count properties.
+ *
+ * In practice this is lightweight since a limit is typically set when the
+ * filesystem is created and thus has no children. Once valid, changing the
+ * limit value won't require a re-traversal since the counts are already valid.
+ * When recursively fixing the counts, if a node with a limit is encountered
+ * during the descent, the counts are known to be valid and there is no need to
+ * descend into that filesystem's children. The counts on filesystems above the
+ * one with the new limit will still be uninitialized, unless a limit is
+ * eventually set on one of those filesystems. The counts are always recursively
+ * updated when a limit is set on a dataset, unless there is already a limit.
+ * When a new limit value is set on a filesystem with an existing limit, it is
+ * possible for the new limit to be less than the current count at that level
+ * since a user who can change the limit is also allowed to exceed the limit.
+ *
+ * Once the feature is active, then whenever a filesystem or snapshot is
+ * created, the code recurses up the tree, validating the new count against the
+ * limit at each initialized level. In practice, most levels will not have a
+ * limit set. If there is a limit at any initialized level up the tree, the
+ * check must pass or the creation will fail. Likewise, when a filesystem or
+ * snapshot is destroyed, the counts are recursively adjusted all the way up
+ * the initizized nodes in the tree. Renaming a filesystem into different point
+ * in the tree will first validate, then update the counts on each branch up to
+ * the common ancestor. A receive will also validate the counts and then update
+ * them.
+ *
+ * An exception to the above behavior is that the limit is not enforced if the
+ * user has permission to modify the limit. This is primarily so that
+ * recursive snapshots in the global zone always work. We want to prevent a
+ * denial-of-service in which a lower level delegated dataset could max out its
+ * limit and thus block recursive snapshots from being taken in the global zone.
+ * Because of this, it is possible for the snapshot count to be over the limit
+ * and snapshots taken in the global zone could cause a lower level dataset to
+ * hit or exceed its limit. The administrator taking the global zone recursive
+ * snapshot should be aware of this side-effect and behave accordingly.
+ * For consistency, the filesystem limit is also not enforced if the user can
+ * modify the limit.
+ *
+ * The filesystem and snapshot limits are validated by dsl_fs_ss_limit_check()
+ * and updated by dsl_fs_ss_count_adjust(). A new limit value is setup in
+ * dsl_dir_activate_fs_ss_limit() and the counts are adjusted, if necessary, by
+ * dsl_dir_init_fs_ss_count().
+ *
+ * There is a special case when we receive a filesystem that already exists. In
+ * this case a temporary clone name of %X is created (see dmu_recv_begin). We
+ * never update the filesystem counts for temporary clones.
+ *
+ * Likewise, we do not update the snapshot counts for temporary snapshots,
+ * such as those created by zfs diff.
+ */
+
+extern inline dsl_dir_phys_t *dsl_dir_phys(dsl_dir_t *dd);
+
+static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
+
+static void
+dsl_dir_evict(void *dbu)
+{
+       dsl_dir_t *dd = dbu;
+       int t;
+       ASSERTV(dsl_pool_t *dp = dd->dd_pool);
+
+       dd->dd_dbuf = NULL;
+
+       for (t = 0; t < TXG_SIZE; t++) {
+               ASSERT(!txg_list_member(&dp->dp_dirty_dirs, dd, t));
+               ASSERT(dd->dd_tempreserved[t] == 0);
+               ASSERT(dd->dd_space_towrite[t] == 0);
+       }
+
+       if (dd->dd_parent)
+               dsl_dir_async_rele(dd->dd_parent, dd);
+
+       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);
+       mutex_destroy(&dd->dd_lock);
+       kmem_free(dd, sizeof (dsl_dir_t));
+}
+
+int
+dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
+    const char *tail, void *tag, dsl_dir_t **ddp)
+{
+       dmu_buf_t *dbuf;
+       dsl_dir_t *dd;
+       int err;
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       err = dmu_bonus_hold(dp->dp_meta_objset, ddobj, tag, &dbuf);
+       if (err != 0)
+               return (err);
+       dd = dmu_buf_get_user(dbuf);
+#ifdef ZFS_DEBUG
+       {
+               dmu_object_info_t doi;
+               dmu_object_info_from_db(dbuf, &doi);
+               ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_DSL_DIR);
+               ASSERT3U(doi.doi_bonus_size, >=, sizeof (dsl_dir_phys_t));
+       }
+#endif
+       if (dd == NULL) {
+               dsl_dir_t *winner;
+
+               dd = kmem_zalloc(sizeof (dsl_dir_t), KM_SLEEP);
+               dd->dd_object = 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_dir_snap_cmtime_update(dd);
+
+               if (dsl_dir_phys(dd)->dd_parent_obj) {
+                       err = dsl_dir_hold_obj(dp,
+                           dsl_dir_phys(dd)->dd_parent_obj, NULL, dd,
+                           &dd->dd_parent);
+                       if (err != 0)
+                               goto errout;
+                       if (tail) {
+#ifdef ZFS_DEBUG
+                               uint64_t foundobj;
+
+                               err = zap_lookup(dp->dp_meta_objset,
+                                   dsl_dir_phys(dd->dd_parent)->
+                                   dd_child_dir_zapobj, tail,
+                                   sizeof (foundobj), 1, &foundobj);
+                               ASSERT(err || foundobj == ddobj);
+#endif
+                               (void) strcpy(dd->dd_myname, tail);
+                       } else {
+                               err = zap_value_search(dp->dp_meta_objset,
+                                   dsl_dir_phys(dd->dd_parent)->
+                                   dd_child_dir_zapobj,
+                                   ddobj, 0, dd->dd_myname);
+                       }
+                       if (err != 0)
+                               goto errout;
+               } else {
+                       (void) strcpy(dd->dd_myname, spa_name(dp->dp_spa));
+               }
+
+               if (dsl_dir_is_clone(dd)) {
+                       dmu_buf_t *origin_bonus;
+                       dsl_dataset_phys_t *origin_phys;
+
+                       /*
+                        * We can't open the origin dataset, because
+                        * that would require opening this dsl_dir.
+                        * Just look at its phys directly instead.
+                        */
+                       err = dmu_bonus_hold(dp->dp_meta_objset,
+                           dsl_dir_phys(dd)->dd_origin_obj, FTAG,
+                           &origin_bonus);
+                       if (err != 0)
+                               goto errout;
+                       origin_phys = origin_bonus->db_data;
+                       dd->dd_origin_txg =
+                           origin_phys->ds_creation_txg;
+                       dmu_buf_rele(origin_bonus, FTAG);
+               }
+
+               dmu_buf_init_user(&dd->dd_dbu, dsl_dir_evict, &dd->dd_dbuf);
+               winner = dmu_buf_set_user_ie(dbuf, &dd->dd_dbu);
+               if (winner != NULL) {
+                       if (dd->dd_parent)
+                               dsl_dir_rele(dd->dd_parent, dd);
+                       mutex_destroy(&dd->dd_lock);
+                       kmem_free(dd, sizeof (dsl_dir_t));
+                       dd = winner;
+               } else {
+                       spa_open_ref(dp->dp_spa, dd);
+               }
+       }
+
+       /*
+        * The dsl_dir_t has both open-to-close and instantiate-to-evict
+        * holds on the spa.  We need the open-to-close holds because
+        * otherwise the spa_refcnt wouldn't change when we open a
+        * dir which the spa also has open, so we could incorrectly
+        * think it was OK to unload/export/destroy the pool.  We need
+        * the instantiate-to-evict hold because the dsl_dir_t has a
+        * pointer to the dd_pool, which has a pointer to the spa_t.
+        */
+       spa_open_ref(dp->dp_spa, tag);
+       ASSERT3P(dd->dd_pool, ==, dp);
+       ASSERT3U(dd->dd_object, ==, ddobj);
+       ASSERT3P(dd->dd_dbuf, ==, dbuf);
+       *ddp = dd;
+       return (0);
+
+errout:
+       if (dd->dd_parent)
+               dsl_dir_rele(dd->dd_parent, dd);
+       mutex_destroy(&dd->dd_lock);
+       kmem_free(dd, sizeof (dsl_dir_t));
+       dmu_buf_rele(dbuf, tag);
+       return (err);
+}
+
+void
+dsl_dir_rele(dsl_dir_t *dd, void *tag)
+{
+       dprintf_dd(dd, "%s\n", "");
+       spa_close(dd->dd_pool->dp_spa, tag);
+       dmu_buf_rele(dd->dd_dbuf, tag);
+}
+
+/*
+ * Remove a reference to the given dsl dir that is being asynchronously
+ * released.  Async releases occur from a taskq performing eviction of
+ * dsl datasets and dirs.  This process is identical to a normal release
+ * with the exception of using the async API for releasing the reference on
+ * the spa.
+ */
+void
+dsl_dir_async_rele(dsl_dir_t *dd, void *tag)
+{
+       dprintf_dd(dd, "%s\n", "");
+       spa_async_close(dd->dd_pool->dp_spa, tag);
+       dmu_buf_rele(dd->dd_dbuf, tag);
+}
+
+/* buf must be long enough (MAXNAMELEN + strlen(MOS_DIR_NAME) + 1 should do) */
+void
+dsl_dir_name(dsl_dir_t *dd, char *buf)
+{
+       if (dd->dd_parent) {
+               dsl_dir_name(dd->dd_parent, buf);
+               (void) strcat(buf, "/");
+       } else {
+               buf[0] = '\0';
+       }
+       if (!MUTEX_HELD(&dd->dd_lock)) {
+               /*
+                * recursive mutex so that we can use
+                * dprintf_dd() with dd_lock held
+                */
+               mutex_enter(&dd->dd_lock);
+               (void) strcat(buf, dd->dd_myname);
+               mutex_exit(&dd->dd_lock);
+       } else {
+               (void) strcat(buf, dd->dd_myname);
+       }
+}
+
+/* Calculate name length, avoiding all the strcat calls of dsl_dir_name */
+int
+dsl_dir_namelen(dsl_dir_t *dd)
+{
+       int result = 0;
+
+       if (dd->dd_parent) {
+               /* parent's name + 1 for the "/" */
+               result = dsl_dir_namelen(dd->dd_parent) + 1;
+       }
+
+       if (!MUTEX_HELD(&dd->dd_lock)) {
+               /* see dsl_dir_name */
+               mutex_enter(&dd->dd_lock);
+               result += strlen(dd->dd_myname);
+               mutex_exit(&dd->dd_lock);
+       } else {
+               result += strlen(dd->dd_myname);
+       }
+
+       return (result);
+}
+
+static int
+getcomponent(const char *path, char *component, const char **nextp)
+{
+       char *p;
+
+       if ((path == NULL) || (path[0] == '\0'))
+               return (SET_ERROR(ENOENT));
+       /* This would be a good place to reserve some namespace... */
+       p = strpbrk(path, "/@");
+       if (p && (p[1] == '/' || p[1] == '@')) {
+               /* two separators in a row */
+               return (SET_ERROR(EINVAL));
+       }
+       if (p == NULL || p == path) {
+               /*
+                * if the first thing is an @ or /, it had better be an
+                * @ and it had better not have any more ats or slashes,
+                * and it had better have something after the @.
+                */
+               if (p != NULL &&
+                   (p[0] != '@' || strpbrk(path+1, "/@") || p[1] == '\0'))
+                       return (SET_ERROR(EINVAL));
+               if (strlen(path) >= MAXNAMELEN)
+                       return (SET_ERROR(ENAMETOOLONG));
+               (void) strcpy(component, path);
+               p = NULL;
+       } else if (p[0] == '/') {
+               if (p - path >= MAXNAMELEN)
+                       return (SET_ERROR(ENAMETOOLONG));
+               (void) strncpy(component, path, p - path);
+               component[p - path] = '\0';
+               p++;
+       } else if (p[0] == '@') {
+               /*
+                * if the next separator is an @, there better not be
+                * any more slashes.
+                */
+               if (strchr(path, '/'))
+                       return (SET_ERROR(EINVAL));
+               if (p - path >= MAXNAMELEN)
+                       return (SET_ERROR(ENAMETOOLONG));
+               (void) strncpy(component, path, p - path);
+               component[p - path] = '\0';
+       } else {
+               panic("invalid p=%p", (void *)p);
+       }
+       *nextp = p;
+       return (0);
+}
+
+/*
+ * Return the dsl_dir_t, and possibly the last component which couldn't
+ * be found in *tail.  The name must be in the specified dsl_pool_t.  This
+ * thread must hold the dp_config_rwlock for the pool.  Returns NULL if the
+ * path is bogus, or if tail==NULL and we couldn't parse the whole name.
+ * (*tail)[0] == '@' means that the last component is a snapshot.
+ */
+int
+dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
+    dsl_dir_t **ddp, const char **tailp)
+{
+       char *buf;
+       const char *spaname, *next, *nextnext = NULL;
+       int err;
+       dsl_dir_t *dd;
+       uint64_t ddobj;
+
+       buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       err = getcomponent(name, buf, &next);
+       if (err != 0)
+               goto error;
+
+       /* Make sure the name is in the specified pool. */
+       spaname = spa_name(dp->dp_spa);
+       if (strcmp(buf, spaname) != 0) {
+               err = SET_ERROR(EXDEV);
+               goto error;
+       }
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       err = dsl_dir_hold_obj(dp, dp->dp_root_dir_obj, NULL, tag, &dd);
+       if (err != 0) {
+               goto error;
+       }
+
+       while (next != NULL) {
+               dsl_dir_t *child_dd;
+               err = getcomponent(next, buf, &nextnext);
+               if (err != 0)
+                       break;
+               ASSERT(next[0] != '\0');
+               if (next[0] == '@')
+                       break;
+               dprintf("looking up %s in obj%lld\n",
+                   buf, dsl_dir_phys(dd)->dd_child_dir_zapobj);
+
+               err = zap_lookup(dp->dp_meta_objset,
+                   dsl_dir_phys(dd)->dd_child_dir_zapobj,
+                   buf, sizeof (ddobj), 1, &ddobj);
+               if (err != 0) {
+                       if (err == ENOENT)
+                               err = 0;
+                       break;
+               }
+
+               err = dsl_dir_hold_obj(dp, ddobj, buf, tag, &child_dd);
+               if (err != 0)
+                       break;
+               dsl_dir_rele(dd, tag);
+               dd = child_dd;
+               next = nextnext;
+       }
+
+       if (err != 0) {
+               dsl_dir_rele(dd, tag);
+               goto error;
+       }
+
+       /*
+        * It's an error if there's more than one component left, or
+        * tailp==NULL and there's any component left.
+        */
+       if (next != NULL &&
+           (tailp == NULL || (nextnext && nextnext[0] != '\0'))) {
+               /* bad path name */
+               dsl_dir_rele(dd, tag);
+               dprintf("next=%p (%s) tail=%p\n", next, next?next:"", tailp);
+               err = SET_ERROR(ENOENT);
+       }
+       if (tailp != NULL)
+               *tailp = next;
+       *ddp = dd;
+error:
+       kmem_free(buf, MAXNAMELEN);
+       return (err);
+}
+
+/*
+ * If the counts are already initialized for this filesystem and its
+ * descendants then do nothing, otherwise initialize the counts.
+ *
+ * The counts on this filesystem, and those below, may be uninitialized due to
+ * either the use of a pre-existing pool which did not support the
+ * filesystem/snapshot limit feature, or one in which the feature had not yet
+ * been enabled.
+ *
+ * Recursively descend the filesystem tree and update the filesystem/snapshot
+ * counts on each filesystem below, then update the cumulative count on the
+ * current filesystem. If the filesystem already has a count set on it,
+ * then we know that its counts, and the counts on the filesystems below it,
+ * are already correct, so we don't have to update this filesystem.
+ */
+static void
+dsl_dir_init_fs_ss_count(dsl_dir_t *dd, dmu_tx_t *tx)
+{
+       uint64_t my_fs_cnt = 0;
+       uint64_t my_ss_cnt = 0;
+       dsl_pool_t *dp = dd->dd_pool;
+       objset_t *os = dp->dp_meta_objset;
+       zap_cursor_t *zc;
+       zap_attribute_t *za;
+       dsl_dataset_t *ds;
+
+       ASSERT(spa_feature_is_active(dp->dp_spa, SPA_FEATURE_FS_SS_LIMIT));
+       ASSERT(dsl_pool_config_held(dp));
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       dsl_dir_zapify(dd, tx);
+
+       /*
+        * If the filesystem count has already been initialized then we
+        * don't need to recurse down any further.
+        */
+       if (zap_contains(os, dd->dd_object, DD_FIELD_FILESYSTEM_COUNT) == 0)
+               return;
+
+       zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
+       za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+
+       /* Iterate my child dirs */
+       for (zap_cursor_init(zc, os, dsl_dir_phys(dd)->dd_child_dir_zapobj);
+           zap_cursor_retrieve(zc, za) == 0; zap_cursor_advance(zc)) {
+               dsl_dir_t *chld_dd;
+               uint64_t count;
+
+               VERIFY0(dsl_dir_hold_obj(dp, za->za_first_integer, NULL, FTAG,
+                   &chld_dd));
+
+               /*
+                * Ignore hidden ($FREE, $MOS & $ORIGIN) objsets and
+                * temporary datasets.
+                */
+               if (chld_dd->dd_myname[0] == '$' ||
+                   chld_dd->dd_myname[0] == '%') {
+                       dsl_dir_rele(chld_dd, FTAG);
+                       continue;
+               }
+
+               my_fs_cnt++;    /* count this child */
+
+               dsl_dir_init_fs_ss_count(chld_dd, tx);
+
+               VERIFY0(zap_lookup(os, chld_dd->dd_object,
+                   DD_FIELD_FILESYSTEM_COUNT, sizeof (count), 1, &count));
+               my_fs_cnt += count;
+               VERIFY0(zap_lookup(os, chld_dd->dd_object,
+                   DD_FIELD_SNAPSHOT_COUNT, sizeof (count), 1, &count));
+               my_ss_cnt += count;
+
+               dsl_dir_rele(chld_dd, FTAG);
+       }
+       zap_cursor_fini(zc);
+       /* Count my snapshots (we counted children's snapshots above) */
+       VERIFY0(dsl_dataset_hold_obj(dd->dd_pool,
+           dsl_dir_phys(dd)->dd_head_dataset_obj, FTAG, &ds));
+
+       for (zap_cursor_init(zc, os, dsl_dataset_phys(ds)->ds_snapnames_zapobj);
+           zap_cursor_retrieve(zc, za) == 0;
+           zap_cursor_advance(zc)) {
+               /* Don't count temporary snapshots */
+               if (za->za_name[0] != '%')
+                       my_ss_cnt++;
+       }
+       zap_cursor_fini(zc);
+
+       dsl_dataset_rele(ds, FTAG);
+
+       kmem_free(zc, sizeof (zap_cursor_t));
+       kmem_free(za, sizeof (zap_attribute_t));
+
+       /* we're in a sync task, update counts */
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+       VERIFY0(zap_add(os, dd->dd_object, DD_FIELD_FILESYSTEM_COUNT,
+           sizeof (my_fs_cnt), 1, &my_fs_cnt, tx));
+       VERIFY0(zap_add(os, dd->dd_object, DD_FIELD_SNAPSHOT_COUNT,
+           sizeof (my_ss_cnt), 1, &my_ss_cnt, tx));
+}
+
+static int
+dsl_dir_actv_fs_ss_limit_check(void *arg, dmu_tx_t *tx)
+{
+       char *ddname = (char *)arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       dsl_dir_t *dd;
+       int error;
+
+       error = dsl_dataset_hold(dp, ddname, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_FS_SS_LIMIT)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       dd = ds->ds_dir;
+       if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_FS_SS_LIMIT) &&
+           dsl_dir_is_zapified(dd) &&
+           zap_contains(dp->dp_meta_objset, dd->dd_object,
+           DD_FIELD_FILESYSTEM_COUNT) == 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EALREADY));
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+static void
+dsl_dir_actv_fs_ss_limit_sync(void *arg, dmu_tx_t *tx)
+{
+       char *ddname = (char *)arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       spa_t *spa;
+
+       VERIFY0(dsl_dataset_hold(dp, ddname, FTAG, &ds));
+
+       spa = dsl_dataset_get_spa(ds);
+
+       if (!spa_feature_is_active(spa, SPA_FEATURE_FS_SS_LIMIT)) {
+               /*
+                * Since the feature was not active and we're now setting a
+                * limit, increment the feature-active counter so that the
+                * feature becomes active for the first time.
+                *
+                * We are already in a sync task so we can update the MOS.
+                */
+               spa_feature_incr(spa, SPA_FEATURE_FS_SS_LIMIT, tx);
+       }
+
+       /*
+        * Since we are now setting a non-UINT64_MAX limit on the filesystem,
+        * we need to ensure the counts are correct. Descend down the tree from
+        * this point and update all of the counts to be accurate.
+        */
+       dsl_dir_init_fs_ss_count(ds->ds_dir, tx);
+
+       dsl_dataset_rele(ds, FTAG);
+}
+
+/*
+ * Make sure the feature is enabled and activate it if necessary.
+ * Since we're setting a limit, ensure the on-disk counts are valid.
+ * This is only called by the ioctl path when setting a limit value.
+ *
+ * We do not need to validate the new limit, since users who can change the
+ * limit are also allowed to exceed the limit.
+ */
+int
+dsl_dir_activate_fs_ss_limit(const char *ddname)
+{
+       int error;
+
+       error = dsl_sync_task(ddname, dsl_dir_actv_fs_ss_limit_check,
+           dsl_dir_actv_fs_ss_limit_sync, (void *)ddname, 0,
+           ZFS_SPACE_CHECK_RESERVED);
+
+       if (error == EALREADY)
+               error = 0;
+
+       return (error);
+}
+
+/*
+ * Used to determine if the filesystem_limit or snapshot_limit should be
+ * enforced. We allow the limit to be exceeded if the user has permission to
+ * write the property value. We pass in the creds that we got in the open
+ * context since we will always be the GZ root in syncing context. We also have
+ * to handle the case where we are allowed to change the limit on the current
+ * dataset, but there may be another limit in the tree above.
+ *
+ * We can never modify these two properties within a non-global zone. In
+ * addition, the other checks are modeled on zfs_secpolicy_write_perms. We
+ * can't use that function since we are already holding the dp_config_rwlock.
+ * In addition, we already have the dd and dealing with snapshots is simplified
+ * in this code.
+ */
+
+typedef enum {
+       ENFORCE_ALWAYS,
+       ENFORCE_NEVER,
+       ENFORCE_ABOVE
+} enforce_res_t;
+
+static enforce_res_t
+dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
+{
+       enforce_res_t enforce = ENFORCE_ALWAYS;
+       uint64_t obj;
+       dsl_dataset_t *ds;
+       uint64_t zoned;
+
+       ASSERT(prop == ZFS_PROP_FILESYSTEM_LIMIT ||
+           prop == ZFS_PROP_SNAPSHOT_LIMIT);
+
+#ifdef _KERNEL
+       if (crgetzoneid(cr) != GLOBAL_ZONEID)
+               return (ENFORCE_ALWAYS);
+
+       if (secpolicy_zfs(cr) == 0)
+               return (ENFORCE_NEVER);
+#endif
+
+       if ((obj = dsl_dir_phys(dd)->dd_head_dataset_obj) == 0)
+               return (ENFORCE_ALWAYS);
+
+       ASSERT(dsl_pool_config_held(dd->dd_pool));
+
+       if (dsl_dataset_hold_obj(dd->dd_pool, obj, FTAG, &ds) != 0)
+               return (ENFORCE_ALWAYS);
+
+       if (dsl_prop_get_ds(ds, "zoned", 8, 1, &zoned, NULL) || zoned) {
+               /* Only root can access zoned fs's from the GZ */
+               enforce = ENFORCE_ALWAYS;
+       } else {
+               if (dsl_deleg_access_impl(ds, zfs_prop_to_name(prop), cr) == 0)
+                       enforce = ENFORCE_ABOVE;
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (enforce);
+}
+
+/*
+ * Check if adding additional child filesystem(s) would exceed any filesystem
+ * limits or adding additional snapshot(s) would exceed any snapshot limits.
+ * The prop argument indicates which limit to check.
+ *
+ * Note that all filesystem limits up to the root (or the highest
+ * initialized) filesystem or the given ancestor must be satisfied.
+ */
+int
+dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
+    dsl_dir_t *ancestor, cred_t *cr)
+{
+       objset_t *os = dd->dd_pool->dp_meta_objset;
+       uint64_t limit, count;
+       char *count_prop;
+       enforce_res_t enforce;
+       int err = 0;
+
+       ASSERT(dsl_pool_config_held(dd->dd_pool));
+       ASSERT(prop == ZFS_PROP_FILESYSTEM_LIMIT ||
+           prop == ZFS_PROP_SNAPSHOT_LIMIT);
+
+       /*
+        * If we're allowed to change the limit, don't enforce the limit
+        * e.g. this can happen if a snapshot is taken by an administrative
+        * user in the global zone (i.e. a recursive snapshot by root).
+        * However, we must handle the case of delegated permissions where we
+        * are allowed to change the limit on the current dataset, but there
+        * is another limit in the tree above.
+        */
+       enforce = dsl_enforce_ds_ss_limits(dd, prop, cr);
+       if (enforce == ENFORCE_NEVER)
+               return (0);
+
+       /*
+        * e.g. if renaming a dataset with no snapshots, count adjustment
+        * is 0.
+        */
+       if (delta == 0)
+               return (0);
+
+       if (prop == ZFS_PROP_SNAPSHOT_LIMIT) {
+               /*
+                * We don't enforce the limit for temporary snapshots. This is
+                * indicated by a NULL cred_t argument.
+                */
+               if (cr == NULL)
+                       return (0);
+
+               count_prop = DD_FIELD_SNAPSHOT_COUNT;
+       } else {
+               count_prop = DD_FIELD_FILESYSTEM_COUNT;
+       }
+
+       /*
+        * If an ancestor has been provided, stop checking the limit once we
+        * hit that dir. We need this during rename so that we don't overcount
+        * the check once we recurse up to the common ancestor.
+        */
+       if (ancestor == dd)
+               return (0);
+
+       /*
+        * If we hit an uninitialized node while recursing up the tree, we can
+        * stop since we know there is no limit here (or above). The counts are
+        * not valid on this node and we know we won't touch this node's counts.
+        */
+       if (!dsl_dir_is_zapified(dd) || zap_lookup(os, dd->dd_object,
+           count_prop, sizeof (count), 1, &count) == ENOENT)
+               return (0);
+
+       err = dsl_prop_get_dd(dd, zfs_prop_to_name(prop), 8, 1, &limit, NULL,
+           B_FALSE);
+       if (err != 0)
+               return (err);
+
+       /* Is there a limit which we've hit? */
+       if (enforce == ENFORCE_ALWAYS && (count + delta) > limit)
+               return (SET_ERROR(EDQUOT));
+
+       if (dd->dd_parent != NULL)
+               err = dsl_fs_ss_limit_check(dd->dd_parent, delta, prop,
+                   ancestor, cr);
+
+       return (err);
+}
+
+/*
+ * Adjust the filesystem or snapshot count for the specified dsl_dir_t and all
+ * parents. When a new filesystem/snapshot is created, increment the count on
+ * all parents, and when a filesystem/snapshot is destroyed, decrement the
+ * count.
+ */
+void
+dsl_fs_ss_count_adjust(dsl_dir_t *dd, int64_t delta, const char *prop,
+    dmu_tx_t *tx)
+{
+       int err;
+       objset_t *os = dd->dd_pool->dp_meta_objset;
+       uint64_t count;
+
+       ASSERT(dsl_pool_config_held(dd->dd_pool));
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(strcmp(prop, DD_FIELD_FILESYSTEM_COUNT) == 0 ||
+           strcmp(prop, DD_FIELD_SNAPSHOT_COUNT) == 0);
+
+       /*
+        * When we receive an incremental stream into a filesystem that already
+        * exists, a temporary clone is created.  We don't count this temporary
+        * clone, whose name begins with a '%'. We also ignore hidden ($FREE,
+        * $MOS & $ORIGIN) objsets.
+        */
+       if ((dd->dd_myname[0] == '%' || dd->dd_myname[0] == '$') &&
+           strcmp(prop, DD_FIELD_FILESYSTEM_COUNT) == 0)
+               return;
+
+       /*
+        * e.g. if renaming a dataset with no snapshots, count adjustment is 0
+        */
+       if (delta == 0)
+               return;
+
+       /*
+        * If we hit an uninitialized node while recursing up the tree, we can
+        * stop since we know the counts are not valid on this node and we
+        * know we shouldn't touch this node's counts. An uninitialized count
+        * on the node indicates that either the feature has not yet been
+        * activated or there are no limits on this part of the tree.
+        */
+       if (!dsl_dir_is_zapified(dd) || (err = zap_lookup(os, dd->dd_object,
+           prop, sizeof (count), 1, &count)) == ENOENT)
+               return;
+       VERIFY0(err);
+
+       count += delta;
+       /* Use a signed verify to make sure we're not neg. */
+       VERIFY3S(count, >=, 0);
+
+       VERIFY0(zap_update(os, dd->dd_object, prop, sizeof (count), 1, &count,
+           tx));
+
+       /* Roll up this additional count into our ancestors */
+       if (dd->dd_parent != NULL)
+               dsl_fs_ss_count_adjust(dd->dd_parent, delta, prop, tx);
+}
+
+uint64_t
+dsl_dir_create_sync(dsl_pool_t *dp, dsl_dir_t *pds, const char *name,
+    dmu_tx_t *tx)
+{
+       objset_t *mos = dp->dp_meta_objset;
+       uint64_t ddobj;
+       dsl_dir_phys_t *ddphys;
+       dmu_buf_t *dbuf;
+
+       ddobj = dmu_object_alloc(mos, DMU_OT_DSL_DIR, 0,
+           DMU_OT_DSL_DIR, sizeof (dsl_dir_phys_t), tx);
+       if (pds) {
+               VERIFY(0 == zap_add(mos, dsl_dir_phys(pds)->dd_child_dir_zapobj,
+                   name, sizeof (uint64_t), 1, &ddobj, tx));
+       } else {
+               /* it's the root dir */
+               VERIFY(0 == zap_add(mos, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_ROOT_DATASET, sizeof (uint64_t), 1, &ddobj, tx));
+       }
+       VERIFY(0 == dmu_bonus_hold(mos, ddobj, FTAG, &dbuf));
+       dmu_buf_will_dirty(dbuf, tx);
+       ddphys = dbuf->db_data;
+
+       ddphys->dd_creation_time = gethrestime_sec();
+       if (pds) {
+               ddphys->dd_parent_obj = pds->dd_object;
+
+               /* update the filesystem counts */
+               dsl_fs_ss_count_adjust(pds, 1, DD_FIELD_FILESYSTEM_COUNT, tx);
+       }
+       ddphys->dd_props_zapobj = zap_create(mos,
+           DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
+       ddphys->dd_child_dir_zapobj = zap_create(mos,
+           DMU_OT_DSL_DIR_CHILD_MAP, DMU_OT_NONE, 0, tx);
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_USED_BREAKDOWN)
+               ddphys->dd_flags |= DD_FLAG_USED_BREAKDOWN;
+       dmu_buf_rele(dbuf, FTAG);
+
+       return (ddobj);
+}
+
+boolean_t
+dsl_dir_is_clone(dsl_dir_t *dd)
+{
+       return (dsl_dir_phys(dd)->dd_origin_obj &&
+           (dd->dd_pool->dp_origin_snap == NULL ||
+           dsl_dir_phys(dd)->dd_origin_obj !=
+           dd->dd_pool->dp_origin_snap->ds_object));
+}
+
+void
+dsl_dir_stats(dsl_dir_t *dd, nvlist_t *nv)
+{
+       mutex_enter(&dd->dd_lock);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
+           dsl_dir_phys(dd)->dd_used_bytes);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_QUOTA,
+           dsl_dir_phys(dd)->dd_quota);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_RESERVATION,
+           dsl_dir_phys(dd)->dd_reserved);
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO,
+           dsl_dir_phys(dd)->dd_compressed_bytes == 0 ? 100 :
+           (dsl_dir_phys(dd)->dd_uncompressed_bytes * 100 /
+           dsl_dir_phys(dd)->dd_compressed_bytes));
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALUSED,
+           dsl_dir_phys(dd)->dd_uncompressed_bytes);
+       if (dsl_dir_phys(dd)->dd_flags & DD_FLAG_USED_BREAKDOWN) {
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USEDSNAP,
+                   dsl_dir_phys(dd)->dd_used_breakdown[DD_USED_SNAP]);
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USEDDS,
+                   dsl_dir_phys(dd)->dd_used_breakdown[DD_USED_HEAD]);
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USEDREFRESERV,
+                   dsl_dir_phys(dd)->dd_used_breakdown[DD_USED_REFRSRV]);
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USEDCHILD,
+                   dsl_dir_phys(dd)->dd_used_breakdown[DD_USED_CHILD] +
+                   dsl_dir_phys(dd)->dd_used_breakdown[DD_USED_CHILD_RSRV]);
+       }
+       mutex_exit(&dd->dd_lock);
+
+       if (dsl_dir_is_zapified(dd)) {
+               uint64_t count;
+               objset_t *os = dd->dd_pool->dp_meta_objset;
+
+               if (zap_lookup(os, dd->dd_object, DD_FIELD_FILESYSTEM_COUNT,
+                   sizeof (count), 1, &count) == 0) {
+                       dsl_prop_nvlist_add_uint64(nv,
+                           ZFS_PROP_FILESYSTEM_COUNT, count);
+               }
+               if (zap_lookup(os, dd->dd_object, DD_FIELD_SNAPSHOT_COUNT,
+                   sizeof (count), 1, &count) == 0) {
+                       dsl_prop_nvlist_add_uint64(nv,
+                           ZFS_PROP_SNAPSHOT_COUNT, count);
+               }
+       }
+
+       if (dsl_dir_is_clone(dd)) {
+               dsl_dataset_t *ds;
+               char buf[MAXNAMELEN];
+
+               VERIFY0(dsl_dataset_hold_obj(dd->dd_pool,
+                   dsl_dir_phys(dd)->dd_origin_obj, FTAG, &ds));
+               dsl_dataset_name(ds, buf);
+               dsl_dataset_rele(ds, FTAG);
+               dsl_prop_nvlist_add_string(nv, ZFS_PROP_ORIGIN, buf);
+       }
+}
+
+void
+dsl_dir_dirty(dsl_dir_t *dd, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dd->dd_pool;
+
+       ASSERT(dsl_dir_phys(dd));
+
+       if (txg_list_add(&dp->dp_dirty_dirs, dd, tx->tx_txg)) {
+               /* up the hold count until we can be written out */
+               dmu_buf_add_ref(dd->dd_dbuf, dd);
+       }
+}
+
+static int64_t
+parent_delta(dsl_dir_t *dd, uint64_t used, int64_t delta)
+{
+       uint64_t old_accounted = MAX(used, dsl_dir_phys(dd)->dd_reserved);
+       uint64_t new_accounted =
+           MAX(used + delta, dsl_dir_phys(dd)->dd_reserved);
+       return (new_accounted - old_accounted);
+}
+
+void
+dsl_dir_sync(dsl_dir_t *dd, dmu_tx_t *tx)
+{
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       mutex_enter(&dd->dd_lock);
+       ASSERT0(dd->dd_tempreserved[tx->tx_txg&TXG_MASK]);
+       dprintf_dd(dd, "txg=%llu towrite=%lluK\n", tx->tx_txg,
+           dd->dd_space_towrite[tx->tx_txg&TXG_MASK] / 1024);
+       dd->dd_space_towrite[tx->tx_txg&TXG_MASK] = 0;
+       mutex_exit(&dd->dd_lock);
+
+       /* release the hold from dsl_dir_dirty */
+       dmu_buf_rele(dd->dd_dbuf, dd);
+}
+
+static uint64_t
+dsl_dir_space_towrite(dsl_dir_t *dd)
+{
+       uint64_t space = 0;
+       int i;
+
+       ASSERT(MUTEX_HELD(&dd->dd_lock));
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               space += dd->dd_space_towrite[i&TXG_MASK];
+               ASSERT3U(dd->dd_space_towrite[i&TXG_MASK], >=, 0);
+       }
+       return (space);
+}
+
+/*
+ * How much space would dd have available if ancestor had delta applied
+ * to it?  If ondiskonly is set, we're only interested in what's
+ * on-disk, not estimated pending changes.
+ */
+uint64_t
+dsl_dir_space_available(dsl_dir_t *dd,
+    dsl_dir_t *ancestor, int64_t delta, int ondiskonly)
+{
+       uint64_t parentspace, myspace, quota, used;
+
+       /*
+        * If there are no restrictions otherwise, assume we have
+        * unlimited space available.
+        */
+       quota = UINT64_MAX;
+       parentspace = UINT64_MAX;
+
+       if (dd->dd_parent != NULL) {
+               parentspace = dsl_dir_space_available(dd->dd_parent,
+                   ancestor, delta, ondiskonly);
+       }
+
+       mutex_enter(&dd->dd_lock);
+       if (dsl_dir_phys(dd)->dd_quota != 0)
+               quota = dsl_dir_phys(dd)->dd_quota;
+       used = dsl_dir_phys(dd)->dd_used_bytes;
+       if (!ondiskonly)
+               used += dsl_dir_space_towrite(dd);
+
+       if (dd->dd_parent == NULL) {
+               uint64_t poolsize = dsl_pool_adjustedsize(dd->dd_pool, FALSE);
+               quota = MIN(quota, poolsize);
+       }
+
+       if (dsl_dir_phys(dd)->dd_reserved > used && parentspace != UINT64_MAX) {
+               /*
+                * We have some space reserved, in addition to what our
+                * parent gave us.
+                */
+               parentspace += dsl_dir_phys(dd)->dd_reserved - used;
+       }
+
+       if (dd == ancestor) {
+               ASSERT(delta <= 0);
+               ASSERT(used >= -delta);
+               used += delta;
+               if (parentspace != UINT64_MAX)
+                       parentspace -= delta;
+       }
+
+       if (used > quota) {
+               /* over quota */
+               myspace = 0;
+       } else {
+               /*
+                * the lesser of the space provided by our parent and
+                * the space left in our quota
+                */
+               myspace = MIN(parentspace, quota - used);
+       }
+
+       mutex_exit(&dd->dd_lock);
+
+       return (myspace);
+}
+
+struct tempreserve {
+       list_node_t tr_node;
+       dsl_dir_t *tr_ds;
+       uint64_t tr_size;
+};
+
+static int
+dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree,
+    boolean_t ignorequota, boolean_t checkrefquota, list_t *tr_list,
+    dmu_tx_t *tx, boolean_t first)
+{
+       uint64_t txg = tx->tx_txg;
+       uint64_t est_inflight, used_on_disk, quota, parent_rsrv;
+       uint64_t deferred = 0;
+       struct tempreserve *tr;
+       int retval = EDQUOT;
+       int txgidx = txg & TXG_MASK;
+       int i;
+       uint64_t ref_rsrv = 0;
+
+       ASSERT3U(txg, !=, 0);
+       ASSERT3S(asize, >, 0);
+
+       mutex_enter(&dd->dd_lock);
+
+       /*
+        * Check against the dsl_dir's quota.  We don't add in the delta
+        * when checking for over-quota because they get one free hit.
+        */
+       est_inflight = dsl_dir_space_towrite(dd);
+       for (i = 0; i < TXG_SIZE; i++)
+               est_inflight += dd->dd_tempreserved[i];
+       used_on_disk = dsl_dir_phys(dd)->dd_used_bytes;
+
+       /*
+        * On the first iteration, fetch the dataset's used-on-disk and
+        * refreservation values. Also, if checkrefquota is set, test if
+        * allocating this space would exceed the dataset's refquota.
+        */
+       if (first && tx->tx_objset) {
+               int error;
+               dsl_dataset_t *ds = tx->tx_objset->os_dsl_dataset;
+
+               error = dsl_dataset_check_quota(ds, checkrefquota,
+                   asize, est_inflight, &used_on_disk, &ref_rsrv);
+               if (error) {
+                       mutex_exit(&dd->dd_lock);
+                       DMU_TX_STAT_BUMP(dmu_tx_quota);
+                       return (error);
+               }
+       }
+
+       /*
+        * If this transaction will result in a net free of space,
+        * we want to let it through.
+        */
+       if (ignorequota || netfree || dsl_dir_phys(dd)->dd_quota == 0)
+               quota = UINT64_MAX;
+       else
+               quota = dsl_dir_phys(dd)->dd_quota;
+
+       /*
+        * Adjust the quota against the actual pool size at the root
+        * minus any outstanding deferred frees.
+        * To ensure that it's possible to remove files from a full
+        * pool without inducing transient overcommits, we throttle
+        * netfree transactions against a quota that is slightly larger,
+        * but still within the pool's allocation slop.  In cases where
+        * we're very close to full, this will allow a steady trickle of
+        * removes to get through.
+        */
+       if (dd->dd_parent == NULL) {
+               spa_t *spa = dd->dd_pool->dp_spa;
+               uint64_t poolsize = dsl_pool_adjustedsize(dd->dd_pool, netfree);
+               deferred = metaslab_class_get_deferred(spa_normal_class(spa));
+               if (poolsize - deferred < quota) {
+                       quota = poolsize - deferred;
+                       retval = ENOSPC;
+               }
+       }
+
+       /*
+        * If they are requesting more space, and our current estimate
+        * is over quota, they get to try again unless the actual
+        * on-disk is over quota and there are no pending changes (which
+        * may free up space for us).
+        */
+       if (used_on_disk + est_inflight >= quota) {
+               if (est_inflight > 0 || used_on_disk < quota ||
+                   (retval == ENOSPC && used_on_disk < quota + deferred))
+                       retval = ERESTART;
+               dprintf_dd(dd, "failing: used=%lluK inflight = %lluK "
+                   "quota=%lluK tr=%lluK err=%d\n",
+                   used_on_disk>>10, est_inflight>>10,
+                   quota>>10, asize>>10, retval);
+               mutex_exit(&dd->dd_lock);
+               DMU_TX_STAT_BUMP(dmu_tx_quota);
+               return (SET_ERROR(retval));
+       }
+
+       /* We need to up our estimated delta before dropping dd_lock */
+       dd->dd_tempreserved[txgidx] += asize;
+
+       parent_rsrv = parent_delta(dd, used_on_disk + est_inflight,
+           asize - ref_rsrv);
+       mutex_exit(&dd->dd_lock);
+
+       tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
+       tr->tr_ds = dd;
+       tr->tr_size = asize;
+       list_insert_tail(tr_list, tr);
+
+       /* see if it's OK with our parent */
+       if (dd->dd_parent && parent_rsrv) {
+               boolean_t ismos = (dsl_dir_phys(dd)->dd_head_dataset_obj == 0);
+
+               return (dsl_dir_tempreserve_impl(dd->dd_parent,
+                   parent_rsrv, netfree, ismos, TRUE, tr_list, tx, FALSE));
+       } else {
+               return (0);
+       }
+}
+
+/*
+ * Reserve space in this dsl_dir, to be used in this tx's txg.
+ * After the space has been dirtied (and dsl_dir_willuse_space()
+ * has been called), the reservation should be canceled, using
+ * dsl_dir_tempreserve_clear().
+ */
+int
+dsl_dir_tempreserve_space(dsl_dir_t *dd, uint64_t lsize, uint64_t asize,
+    uint64_t fsize, uint64_t usize, void **tr_cookiep, dmu_tx_t *tx)
+{
+       int err;
+       list_t *tr_list;
+
+       if (asize == 0) {
+               *tr_cookiep = NULL;
+               return (0);
+       }
+
+       tr_list = kmem_alloc(sizeof (list_t), KM_SLEEP);
+       list_create(tr_list, sizeof (struct tempreserve),
+           offsetof(struct tempreserve, tr_node));
+       ASSERT3S(asize, >, 0);
+       ASSERT3S(fsize, >=, 0);
+
+       err = arc_tempreserve_space(lsize, tx->tx_txg);
+       if (err == 0) {
+               struct tempreserve *tr;
+
+               tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
+               tr->tr_size = lsize;
+               list_insert_tail(tr_list, tr);
+       } else {
+               if (err == EAGAIN) {
+                       /*
+                        * If arc_memory_throttle() detected that pageout
+                        * is running and we are low on memory, we delay new
+                        * non-pageout transactions to give pageout an
+                        * advantage.
+                        *
+                        * It is unfortunate to be delaying while the caller's
+                        * locks are held.
+                        */
+                       txg_delay(dd->dd_pool, tx->tx_txg,
+                           MSEC2NSEC(10), MSEC2NSEC(10));
+                       err = SET_ERROR(ERESTART);
+               }
+       }
+
+       if (err == 0) {
+               err = dsl_dir_tempreserve_impl(dd, asize, fsize >= asize,
+                   FALSE, asize > usize, tr_list, tx, TRUE);
+       }
+
+       if (err != 0)
+               dsl_dir_tempreserve_clear(tr_list, tx);
+       else
+               *tr_cookiep = tr_list;
+
+       return (err);
+}
+
+/*
+ * Clear a temporary reservation that we previously made with
+ * dsl_dir_tempreserve_space().
+ */
+void
+dsl_dir_tempreserve_clear(void *tr_cookie, dmu_tx_t *tx)
+{
+       int txgidx = tx->tx_txg & TXG_MASK;
+       list_t *tr_list = tr_cookie;
+       struct tempreserve *tr;
+
+       ASSERT3U(tx->tx_txg, !=, 0);
+
+       if (tr_cookie == NULL)
+               return;
+
+       while ((tr = list_head(tr_list)) != NULL) {
+               if (tr->tr_ds) {
+                       mutex_enter(&tr->tr_ds->dd_lock);
+                       ASSERT3U(tr->tr_ds->dd_tempreserved[txgidx], >=,
+                           tr->tr_size);
+                       tr->tr_ds->dd_tempreserved[txgidx] -= tr->tr_size;
+                       mutex_exit(&tr->tr_ds->dd_lock);
+               } else {
+                       arc_tempreserve_clear(tr->tr_size);
+               }
+               list_remove(tr_list, tr);
+               kmem_free(tr, sizeof (struct tempreserve));
+       }
+
+       kmem_free(tr_list, sizeof (list_t));
+}
+
+/*
+ * This should be called from open context when we think we're going to write
+ * or free space, for example when dirtying data. Be conservative; it's okay
+ * to write less space or free more, but we don't want to write more or free
+ * less than the amount specified.
+ *
+ * NOTE: The behavior of this function is identical to the Illumos / FreeBSD
+ * version however it has been adjusted to use an iterative rather then
+ * recursive algorithm to minimize stack usage.
+ */
+void
+dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
+{
+       int64_t parent_space;
+       uint64_t est_used;
+
+       do {
+               mutex_enter(&dd->dd_lock);
+               if (space > 0)
+                       dd->dd_space_towrite[tx->tx_txg & TXG_MASK] += space;
+
+               est_used = dsl_dir_space_towrite(dd) +
+                   dsl_dir_phys(dd)->dd_used_bytes;
+               parent_space = parent_delta(dd, est_used, space);
+               mutex_exit(&dd->dd_lock);
+
+               /* Make sure that we clean up dd_space_to* */
+               dsl_dir_dirty(dd, tx);
+
+               dd = dd->dd_parent;
+               space = parent_space;
+       } while (space && dd);
+}
+
+/* call from syncing context when we actually write/free space for this dd */
+void
+dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
+    int64_t used, int64_t compressed, int64_t uncompressed, dmu_tx_t *tx)
+{
+       int64_t accounted_delta;
+
+       /*
+        * dsl_dataset_set_refreservation_sync_impl() calls this with
+        * dd_lock held, so that it can atomically update
+        * ds->ds_reserved and the dsl_dir accounting, so that
+        * dsl_dataset_check_quota() can see dataset and dir accounting
+        * consistently.
+        */
+       boolean_t needlock = !MUTEX_HELD(&dd->dd_lock);
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(type < DD_USED_NUM);
+
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+
+       if (needlock)
+               mutex_enter(&dd->dd_lock);
+       accounted_delta =
+           parent_delta(dd, dsl_dir_phys(dd)->dd_used_bytes, used);
+       ASSERT(used >= 0 || dsl_dir_phys(dd)->dd_used_bytes >= -used);
+       ASSERT(compressed >= 0 ||
+           dsl_dir_phys(dd)->dd_compressed_bytes >= -compressed);
+       ASSERT(uncompressed >= 0 ||
+           dsl_dir_phys(dd)->dd_uncompressed_bytes >= -uncompressed);
+       dsl_dir_phys(dd)->dd_used_bytes += used;
+       dsl_dir_phys(dd)->dd_uncompressed_bytes += uncompressed;
+       dsl_dir_phys(dd)->dd_compressed_bytes += compressed;
+
+       if (dsl_dir_phys(dd)->dd_flags & DD_FLAG_USED_BREAKDOWN) {
+               ASSERT(used > 0 ||
+                   dsl_dir_phys(dd)->dd_used_breakdown[type] >= -used);
+               dsl_dir_phys(dd)->dd_used_breakdown[type] += used;
+#ifdef DEBUG
+               {
+                       dd_used_t t;
+                       uint64_t u = 0;
+                       for (t = 0; t < DD_USED_NUM; t++)
+                               u += dsl_dir_phys(dd)->dd_used_breakdown[t];
+                       ASSERT3U(u, ==, dsl_dir_phys(dd)->dd_used_bytes);
+               }
+#endif
+       }
+       if (needlock)
+               mutex_exit(&dd->dd_lock);
+
+       if (dd->dd_parent != NULL) {
+               dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
+                   accounted_delta, compressed, uncompressed, tx);
+               dsl_dir_transfer_space(dd->dd_parent,
+                   used - accounted_delta,
+                   DD_USED_CHILD_RSRV, DD_USED_CHILD, tx);
+       }
+}
+
+void
+dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta,
+    dd_used_t oldtype, dd_used_t newtype, dmu_tx_t *tx)
+{
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(oldtype < DD_USED_NUM);
+       ASSERT(newtype < DD_USED_NUM);
+
+       if (delta == 0 ||
+           !(dsl_dir_phys(dd)->dd_flags & DD_FLAG_USED_BREAKDOWN))
+               return;
+
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+       mutex_enter(&dd->dd_lock);
+       ASSERT(delta > 0 ?
+           dsl_dir_phys(dd)->dd_used_breakdown[oldtype] >= delta :
+           dsl_dir_phys(dd)->dd_used_breakdown[newtype] >= -delta);
+       ASSERT(dsl_dir_phys(dd)->dd_used_bytes >= ABS(delta));
+       dsl_dir_phys(dd)->dd_used_breakdown[oldtype] -= delta;
+       dsl_dir_phys(dd)->dd_used_breakdown[newtype] += delta;
+       mutex_exit(&dd->dd_lock);
+}
+
+typedef struct dsl_dir_set_qr_arg {
+       const char *ddsqra_name;
+       zprop_source_t ddsqra_source;
+       uint64_t ddsqra_value;
+} dsl_dir_set_qr_arg_t;
+
+static int
+dsl_dir_set_quota_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dir_set_qr_arg_t *ddsqra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       int error;
+       uint64_t towrite, newval;
+
+       error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       error = dsl_prop_predict(ds->ds_dir, "quota",
+           ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       if (newval == 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (0);
+       }
+
+       mutex_enter(&ds->ds_dir->dd_lock);
+       /*
+        * If we are doing the preliminary check in open context, and
+        * there are pending changes, then don't fail it, since the
+        * pending changes could under-estimate the amount of space to be
+        * freed up.
+        */
+       towrite = dsl_dir_space_towrite(ds->ds_dir);
+       if ((dmu_tx_is_syncing(tx) || towrite == 0) &&
+           (newval < dsl_dir_phys(ds->ds_dir)->dd_reserved ||
+           newval < dsl_dir_phys(ds->ds_dir)->dd_used_bytes + towrite)) {
+               error = SET_ERROR(ENOSPC);
+       }
+       mutex_exit(&ds->ds_dir->dd_lock);
+       dsl_dataset_rele(ds, FTAG);
+       return (error);
+}
+
+static void
+dsl_dir_set_quota_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dir_set_qr_arg_t *ddsqra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       uint64_t newval;
+
+       VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds));
+
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_RECVD_PROPS) {
+               dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_QUOTA),
+                   ddsqra->ddsqra_source, sizeof (ddsqra->ddsqra_value), 1,
+                   &ddsqra->ddsqra_value, tx);
+
+               VERIFY0(dsl_prop_get_int_ds(ds,
+                   zfs_prop_to_name(ZFS_PROP_QUOTA), &newval));
+       } else {
+               newval = ddsqra->ddsqra_value;
+               spa_history_log_internal_ds(ds, "set", tx, "%s=%lld",
+                   zfs_prop_to_name(ZFS_PROP_QUOTA), (longlong_t)newval);
+       }
+
+       dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx);
+       mutex_enter(&ds->ds_dir->dd_lock);
+       dsl_dir_phys(ds->ds_dir)->dd_quota = newval;
+       mutex_exit(&ds->ds_dir->dd_lock);
+       dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_dir_set_quota(const char *ddname, zprop_source_t source, uint64_t quota)
+{
+       dsl_dir_set_qr_arg_t ddsqra;
+
+       ddsqra.ddsqra_name = ddname;
+       ddsqra.ddsqra_source = source;
+       ddsqra.ddsqra_value = quota;
+
+       return (dsl_sync_task(ddname, dsl_dir_set_quota_check,
+           dsl_dir_set_quota_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+int
+dsl_dir_set_reservation_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dir_set_qr_arg_t *ddsqra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       dsl_dir_t *dd;
+       uint64_t newval, used, avail;
+       int error;
+
+       error = dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds);
+       if (error != 0)
+               return (error);
+       dd = ds->ds_dir;
+
+       /*
+        * If we are doing the preliminary check in open context, the
+        * space estimates may be inaccurate.
+        */
+       if (!dmu_tx_is_syncing(tx)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (0);
+       }
+
+       error = dsl_prop_predict(ds->ds_dir,
+           zfs_prop_to_name(ZFS_PROP_RESERVATION),
+           ddsqra->ddsqra_source, ddsqra->ddsqra_value, &newval);
+       if (error != 0) {
+               dsl_dataset_rele(ds, FTAG);
+               return (error);
+       }
+
+       mutex_enter(&dd->dd_lock);
+       used = dsl_dir_phys(dd)->dd_used_bytes;
+       mutex_exit(&dd->dd_lock);
+
+       if (dd->dd_parent) {
+               avail = dsl_dir_space_available(dd->dd_parent,
+                   NULL, 0, FALSE);
+       } else {
+               avail = dsl_pool_adjustedsize(dd->dd_pool, B_FALSE) - used;
+       }
+
+       if (MAX(used, newval) > MAX(used, dsl_dir_phys(dd)->dd_reserved)) {
+               uint64_t delta = MAX(used, newval) -
+                   MAX(used, dsl_dir_phys(dd)->dd_reserved);
+
+               if (delta > avail ||
+                   (dsl_dir_phys(dd)->dd_quota > 0 &&
+                   newval > dsl_dir_phys(dd)->dd_quota))
+                       error = SET_ERROR(ENOSPC);
+       }
+
+       dsl_dataset_rele(ds, FTAG);
+       return (error);
+}
+
+void
+dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value, dmu_tx_t *tx)
+{
+       uint64_t used;
+       int64_t delta;
+
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+
+       mutex_enter(&dd->dd_lock);
+       used = dsl_dir_phys(dd)->dd_used_bytes;
+       delta = MAX(used, value) - MAX(used, dsl_dir_phys(dd)->dd_reserved);
+       dsl_dir_phys(dd)->dd_reserved = value;
+
+       if (dd->dd_parent != NULL) {
+               /* Roll up this additional usage into our ancestors */
+               dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD_RSRV,
+                   delta, 0, 0, tx);
+       }
+       mutex_exit(&dd->dd_lock);
+}
+
+static void
+dsl_dir_set_reservation_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dir_set_qr_arg_t *ddsqra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       uint64_t newval;
+
+       VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds));
+
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_RECVD_PROPS) {
+               dsl_prop_set_sync_impl(ds,
+                   zfs_prop_to_name(ZFS_PROP_RESERVATION),
+                   ddsqra->ddsqra_source, sizeof (ddsqra->ddsqra_value), 1,
+                   &ddsqra->ddsqra_value, tx);
+
+               VERIFY0(dsl_prop_get_int_ds(ds,
+                   zfs_prop_to_name(ZFS_PROP_RESERVATION), &newval));
+       } else {
+               newval = ddsqra->ddsqra_value;
+               spa_history_log_internal_ds(ds, "set", tx, "%s=%lld",
+                   zfs_prop_to_name(ZFS_PROP_RESERVATION),
+                   (longlong_t)newval);
+       }
+
+       dsl_dir_set_reservation_sync_impl(ds->ds_dir, newval, tx);
+       dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
+    uint64_t reservation)
+{
+       dsl_dir_set_qr_arg_t ddsqra;
+
+       ddsqra.ddsqra_name = ddname;
+       ddsqra.ddsqra_source = source;
+       ddsqra.ddsqra_value = reservation;
+
+       return (dsl_sync_task(ddname, dsl_dir_set_reservation_check,
+           dsl_dir_set_reservation_sync, &ddsqra, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+static dsl_dir_t *
+closest_common_ancestor(dsl_dir_t *ds1, dsl_dir_t *ds2)
+{
+       for (; ds1; ds1 = ds1->dd_parent) {
+               dsl_dir_t *dd;
+               for (dd = ds2; dd; dd = dd->dd_parent) {
+                       if (ds1 == dd)
+                               return (dd);
+               }
+       }
+       return (NULL);
+}
+
+/*
+ * If delta is applied to dd, how much of that delta would be applied to
+ * ancestor?  Syncing context only.
+ */
+static int64_t
+would_change(dsl_dir_t *dd, int64_t delta, dsl_dir_t *ancestor)
+{
+       if (dd == ancestor)
+               return (delta);
+
+       mutex_enter(&dd->dd_lock);
+       delta = parent_delta(dd, dsl_dir_phys(dd)->dd_used_bytes, delta);
+       mutex_exit(&dd->dd_lock);
+       return (would_change(dd->dd_parent, delta, ancestor));
+}
+
+typedef struct dsl_dir_rename_arg {
+       const char *ddra_oldname;
+       const char *ddra_newname;
+       cred_t *ddra_cred;
+} dsl_dir_rename_arg_t;
+
+/* ARGSUSED */
+static int
+dsl_valid_rename(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
+{
+       int *deltap = arg;
+       char namebuf[MAXNAMELEN];
+
+       dsl_dataset_name(ds, namebuf);
+
+       if (strlen(namebuf) + *deltap >= MAXNAMELEN)
+               return (SET_ERROR(ENAMETOOLONG));
+       return (0);
+}
+
+static int
+dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dir_rename_arg_t *ddra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *dd, *newparent;
+       const char *mynewname;
+       int error;
+       int delta = strlen(ddra->ddra_newname) - strlen(ddra->ddra_oldname);
+
+       /* target dir should exist */
+       error = dsl_dir_hold(dp, ddra->ddra_oldname, FTAG, &dd, NULL);
+       if (error != 0)
+               return (error);
+
+       /* new parent should exist */
+       error = dsl_dir_hold(dp, ddra->ddra_newname, FTAG,
+           &newparent, &mynewname);
+       if (error != 0) {
+               dsl_dir_rele(dd, FTAG);
+               return (error);
+       }
+
+       /* can't rename to different pool */
+       if (dd->dd_pool != newparent->dd_pool) {
+               dsl_dir_rele(newparent, FTAG);
+               dsl_dir_rele(dd, FTAG);
+               return (SET_ERROR(EXDEV));
+       }
+
+       /* new name should not already exist */
+       if (mynewname == NULL) {
+               dsl_dir_rele(newparent, FTAG);
+               dsl_dir_rele(dd, FTAG);
+               return (SET_ERROR(EEXIST));
+       }
+
+       /* if the name length is growing, validate child name lengths */
+       if (delta > 0) {
+               error = dmu_objset_find_dp(dp, dd->dd_object, dsl_valid_rename,
+                   &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
+               if (error != 0) {
+                       dsl_dir_rele(newparent, FTAG);
+                       dsl_dir_rele(dd, FTAG);
+                       return (error);
+               }
+       }
+
+       if (dmu_tx_is_syncing(tx)) {
+               if (spa_feature_is_active(dp->dp_spa,
+                   SPA_FEATURE_FS_SS_LIMIT)) {
+                       /*
+                        * Although this is the check function and we don't
+                        * normally make on-disk changes in check functions,
+                        * we need to do that here.
+                        *
+                        * Ensure this portion of the tree's counts have been
+                        * initialized in case the new parent has limits set.
+                        */
+                       dsl_dir_init_fs_ss_count(dd, tx);
+               }
+       }
+
+       if (newparent != dd->dd_parent) {
+               /* is there enough space? */
+               uint64_t myspace =
+                   MAX(dsl_dir_phys(dd)->dd_used_bytes,
+                   dsl_dir_phys(dd)->dd_reserved);
+               objset_t *os = dd->dd_pool->dp_meta_objset;
+               uint64_t fs_cnt = 0;
+               uint64_t ss_cnt = 0;
+
+               if (dsl_dir_is_zapified(dd)) {
+                       int err;
+
+                       err = zap_lookup(os, dd->dd_object,
+                           DD_FIELD_FILESYSTEM_COUNT, sizeof (fs_cnt), 1,
+                           &fs_cnt);
+                       if (err != ENOENT && err != 0) {
+                               dsl_dir_rele(newparent, FTAG);
+                               dsl_dir_rele(dd, FTAG);
+                               return (err);
+                       }
+
+                       /*
+                        * have to add 1 for the filesystem itself that we're
+                        * moving
+                        */
+                       fs_cnt++;
+
+                       err = zap_lookup(os, dd->dd_object,
+                           DD_FIELD_SNAPSHOT_COUNT, sizeof (ss_cnt), 1,
+                           &ss_cnt);
+                       if (err != ENOENT && err != 0) {
+                               dsl_dir_rele(newparent, FTAG);
+                               dsl_dir_rele(dd, FTAG);
+                               return (err);
+                       }
+               }
+
+               /* no rename into our descendant */
+               if (closest_common_ancestor(dd, newparent) == dd) {
+                       dsl_dir_rele(newparent, FTAG);
+                       dsl_dir_rele(dd, FTAG);
+                       return (SET_ERROR(EINVAL));
+               }
+
+               error = dsl_dir_transfer_possible(dd->dd_parent,
+                   newparent, fs_cnt, ss_cnt, myspace, ddra->ddra_cred);
+               if (error != 0) {
+                       dsl_dir_rele(newparent, FTAG);
+                       dsl_dir_rele(dd, FTAG);
+                       return (error);
+               }
+       }
+
+       dsl_dir_rele(newparent, FTAG);
+       dsl_dir_rele(dd, FTAG);
+       return (0);
+}
+
+static void
+dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dir_rename_arg_t *ddra = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *dd, *newparent;
+       const char *mynewname;
+       int error;
+       objset_t *mos = dp->dp_meta_objset;
+
+       VERIFY0(dsl_dir_hold(dp, ddra->ddra_oldname, FTAG, &dd, NULL));
+       VERIFY0(dsl_dir_hold(dp, ddra->ddra_newname, FTAG, &newparent,
+           &mynewname));
+
+       /* Log this before we change the name. */
+       spa_history_log_internal_dd(dd, "rename", tx,
+           "-> %s", ddra->ddra_newname);
+
+       if (newparent != dd->dd_parent) {
+               objset_t *os = dd->dd_pool->dp_meta_objset;
+               uint64_t fs_cnt = 0;
+               uint64_t ss_cnt = 0;
+
+               /*
+                * We already made sure the dd counts were initialized in the
+                * check function.
+                */
+               if (spa_feature_is_active(dp->dp_spa,
+                   SPA_FEATURE_FS_SS_LIMIT)) {
+                       VERIFY0(zap_lookup(os, dd->dd_object,
+                           DD_FIELD_FILESYSTEM_COUNT, sizeof (fs_cnt), 1,
+                           &fs_cnt));
+                       /* add 1 for the filesystem itself that we're moving */
+                       fs_cnt++;
+
+                       VERIFY0(zap_lookup(os, dd->dd_object,
+                           DD_FIELD_SNAPSHOT_COUNT, sizeof (ss_cnt), 1,
+                           &ss_cnt));
+               }
+
+               dsl_fs_ss_count_adjust(dd->dd_parent, -fs_cnt,
+                   DD_FIELD_FILESYSTEM_COUNT, tx);
+               dsl_fs_ss_count_adjust(newparent, fs_cnt,
+                   DD_FIELD_FILESYSTEM_COUNT, tx);
+
+               dsl_fs_ss_count_adjust(dd->dd_parent, -ss_cnt,
+                   DD_FIELD_SNAPSHOT_COUNT, tx);
+               dsl_fs_ss_count_adjust(newparent, ss_cnt,
+                   DD_FIELD_SNAPSHOT_COUNT, tx);
+
+               dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
+                   -dsl_dir_phys(dd)->dd_used_bytes,
+                   -dsl_dir_phys(dd)->dd_compressed_bytes,
+                   -dsl_dir_phys(dd)->dd_uncompressed_bytes, tx);
+               dsl_dir_diduse_space(newparent, DD_USED_CHILD,
+                   dsl_dir_phys(dd)->dd_used_bytes,
+                   dsl_dir_phys(dd)->dd_compressed_bytes,
+                   dsl_dir_phys(dd)->dd_uncompressed_bytes, tx);
+
+               if (dsl_dir_phys(dd)->dd_reserved >
+                   dsl_dir_phys(dd)->dd_used_bytes) {
+                       uint64_t unused_rsrv = dsl_dir_phys(dd)->dd_reserved -
+                           dsl_dir_phys(dd)->dd_used_bytes;
+
+                       dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD_RSRV,
+                           -unused_rsrv, 0, 0, tx);
+                       dsl_dir_diduse_space(newparent, DD_USED_CHILD_RSRV,
+                           unused_rsrv, 0, 0, tx);
+               }
+       }
+
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
+
+       /* remove from old parent zapobj */
+       error = zap_remove(mos,
+           dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj,
+           dd->dd_myname, tx);
+       ASSERT0(error);
+
+       (void) strcpy(dd->dd_myname, mynewname);
+       dsl_dir_rele(dd->dd_parent, dd);
+       dsl_dir_phys(dd)->dd_parent_obj = newparent->dd_object;
+       VERIFY0(dsl_dir_hold_obj(dp,
+           newparent->dd_object, NULL, dd, &dd->dd_parent));
+
+       /* add to new parent zapobj */
+       VERIFY0(zap_add(mos, dsl_dir_phys(newparent)->dd_child_dir_zapobj,
+           dd->dd_myname, 8, 1, &dd->dd_object, tx));
+
+       zvol_rename_minors(dp->dp_spa, ddra->ddra_oldname,
+           ddra->ddra_newname, B_TRUE);
+
+       dsl_prop_notify_all(dd);
+
+       dsl_dir_rele(newparent, FTAG);
+       dsl_dir_rele(dd, FTAG);
+}
+
+int
+dsl_dir_rename(const char *oldname, const char *newname)
+{
+       dsl_dir_rename_arg_t ddra;
+
+       ddra.ddra_oldname = oldname;
+       ddra.ddra_newname = newname;
+       ddra.ddra_cred = CRED();
+
+       return (dsl_sync_task(oldname,
+           dsl_dir_rename_check, dsl_dir_rename_sync, &ddra,
+           3, ZFS_SPACE_CHECK_RESERVED));
+}
+
+int
+dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
+    uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *cr)
+{
+       dsl_dir_t *ancestor;
+       int64_t adelta;
+       uint64_t avail;
+       int err;
+
+       ancestor = closest_common_ancestor(sdd, tdd);
+       adelta = would_change(sdd, -space, ancestor);
+       avail = dsl_dir_space_available(tdd, ancestor, adelta, FALSE);
+       if (avail < space)
+               return (SET_ERROR(ENOSPC));
+
+       err = dsl_fs_ss_limit_check(tdd, fs_cnt, ZFS_PROP_FILESYSTEM_LIMIT,
+           ancestor, cr);
+       if (err != 0)
+               return (err);
+       err = dsl_fs_ss_limit_check(tdd, ss_cnt, ZFS_PROP_SNAPSHOT_LIMIT,
+           ancestor, cr);
+       if (err != 0)
+               return (err);
+
+       return (0);
+}
+
+timestruc_t
+dsl_dir_snap_cmtime(dsl_dir_t *dd)
+{
+       timestruc_t t;
+
+       mutex_enter(&dd->dd_lock);
+       t = dd->dd_snap_cmtime;
+       mutex_exit(&dd->dd_lock);
+
+       return (t);
+}
+
+void
+dsl_dir_snap_cmtime_update(dsl_dir_t *dd)
+{
+       timestruc_t t;
+
+       gethrestime(&t);
+       mutex_enter(&dd->dd_lock);
+       dd->dd_snap_cmtime = t;
+       mutex_exit(&dd->dd_lock);
+}
+
+void
+dsl_dir_zapify(dsl_dir_t *dd, dmu_tx_t *tx)
+{
+       objset_t *mos = dd->dd_pool->dp_meta_objset;
+       dmu_object_zapify(mos, dd->dd_object, DMU_OT_DSL_DIR, tx);
+}
+
+boolean_t
+dsl_dir_is_zapified(dsl_dir_t *dd)
+{
+       dmu_object_info_t doi;
+
+       dmu_object_info_from_db(dd->dd_dbuf, &doi);
+       return (doi.doi_type == DMU_OTN_ZAP_METADATA);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_dir_set_quota);
+EXPORT_SYMBOL(dsl_dir_set_reservation);
+#endif
diff --git a/zfs/module/zfs/dsl_pool.c b/zfs/module/zfs/dsl_pool.c
new file mode 100755 (executable)
index 0000000..cf5259a
--- /dev/null
@@ -0,0 +1,1115 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dsl_scan.h>
+#include <sys/dnode.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_objset.h>
+#include <sys/arc.h>
+#include <sys/zap.h>
+#include <sys/zio.h>
+#include <sys/zfs_context.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/spa_impl.h>
+#include <sys/dsl_deadlist.h>
+#include <sys/bptree.h>
+#include <sys/zfeature.h>
+#include <sys/zil_impl.h>
+#include <sys/dsl_userhold.h>
+#include <sys/trace_txg.h>
+
+/*
+ * ZFS Write Throttle
+ * ------------------
+ *
+ * ZFS must limit the rate of incoming writes to the rate at which it is able
+ * to sync data modifications to the backend storage. Throttling by too much
+ * creates an artificial limit; throttling by too little can only be sustained
+ * for short periods and would lead to highly lumpy performance. On a per-pool
+ * basis, ZFS tracks the amount of modified (dirty) data. As operations change
+ * data, the amount of dirty data increases; as ZFS syncs out data, the amount
+ * of dirty data decreases. When the amount of dirty data exceeds a
+ * predetermined threshold further modifications are blocked until the amount
+ * of dirty data decreases (as data is synced out).
+ *
+ * The limit on dirty data is tunable, and should be adjusted according to
+ * both the IO capacity and available memory of the system. The larger the
+ * window, the more ZFS is able to aggregate and amortize metadata (and data)
+ * changes. However, memory is a limited resource, and allowing for more dirty
+ * data comes at the cost of keeping other useful data in memory (for example
+ * ZFS data cached by the ARC).
+ *
+ * Implementation
+ *
+ * As buffers are modified dsl_pool_willuse_space() increments both the per-
+ * txg (dp_dirty_pertxg[]) and poolwide (dp_dirty_total) accounting of
+ * dirty space used; dsl_pool_dirty_space() decrements those values as data
+ * is synced out from dsl_pool_sync(). While only the poolwide value is
+ * relevant, the per-txg value is useful for debugging. The tunable
+ * zfs_dirty_data_max determines the dirty space limit. Once that value is
+ * exceeded, new writes are halted until space frees up.
+ *
+ * The zfs_dirty_data_sync tunable dictates the threshold at which we
+ * ensure that there is a txg syncing (see the comment in txg.c for a full
+ * description of transaction group stages).
+ *
+ * The IO scheduler uses both the dirty space limit and current amount of
+ * dirty data as inputs. Those values affect the number of concurrent IOs ZFS
+ * issues. See the comment in vdev_queue.c for details of the IO scheduler.
+ *
+ * The delay is also calculated based on the amount of dirty data.  See the
+ * comment above dmu_tx_delay() for details.
+ */
+
+/*
+ * zfs_dirty_data_max will be set to zfs_dirty_data_max_percent% of all memory,
+ * capped at zfs_dirty_data_max_max.  It can also be overridden with a module
+ * parameter.
+ */
+unsigned long zfs_dirty_data_max = 0;
+unsigned long zfs_dirty_data_max_max = 0;
+int zfs_dirty_data_max_percent = 10;
+int zfs_dirty_data_max_max_percent = 25;
+
+/*
+ * If there is at least this much dirty data, push out a txg.
+ */
+unsigned long zfs_dirty_data_sync = 64 * 1024 * 1024;
+
+/*
+ * Once there is this amount of dirty data, the dmu_tx_delay() will kick in
+ * and delay each transaction.
+ * This value should be >= zfs_vdev_async_write_active_max_dirty_percent.
+ */
+int zfs_delay_min_dirty_percent = 60;
+
+/*
+ * This controls how quickly the delay approaches infinity.
+ * Larger values cause it to delay more for a given amount of dirty data.
+ * Therefore larger values will cause there to be less dirty data for a
+ * given throughput.
+ *
+ * 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.
+ *
+ * Note: zfs_delay_scale * zfs_dirty_data_max must be < 2^64, due to the
+ * multiply in dmu_tx_delay().
+ */
+unsigned long zfs_delay_scale = 1000 * 1000 * 1000 / 2000;
+
+hrtime_t zfs_throttle_delay = MSEC2NSEC(10);
+hrtime_t zfs_throttle_resolution = MSEC2NSEC(10);
+
+int
+dsl_pool_open_special_dir(dsl_pool_t *dp, const char *name, dsl_dir_t **ddp)
+{
+       uint64_t obj;
+       int err;
+
+       err = zap_lookup(dp->dp_meta_objset,
+           dsl_dir_phys(dp->dp_root_dir)->dd_child_dir_zapobj,
+           name, sizeof (obj), 1, &obj);
+       if (err)
+               return (err);
+
+       return (dsl_dir_hold_obj(dp, obj, name, dp, ddp));
+}
+
+static dsl_pool_t *
+dsl_pool_open_impl(spa_t *spa, uint64_t txg)
+{
+       dsl_pool_t *dp;
+       blkptr_t *bp = spa_get_rootblkptr(spa);
+
+       dp = kmem_zalloc(sizeof (dsl_pool_t), KM_SLEEP);
+       dp->dp_spa = spa;
+       dp->dp_meta_rootbp = *bp;
+       rrw_init(&dp->dp_config_rwlock, B_TRUE);
+       txg_init(dp, txg);
+
+       txg_list_create(&dp->dp_dirty_datasets,
+           offsetof(dsl_dataset_t, ds_dirty_link));
+       txg_list_create(&dp->dp_dirty_zilogs,
+           offsetof(zilog_t, zl_dirty_link));
+       txg_list_create(&dp->dp_dirty_dirs,
+           offsetof(dsl_dir_t, dd_dirty_link));
+       txg_list_create(&dp->dp_sync_tasks,
+           offsetof(dsl_sync_task_t, dst_node));
+
+       mutex_init(&dp->dp_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&dp->dp_spaceavail_cv, NULL, CV_DEFAULT, NULL);
+
+       dp->dp_iput_taskq = taskq_create("z_iput", max_ncpus, defclsyspri,
+           max_ncpus * 8, INT_MAX, TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
+
+       return (dp);
+}
+
+int
+dsl_pool_init(spa_t *spa, uint64_t txg, dsl_pool_t **dpp)
+{
+       int err;
+       dsl_pool_t *dp = dsl_pool_open_impl(spa, txg);
+
+       /*
+        * Initialize the caller's dsl_pool_t structure before we actually open
+        * the meta objset.  This is done because a self-healing write zio may
+        * be issued as part of dmu_objset_open_impl() and the spa needs its
+        * dsl_pool_t initialized in order to handle the write.
+        */
+       *dpp = dp;
+
+       err = dmu_objset_open_impl(spa, NULL, &dp->dp_meta_rootbp,
+           &dp->dp_meta_objset);
+       if (err != 0) {
+               dsl_pool_close(dp);
+               *dpp = NULL;
+       }
+
+       return (err);
+}
+
+int
+dsl_pool_open(dsl_pool_t *dp)
+{
+       int err;
+       dsl_dir_t *dd;
+       dsl_dataset_t *ds;
+       uint64_t obj;
+
+       rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
+       err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_ROOT_DATASET, sizeof (uint64_t), 1,
+           &dp->dp_root_dir_obj);
+       if (err)
+               goto out;
+
+       err = dsl_dir_hold_obj(dp, dp->dp_root_dir_obj,
+           NULL, dp, &dp->dp_root_dir);
+       if (err)
+               goto out;
+
+       err = dsl_pool_open_special_dir(dp, MOS_DIR_NAME, &dp->dp_mos_dir);
+       if (err)
+               goto out;
+
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_ORIGIN) {
+               err = dsl_pool_open_special_dir(dp, ORIGIN_DIR_NAME, &dd);
+               if (err)
+                       goto out;
+               err = dsl_dataset_hold_obj(dp,
+                   dsl_dir_phys(dd)->dd_head_dataset_obj, FTAG, &ds);
+               if (err == 0) {
+                       err = dsl_dataset_hold_obj(dp,
+                           dsl_dataset_phys(ds)->ds_prev_snap_obj, dp,
+                           &dp->dp_origin_snap);
+                       dsl_dataset_rele(ds, FTAG);
+               }
+               dsl_dir_rele(dd, dp);
+               if (err)
+                       goto out;
+       }
+
+       if (spa_version(dp->dp_spa) >= SPA_VERSION_DEADLISTS) {
+               err = dsl_pool_open_special_dir(dp, FREE_DIR_NAME,
+                   &dp->dp_free_dir);
+               if (err)
+                       goto out;
+
+               err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_FREE_BPOBJ, sizeof (uint64_t), 1, &obj);
+               if (err)
+                       goto out;
+               VERIFY0(bpobj_open(&dp->dp_free_bpobj,
+                   dp->dp_meta_objset, obj));
+       }
+
+       /*
+        * Note: errors ignored, because the leak dir will not exist if we
+        * have not encountered a leak yet.
+        */
+       (void) dsl_pool_open_special_dir(dp, LEAK_DIR_NAME,
+           &dp->dp_leak_dir);
+
+       if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) {
+               err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1,
+                   &dp->dp_bptree_obj);
+               if (err != 0)
+                       goto out;
+       }
+
+       if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMPTY_BPOBJ)) {
+               err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
+                   &dp->dp_empty_bpobj);
+               if (err != 0)
+                       goto out;
+       }
+
+       err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_TMP_USERREFS, sizeof (uint64_t), 1,
+           &dp->dp_tmp_userrefs_obj);
+       if (err == ENOENT)
+               err = 0;
+       if (err)
+               goto out;
+
+       err = dsl_scan_init(dp, dp->dp_tx.tx_open_txg);
+
+out:
+       rrw_exit(&dp->dp_config_rwlock, FTAG);
+       return (err);
+}
+
+void
+dsl_pool_close(dsl_pool_t *dp)
+{
+       /*
+        * Drop our references from dsl_pool_open().
+        *
+        * Since we held the origin_snap from "syncing" context (which
+        * includes pool-opening context), it actually only got a "ref"
+        * and not a hold, so just drop that here.
+        */
+       if (dp->dp_origin_snap)
+               dsl_dataset_rele(dp->dp_origin_snap, dp);
+       if (dp->dp_mos_dir)
+               dsl_dir_rele(dp->dp_mos_dir, dp);
+       if (dp->dp_free_dir)
+               dsl_dir_rele(dp->dp_free_dir, dp);
+       if (dp->dp_leak_dir)
+               dsl_dir_rele(dp->dp_leak_dir, dp);
+       if (dp->dp_root_dir)
+               dsl_dir_rele(dp->dp_root_dir, dp);
+
+       bpobj_close(&dp->dp_free_bpobj);
+
+       /* undo the dmu_objset_open_impl(mos) from dsl_pool_open() */
+       if (dp->dp_meta_objset)
+               dmu_objset_evict(dp->dp_meta_objset);
+
+       txg_list_destroy(&dp->dp_dirty_datasets);
+       txg_list_destroy(&dp->dp_dirty_zilogs);
+       txg_list_destroy(&dp->dp_sync_tasks);
+       txg_list_destroy(&dp->dp_dirty_dirs);
+
+       /*
+        * We can't set retry to TRUE since we're explicitly specifying
+        * a spa to flush. This is good enough; any missed buffers for
+        * this spa won't cause trouble, and they'll eventually fall
+        * out of the ARC just like any other unused buffer.
+        */
+       arc_flush(dp->dp_spa, FALSE);
+
+       txg_fini(dp);
+       dsl_scan_fini(dp);
+       dmu_buf_user_evict_wait();
+
+       rrw_destroy(&dp->dp_config_rwlock);
+       mutex_destroy(&dp->dp_lock);
+       taskq_destroy(dp->dp_iput_taskq);
+       if (dp->dp_blkstats)
+               vmem_free(dp->dp_blkstats, sizeof (zfs_all_blkstats_t));
+       kmem_free(dp, sizeof (dsl_pool_t));
+}
+
+dsl_pool_t *
+dsl_pool_create(spa_t *spa, nvlist_t *zplprops, uint64_t txg)
+{
+       int err;
+       dsl_pool_t *dp = dsl_pool_open_impl(spa, txg);
+       dmu_tx_t *tx = dmu_tx_create_assigned(dp, txg);
+       objset_t *os;
+       dsl_dataset_t *ds;
+       uint64_t obj;
+
+       rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
+
+       /* create and open the MOS (meta-objset) */
+       dp->dp_meta_objset = dmu_objset_create_impl(spa,
+           NULL, &dp->dp_meta_rootbp, DMU_OST_META, tx);
+
+       /* create the pool directory */
+       err = zap_create_claim(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_OT_OBJECT_DIRECTORY, DMU_OT_NONE, 0, tx);
+       ASSERT0(err);
+
+       /* Initialize scan structures */
+       VERIFY0(dsl_scan_init(dp, txg));
+
+       /* create and open the root dir */
+       dp->dp_root_dir_obj = dsl_dir_create_sync(dp, NULL, NULL, tx);
+       VERIFY0(dsl_dir_hold_obj(dp, dp->dp_root_dir_obj,
+           NULL, dp, &dp->dp_root_dir));
+
+       /* create and open the meta-objset dir */
+       (void) dsl_dir_create_sync(dp, dp->dp_root_dir, MOS_DIR_NAME, tx);
+       VERIFY0(dsl_pool_open_special_dir(dp,
+           MOS_DIR_NAME, &dp->dp_mos_dir));
+
+       if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
+               /* create and open the free dir */
+               (void) dsl_dir_create_sync(dp, dp->dp_root_dir,
+                   FREE_DIR_NAME, tx);
+               VERIFY0(dsl_pool_open_special_dir(dp,
+                   FREE_DIR_NAME, &dp->dp_free_dir));
+
+               /* create and open the free_bplist */
+               obj = bpobj_alloc(dp->dp_meta_objset, SPA_OLD_MAXBLOCKSIZE, tx);
+               VERIFY(zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_FREE_BPOBJ, sizeof (uint64_t), 1, &obj, tx) == 0);
+               VERIFY0(bpobj_open(&dp->dp_free_bpobj,
+                   dp->dp_meta_objset, obj));
+       }
+
+       if (spa_version(spa) >= SPA_VERSION_DSL_SCRUB)
+               dsl_pool_create_origin(dp, tx);
+
+       /* create the root dataset */
+       obj = dsl_dataset_create_sync_dd(dp->dp_root_dir, NULL, 0, tx);
+
+       /* create the root objset */
+       VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG, &ds));
+       VERIFY(NULL != (os = dmu_objset_create_impl(dp->dp_spa, ds,
+           dsl_dataset_get_blkptr(ds), DMU_OST_ZFS, tx)));
+#ifdef _KERNEL
+       zfs_create_fs(os, kcred, zplprops, tx);
+#endif
+       dsl_dataset_rele(ds, FTAG);
+
+       dmu_tx_commit(tx);
+
+       rrw_exit(&dp->dp_config_rwlock, FTAG);
+
+       return (dp);
+}
+
+/*
+ * Account for the meta-objset space in its placeholder dsl_dir.
+ */
+void
+dsl_pool_mos_diduse_space(dsl_pool_t *dp,
+    int64_t used, int64_t comp, int64_t uncomp)
+{
+       ASSERT3U(comp, ==, uncomp); /* it's all metadata */
+       mutex_enter(&dp->dp_lock);
+       dp->dp_mos_used_delta += used;
+       dp->dp_mos_compressed_delta += comp;
+       dp->dp_mos_uncompressed_delta += uncomp;
+       mutex_exit(&dp->dp_lock);
+}
+
+static int
+deadlist_enqueue_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       dsl_deadlist_t *dl = arg;
+       dsl_deadlist_insert(dl, bp, tx);
+       return (0);
+}
+
+static void
+dsl_pool_sync_mos(dsl_pool_t *dp, dmu_tx_t *tx)
+{
+       zio_t *zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
+       dmu_objset_sync(dp->dp_meta_objset, zio, tx);
+       VERIFY0(zio_wait(zio));
+       dprintf_bp(&dp->dp_meta_rootbp, "meta objset rootbp is %s", "");
+       spa_set_rootblkptr(dp->dp_spa, &dp->dp_meta_rootbp);
+}
+
+static void
+dsl_pool_dirty_delta(dsl_pool_t *dp, int64_t delta)
+{
+       ASSERT(MUTEX_HELD(&dp->dp_lock));
+
+       if (delta < 0)
+               ASSERT3U(-delta, <=, dp->dp_dirty_total);
+
+       dp->dp_dirty_total += delta;
+
+       /*
+        * Note: we signal even when increasing dp_dirty_total.
+        * This ensures forward progress -- each thread wakes the next waiter.
+        */
+       if (dp->dp_dirty_total <= zfs_dirty_data_max)
+               cv_signal(&dp->dp_spaceavail_cv);
+}
+
+void
+dsl_pool_sync(dsl_pool_t *dp, uint64_t txg)
+{
+       zio_t *zio;
+       dmu_tx_t *tx;
+       dsl_dir_t *dd;
+       dsl_dataset_t *ds;
+       objset_t *mos = dp->dp_meta_objset;
+       list_t synced_datasets;
+
+       list_create(&synced_datasets, sizeof (dsl_dataset_t),
+           offsetof(dsl_dataset_t, ds_synced_link));
+
+       tx = dmu_tx_create_assigned(dp, txg);
+
+       /*
+        * Write out all dirty blocks of dirty datasets.
+        */
+       zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
+       while ((ds = txg_list_remove(&dp->dp_dirty_datasets, txg)) != NULL) {
+               /*
+                * We must not sync any non-MOS datasets twice, because
+                * we may have taken a snapshot of them.  However, we
+                * may sync newly-created datasets on pass 2.
+                */
+               ASSERT(!list_link_active(&ds->ds_synced_link));
+               list_insert_tail(&synced_datasets, ds);
+               dsl_dataset_sync(ds, zio, tx);
+       }
+       VERIFY0(zio_wait(zio));
+
+       /*
+        * We have written all of the accounted dirty data, so our
+        * dp_space_towrite should now be zero.  However, some seldom-used
+        * code paths do not adhere to this (e.g. dbuf_undirty(), also
+        * rounding error in dbuf_write_physdone).
+        * Shore up the accounting of any dirtied space now.
+        */
+       dsl_pool_undirty_space(dp, dp->dp_dirty_pertxg[txg & TXG_MASK], txg);
+
+       /*
+        * After the data blocks have been written (ensured by the zio_wait()
+        * above), update the user/group space accounting.
+        */
+       for (ds = list_head(&synced_datasets); ds != NULL;
+           ds = list_next(&synced_datasets, ds)) {
+               dmu_objset_do_userquota_updates(ds->ds_objset, tx);
+       }
+
+       /*
+        * Sync the datasets again to push out the changes due to
+        * userspace updates.  This must be done before we process the
+        * sync tasks, so that any snapshots will have the correct
+        * user accounting information (and we won't get confused
+        * about which blocks are part of the snapshot).
+        */
+       zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
+       while ((ds = txg_list_remove(&dp->dp_dirty_datasets, txg)) != NULL) {
+               ASSERT(list_link_active(&ds->ds_synced_link));
+               dmu_buf_rele(ds->ds_dbuf, ds);
+               dsl_dataset_sync(ds, zio, tx);
+       }
+       VERIFY0(zio_wait(zio));
+
+       /*
+        * Now that the datasets have been completely synced, we can
+        * clean up our in-memory structures accumulated while syncing:
+        *
+        *  - move dead blocks from the pending deadlist to the on-disk deadlist
+        *  - release hold from dsl_dataset_dirty()
+        */
+       while ((ds = list_remove_head(&synced_datasets)) != NULL) {
+               ASSERTV(objset_t *os = ds->ds_objset);
+               bplist_iterate(&ds->ds_pending_deadlist,
+                   deadlist_enqueue_cb, &ds->ds_deadlist, tx);
+               ASSERT(!dmu_objset_is_dirty(os, txg));
+               dmu_buf_rele(ds->ds_dbuf, ds);
+       }
+
+       while ((dd = txg_list_remove(&dp->dp_dirty_dirs, txg)) != NULL) {
+               dsl_dir_sync(dd, tx);
+       }
+
+       /*
+        * The MOS's space is accounted for in the pool/$MOS
+        * (dp_mos_dir).  We can't modify the mos while we're syncing
+        * it, so we remember the deltas and apply them here.
+        */
+       if (dp->dp_mos_used_delta != 0 || dp->dp_mos_compressed_delta != 0 ||
+           dp->dp_mos_uncompressed_delta != 0) {
+               dsl_dir_diduse_space(dp->dp_mos_dir, DD_USED_HEAD,
+                   dp->dp_mos_used_delta,
+                   dp->dp_mos_compressed_delta,
+                   dp->dp_mos_uncompressed_delta, tx);
+               dp->dp_mos_used_delta = 0;
+               dp->dp_mos_compressed_delta = 0;
+               dp->dp_mos_uncompressed_delta = 0;
+       }
+
+       if (list_head(&mos->os_dirty_dnodes[txg & TXG_MASK]) != NULL ||
+           list_head(&mos->os_free_dnodes[txg & TXG_MASK]) != NULL) {
+               dsl_pool_sync_mos(dp, tx);
+       }
+
+       /*
+        * If we modify a dataset in the same txg that we want to destroy it,
+        * its dsl_dir's dd_dbuf will be dirty, and thus have a hold on it.
+        * dsl_dir_destroy_check() will fail if there are unexpected holds.
+        * Therefore, we want to sync the MOS (thus syncing the dd_dbuf
+        * and clearing the hold on it) before we process the sync_tasks.
+        * The MOS data dirtied by the sync_tasks will be synced on the next
+        * pass.
+        */
+       if (!txg_list_empty(&dp->dp_sync_tasks, txg)) {
+               dsl_sync_task_t *dst;
+               /*
+                * No more sync tasks should have been added while we
+                * were syncing.
+                */
+               ASSERT3U(spa_sync_pass(dp->dp_spa), ==, 1);
+               while ((dst = txg_list_remove(&dp->dp_sync_tasks, txg)) != NULL)
+                       dsl_sync_task_sync(dst, tx);
+       }
+
+       dmu_tx_commit(tx);
+
+       DTRACE_PROBE2(dsl_pool_sync__done, dsl_pool_t *dp, dp, uint64_t, txg);
+}
+
+void
+dsl_pool_sync_done(dsl_pool_t *dp, uint64_t txg)
+{
+       zilog_t *zilog;
+
+       while ((zilog = txg_list_remove(&dp->dp_dirty_zilogs, txg))) {
+               dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os);
+               zil_clean(zilog, txg);
+               ASSERT(!dmu_objset_is_dirty(zilog->zl_os, txg));
+               dmu_buf_rele(ds->ds_dbuf, zilog);
+       }
+       ASSERT(!dmu_objset_is_dirty(dp->dp_meta_objset, txg));
+}
+
+/*
+ * TRUE if the current thread is the tx_sync_thread or if we
+ * are being called from SPA context during pool initialization.
+ */
+int
+dsl_pool_sync_context(dsl_pool_t *dp)
+{
+       return (curthread == dp->dp_tx.tx_sync_thread ||
+           spa_is_initializing(dp->dp_spa));
+}
+
+uint64_t
+dsl_pool_adjustedsize(dsl_pool_t *dp, boolean_t netfree)
+{
+       uint64_t space, resv;
+
+       /*
+        * If we're trying to assess whether it's OK to do a free,
+        * cut the reservation in half to allow forward progress
+        * (e.g. make it possible to rm(1) files from a full pool).
+        */
+       space = spa_get_dspace(dp->dp_spa);
+       resv = spa_get_slop_space(dp->dp_spa);
+       if (netfree)
+               resv >>= 1;
+
+       return (space - resv);
+}
+
+boolean_t
+dsl_pool_need_dirty_delay(dsl_pool_t *dp)
+{
+       uint64_t delay_min_bytes =
+           zfs_dirty_data_max * zfs_delay_min_dirty_percent / 100;
+       boolean_t rv;
+
+       mutex_enter(&dp->dp_lock);
+       if (dp->dp_dirty_total > zfs_dirty_data_sync)
+               txg_kick(dp);
+       rv = (dp->dp_dirty_total > delay_min_bytes);
+       mutex_exit(&dp->dp_lock);
+       return (rv);
+}
+
+void
+dsl_pool_dirty_space(dsl_pool_t *dp, int64_t space, dmu_tx_t *tx)
+{
+       if (space > 0) {
+               mutex_enter(&dp->dp_lock);
+               dp->dp_dirty_pertxg[tx->tx_txg & TXG_MASK] += space;
+               dsl_pool_dirty_delta(dp, space);
+               mutex_exit(&dp->dp_lock);
+       }
+}
+
+void
+dsl_pool_undirty_space(dsl_pool_t *dp, int64_t space, uint64_t txg)
+{
+       ASSERT3S(space, >=, 0);
+       if (space == 0)
+               return;
+
+       mutex_enter(&dp->dp_lock);
+       if (dp->dp_dirty_pertxg[txg & TXG_MASK] < space) {
+               /* XXX writing something we didn't dirty? */
+               space = dp->dp_dirty_pertxg[txg & TXG_MASK];
+       }
+       ASSERT3U(dp->dp_dirty_pertxg[txg & TXG_MASK], >=, space);
+       dp->dp_dirty_pertxg[txg & TXG_MASK] -= space;
+       ASSERT3U(dp->dp_dirty_total, >=, space);
+       dsl_pool_dirty_delta(dp, -space);
+       mutex_exit(&dp->dp_lock);
+}
+
+/* ARGSUSED */
+static int
+upgrade_clones_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg)
+{
+       dmu_tx_t *tx = arg;
+       dsl_dataset_t *ds, *prev = NULL;
+       int err;
+
+       err = dsl_dataset_hold_obj(dp, hds->ds_object, FTAG, &ds);
+       if (err)
+               return (err);
+
+       while (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
+               err = dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
+               if (err) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (err);
+               }
+
+               if (dsl_dataset_phys(prev)->ds_next_snap_obj != ds->ds_object)
+                       break;
+               dsl_dataset_rele(ds, FTAG);
+               ds = prev;
+               prev = NULL;
+       }
+
+       if (prev == NULL) {
+               prev = dp->dp_origin_snap;
+
+               /*
+                * The $ORIGIN can't have any data, or the accounting
+                * will be wrong.
+                */
+               ASSERT0(dsl_dataset_phys(prev)->ds_bp.blk_birth);
+
+               /* The origin doesn't get attached to itself */
+               if (ds->ds_object == prev->ds_object) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (0);
+               }
+
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               dsl_dataset_phys(ds)->ds_prev_snap_obj = prev->ds_object;
+               dsl_dataset_phys(ds)->ds_prev_snap_txg =
+                   dsl_dataset_phys(prev)->ds_creation_txg;
+
+               dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx);
+               dsl_dir_phys(ds->ds_dir)->dd_origin_obj = prev->ds_object;
+
+               dmu_buf_will_dirty(prev->ds_dbuf, tx);
+               dsl_dataset_phys(prev)->ds_num_children++;
+
+               if (dsl_dataset_phys(ds)->ds_next_snap_obj == 0) {
+                       ASSERT(ds->ds_prev == NULL);
+                       VERIFY0(dsl_dataset_hold_obj(dp,
+                           dsl_dataset_phys(ds)->ds_prev_snap_obj,
+                           ds, &ds->ds_prev));
+               }
+       }
+
+       ASSERT3U(dsl_dir_phys(ds->ds_dir)->dd_origin_obj, ==, prev->ds_object);
+       ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_obj, ==, prev->ds_object);
+
+       if (dsl_dataset_phys(prev)->ds_next_clones_obj == 0) {
+               dmu_buf_will_dirty(prev->ds_dbuf, tx);
+               dsl_dataset_phys(prev)->ds_next_clones_obj =
+                   zap_create(dp->dp_meta_objset,
+                   DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx);
+       }
+       VERIFY0(zap_add_int(dp->dp_meta_objset,
+           dsl_dataset_phys(prev)->ds_next_clones_obj, ds->ds_object, tx));
+
+       dsl_dataset_rele(ds, FTAG);
+       if (prev != dp->dp_origin_snap)
+               dsl_dataset_rele(prev, FTAG);
+       return (0);
+}
+
+void
+dsl_pool_upgrade_clones(dsl_pool_t *dp, dmu_tx_t *tx)
+{
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(dp->dp_origin_snap != NULL);
+
+       VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj, upgrade_clones_cb,
+           tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE));
+}
+
+/* ARGSUSED */
+static int
+upgrade_dir_clones_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
+{
+       dmu_tx_t *tx = arg;
+       objset_t *mos = dp->dp_meta_objset;
+
+       if (dsl_dir_phys(ds->ds_dir)->dd_origin_obj != 0) {
+               dsl_dataset_t *origin;
+
+               VERIFY0(dsl_dataset_hold_obj(dp,
+                   dsl_dir_phys(ds->ds_dir)->dd_origin_obj, FTAG, &origin));
+
+               if (dsl_dir_phys(origin->ds_dir)->dd_clones == 0) {
+                       dmu_buf_will_dirty(origin->ds_dir->dd_dbuf, tx);
+                       dsl_dir_phys(origin->ds_dir)->dd_clones =
+                           zap_create(mos, DMU_OT_DSL_CLONES, DMU_OT_NONE,
+                           0, tx);
+               }
+
+               VERIFY0(zap_add_int(dp->dp_meta_objset,
+                   dsl_dir_phys(origin->ds_dir)->dd_clones,
+                   ds->ds_object, tx));
+
+               dsl_dataset_rele(origin, FTAG);
+       }
+       return (0);
+}
+
+void
+dsl_pool_upgrade_dir_clones(dsl_pool_t *dp, dmu_tx_t *tx)
+{
+       uint64_t obj;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       (void) dsl_dir_create_sync(dp, dp->dp_root_dir, FREE_DIR_NAME, tx);
+       VERIFY0(dsl_pool_open_special_dir(dp,
+           FREE_DIR_NAME, &dp->dp_free_dir));
+
+       /*
+        * We can't use bpobj_alloc(), because spa_version() still
+        * returns the old version, and we need a new-version bpobj with
+        * subobj support.  So call dmu_object_alloc() directly.
+        */
+       obj = dmu_object_alloc(dp->dp_meta_objset, DMU_OT_BPOBJ,
+           SPA_OLD_MAXBLOCKSIZE, DMU_OT_BPOBJ_HDR, sizeof (bpobj_phys_t), tx);
+       VERIFY0(zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_FREE_BPOBJ, sizeof (uint64_t), 1, &obj, tx));
+       VERIFY0(bpobj_open(&dp->dp_free_bpobj, dp->dp_meta_objset, obj));
+
+       VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj,
+           upgrade_dir_clones_cb, tx, DS_FIND_CHILDREN | DS_FIND_SERIALIZE));
+}
+
+void
+dsl_pool_create_origin(dsl_pool_t *dp, dmu_tx_t *tx)
+{
+       uint64_t dsobj;
+       dsl_dataset_t *ds;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT(dp->dp_origin_snap == NULL);
+       ASSERT(rrw_held(&dp->dp_config_rwlock, RW_WRITER));
+
+       /* create the origin dir, ds, & snap-ds */
+       dsobj = dsl_dataset_create_sync(dp->dp_root_dir, ORIGIN_DIR_NAME,
+           NULL, 0, kcred, tx);
+       VERIFY0(dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
+       dsl_dataset_snapshot_sync_impl(ds, ORIGIN_DIR_NAME, tx);
+       VERIFY0(dsl_dataset_hold_obj(dp, dsl_dataset_phys(ds)->ds_prev_snap_obj,
+           dp, &dp->dp_origin_snap));
+       dsl_dataset_rele(ds, FTAG);
+}
+
+taskq_t *
+dsl_pool_iput_taskq(dsl_pool_t *dp)
+{
+       return (dp->dp_iput_taskq);
+}
+
+/*
+ * Walk through the pool-wide zap object of temporary snapshot user holds
+ * and release them.
+ */
+void
+dsl_pool_clean_tmp_userrefs(dsl_pool_t *dp)
+{
+       zap_attribute_t za;
+       zap_cursor_t zc;
+       objset_t *mos = dp->dp_meta_objset;
+       uint64_t zapobj = dp->dp_tmp_userrefs_obj;
+       nvlist_t *holds;
+
+       if (zapobj == 0)
+               return;
+       ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
+
+       holds = fnvlist_alloc();
+
+       for (zap_cursor_init(&zc, mos, zapobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               char *htag;
+               nvlist_t *tags;
+
+               htag = strchr(za.za_name, '-');
+               *htag = '\0';
+               ++htag;
+               if (nvlist_lookup_nvlist(holds, za.za_name, &tags) != 0) {
+                       tags = fnvlist_alloc();
+                       fnvlist_add_boolean(tags, htag);
+                       fnvlist_add_nvlist(holds, za.za_name, tags);
+                       fnvlist_free(tags);
+               } else {
+                       fnvlist_add_boolean(tags, htag);
+               }
+       }
+       dsl_dataset_user_release_tmp(dp, holds);
+       fnvlist_free(holds);
+       zap_cursor_fini(&zc);
+}
+
+/*
+ * Create the pool-wide zap object for storing temporary snapshot holds.
+ */
+void
+dsl_pool_user_hold_create_obj(dsl_pool_t *dp, dmu_tx_t *tx)
+{
+       objset_t *mos = dp->dp_meta_objset;
+
+       ASSERT(dp->dp_tmp_userrefs_obj == 0);
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       dp->dp_tmp_userrefs_obj = zap_create_link(mos, DMU_OT_USERREFS,
+           DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_TMP_USERREFS, tx);
+}
+
+static int
+dsl_pool_user_hold_rele_impl(dsl_pool_t *dp, uint64_t dsobj,
+    const char *tag, uint64_t now, dmu_tx_t *tx, boolean_t holding)
+{
+       objset_t *mos = dp->dp_meta_objset;
+       uint64_t zapobj = dp->dp_tmp_userrefs_obj;
+       char *name;
+       int error;
+
+       ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       /*
+        * If the pool was created prior to SPA_VERSION_USERREFS, the
+        * zap object for temporary holds might not exist yet.
+        */
+       if (zapobj == 0) {
+               if (holding) {
+                       dsl_pool_user_hold_create_obj(dp, tx);
+                       zapobj = dp->dp_tmp_userrefs_obj;
+               } else {
+                       return (SET_ERROR(ENOENT));
+               }
+       }
+
+       name = kmem_asprintf("%llx-%s", (u_longlong_t)dsobj, tag);
+       if (holding)
+               error = zap_add(mos, zapobj, name, 8, 1, &now, tx);
+       else
+               error = zap_remove(mos, zapobj, name, tx);
+       strfree(name);
+
+       return (error);
+}
+
+/*
+ * Add a temporary hold for the given dataset object and tag.
+ */
+int
+dsl_pool_user_hold(dsl_pool_t *dp, uint64_t dsobj, const char *tag,
+    uint64_t now, dmu_tx_t *tx)
+{
+       return (dsl_pool_user_hold_rele_impl(dp, dsobj, tag, now, tx, B_TRUE));
+}
+
+/*
+ * Release a temporary hold for the given dataset object and tag.
+ */
+int
+dsl_pool_user_release(dsl_pool_t *dp, uint64_t dsobj, const char *tag,
+    dmu_tx_t *tx)
+{
+       return (dsl_pool_user_hold_rele_impl(dp, dsobj, tag, 0,
+           tx, B_FALSE));
+}
+
+/*
+ * DSL Pool Configuration Lock
+ *
+ * The dp_config_rwlock protects against changes to DSL state (e.g. dataset
+ * creation / destruction / rename / property setting).  It must be held for
+ * read to hold a dataset or dsl_dir.  I.e. you must call
+ * dsl_pool_config_enter() or dsl_pool_hold() before calling
+ * dsl_{dataset,dir}_hold{_obj}.  In most circumstances, the dp_config_rwlock
+ * must be held continuously until all datasets and dsl_dirs are released.
+ *
+ * The only exception to this rule is that if a "long hold" is placed on
+ * a dataset, then the dp_config_rwlock may be dropped while the dataset
+ * is still held.  The long hold will prevent the dataset from being
+ * destroyed -- the destroy will fail with EBUSY.  A long hold can be
+ * obtained by calling dsl_dataset_long_hold(), or by "owning" a dataset
+ * (by calling dsl_{dataset,objset}_{try}own{_obj}).
+ *
+ * Legitimate long-holders (including owners) should be long-running, cancelable
+ * tasks that should cause "zfs destroy" to fail.  This includes DMU
+ * consumers (i.e. a ZPL filesystem being mounted or ZVOL being open),
+ * "zfs send", and "zfs diff".  There are several other long-holders whose
+ * uses are suboptimal (e.g. "zfs promote", and zil_suspend()).
+ *
+ * The usual formula for long-holding would be:
+ * dsl_pool_hold()
+ * dsl_dataset_hold()
+ * ... perform checks ...
+ * dsl_dataset_long_hold()
+ * dsl_pool_rele()
+ * ... perform long-running task ...
+ * dsl_dataset_long_rele()
+ * dsl_dataset_rele()
+ *
+ * Note that when the long hold is released, the dataset is still held but
+ * the pool is not held.  The dataset may change arbitrarily during this time
+ * (e.g. it could be destroyed).  Therefore you shouldn't do anything to the
+ * dataset except release it.
+ *
+ * User-initiated operations (e.g. ioctls, zfs_ioc_*()) are either read-only
+ * or modifying operations.
+ *
+ * Modifying operations should generally use dsl_sync_task().  The synctask
+ * infrastructure enforces proper locking strategy with respect to the
+ * dp_config_rwlock.  See the comment above dsl_sync_task() for details.
+ *
+ * Read-only operations will manually hold the pool, then the dataset, obtain
+ * information from the dataset, then release the pool and dataset.
+ * dmu_objset_{hold,rele}() are convenience routines that also do the pool
+ * hold/rele.
+ */
+
+int
+dsl_pool_hold(const char *name, void *tag, dsl_pool_t **dp)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(name, &spa, tag);
+       if (error == 0) {
+               *dp = spa_get_dsl(spa);
+               dsl_pool_config_enter(*dp, tag);
+       }
+       return (error);
+}
+
+void
+dsl_pool_rele(dsl_pool_t *dp, void *tag)
+{
+       dsl_pool_config_exit(dp, tag);
+       spa_close(dp->dp_spa, tag);
+}
+
+void
+dsl_pool_config_enter(dsl_pool_t *dp, void *tag)
+{
+       /*
+        * We use a "reentrant" reader-writer lock, but not reentrantly.
+        *
+        * The rrwlock can (with the track_all flag) track all reading threads,
+        * which is very useful for debugging which code path failed to release
+        * the lock, and for verifying that the *current* thread does hold
+        * the lock.
+        *
+        * (Unlike a rwlock, which knows that N threads hold it for
+        * read, but not *which* threads, so rw_held(RW_READER) returns TRUE
+        * if any thread holds it for read, even if this thread doesn't).
+        */
+       ASSERT(!rrw_held(&dp->dp_config_rwlock, RW_READER));
+       rrw_enter(&dp->dp_config_rwlock, RW_READER, tag);
+}
+
+void
+dsl_pool_config_enter_prio(dsl_pool_t *dp, void *tag)
+{
+       ASSERT(!rrw_held(&dp->dp_config_rwlock, RW_READER));
+       rrw_enter_read_prio(&dp->dp_config_rwlock, tag);
+}
+
+void
+dsl_pool_config_exit(dsl_pool_t *dp, void *tag)
+{
+       rrw_exit(&dp->dp_config_rwlock, tag);
+}
+
+boolean_t
+dsl_pool_config_held(dsl_pool_t *dp)
+{
+       return (RRW_LOCK_HELD(&dp->dp_config_rwlock));
+}
+
+boolean_t
+dsl_pool_config_held_writer(dsl_pool_t *dp)
+{
+       return (RRW_WRITE_HELD(&dp->dp_config_rwlock));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_pool_config_enter);
+EXPORT_SYMBOL(dsl_pool_config_exit);
+
+/* zfs_dirty_data_max_percent only applied at module load in arc_init(). */
+module_param(zfs_dirty_data_max_percent, int, 0444);
+MODULE_PARM_DESC(zfs_dirty_data_max_percent, "percent of ram can be dirty");
+
+/* zfs_dirty_data_max_max_percent only applied at module load in arc_init(). */
+module_param(zfs_dirty_data_max_max_percent, int, 0444);
+MODULE_PARM_DESC(zfs_dirty_data_max_max_percent,
+       "zfs_dirty_data_max upper bound as % of RAM");
+
+module_param(zfs_delay_min_dirty_percent, int, 0644);
+MODULE_PARM_DESC(zfs_delay_min_dirty_percent, "transaction delay threshold");
+
+module_param(zfs_dirty_data_max, ulong, 0644);
+MODULE_PARM_DESC(zfs_dirty_data_max, "determines the dirty space limit");
+
+/* zfs_dirty_data_max_max only applied at module load in arc_init(). */
+module_param(zfs_dirty_data_max_max, ulong, 0444);
+MODULE_PARM_DESC(zfs_dirty_data_max_max,
+       "zfs_dirty_data_max upper bound in bytes");
+
+module_param(zfs_dirty_data_sync, ulong, 0644);
+MODULE_PARM_DESC(zfs_dirty_data_sync, "sync txg when this much dirty data");
+
+module_param(zfs_delay_scale, ulong, 0644);
+MODULE_PARM_DESC(zfs_delay_scale, "how quickly delay approaches infinity");
+#endif
diff --git a/zfs/module/zfs/dsl_prop.c b/zfs/module/zfs/dsl_prop.c
new file mode 100644 (file)
index 0000000..28b101e
--- /dev/null
@@ -0,0 +1,1175 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Martin Matuska. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/spa.h>
+#include <sys/zap.h>
+#include <sys/fs/zfs.h>
+
+#include "zfs_prop.h"
+
+#define        ZPROP_INHERIT_SUFFIX "$inherit"
+#define        ZPROP_RECVD_SUFFIX "$recvd"
+
+static int
+dodefault(const char *propname, 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 ||
+           (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
+               return (SET_ERROR(ENOENT));
+
+       if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
+               if (intsz != 1)
+                       return (SET_ERROR(EOVERFLOW));
+               (void) strncpy(buf, zfs_prop_default_string(prop),
+                   numints);
+       } else {
+               if (intsz != 8 || numints < 1)
+                       return (SET_ERROR(EOVERFLOW));
+
+               *(uint64_t *)buf = zfs_prop_default_numeric(prop);
+       }
+
+       return (0);
+}
+
+int
+dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
+    int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
+{
+       int err = ENOENT;
+       dsl_dir_t *target = dd;
+       objset_t *mos = dd->dd_pool->dp_meta_objset;
+       zfs_prop_t prop;
+       boolean_t inheritable;
+       boolean_t inheriting = B_FALSE;
+       char *inheritstr;
+       char *recvdstr;
+
+       ASSERT(dsl_pool_config_held(dd->dd_pool));
+
+       if (setpoint)
+               setpoint[0] = '\0';
+
+       prop = zfs_name_to_prop(propname);
+       inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
+       inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
+       recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
+
+       /*
+        * Note: dd may become NULL, therefore we shouldn't dereference it
+        * after this loop.
+        */
+       for (; dd != NULL; dd = dd->dd_parent) {
+               if (dd != target || snapshot) {
+                       if (!inheritable)
+                               break;
+                       inheriting = B_TRUE;
+               }
+
+               /* Check for a local value. */
+               err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
+                   propname, intsz, numints, buf);
+               if (err != ENOENT) {
+                       if (setpoint != NULL && err == 0)
+                               dsl_dir_name(dd, setpoint);
+                       break;
+               }
+
+               /*
+                * Skip the check for a received value if there is an explicit
+                * inheritance entry.
+                */
+               err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
+                   inheritstr);
+               if (err != 0 && err != ENOENT)
+                       break;
+
+               if (err == ENOENT) {
+                       /* Check for a received value. */
+                       err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
+                           recvdstr, intsz, numints, buf);
+                       if (err != ENOENT) {
+                               if (setpoint != NULL && err == 0) {
+                                       if (inheriting) {
+                                               dsl_dir_name(dd, setpoint);
+                                       } else {
+                                               (void) strcpy(setpoint,
+                                                   ZPROP_SOURCE_VAL_RECVD);
+                                       }
+                               }
+                               break;
+                       }
+               }
+
+               /*
+                * If we found an explicit inheritance entry, err is zero even
+                * though we haven't yet found the value, so reinitializing err
+                * at the end of the loop (instead of at the beginning) ensures
+                * that err has a valid post-loop value.
+                */
+               err = SET_ERROR(ENOENT);
+       }
+
+       if (err == ENOENT)
+               err = dodefault(propname, intsz, numints, buf);
+
+       strfree(inheritstr);
+       strfree(recvdstr);
+
+       return (err);
+}
+
+int
+dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
+    int intsz, int numints, void *buf, char *setpoint)
+{
+       zfs_prop_t prop = zfs_name_to_prop(propname);
+       boolean_t inheritable;
+       uint64_t zapobj;
+
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
+       inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
+       zapobj = dsl_dataset_phys(ds)->ds_props_obj;
+
+       if (zapobj != 0) {
+               objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+               int err;
+
+               ASSERT(ds->ds_is_snapshot);
+
+               /* Check for a local value. */
+               err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
+               if (err != ENOENT) {
+                       if (setpoint != NULL && err == 0)
+                               dsl_dataset_name(ds, setpoint);
+                       return (err);
+               }
+
+               /*
+                * Skip the check for a received value if there is an explicit
+                * inheritance entry.
+                */
+               if (inheritable) {
+                       char *inheritstr = kmem_asprintf("%s%s", propname,
+                           ZPROP_INHERIT_SUFFIX);
+                       err = zap_contains(mos, zapobj, inheritstr);
+                       strfree(inheritstr);
+                       if (err != 0 && err != ENOENT)
+                               return (err);
+               }
+
+               if (err == ENOENT) {
+                       /* Check for a received value. */
+                       char *recvdstr = kmem_asprintf("%s%s", propname,
+                           ZPROP_RECVD_SUFFIX);
+                       err = zap_lookup(mos, zapobj, recvdstr,
+                           intsz, numints, buf);
+                       strfree(recvdstr);
+                       if (err != ENOENT) {
+                               if (setpoint != NULL && err == 0)
+                                       (void) strcpy(setpoint,
+                                           ZPROP_SOURCE_VAL_RECVD);
+                               return (err);
+                       }
+               }
+       }
+
+       return (dsl_prop_get_dd(ds->ds_dir, propname,
+           intsz, numints, buf, setpoint, ds->ds_is_snapshot));
+}
+
+/*
+ * Register interest in the named property.  We'll call the callback
+ * once to notify it of the current property value, and again each time
+ * the property changes, until this callback is unregistered.
+ *
+ * Return 0 on success, errno if the prop is not an integer value.
+ */
+int
+dsl_prop_register(dsl_dataset_t *ds, const char *propname,
+    dsl_prop_changed_cb_t *callback, void *cbarg)
+{
+       dsl_dir_t *dd = ds->ds_dir;
+       uint64_t value;
+       dsl_prop_cb_record_t *cbr;
+       int err;
+       ASSERTV(dsl_pool_t *dp = dd->dd_pool);
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       err = dsl_prop_get_int_ds(ds, propname, &value);
+       if (err != 0)
+               return (err);
+
+       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);
+       mutex_exit(&dd->dd_lock);
+
+       cbr->cbr_func(cbr->cbr_arg, value);
+       return (0);
+}
+
+int
+dsl_prop_get(const char *dsname, const char *propname,
+    int intsz, int numints, void *buf, char *setpoint)
+{
+       objset_t *os;
+       int error;
+
+       error = dmu_objset_hold(dsname, FTAG, &os);
+       if (error != 0)
+               return (error);
+
+       error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
+           intsz, numints, buf, setpoint);
+
+       dmu_objset_rele(os, FTAG);
+       return (error);
+}
+
+/*
+ * Get the current property value.  It may have changed by the time this
+ * function returns, so it is NOT safe to follow up with
+ * dsl_prop_register() and assume that the value has not changed in
+ * between.
+ *
+ * Return 0 on success, ENOENT if ddname is invalid.
+ */
+int
+dsl_prop_get_integer(const char *ddname, const char *propname,
+    uint64_t *valuep, char *setpoint)
+{
+       return (dsl_prop_get(ddname, propname, 8, 1, valuep, setpoint));
+}
+
+int
+dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
+    uint64_t *valuep)
+{
+       return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
+}
+
+/*
+ * Predict the effective value of the given special property if it were set with
+ * the given value and source. This is not a general purpose function. It exists
+ * only to handle the special requirements of the quota and reservation
+ * properties. The fact that these properties are non-inheritable greatly
+ * simplifies the prediction logic.
+ *
+ * Returns 0 on success, a positive error code on failure, or -1 if called with
+ * a property not handled by this function.
+ */
+int
+dsl_prop_predict(dsl_dir_t *dd, const char *propname,
+    zprop_source_t source, uint64_t value, uint64_t *newvalp)
+{
+       zfs_prop_t prop = zfs_name_to_prop(propname);
+       objset_t *mos;
+       uint64_t zapobj;
+       uint64_t version;
+       char *recvdstr;
+       int err = 0;
+
+       switch (prop) {
+       case ZFS_PROP_QUOTA:
+       case ZFS_PROP_RESERVATION:
+       case ZFS_PROP_REFQUOTA:
+       case ZFS_PROP_REFRESERVATION:
+               break;
+       default:
+               return (-1);
+       }
+
+       mos = dd->dd_pool->dp_meta_objset;
+       zapobj = dsl_dir_phys(dd)->dd_props_zapobj;
+       recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
+
+       version = spa_version(dd->dd_pool->dp_spa);
+       if (version < SPA_VERSION_RECVD_PROPS) {
+               if (source & ZPROP_SRC_NONE)
+                       source = ZPROP_SRC_NONE;
+               else if (source & ZPROP_SRC_RECEIVED)
+                       source = ZPROP_SRC_LOCAL;
+       }
+
+       switch ((int)source) {
+       case ZPROP_SRC_NONE:
+               /* Revert to the received value, if any. */
+               err = zap_lookup(mos, zapobj, recvdstr, 8, 1, newvalp);
+               if (err == ENOENT)
+                       *newvalp = 0;
+               break;
+       case ZPROP_SRC_LOCAL:
+               *newvalp = value;
+               break;
+       case ZPROP_SRC_RECEIVED:
+               /*
+                * If there's no local setting, then the new received value will
+                * be the effective value.
+                */
+               err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
+               if (err == ENOENT)
+                       *newvalp = value;
+               break;
+       case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
+               /*
+                * We're clearing the received value, so the local setting (if
+                * it exists) remains the effective value.
+                */
+               err = zap_lookup(mos, zapobj, propname, 8, 1, newvalp);
+               if (err == ENOENT)
+                       *newvalp = 0;
+               break;
+       default:
+               panic("unexpected property source: %d", source);
+       }
+
+       strfree(recvdstr);
+
+       if (err == ENOENT)
+               return (0);
+
+       return (err);
+}
+
+/*
+ * Unregister this callback.  Return 0 on success, ENOENT if ddname is
+ * invalid, or ENOMSG if no matching callback registered.
+ */
+int
+dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
+    dsl_prop_changed_cb_t *callback, void *cbarg)
+{
+       dsl_dir_t *dd = ds->ds_dir;
+       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 &&
+                   cbr->cbr_func == callback &&
+                   cbr->cbr_arg == cbarg &&
+                   strcmp(cbr->cbr_propname, propname) == 0)
+                       break;
+       }
+
+       if (cbr == NULL) {
+               mutex_exit(&dd->dd_lock);
+               return (SET_ERROR(ENOMSG));
+       }
+
+       list_remove(&dd->dd_prop_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)
+{
+       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;
+               }
+       }
+       mutex_exit(&dd->dd_lock);
+       return (rv);
+}
+
+/* ARGSUSED */
+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_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;
+
+               /*
+                * 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;
+
+               if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname,
+                   sizeof (value), 1, &value, NULL) == 0)
+                       cbr->cbr_func(cbr->cbr_arg, value);
+
+               dsl_dataset_rele(cbr->cbr_ds, FTAG);
+       }
+       mutex_exit(&dd->dd_lock);
+
+       return (0);
+}
+
+/*
+ * Update all property values for ddobj & its descendants.  This is used
+ * when renaming the dir.
+ */
+void
+dsl_prop_notify_all(dsl_dir_t *dd)
+{
+       dsl_pool_t *dp = dd->dd_pool;
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+       (void) dmu_objset_find_dp(dp, dd->dd_object, dsl_prop_notify_all_cb,
+           NULL, DS_FIND_CHILDREN);
+}
+
+static void
+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_cb_record_t *cbr;
+       objset_t *mos = dp->dp_meta_objset;
+       zap_cursor_t zc;
+       zap_attribute_t *za;
+       int err;
+
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+       err = dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd);
+       if (err)
+               return;
+
+       if (!first) {
+               /*
+                * If the prop is set here, then this change is not
+                * being inherited here or below; stop the recursion.
+                */
+               err = zap_contains(mos, dsl_dir_phys(dd)->dd_props_zapobj,
+                   propname);
+               if (err == 0) {
+                       dsl_dir_rele(dd, FTAG);
+                       return;
+               }
+               ASSERT3U(err, ==, ENOENT);
+       }
+
+       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;
+
+               /*
+                * 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;
+
+               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);
+
+               dsl_dataset_rele(cbr->cbr_ds, FTAG);
+       }
+       mutex_exit(&dd->dd_lock);
+
+       za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+       for (zap_cursor_init(&zc, mos,
+           dsl_dir_phys(dd)->dd_child_dir_zapobj);
+           zap_cursor_retrieve(&zc, za) == 0;
+           zap_cursor_advance(&zc)) {
+               dsl_prop_changed_notify(dp, za->za_first_integer,
+                   propname, value, FALSE);
+       }
+       kmem_free(za, sizeof (zap_attribute_t));
+       zap_cursor_fini(&zc);
+       dsl_dir_rele(dd, FTAG);
+}
+
+void
+dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
+    zprop_source_t source, int intsz, int numints, const void *value,
+    dmu_tx_t *tx)
+{
+       objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       uint64_t zapobj, intval, dummy;
+       int isint;
+       char valbuf[32];
+       const char *valstr = NULL;
+       char *inheritstr;
+       char *recvdstr;
+       char *tbuf = NULL;
+       int err;
+       uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
+
+       isint = (dodefault(propname, 8, 1, &intval) == 0);
+
+       if (ds->ds_is_snapshot) {
+               ASSERT(version >= SPA_VERSION_SNAP_PROPS);
+               if (dsl_dataset_phys(ds)->ds_props_obj == 0) {
+                       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+                       dsl_dataset_phys(ds)->ds_props_obj =
+                           zap_create(mos,
+                           DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx);
+               }
+               zapobj = dsl_dataset_phys(ds)->ds_props_obj;
+       } else {
+               zapobj = dsl_dir_phys(ds->ds_dir)->dd_props_zapobj;
+       }
+
+       if (version < SPA_VERSION_RECVD_PROPS) {
+               if (source & ZPROP_SRC_NONE)
+                       source = ZPROP_SRC_NONE;
+               else if (source & ZPROP_SRC_RECEIVED)
+                       source = ZPROP_SRC_LOCAL;
+       }
+
+       inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
+       recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
+
+       switch ((int)source) {
+       case ZPROP_SRC_NONE:
+               /*
+                * revert to received value, if any (inherit -S)
+                * - remove propname
+                * - remove propname$inherit
+                */
+               err = zap_remove(mos, zapobj, propname, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               err = zap_remove(mos, zapobj, inheritstr, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               break;
+       case ZPROP_SRC_LOCAL:
+               /*
+                * remove propname$inherit
+                * set propname -> value
+                */
+               err = zap_remove(mos, zapobj, inheritstr, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               VERIFY0(zap_update(mos, zapobj, propname,
+                   intsz, numints, value, tx));
+               break;
+       case ZPROP_SRC_INHERITED:
+               /*
+                * explicitly inherit
+                * - remove propname
+                * - set propname$inherit
+                */
+               err = zap_remove(mos, zapobj, propname, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               if (version >= SPA_VERSION_RECVD_PROPS &&
+                   dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
+                       dummy = 0;
+                       VERIFY0(zap_update(mos, zapobj, inheritstr,
+                           8, 1, &dummy, tx));
+               }
+               break;
+       case ZPROP_SRC_RECEIVED:
+               /*
+                * set propname$recvd -> value
+                */
+               err = zap_update(mos, zapobj, recvdstr,
+                   intsz, numints, value, tx);
+               ASSERT(err == 0);
+               break;
+       case (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED):
+               /*
+                * clear local and received settings
+                * - remove propname
+                * - remove propname$inherit
+                * - remove propname$recvd
+                */
+               err = zap_remove(mos, zapobj, propname, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               err = zap_remove(mos, zapobj, inheritstr, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               /* FALLTHRU */
+       case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED):
+               /*
+                * remove propname$recvd
+                */
+               err = zap_remove(mos, zapobj, recvdstr, tx);
+               ASSERT(err == 0 || err == ENOENT);
+               break;
+       default:
+               cmn_err(CE_PANIC, "unexpected property source: %d", source);
+       }
+
+       strfree(inheritstr);
+       strfree(recvdstr);
+
+       if (isint) {
+               VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
+
+               if (ds->ds_is_snapshot) {
+                       dsl_prop_cb_record_t *cbr;
+                       /*
+                        * It's a snapshot; nothing can inherit this
+                        * property, so just look for callbacks on this
+                        * 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)
+                                       cbr->cbr_func(cbr->cbr_arg, intval);
+                       }
+                       mutex_exit(&ds->ds_dir->dd_lock);
+               } else {
+                       dsl_prop_changed_notify(ds->ds_dir->dd_pool,
+                           ds->ds_dir->dd_object, propname, intval, TRUE);
+               }
+
+               (void) snprintf(valbuf, sizeof (valbuf),
+                   "%lld", (longlong_t)intval);
+               valstr = valbuf;
+       } else {
+               if (source == ZPROP_SRC_LOCAL) {
+                       valstr = value;
+               } else {
+                       tbuf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
+                       if (dsl_prop_get_ds(ds, propname, 1,
+                           ZAP_MAXVALUELEN, tbuf, NULL) == 0)
+                               valstr = tbuf;
+               }
+       }
+
+       spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
+           source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
+           "%s=%s", propname, (valstr == NULL ? "" : valstr));
+
+       if (tbuf != NULL)
+               kmem_free(tbuf, ZAP_MAXVALUELEN);
+}
+
+int
+dsl_prop_set_int(const char *dsname, const char *propname,
+    zprop_source_t source, uint64_t value)
+{
+       nvlist_t *nvl = fnvlist_alloc();
+       int error;
+
+       fnvlist_add_uint64(nvl, propname, value);
+       error = dsl_props_set(dsname, source, nvl);
+       fnvlist_free(nvl);
+       return (error);
+}
+
+int
+dsl_prop_set_string(const char *dsname, const char *propname,
+    zprop_source_t source, const char *value)
+{
+       nvlist_t *nvl = fnvlist_alloc();
+       int error;
+
+       fnvlist_add_string(nvl, propname, value);
+       error = dsl_props_set(dsname, source, nvl);
+       fnvlist_free(nvl);
+       return (error);
+}
+
+int
+dsl_prop_inherit(const char *dsname, const char *propname,
+    zprop_source_t source)
+{
+       nvlist_t *nvl = fnvlist_alloc();
+       int error;
+
+       fnvlist_add_boolean(nvl, propname);
+       error = dsl_props_set(dsname, source, nvl);
+       fnvlist_free(nvl);
+       return (error);
+}
+
+typedef struct dsl_props_set_arg {
+       const char *dpsa_dsname;
+       zprop_source_t dpsa_source;
+       nvlist_t *dpsa_props;
+} dsl_props_set_arg_t;
+
+static int
+dsl_props_set_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_props_set_arg_t *dpsa = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+       uint64_t version;
+       nvpair_t *elem = NULL;
+       int err;
+
+       err = dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds);
+       if (err != 0)
+               return (err);
+
+       version = spa_version(ds->ds_dir->dd_pool->dp_spa);
+       while ((elem = nvlist_next_nvpair(dpsa->dpsa_props, elem)) != NULL) {
+               if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (SET_ERROR(ENAMETOOLONG));
+               }
+               if (nvpair_type(elem) == DATA_TYPE_STRING) {
+                       char *valstr = fnvpair_value_string(elem);
+                       if (strlen(valstr) >= (version <
+                           SPA_VERSION_STMF_PROP ?
+                           ZAP_OLDMAXVALUELEN : ZAP_MAXVALUELEN)) {
+                               dsl_dataset_rele(ds, FTAG);
+                               return (E2BIG);
+                       }
+               }
+       }
+
+       if (ds->ds_is_snapshot && version < SPA_VERSION_SNAP_PROPS) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(ENOTSUP));
+       }
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+void
+dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source,
+    nvlist_t *props, dmu_tx_t *tx)
+{
+       nvpair_t *elem = NULL;
+
+       while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
+               nvpair_t *pair = elem;
+
+               if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+                       /*
+                        * dsl_prop_get_all_impl() returns properties in this
+                        * format.
+                        */
+                       nvlist_t *attrs = fnvpair_value_nvlist(pair);
+                       pair = fnvlist_lookup_nvpair(attrs, ZPROP_VALUE);
+               }
+
+               if (nvpair_type(pair) == DATA_TYPE_STRING) {
+                       const char *value = fnvpair_value_string(pair);
+                       dsl_prop_set_sync_impl(ds, nvpair_name(pair),
+                           source, 1, strlen(value) + 1, value, tx);
+               } else if (nvpair_type(pair) == DATA_TYPE_UINT64) {
+                       uint64_t intval = fnvpair_value_uint64(pair);
+                       dsl_prop_set_sync_impl(ds, nvpair_name(pair),
+                           source, sizeof (intval), 1, &intval, tx);
+               } else if (nvpair_type(pair) == DATA_TYPE_BOOLEAN) {
+                       dsl_prop_set_sync_impl(ds, nvpair_name(pair),
+                           source, 0, 0, NULL, tx);
+               } else {
+                       panic("invalid nvpair type");
+               }
+       }
+}
+
+static void
+dsl_props_set_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_props_set_arg_t *dpsa = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dataset_t *ds;
+
+       VERIFY0(dsl_dataset_hold(dp, dpsa->dpsa_dsname, FTAG, &ds));
+       dsl_props_set_sync_impl(ds, dpsa->dpsa_source, dpsa->dpsa_props, tx);
+       dsl_dataset_rele(ds, FTAG);
+}
+
+/*
+ * All-or-nothing; if any prop can't be set, nothing will be modified.
+ */
+int
+dsl_props_set(const char *dsname, zprop_source_t source, nvlist_t *props)
+{
+       dsl_props_set_arg_t dpsa;
+       int nblks = 0;
+
+       dpsa.dpsa_dsname = dsname;
+       dpsa.dpsa_source = source;
+       dpsa.dpsa_props = props;
+
+       /*
+        * If the source includes NONE, then we will only be removing entries
+        * from the ZAP object.  In that case don't check for ENOSPC.
+        */
+       if ((source & ZPROP_SRC_NONE) == 0)
+               nblks = 2 * fnvlist_num_pairs(props);
+
+       return (dsl_sync_task(dsname, dsl_props_set_check, dsl_props_set_sync,
+           &dpsa, nblks, ZFS_SPACE_CHECK_RESERVED));
+}
+
+typedef enum dsl_prop_getflags {
+       DSL_PROP_GET_INHERITING = 0x1,  /* searching parent of target ds */
+       DSL_PROP_GET_SNAPSHOT = 0x2,    /* snapshot dataset */
+       DSL_PROP_GET_LOCAL = 0x4,       /* local properties */
+       DSL_PROP_GET_RECEIVED = 0x8     /* received properties */
+} dsl_prop_getflags_t;
+
+static int
+dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
+    const char *setpoint, dsl_prop_getflags_t flags, nvlist_t *nv)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int err = 0;
+
+       for (zap_cursor_init(&zc, mos, propobj);
+           (err = zap_cursor_retrieve(&zc, &za)) == 0;
+           zap_cursor_advance(&zc)) {
+               nvlist_t *propval;
+               zfs_prop_t prop;
+               char buf[ZAP_MAXNAMELEN];
+               char *valstr;
+               const char *suffix;
+               const char *propname;
+               const char *source;
+
+               suffix = strchr(za.za_name, '$');
+
+               if (suffix == NULL) {
+                       /*
+                        * Skip local properties if we only want received
+                        * properties.
+                        */
+                       if (flags & DSL_PROP_GET_RECEIVED)
+                               continue;
+
+                       propname = za.za_name;
+                       source = setpoint;
+               } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
+                       /* Skip explicitly inherited entries. */
+                       continue;
+               } else if (strcmp(suffix, ZPROP_RECVD_SUFFIX) == 0) {
+                       if (flags & DSL_PROP_GET_LOCAL)
+                               continue;
+
+                       (void) strncpy(buf, za.za_name, (suffix - za.za_name));
+                       buf[suffix - za.za_name] = '\0';
+                       propname = buf;
+
+                       if (!(flags & DSL_PROP_GET_RECEIVED)) {
+                               /* Skip if locally overridden. */
+                               err = zap_contains(mos, propobj, propname);
+                               if (err == 0)
+                                       continue;
+                               if (err != ENOENT)
+                                       break;
+
+                               /* Skip if explicitly inherited. */
+                               valstr = kmem_asprintf("%s%s", propname,
+                                   ZPROP_INHERIT_SUFFIX);
+                               err = zap_contains(mos, propobj, valstr);
+                               strfree(valstr);
+                               if (err == 0)
+                                       continue;
+                               if (err != ENOENT)
+                                       break;
+                       }
+
+                       source = ((flags & DSL_PROP_GET_INHERITING) ?
+                           setpoint : ZPROP_SOURCE_VAL_RECVD);
+               } else {
+                       /*
+                        * For backward compatibility, skip suffixes we don't
+                        * recognize.
+                        */
+                       continue;
+               }
+
+               prop = zfs_name_to_prop(propname);
+
+               /* Skip non-inheritable properties. */
+               if ((flags & DSL_PROP_GET_INHERITING) && prop != ZPROP_INVAL &&
+                   !zfs_prop_inheritable(prop))
+                       continue;
+
+               /* Skip properties not valid for this type. */
+               if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL &&
+                   !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT, B_FALSE))
+                       continue;
+
+               /* Skip properties already defined. */
+               if (nvlist_exists(nv, propname))
+                       continue;
+
+               VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               if (za.za_integer_length == 1) {
+                       /*
+                        * String property
+                        */
+                       char *tmp = kmem_alloc(za.za_num_integers,
+                           KM_SLEEP);
+                       err = zap_lookup(mos, propobj,
+                           za.za_name, 1, za.za_num_integers, tmp);
+                       if (err != 0) {
+                               kmem_free(tmp, za.za_num_integers);
+                               break;
+                       }
+                       VERIFY(nvlist_add_string(propval, ZPROP_VALUE,
+                           tmp) == 0);
+                       kmem_free(tmp, za.za_num_integers);
+               } else {
+                       /*
+                        * Integer property
+                        */
+                       ASSERT(za.za_integer_length == 8);
+                       (void) nvlist_add_uint64(propval, ZPROP_VALUE,
+                           za.za_first_integer);
+               }
+
+               VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, source) == 0);
+               VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
+               nvlist_free(propval);
+       }
+       zap_cursor_fini(&zc);
+       if (err == ENOENT)
+               err = 0;
+       return (err);
+}
+
+/*
+ * Iterate over all properties for this dataset and return them in an nvlist.
+ */
+static int
+dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
+    dsl_prop_getflags_t flags)
+{
+       dsl_dir_t *dd = ds->ds_dir;
+       dsl_pool_t *dp = dd->dd_pool;
+       objset_t *mos = dp->dp_meta_objset;
+       int err = 0;
+       char setpoint[MAXNAMELEN];
+
+       VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       if (ds->ds_is_snapshot)
+               flags |= DSL_PROP_GET_SNAPSHOT;
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       if (dsl_dataset_phys(ds)->ds_props_obj != 0) {
+               ASSERT(flags & DSL_PROP_GET_SNAPSHOT);
+               dsl_dataset_name(ds, setpoint);
+               err = dsl_prop_get_all_impl(mos,
+                   dsl_dataset_phys(ds)->ds_props_obj, setpoint, flags, *nvp);
+               if (err)
+                       goto out;
+       }
+
+       for (; dd != NULL; dd = dd->dd_parent) {
+               if (dd != ds->ds_dir || (flags & DSL_PROP_GET_SNAPSHOT)) {
+                       if (flags & (DSL_PROP_GET_LOCAL |
+                           DSL_PROP_GET_RECEIVED))
+                               break;
+                       flags |= DSL_PROP_GET_INHERITING;
+               }
+               dsl_dir_name(dd, setpoint);
+               err = dsl_prop_get_all_impl(mos,
+                   dsl_dir_phys(dd)->dd_props_zapobj, setpoint, flags, *nvp);
+               if (err)
+                       break;
+       }
+out:
+       return (err);
+}
+
+boolean_t
+dsl_prop_get_hasrecvd(const char *dsname)
+{
+       uint64_t dummy;
+
+       return (0 ==
+           dsl_prop_get_integer(dsname, ZPROP_HAS_RECVD, &dummy, NULL));
+}
+
+static int
+dsl_prop_set_hasrecvd_impl(const char *dsname, zprop_source_t source)
+{
+       uint64_t version;
+       spa_t *spa;
+       int error = 0;
+
+       VERIFY0(spa_open(dsname, &spa, FTAG));
+       version = spa_version(spa);
+       spa_close(spa, FTAG);
+
+       if (version >= SPA_VERSION_RECVD_PROPS)
+               error = dsl_prop_set_int(dsname, ZPROP_HAS_RECVD, source, 0);
+       return (error);
+}
+
+/*
+ * Call after successfully receiving properties to ensure that only the first
+ * receive on or after SPA_VERSION_RECVD_PROPS blows away local properties.
+ */
+int
+dsl_prop_set_hasrecvd(const char *dsname)
+{
+       int error = 0;
+       if (!dsl_prop_get_hasrecvd(dsname))
+               error = dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_LOCAL);
+       return (error);
+}
+
+void
+dsl_prop_unset_hasrecvd(const char *dsname)
+{
+       VERIFY0(dsl_prop_set_hasrecvd_impl(dsname, ZPROP_SRC_NONE));
+}
+
+int
+dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
+{
+       return (dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, 0));
+}
+
+int
+dsl_prop_get_received(const char *dsname, nvlist_t **nvp)
+{
+       objset_t *os;
+       int error;
+
+       /*
+        * Received properties are not distinguishable from local properties
+        * until the dataset has received properties on or after
+        * SPA_VERSION_RECVD_PROPS.
+        */
+       dsl_prop_getflags_t flags = (dsl_prop_get_hasrecvd(dsname) ?
+           DSL_PROP_GET_RECEIVED : DSL_PROP_GET_LOCAL);
+
+       error = dmu_objset_hold(dsname, FTAG, &os);
+       if (error != 0)
+               return (error);
+       error = dsl_prop_get_all_ds(os->os_dsl_dataset, nvp, flags);
+       dmu_objset_rele(os, FTAG);
+       return (error);
+}
+
+void
+dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
+{
+       nvlist_t *propval;
+       const char *propname = zfs_prop_to_name(prop);
+       uint64_t default_value;
+
+       if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
+               VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
+               return;
+       }
+
+       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 &&
+           value == default_value) {
+               VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
+       }
+       VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
+       nvlist_free(propval);
+}
+
+void
+dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
+{
+       nvlist_t *propval;
+       const char *propname = zfs_prop_to_name(prop);
+
+       if (nvlist_lookup_nvlist(nv, propname, &propval) == 0) {
+               VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
+               return;
+       }
+
+       VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+       VERIFY(nvlist_add_string(propval, ZPROP_VALUE, value) == 0);
+       VERIFY(nvlist_add_nvlist(nv, propname, propval) == 0);
+       nvlist_free(propval);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_prop_register);
+EXPORT_SYMBOL(dsl_prop_unregister);
+EXPORT_SYMBOL(dsl_prop_get);
+EXPORT_SYMBOL(dsl_prop_get_integer);
+EXPORT_SYMBOL(dsl_prop_get_all);
+EXPORT_SYMBOL(dsl_prop_get_received);
+EXPORT_SYMBOL(dsl_prop_get_ds);
+EXPORT_SYMBOL(dsl_prop_get_int_ds);
+EXPORT_SYMBOL(dsl_prop_get_dd);
+EXPORT_SYMBOL(dsl_props_set);
+EXPORT_SYMBOL(dsl_prop_set_int);
+EXPORT_SYMBOL(dsl_prop_set_string);
+EXPORT_SYMBOL(dsl_prop_inherit);
+EXPORT_SYMBOL(dsl_prop_predict);
+EXPORT_SYMBOL(dsl_prop_nvlist_add_uint64);
+EXPORT_SYMBOL(dsl_prop_nvlist_add_string);
+#endif
diff --git a/zfs/module/zfs/dsl_scan.c b/zfs/module/zfs/dsl_scan.c
new file mode 100644 (file)
index 0000000..b989e76
--- /dev/null
@@ -0,0 +1,1907 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/dsl_scan.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dnode.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_objset.h>
+#include <sys/arc.h>
+#include <sys/zap.h>
+#include <sys/zio.h>
+#include <sys/zfs_context.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/spa_impl.h>
+#include <sys/vdev_impl.h>
+#include <sys/zil_impl.h>
+#include <sys/zio_checksum.h>
+#include <sys/ddt.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/zfeature.h>
+#ifdef _KERNEL
+#include <sys/zfs_vfsops.h>
+#endif
+
+typedef int (scan_cb_t)(dsl_pool_t *, const blkptr_t *,
+    const zbookmark_phys_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);
+
+int zfs_top_maxinflight = 32;          /* maximum I/Os per top-level */
+int zfs_resilver_delay = 2;            /* number of ticks to delay resilver */
+int zfs_scrub_delay = 4;               /* number of ticks to delay scrub */
+int zfs_scan_idle = 50;                        /* idle window in clock ticks */
+
+int zfs_scan_min_time_ms = 1000; /* min millisecs to scrub per txg */
+int zfs_free_min_time_ms = 1000; /* min millisecs to free per txg */
+int zfs_resilver_min_time_ms = 3000; /* min millisecs to resilver per txg */
+int zfs_no_scrub_io = B_FALSE; /* set to disable scrub i/o */
+int zfs_no_scrub_prefetch = B_FALSE; /* set to disable scrub prefetch */
+enum ddt_class zfs_scrub_ddt_class_max = DDT_CLASS_DUPLICATE;
+int dsl_scan_delay_completion = B_FALSE; /* set to delay scan completion */
+/* max number of blocks to free in a single TXG */
+ulong zfs_free_max_blocks = 100000;
+
+#define        DSL_SCAN_IS_SCRUB_RESILVER(scn) \
+       ((scn)->scn_phys.scn_func == POOL_SCAN_SCRUB || \
+       (scn)->scn_phys.scn_func == POOL_SCAN_RESILVER)
+
+/* the order has to match pool_scan_type */
+static scan_cb_t *scan_funcs[POOL_SCAN_FUNCS] = {
+       NULL,
+       dsl_scan_scrub_cb,      /* POOL_SCAN_SCRUB */
+       dsl_scan_scrub_cb,      /* POOL_SCAN_RESILVER */
+};
+
+int
+dsl_scan_init(dsl_pool_t *dp, uint64_t txg)
+{
+       int err;
+       dsl_scan_t *scn;
+       spa_t *spa = dp->dp_spa;
+       uint64_t f;
+
+       scn = dp->dp_scan = kmem_zalloc(sizeof (dsl_scan_t), KM_SLEEP);
+       scn->scn_dp = dp;
+
+       /*
+        * It's possible that we're resuming a scan after a reboot so
+        * make sure that the scan_async_destroying flag is initialized
+        * appropriately.
+        */
+       ASSERT(!scn->scn_async_destroying);
+       scn->scn_async_destroying = spa_feature_is_active(dp->dp_spa,
+           SPA_FEATURE_ASYNC_DESTROY);
+
+       err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           "scrub_func", sizeof (uint64_t), 1, &f);
+       if (err == 0) {
+               /*
+                * There was an old-style scrub in progress.  Restart a
+                * new-style scrub from the beginning.
+                */
+               scn->scn_restart_txg = txg;
+               zfs_dbgmsg("old-style scrub was in progress; "
+                   "restarting new-style scrub in txg %llu",
+                   scn->scn_restart_txg);
+
+               /*
+                * Load the queue obj from the old location so that it
+                * can be freed by dsl_scan_done().
+                */
+               (void) zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+                   "scrub_queue", sizeof (uint64_t), 1,
+                   &scn->scn_phys.scn_queue_obj);
+       } else {
+               err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_SCAN, sizeof (uint64_t), SCAN_PHYS_NUMINTS,
+                   &scn->scn_phys);
+               /*
+                * Detect if the pool contains the signature of #2094.  If it
+                * does properly update the scn->scn_phys structure and notify
+                * the administrator by setting an errata for the pool.
+                */
+               if (err == EOVERFLOW) {
+                       uint64_t zaptmp[SCAN_PHYS_NUMINTS + 1];
+                       VERIFY3S(SCAN_PHYS_NUMINTS, ==, 24);
+                       VERIFY3S(offsetof(dsl_scan_phys_t, scn_flags), ==,
+                           (23 * sizeof (uint64_t)));
+
+                       err = zap_lookup(dp->dp_meta_objset,
+                           DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCAN,
+                           sizeof (uint64_t), SCAN_PHYS_NUMINTS + 1, &zaptmp);
+                       if (err == 0) {
+                               uint64_t overflow = zaptmp[SCAN_PHYS_NUMINTS];
+
+                               if (overflow & ~DSL_SCAN_FLAGS_MASK ||
+                                   scn->scn_async_destroying) {
+                                       spa->spa_errata =
+                                           ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY;
+                                       return (EOVERFLOW);
+                               }
+
+                               bcopy(zaptmp, &scn->scn_phys,
+                                   SCAN_PHYS_NUMINTS * sizeof (uint64_t));
+                               scn->scn_phys.scn_flags = overflow;
+
+                               /* Required scrub already in progress. */
+                               if (scn->scn_phys.scn_state == DSS_FINISHED ||
+                                   scn->scn_phys.scn_state == DSS_CANCELED)
+                                       spa->spa_errata =
+                                           ZPOOL_ERRATA_ZOL_2094_SCRUB;
+                       }
+               }
+
+               if (err == ENOENT)
+                       return (0);
+               else if (err)
+                       return (err);
+
+               if (scn->scn_phys.scn_state == DSS_SCANNING &&
+                   spa_prev_software_version(dp->dp_spa) < SPA_VERSION_SCAN) {
+                       /*
+                        * A new-type scrub was in progress on an old
+                        * pool, and the pool was accessed by old
+                        * software.  Restart from the beginning, since
+                        * the old software may have changed the pool in
+                        * the meantime.
+                        */
+                       scn->scn_restart_txg = txg;
+                       zfs_dbgmsg("new-style scrub was modified "
+                           "by old software; restarting in txg %llu",
+                           scn->scn_restart_txg);
+               }
+       }
+
+       spa_scan_stat_init(spa);
+       return (0);
+}
+
+void
+dsl_scan_fini(dsl_pool_t *dp)
+{
+       if (dp->dp_scan) {
+               kmem_free(dp->dp_scan, sizeof (dsl_scan_t));
+               dp->dp_scan = NULL;
+       }
+}
+
+/* ARGSUSED */
+static int
+dsl_scan_setup_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan;
+
+       if (scn->scn_phys.scn_state == DSS_SCANNING)
+               return (SET_ERROR(EBUSY));
+
+       return (0);
+}
+
+static void
+dsl_scan_setup_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan;
+       pool_scan_func_t *funcp = arg;
+       dmu_object_type_t ot = 0;
+       dsl_pool_t *dp = scn->scn_dp;
+       spa_t *spa = dp->dp_spa;
+
+       ASSERT(scn->scn_phys.scn_state != DSS_SCANNING);
+       ASSERT(*funcp > POOL_SCAN_NONE && *funcp < POOL_SCAN_FUNCS);
+       bzero(&scn->scn_phys, sizeof (scn->scn_phys));
+       scn->scn_phys.scn_func = *funcp;
+       scn->scn_phys.scn_state = DSS_SCANNING;
+       scn->scn_phys.scn_min_txg = 0;
+       scn->scn_phys.scn_max_txg = tx->tx_txg;
+       scn->scn_phys.scn_ddt_class_max = DDT_CLASSES - 1; /* the entire DDT */
+       scn->scn_phys.scn_start_time = gethrestime_sec();
+       scn->scn_phys.scn_errors = 0;
+       scn->scn_phys.scn_to_examine = spa->spa_root_vdev->vdev_stat.vs_alloc;
+       scn->scn_restart_txg = 0;
+       scn->scn_done_txg = 0;
+       spa_scan_stat_init(spa);
+
+       if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
+               scn->scn_phys.scn_ddt_class_max = zfs_scrub_ddt_class_max;
+
+               /* rewrite all disk labels */
+               vdev_config_dirty(spa->spa_root_vdev);
+
+               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);
+               } else {
+                       spa_event_notify(spa, NULL,
+                           FM_EREPORT_ZFS_SCRUB_START);
+               }
+
+               spa->spa_scrub_started = B_TRUE;
+               /*
+                * If this is an incremental scrub, limit the DDT scrub phase
+                * to just the auto-ditto class (for correctness); the rest
+                * of the scrub should go faster using top-down pruning.
+                */
+               if (scn->scn_phys.scn_min_txg > TXG_INITIAL)
+                       scn->scn_phys.scn_ddt_class_max = DDT_CLASS_DITTO;
+
+       }
+
+       /* back to the generic stuff */
+
+       if (dp->dp_blkstats == NULL) {
+               dp->dp_blkstats =
+                   vmem_alloc(sizeof (zfs_all_blkstats_t), KM_SLEEP);
+       }
+       bzero(dp->dp_blkstats, sizeof (zfs_all_blkstats_t));
+
+       if (spa_version(spa) < SPA_VERSION_DSL_SCRUB)
+               ot = DMU_OT_ZAP_OTHER;
+
+       scn->scn_phys.scn_queue_obj = zap_create(dp->dp_meta_objset,
+           ot ? ot : DMU_OT_SCAN_QUEUE, DMU_OT_NONE, 0, tx);
+
+       dsl_scan_sync_state(scn, tx);
+
+       spa_history_log_internal(spa, "scan setup", tx,
+           "func=%u mintxg=%llu maxtxg=%llu",
+           *funcp, scn->scn_phys.scn_min_txg, scn->scn_phys.scn_max_txg);
+}
+
+/* ARGSUSED */
+static void
+dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx)
+{
+       static const char *old_names[] = {
+               "scrub_bookmark",
+               "scrub_ddt_bookmark",
+               "scrub_ddt_class_max",
+               "scrub_queue",
+               "scrub_min_txg",
+               "scrub_max_txg",
+               "scrub_func",
+               "scrub_errors",
+               NULL
+       };
+
+       dsl_pool_t *dp = scn->scn_dp;
+       spa_t *spa = dp->dp_spa;
+       int i;
+
+       /* Remove any remnants of an old-style scrub. */
+       for (i = 0; old_names[i]; i++) {
+               (void) zap_remove(dp->dp_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT, old_names[i], tx);
+       }
+
+       if (scn->scn_phys.scn_queue_obj != 0) {
+               VERIFY(0 == dmu_object_free(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, tx));
+               scn->scn_phys.scn_queue_obj = 0;
+       }
+
+       /*
+        * If we were "restarted" from a stopped state, don't bother
+        * with anything else.
+        */
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return;
+
+       if (complete)
+               scn->scn_phys.scn_state = DSS_FINISHED;
+       else
+               scn->scn_phys.scn_state = DSS_CANCELED;
+
+       spa_history_log_internal(spa, "scan done", tx,
+           "complete=%u", complete);
+
+       if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
+               mutex_enter(&spa->spa_scrub_lock);
+               while (spa->spa_scrub_inflight > 0) {
+                       cv_wait(&spa->spa_scrub_io_cv,
+                           &spa->spa_scrub_lock);
+               }
+               mutex_exit(&spa->spa_scrub_lock);
+               spa->spa_scrub_started = B_FALSE;
+               spa->spa_scrub_active = B_FALSE;
+
+               /*
+                * If the scrub/resilver completed, update all DTLs to
+                * reflect this.  Whether it succeeded or not, vacate
+                * all temporary scrub DTLs.
+                */
+               vdev_dtl_reassess(spa->spa_root_vdev, tx->tx_txg,
+                   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);
+               }
+               spa_errlog_rotate(spa);
+
+               /*
+                * We may have finished replacing a device.
+                * Let the async thread assess this and handle the detach.
+                */
+               spa_async_request(spa, SPA_ASYNC_RESILVER_DONE);
+       }
+
+       scn->scn_phys.scn_end_time = gethrestime_sec();
+
+       if (spa->spa_errata == ZPOOL_ERRATA_ZOL_2094_SCRUB)
+               spa->spa_errata = 0;
+}
+
+/* ARGSUSED */
+static int
+dsl_scan_cancel_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan;
+
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return (SET_ERROR(ENOENT));
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+dsl_scan_cancel_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_scan_t *scn = dmu_tx_pool(tx)->dp_scan;
+
+       dsl_scan_done(scn, B_FALSE, tx);
+       dsl_scan_sync_state(scn, tx);
+}
+
+int
+dsl_scan_cancel(dsl_pool_t *dp)
+{
+       return (dsl_sync_task(spa_name(dp->dp_spa), dsl_scan_cancel_check,
+           dsl_scan_cancel_sync, NULL, 3, ZFS_SPACE_CHECK_RESERVED));
+}
+
+static void dsl_scan_visitbp(blkptr_t *bp, const zbookmark_phys_t *zb,
+    dnode_phys_t *dnp, dsl_dataset_t *ds, dsl_scan_t *scn,
+    dmu_objset_type_t ostype, dmu_tx_t *tx);
+inline __attribute__((always_inline)) static void dsl_scan_visitdnode(
+    dsl_scan_t *, dsl_dataset_t *ds, dmu_objset_type_t ostype,
+    dnode_phys_t *dnp, uint64_t object, dmu_tx_t *tx);
+
+void
+dsl_free(dsl_pool_t *dp, uint64_t txg, const blkptr_t *bp)
+{
+       zio_free(dp->dp_spa, txg, bp);
+}
+
+void
+dsl_free_sync(zio_t *pio, dsl_pool_t *dp, uint64_t txg, const blkptr_t *bpp)
+{
+       ASSERT(dsl_pool_sync_context(dp));
+       zio_nowait(zio_free_sync(pio, dp->dp_spa, txg, bpp, pio->io_flags));
+}
+
+static uint64_t
+dsl_scan_ds_maxtxg(dsl_dataset_t *ds)
+{
+       uint64_t smt = ds->ds_dir->dd_pool->dp_scan->scn_phys.scn_max_txg;
+       if (ds->ds_is_snapshot)
+               return (MIN(smt, dsl_dataset_phys(ds)->ds_creation_txg));
+       return (smt);
+}
+
+static void
+dsl_scan_sync_state(dsl_scan_t *scn, dmu_tx_t *tx)
+{
+       VERIFY0(zap_update(scn->scn_dp->dp_meta_objset,
+           DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_SCAN, sizeof (uint64_t), SCAN_PHYS_NUMINTS,
+           &scn->scn_phys, tx));
+}
+
+extern int zfs_vdev_async_write_active_min_dirty_percent;
+
+static boolean_t
+dsl_scan_check_pause(dsl_scan_t *scn, const zbookmark_phys_t *zb)
+{
+       uint64_t elapsed_nanosecs;
+       int mintime;
+       int dirty_pct;
+
+       /* we never skip user/group accounting objects */
+       if (zb && (int64_t)zb->zb_object < 0)
+               return (B_FALSE);
+
+       if (scn->scn_pausing)
+               return (B_TRUE); /* we're already pausing */
+
+       if (!ZB_IS_ZERO(&scn->scn_phys.scn_bookmark))
+               return (B_FALSE); /* we're resuming */
+
+       /* We only know how to resume from level-0 blocks. */
+       if (zb && zb->zb_level != 0)
+               return (B_FALSE);
+
+       /*
+        * We pause if:
+        *  - we have scanned for the maximum time: an entire txg
+        *    timeout (default 5 sec)
+        *  or
+        *  - we have scanned for at least the minimum time (default 1 sec
+        *    for scrub, 3 sec for resilver), and either we have sufficient
+        *    dirty data that we are starting to write more quickly
+        *    (default 30%), or someone is explicitly waiting for this txg
+        *    to complete.
+        *  or
+        *  - the spa is shutting down because this pool is being exported
+        *    or the machine is rebooting.
+        */
+       mintime = (scn->scn_phys.scn_func == POOL_SCAN_RESILVER) ?
+           zfs_resilver_min_time_ms : zfs_scan_min_time_ms;
+       elapsed_nanosecs = gethrtime() - scn->scn_sync_start_time;
+       dirty_pct = scn->scn_dp->dp_dirty_total * 100 / zfs_dirty_data_max;
+       if (elapsed_nanosecs / NANOSEC >= zfs_txg_timeout ||
+           (NSEC2MSEC(elapsed_nanosecs) > mintime &&
+           (txg_sync_waiting(scn->scn_dp) ||
+           dirty_pct >= zfs_vdev_async_write_active_min_dirty_percent)) ||
+           spa_shutting_down(scn->scn_dp->dp_spa)) {
+               if (zb) {
+                       dprintf("pausing at bookmark %llx/%llx/%llx/%llx\n",
+                           (longlong_t)zb->zb_objset,
+                           (longlong_t)zb->zb_object,
+                           (longlong_t)zb->zb_level,
+                           (longlong_t)zb->zb_blkid);
+                       scn->scn_phys.scn_bookmark = *zb;
+               }
+               dprintf("pausing at DDT bookmark %llx/%llx/%llx/%llx\n",
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_class,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_type,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_checksum,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_cursor);
+               scn->scn_pausing = B_TRUE;
+               return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+typedef struct zil_scan_arg {
+       dsl_pool_t      *zsa_dp;
+       zil_header_t    *zsa_zh;
+} zil_scan_arg_t;
+
+/* ARGSUSED */
+static int
+dsl_scan_zil_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
+{
+       zil_scan_arg_t *zsa = arg;
+       dsl_pool_t *dp = zsa->zsa_dp;
+       dsl_scan_t *scn = dp->dp_scan;
+       zil_header_t *zh = zsa->zsa_zh;
+       zbookmark_phys_t zb;
+
+       if (BP_IS_HOLE(bp) || bp->blk_birth <= scn->scn_phys.scn_cur_min_txg)
+               return (0);
+
+       /*
+        * One block ("stubby") can be allocated a long time ago; we
+        * want to visit that one because it has been allocated
+        * (on-disk) even if it hasn't been claimed (even though for
+        * scrub there's nothing to do to it).
+        */
+       if (claim_txg == 0 && bp->blk_birth >= spa_first_txg(dp->dp_spa))
+               return (0);
+
+       SET_BOOKMARK(&zb, zh->zh_log.blk_cksum.zc_word[ZIL_ZC_OBJSET],
+           ZB_ZIL_OBJECT, ZB_ZIL_LEVEL, bp->blk_cksum.zc_word[ZIL_ZC_SEQ]);
+
+       VERIFY(0 == scan_funcs[scn->scn_phys.scn_func](dp, bp, &zb));
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+dsl_scan_zil_record(zilog_t *zilog, lr_t *lrc, void *arg, uint64_t claim_txg)
+{
+       if (lrc->lrc_txtype == TX_WRITE) {
+               zil_scan_arg_t *zsa = arg;
+               dsl_pool_t *dp = zsa->zsa_dp;
+               dsl_scan_t *scn = dp->dp_scan;
+               zil_header_t *zh = zsa->zsa_zh;
+               lr_write_t *lr = (lr_write_t *)lrc;
+               blkptr_t *bp = &lr->lr_blkptr;
+               zbookmark_phys_t zb;
+
+               if (BP_IS_HOLE(bp) ||
+                   bp->blk_birth <= scn->scn_phys.scn_cur_min_txg)
+                       return (0);
+
+               /*
+                * birth can be < claim_txg if this record's txg is
+                * already txg sync'ed (but this log block contains
+                * other records that are not synced)
+                */
+               if (claim_txg == 0 || bp->blk_birth < claim_txg)
+                       return (0);
+
+               SET_BOOKMARK(&zb, zh->zh_log.blk_cksum.zc_word[ZIL_ZC_OBJSET],
+                   lr->lr_foid, ZB_ZIL_LEVEL,
+                   lr->lr_offset / BP_GET_LSIZE(bp));
+
+               VERIFY(0 == scan_funcs[scn->scn_phys.scn_func](dp, bp, &zb));
+       }
+       return (0);
+}
+
+static void
+dsl_scan_zil(dsl_pool_t *dp, zil_header_t *zh)
+{
+       uint64_t claim_txg = zh->zh_claim_txg;
+       zil_scan_arg_t zsa = { dp, zh };
+       zilog_t *zilog;
+
+       /*
+        * We only want to visit blocks that have been claimed but not yet
+        * replayed (or, in read-only mode, blocks that *would* be claimed).
+        */
+       if (claim_txg == 0 && spa_writeable(dp->dp_spa))
+               return;
+
+       zilog = zil_alloc(dp->dp_meta_objset, zh);
+
+       (void) zil_parse(zilog, dsl_scan_zil_block, dsl_scan_zil_record, &zsa,
+           claim_txg);
+
+       zil_free(zilog);
+}
+
+/* ARGSUSED */
+static void
+dsl_scan_prefetch(dsl_scan_t *scn, arc_buf_t *buf, blkptr_t *bp,
+    uint64_t objset, uint64_t object, uint64_t blkid)
+{
+       zbookmark_phys_t czb;
+       arc_flags_t flags = ARC_FLAG_NOWAIT | ARC_FLAG_PREFETCH;
+
+       if (zfs_no_scrub_prefetch)
+               return;
+
+       if (BP_IS_HOLE(bp) || bp->blk_birth <= scn->scn_phys.scn_min_txg ||
+           (BP_GET_LEVEL(bp) == 0 && BP_GET_TYPE(bp) != DMU_OT_DNODE))
+               return;
+
+       SET_BOOKMARK(&czb, objset, object, BP_GET_LEVEL(bp), blkid);
+
+       (void) arc_read(scn->scn_zio_root, scn->scn_dp->dp_spa, bp,
+           NULL, NULL, ZIO_PRIORITY_ASYNC_READ,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_SCAN_THREAD, &flags, &czb);
+}
+
+static boolean_t
+dsl_scan_check_resume(dsl_scan_t *scn, const dnode_phys_t *dnp,
+    const zbookmark_phys_t *zb)
+{
+       /*
+        * We never skip over user/group accounting objects (obj<0)
+        */
+       if (!ZB_IS_ZERO(&scn->scn_phys.scn_bookmark) &&
+           (int64_t)zb->zb_object >= 0) {
+               /*
+                * 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))
+                       return (B_TRUE);
+
+               /*
+                * If we found the block we're trying to resume from, or
+                * we went past it to a different object, zero it out to
+                * indicate that it's OK to start checking for pausing
+                * again.
+                */
+               if (bcmp(zb, &scn->scn_phys.scn_bookmark, sizeof (*zb)) == 0 ||
+                   zb->zb_object > scn->scn_phys.scn_bookmark.zb_object) {
+                       dprintf("resuming at %llx/%llx/%llx/%llx\n",
+                           (longlong_t)zb->zb_objset,
+                           (longlong_t)zb->zb_object,
+                           (longlong_t)zb->zb_level,
+                           (longlong_t)zb->zb_blkid);
+                       bzero(&scn->scn_phys.scn_bookmark, sizeof (*zb));
+               }
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Return nonzero on i/o error.
+ * Return new buf to write out in *bufp.
+ */
+inline __attribute__((always_inline)) static int
+dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
+    dnode_phys_t *dnp, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = scn->scn_dp;
+       int zio_flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SCAN_THREAD;
+       int err;
+
+       if (BP_GET_LEVEL(bp) > 0) {
+               arc_flags_t flags = ARC_FLAG_WAIT;
+               int i;
+               blkptr_t *cbp;
+               int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
+               arc_buf_t *buf;
+
+               err = arc_read(NULL, dp->dp_spa, bp, arc_getbuf_func, &buf,
+                   ZIO_PRIORITY_ASYNC_READ, zio_flags, &flags, zb);
+               if (err) {
+                       scn->scn_phys.scn_errors++;
+                       return (err);
+               }
+               for (i = 0, cbp = buf->b_data; i < epb; i++, cbp++) {
+                       dsl_scan_prefetch(scn, buf, cbp, zb->zb_objset,
+                           zb->zb_object, zb->zb_blkid * epb + i);
+               }
+               for (i = 0, cbp = buf->b_data; 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);
+                       dsl_scan_visitbp(cbp, &czb, dnp,
+                           ds, scn, ostype, tx);
+               }
+               (void) arc_buf_remove_ref(buf, &buf);
+       } else if (BP_GET_TYPE(bp) == DMU_OT_DNODE) {
+               arc_flags_t flags = ARC_FLAG_WAIT;
+               dnode_phys_t *cdnp;
+               int i, j;
+               int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
+               arc_buf_t *buf;
+
+               err = arc_read(NULL, dp->dp_spa, bp, arc_getbuf_func, &buf,
+                   ZIO_PRIORITY_ASYNC_READ, zio_flags, &flags, zb);
+               if (err) {
+                       scn->scn_phys.scn_errors++;
+                       return (err);
+               }
+               for (i = 0, cdnp = buf->b_data; i < epb; i++, cdnp++) {
+                       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++) {
+                       dsl_scan_visitdnode(scn, ds, ostype,
+                           cdnp, zb->zb_blkid * epb + i, tx);
+               }
+
+               (void) arc_buf_remove_ref(buf, &buf);
+       } else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
+               arc_flags_t flags = ARC_FLAG_WAIT;
+               objset_phys_t *osp;
+               arc_buf_t *buf;
+
+               err = arc_read(NULL, dp->dp_spa, bp, arc_getbuf_func, &buf,
+                   ZIO_PRIORITY_ASYNC_READ, zio_flags, &flags, zb);
+               if (err) {
+                       scn->scn_phys.scn_errors++;
+                       return (err);
+               }
+
+               osp = buf->b_data;
+
+               dsl_scan_visitdnode(scn, ds, osp->os_type,
+                   &osp->os_meta_dnode, DMU_META_DNODE_OBJECT, tx);
+
+               if (OBJSET_BUF_HAS_USERUSED(buf)) {
+                       /*
+                        * We also always visit user/group accounting
+                        * objects, and never skip them, even if we are
+                        * pausing.  This is necessary so that the space
+                        * deltas from this txg get integrated.
+                        */
+                       dsl_scan_visitdnode(scn, ds, osp->os_type,
+                           &osp->os_groupused_dnode,
+                           DMU_GROUPUSED_OBJECT, tx);
+                       dsl_scan_visitdnode(scn, ds, osp->os_type,
+                           &osp->os_userused_dnode,
+                           DMU_USERUSED_OBJECT, tx);
+               }
+               (void) arc_buf_remove_ref(buf, &buf);
+       }
+
+       return (0);
+}
+
+inline __attribute__((always_inline)) static void
+dsl_scan_visitdnode(dsl_scan_t *scn, dsl_dataset_t *ds,
+    dmu_objset_type_t ostype, dnode_phys_t *dnp,
+    uint64_t object, dmu_tx_t *tx)
+{
+       int j;
+
+       for (j = 0; j < dnp->dn_nblkptr; j++) {
+               zbookmark_phys_t czb;
+
+               SET_BOOKMARK(&czb, ds ? ds->ds_object : 0, object,
+                   dnp->dn_nlevels - 1, j);
+               dsl_scan_visitbp(&dnp->dn_blkptr[j],
+                   &czb, dnp, ds, scn, ostype, tx);
+       }
+
+       if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
+               zbookmark_phys_t czb;
+               SET_BOOKMARK(&czb, ds ? ds->ds_object : 0, object,
+                   0, DMU_SPILL_BLKID);
+               dsl_scan_visitbp(&dnp->dn_spill,
+                   &czb, dnp, ds, scn, ostype, tx);
+       }
+}
+
+/*
+ * The arguments are in this order because mdb can only print the
+ * first 5; we want them to be useful.
+ */
+static void
+dsl_scan_visitbp(blkptr_t *bp, const zbookmark_phys_t *zb,
+    dnode_phys_t *dnp, dsl_dataset_t *ds, dsl_scan_t *scn,
+    dmu_objset_type_t ostype, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = scn->scn_dp;
+       blkptr_t *bp_toread;
+
+       bp_toread = kmem_alloc(sizeof (blkptr_t), KM_SLEEP);
+       *bp_toread = *bp;
+
+       /* ASSERT(pbuf == NULL || arc_released(pbuf)); */
+
+       if (dsl_scan_check_pause(scn, zb))
+               goto out;
+
+       if (dsl_scan_check_resume(scn, dnp, zb))
+               goto out;
+
+       if (BP_IS_HOLE(bp))
+               goto out;
+
+       scn->scn_visited_this_txg++;
+
+       /*
+        * This debugging is commented out to conserve stack space.  This
+        * function is called recursively and the debugging addes several
+        * bytes to the stack for each call.  It can be commented back in
+        * if required to debug an issue in dsl_scan_visitbp().
+        *
+        * dprintf_bp(bp,
+        *    "visiting ds=%p/%llu zb=%llx/%llx/%llx/%llx bp=%p",
+        *    ds, ds ? ds->ds_object : 0,
+        *    zb->zb_objset, zb->zb_object, zb->zb_level, zb->zb_blkid,
+        *    bp);
+        */
+
+       if (bp->blk_birth <= scn->scn_phys.scn_cur_min_txg)
+               goto out;
+
+       if (dsl_scan_recurse(scn, ds, ostype, dnp, bp_toread, zb, tx) != 0)
+               goto out;
+
+       /*
+        * If dsl_scan_ddt() has aready visited this block, it will have
+        * already done any translations or scrubbing, so don't call the
+        * callback again.
+        */
+       if (ddt_class_contains(dp->dp_spa,
+           scn->scn_phys.scn_ddt_class_max, bp)) {
+               goto out;
+       }
+
+       /*
+        * If this block is from the future (after cur_max_txg), then we
+        * are doing this on behalf of a deleted snapshot, and we will
+        * revisit the future block on the next pass of this dataset.
+        * Don't scan it now unless we need to because something
+        * under it was modified.
+        */
+       if (BP_PHYSICAL_BIRTH(bp) <= scn->scn_phys.scn_cur_max_txg) {
+               scan_funcs[scn->scn_phys.scn_func](dp, bp, zb);
+       }
+out:
+       kmem_free(bp_toread, sizeof (blkptr_t));
+}
+
+static void
+dsl_scan_visit_rootbp(dsl_scan_t *scn, dsl_dataset_t *ds, blkptr_t *bp,
+    dmu_tx_t *tx)
+{
+       zbookmark_phys_t zb;
+
+       SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET,
+           ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
+       dsl_scan_visitbp(bp, &zb, NULL,
+           ds, scn, DMU_OST_NONE, tx);
+
+       dprintf_ds(ds, "finished scan%s", "");
+}
+
+void
+dsl_scan_ds_destroyed(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       dsl_scan_t *scn = dp->dp_scan;
+       uint64_t mintxg;
+
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return;
+
+       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. */
+                       scn->scn_phys.scn_bookmark.zb_objset =
+                           dsl_dataset_phys(ds)->ds_next_snap_obj;
+                       zfs_dbgmsg("destroying ds %llu; currently traversing; "
+                           "reset zb_objset to %llu",
+                           (u_longlong_t)ds->ds_object,
+                           (u_longlong_t)dsl_dataset_phys(ds)->
+                           ds_next_snap_obj);
+                       scn->scn_phys.scn_flags |= DSF_VISIT_DS_AGAIN;
+               } else {
+                       SET_BOOKMARK(&scn->scn_phys.scn_bookmark,
+                           ZB_DESTROYED_OBJSET, 0, 0, 0);
+                       zfs_dbgmsg("destroying ds %llu; currently traversing; "
+                           "reset bookmark to -1,0,0,0",
+                           (u_longlong_t)ds->ds_object);
+               }
+       } else if (zap_lookup_int_key(dp->dp_meta_objset,
+           scn->scn_phys.scn_queue_obj, ds->ds_object, &mintxg) == 0) {
+               ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1);
+               VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds->ds_object, tx));
+               if (ds->ds_is_snapshot) {
+                       /*
+                        * We keep the same mintxg; it could be >
+                        * ds_creation_txg if the previous snapshot was
+                        * deleted too.
+                        */
+                       VERIFY(zap_add_int_key(dp->dp_meta_objset,
+                           scn->scn_phys.scn_queue_obj,
+                           dsl_dataset_phys(ds)->ds_next_snap_obj,
+                           mintxg, tx) == 0);
+                       zfs_dbgmsg("destroying ds %llu; in queue; "
+                           "replacing with %llu",
+                           (u_longlong_t)ds->ds_object,
+                           (u_longlong_t)dsl_dataset_phys(ds)->
+                           ds_next_snap_obj);
+               } else {
+                       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);
+       }
+
+       /*
+        * dsl_scan_sync() should be called after this, and should sync
+        * out our changed state, but just to be safe, do it here.
+        */
+       dsl_scan_sync_state(scn, tx);
+}
+
+void
+dsl_scan_ds_snapshotted(dsl_dataset_t *ds, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       dsl_scan_t *scn = dp->dp_scan;
+       uint64_t mintxg;
+
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return;
+
+       ASSERT(dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
+
+       if (scn->scn_phys.scn_bookmark.zb_objset == ds->ds_object) {
+               scn->scn_phys.scn_bookmark.zb_objset =
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj;
+               zfs_dbgmsg("snapshotting ds %llu; currently traversing; "
+                   "reset zb_objset to %llu",
+                   (u_longlong_t)ds->ds_object,
+                   (u_longlong_t)dsl_dataset_phys(ds)->ds_prev_snap_obj);
+       } else if (zap_lookup_int_key(dp->dp_meta_objset,
+           scn->scn_phys.scn_queue_obj, ds->ds_object, &mintxg) == 0) {
+               VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds->ds_object, tx));
+               VERIFY(zap_add_int_key(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj, mintxg, tx) == 0);
+               zfs_dbgmsg("snapshotting ds %llu; in queue; "
+                   "replacing with %llu",
+                   (u_longlong_t)ds->ds_object,
+                   (u_longlong_t)dsl_dataset_phys(ds)->ds_prev_snap_obj);
+       }
+       dsl_scan_sync_state(scn, tx);
+}
+
+void
+dsl_scan_ds_clone_swapped(dsl_dataset_t *ds1, dsl_dataset_t *ds2, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = ds1->ds_dir->dd_pool;
+       dsl_scan_t *scn = dp->dp_scan;
+       uint64_t mintxg;
+
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return;
+
+       if (scn->scn_phys.scn_bookmark.zb_objset == ds1->ds_object) {
+               scn->scn_phys.scn_bookmark.zb_objset = ds2->ds_object;
+               zfs_dbgmsg("clone_swap ds %llu; currently traversing; "
+                   "reset zb_objset to %llu",
+                   (u_longlong_t)ds1->ds_object,
+                   (u_longlong_t)ds2->ds_object);
+       } else if (scn->scn_phys.scn_bookmark.zb_objset == ds2->ds_object) {
+               scn->scn_phys.scn_bookmark.zb_objset = ds1->ds_object;
+               zfs_dbgmsg("clone_swap ds %llu; currently traversing; "
+                   "reset zb_objset to %llu",
+                   (u_longlong_t)ds2->ds_object,
+                   (u_longlong_t)ds1->ds_object);
+       }
+
+       if (zap_lookup_int_key(dp->dp_meta_objset, scn->scn_phys.scn_queue_obj,
+           ds1->ds_object, &mintxg) == 0) {
+               int err;
+
+               ASSERT3U(mintxg, ==, dsl_dataset_phys(ds1)->ds_prev_snap_txg);
+               ASSERT3U(mintxg, ==, dsl_dataset_phys(ds2)->ds_prev_snap_txg);
+               VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds1->ds_object, tx));
+               err = zap_add_int_key(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds2->ds_object, mintxg, tx);
+               VERIFY(err == 0 || err == EEXIST);
+               if (err == EEXIST) {
+                       /* Both were there to begin with */
+                       VERIFY(0 == zap_add_int_key(dp->dp_meta_objset,
+                           scn->scn_phys.scn_queue_obj,
+                           ds1->ds_object, mintxg, tx));
+               }
+               zfs_dbgmsg("clone_swap ds %llu; in queue; "
+                   "replacing with %llu",
+                   (u_longlong_t)ds1->ds_object,
+                   (u_longlong_t)ds2->ds_object);
+       } else if (zap_lookup_int_key(dp->dp_meta_objset,
+           scn->scn_phys.scn_queue_obj, ds2->ds_object, &mintxg) == 0) {
+               ASSERT3U(mintxg, ==, dsl_dataset_phys(ds1)->ds_prev_snap_txg);
+               ASSERT3U(mintxg, ==, dsl_dataset_phys(ds2)->ds_prev_snap_txg);
+               VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds2->ds_object, tx));
+               VERIFY(0 == zap_add_int_key(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds1->ds_object, mintxg, tx));
+               zfs_dbgmsg("clone_swap ds %llu; in queue; "
+                   "replacing with %llu",
+                   (u_longlong_t)ds2->ds_object,
+                   (u_longlong_t)ds1->ds_object);
+       }
+
+       dsl_scan_sync_state(scn, tx);
+}
+
+struct enqueue_clones_arg {
+       dmu_tx_t *tx;
+       uint64_t originobj;
+};
+
+/* ARGSUSED */
+static int
+enqueue_clones_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg)
+{
+       struct enqueue_clones_arg *eca = arg;
+       dsl_dataset_t *ds;
+       int err;
+       dsl_scan_t *scn = dp->dp_scan;
+
+       if (dsl_dir_phys(hds->ds_dir)->dd_origin_obj != eca->originobj)
+               return (0);
+
+       err = dsl_dataset_hold_obj(dp, hds->ds_object, FTAG, &ds);
+       if (err)
+               return (err);
+
+       while (dsl_dataset_phys(ds)->ds_prev_snap_obj != eca->originobj) {
+               dsl_dataset_t *prev;
+               err = dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
+
+               dsl_dataset_rele(ds, FTAG);
+               if (err)
+                       return (err);
+               ds = prev;
+       }
+       VERIFY(zap_add_int_key(dp->dp_meta_objset,
+           scn->scn_phys.scn_queue_obj, ds->ds_object,
+           dsl_dataset_phys(ds)->ds_prev_snap_txg, eca->tx) == 0);
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+static void
+dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = scn->scn_dp;
+       dsl_dataset_t *ds;
+       objset_t *os;
+       char *dsname;
+
+       VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
+
+       if (dmu_objset_from_ds(ds, &os))
+               goto out;
+
+       /*
+        * Only the ZIL in the head (non-snapshot) is valid.  Even though
+        * snapshots can have ZIL block pointers (which may be the same
+        * BP as in the head), they must be ignored.  So we traverse the
+        * ZIL here, rather than in scan_recurse(), because the regular
+        * snapshot block-sharing rules don't apply to it.
+        */
+       if (DSL_SCAN_IS_SCRUB_RESILVER(scn) && !ds->ds_is_snapshot)
+               dsl_scan_zil(dp, &os->os_zil_header);
+
+       /*
+        * Iterate over the bps in this ds.
+        */
+       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);
+       dsl_dataset_name(ds, dsname);
+       zfs_dbgmsg("scanned dataset %llu (%s) with min=%llu max=%llu; "
+           "pausing=%u",
+           (longlong_t)dsobj, dsname,
+           (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);
+
+       if (scn->scn_pausing)
+               goto out;
+
+       /*
+        * We've finished this pass over this dataset.
+        */
+
+       /*
+        * If we did not completely visit this dataset, do another pass.
+        */
+       if (scn->scn_phys.scn_flags & DSF_VISIT_DS_AGAIN) {
+               zfs_dbgmsg("incomplete pass; visiting again");
+               scn->scn_phys.scn_flags &= ~DSF_VISIT_DS_AGAIN;
+               VERIFY(zap_add_int_key(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, ds->ds_object,
+                   scn->scn_phys.scn_cur_max_txg, tx) == 0);
+               goto out;
+       }
+
+       /*
+        * Add descendent datasets to work queue.
+        */
+       if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) {
+               VERIFY(zap_add_int_key(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj,
+                   dsl_dataset_phys(ds)->ds_next_snap_obj,
+                   dsl_dataset_phys(ds)->ds_creation_txg, tx) == 0);
+       }
+       if (dsl_dataset_phys(ds)->ds_num_children > 1) {
+               boolean_t usenext = B_FALSE;
+               if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) {
+                       uint64_t count;
+                       /*
+                        * A bug in a previous version of the code could
+                        * cause upgrade_clones_cb() to not set
+                        * ds_next_snap_obj when it should, leading to a
+                        * missing entry.  Therefore we can only use the
+                        * next_clones_obj when its count is correct.
+                        */
+                       int err = zap_count(dp->dp_meta_objset,
+                           dsl_dataset_phys(ds)->ds_next_clones_obj, &count);
+                       if (err == 0 &&
+                           count == dsl_dataset_phys(ds)->ds_num_children - 1)
+                               usenext = B_TRUE;
+               }
+
+               if (usenext) {
+                       VERIFY0(zap_join_key(dp->dp_meta_objset,
+                           dsl_dataset_phys(ds)->ds_next_clones_obj,
+                           scn->scn_phys.scn_queue_obj,
+                           dsl_dataset_phys(ds)->ds_creation_txg, tx));
+               } else {
+                       struct enqueue_clones_arg eca;
+                       eca.tx = tx;
+                       eca.originobj = ds->ds_object;
+
+                       VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj,
+                           enqueue_clones_cb, &eca, DS_FIND_CHILDREN));
+               }
+       }
+
+out:
+       dsl_dataset_rele(ds, FTAG);
+}
+
+/* ARGSUSED */
+static int
+enqueue_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg)
+{
+       dmu_tx_t *tx = arg;
+       dsl_dataset_t *ds;
+       int err;
+       dsl_scan_t *scn = dp->dp_scan;
+
+       err = dsl_dataset_hold_obj(dp, hds->ds_object, FTAG, &ds);
+       if (err)
+               return (err);
+
+       while (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
+               dsl_dataset_t *prev;
+               err = dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
+               if (err) {
+                       dsl_dataset_rele(ds, FTAG);
+                       return (err);
+               }
+
+               /*
+                * If this is a clone, we don't need to worry about it for now.
+                */
+               if (dsl_dataset_phys(prev)->ds_next_snap_obj != ds->ds_object) {
+                       dsl_dataset_rele(ds, FTAG);
+                       dsl_dataset_rele(prev, FTAG);
+                       return (0);
+               }
+               dsl_dataset_rele(ds, FTAG);
+               ds = prev;
+       }
+
+       VERIFY(zap_add_int_key(dp->dp_meta_objset, scn->scn_phys.scn_queue_obj,
+           ds->ds_object, dsl_dataset_phys(ds)->ds_prev_snap_txg, tx) == 0);
+       dsl_dataset_rele(ds, FTAG);
+       return (0);
+}
+
+/*
+ * Scrub/dedup interaction.
+ *
+ * If there are N references to a deduped block, we don't want to scrub it
+ * N times -- ideally, we should scrub it exactly once.
+ *
+ * We leverage the fact that the dde's replication class (enum ddt_class)
+ * is ordered from highest replication class (DDT_CLASS_DITTO) to lowest
+ * (DDT_CLASS_UNIQUE) so that we may walk the DDT in that order.
+ *
+ * To prevent excess scrubbing, the scrub begins by walking the DDT
+ * to find all blocks with refcnt > 1, and scrubs each of these once.
+ * Since there are two replication classes which contain blocks with
+ * refcnt > 1, we scrub the highest replication class (DDT_CLASS_DITTO) first.
+ * Finally the top-down scrub begins, only visiting blocks with refcnt == 1.
+ *
+ * There would be nothing more to say if a block's refcnt couldn't change
+ * during a scrub, but of course it can so we must account for changes
+ * in a block's replication class.
+ *
+ * Here's an example of what can occur:
+ *
+ * If a block has refcnt > 1 during the DDT scrub phase, but has refcnt == 1
+ * when visited during the top-down scrub phase, it will be scrubbed twice.
+ * This negates our scrub optimization, but is otherwise harmless.
+ *
+ * If a block has refcnt == 1 during the DDT scrub phase, but has refcnt > 1
+ * on each visit during the top-down scrub phase, it will never be scrubbed.
+ * To catch this, ddt_sync_entry() notifies the scrub code whenever a block's
+ * reference class transitions to a higher level (i.e DDT_CLASS_UNIQUE to
+ * DDT_CLASS_DUPLICATE); if it transitions from refcnt == 1 to refcnt > 1
+ * while a scrub is in progress, it scrubs the block right then.
+ */
+static void
+dsl_scan_ddt(dsl_scan_t *scn, dmu_tx_t *tx)
+{
+       ddt_bookmark_t *ddb = &scn->scn_phys.scn_ddt_bookmark;
+       ddt_entry_t dde;
+       int error;
+       uint64_t n = 0;
+
+       bzero(&dde, sizeof (ddt_entry_t));
+
+       while ((error = ddt_walk(scn->scn_dp->dp_spa, ddb, &dde)) == 0) {
+               ddt_t *ddt;
+
+               if (ddb->ddb_class > scn->scn_phys.scn_ddt_class_max)
+                       break;
+               dprintf("visiting ddb=%llu/%llu/%llu/%llx\n",
+                   (longlong_t)ddb->ddb_class,
+                   (longlong_t)ddb->ddb_type,
+                   (longlong_t)ddb->ddb_checksum,
+                   (longlong_t)ddb->ddb_cursor);
+
+               /* There should be no pending changes to the dedup table */
+               ddt = scn->scn_dp->dp_spa->spa_ddt[ddb->ddb_checksum];
+               ASSERT(avl_first(&ddt->ddt_tree) == NULL);
+
+               dsl_scan_ddt_entry(scn, ddb->ddb_checksum, &dde, tx);
+               n++;
+
+               if (dsl_scan_check_pause(scn, NULL))
+                       break;
+       }
+
+       zfs_dbgmsg("scanned %llu ddt entries with class_max = %u; pausing=%u",
+           (longlong_t)n, (int)scn->scn_phys.scn_ddt_class_max,
+           (int)scn->scn_pausing);
+
+       ASSERT(error == 0 || error == ENOENT);
+       ASSERT(error != ENOENT ||
+           ddb->ddb_class > scn->scn_phys.scn_ddt_class_max);
+}
+
+/* ARGSUSED */
+void
+dsl_scan_ddt_entry(dsl_scan_t *scn, enum zio_checksum checksum,
+    ddt_entry_t *dde, dmu_tx_t *tx)
+{
+       const ddt_key_t *ddk = &dde->dde_key;
+       ddt_phys_t *ddp = dde->dde_phys;
+       blkptr_t bp;
+       zbookmark_phys_t zb = { 0 };
+       int p;
+
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return;
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+               if (ddp->ddp_phys_birth == 0 ||
+                   ddp->ddp_phys_birth > scn->scn_phys.scn_max_txg)
+                       continue;
+               ddt_bp_create(checksum, ddk, ddp, &bp);
+
+               scn->scn_visited_this_txg++;
+               scan_funcs[scn->scn_phys.scn_func](scn->scn_dp, &bp, &zb);
+       }
+}
+
+static void
+dsl_scan_visit(dsl_scan_t *scn, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = scn->scn_dp;
+       zap_cursor_t *zc;
+       zap_attribute_t *za;
+
+       if (scn->scn_phys.scn_ddt_bookmark.ddb_class <=
+           scn->scn_phys.scn_ddt_class_max) {
+               scn->scn_phys.scn_cur_min_txg = scn->scn_phys.scn_min_txg;
+               scn->scn_phys.scn_cur_max_txg = scn->scn_phys.scn_max_txg;
+               dsl_scan_ddt(scn, tx);
+               if (scn->scn_pausing)
+                       return;
+       }
+
+       if (scn->scn_phys.scn_bookmark.zb_objset == DMU_META_OBJSET) {
+               /* First do the MOS & ORIGIN */
+
+               scn->scn_phys.scn_cur_min_txg = scn->scn_phys.scn_min_txg;
+               scn->scn_phys.scn_cur_max_txg = scn->scn_phys.scn_max_txg;
+               dsl_scan_visit_rootbp(scn, NULL,
+                   &dp->dp_meta_rootbp, tx);
+               spa_set_rootblkptr(dp->dp_spa, &dp->dp_meta_rootbp);
+               if (scn->scn_pausing)
+                       return;
+
+               if (spa_version(dp->dp_spa) < SPA_VERSION_DSL_SCRUB) {
+                       VERIFY0(dmu_objset_find_dp(dp, dp->dp_root_dir_obj,
+                           enqueue_cb, tx, DS_FIND_CHILDREN));
+               } else {
+                       dsl_scan_visitds(scn,
+                           dp->dp_origin_snap->ds_object, tx);
+               }
+               ASSERT(!scn->scn_pausing);
+       } else if (scn->scn_phys.scn_bookmark.zb_objset !=
+           ZB_DESTROYED_OBJSET) {
+               /*
+                * If we were paused, continue from here.  Note if the
+                * ds we were paused on was deleted, the zb_objset may
+                * be -1, so we will skip this and find a new objset
+                * below.
+                */
+               dsl_scan_visitds(scn, scn->scn_phys.scn_bookmark.zb_objset, tx);
+               if (scn->scn_pausing)
+                       return;
+       }
+
+       /*
+        * In case we were paused right at the end of the ds, zero the
+        * bookmark so we don't think that we're still trying to resume.
+        */
+       bzero(&scn->scn_phys.scn_bookmark, sizeof (zbookmark_phys_t));
+       zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
+       za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+
+       /* keep pulling things out of the zap-object-as-queue */
+       while (zap_cursor_init(zc, dp->dp_meta_objset,
+           scn->scn_phys.scn_queue_obj),
+           zap_cursor_retrieve(zc, za) == 0) {
+               dsl_dataset_t *ds;
+               uint64_t dsobj;
+
+               dsobj = strtonum(za->za_name, NULL);
+               VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset,
+                   scn->scn_phys.scn_queue_obj, dsobj, tx));
+
+               /* Set up min/max txg */
+               VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
+               if (za->za_first_integer != 0) {
+                       scn->scn_phys.scn_cur_min_txg =
+                           MAX(scn->scn_phys.scn_min_txg,
+                           za->za_first_integer);
+               } else {
+                       scn->scn_phys.scn_cur_min_txg =
+                           MAX(scn->scn_phys.scn_min_txg,
+                           dsl_dataset_phys(ds)->ds_prev_snap_txg);
+               }
+               scn->scn_phys.scn_cur_max_txg = dsl_scan_ds_maxtxg(ds);
+               dsl_dataset_rele(ds, FTAG);
+
+               dsl_scan_visitds(scn, dsobj, tx);
+               zap_cursor_fini(zc);
+               if (scn->scn_pausing)
+                       goto out;
+       }
+       zap_cursor_fini(zc);
+out:
+       kmem_free(za, sizeof (zap_attribute_t));
+       kmem_free(zc, sizeof (zap_cursor_t));
+}
+
+static boolean_t
+dsl_scan_free_should_pause(dsl_scan_t *scn)
+{
+       uint64_t elapsed_nanosecs;
+
+       if (zfs_recover)
+               return (B_FALSE);
+
+       if (scn->scn_visited_this_txg >= zfs_free_max_blocks)
+               return (B_TRUE);
+
+       elapsed_nanosecs = gethrtime() - scn->scn_sync_start_time;
+       return (elapsed_nanosecs / NANOSEC > zfs_txg_timeout ||
+           (NSEC2MSEC(elapsed_nanosecs) > zfs_free_min_time_ms &&
+           txg_sync_waiting(scn->scn_dp)) ||
+           spa_shutting_down(scn->scn_dp->dp_spa));
+}
+
+static int
+dsl_scan_free_block_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       dsl_scan_t *scn = arg;
+
+       if (!scn->scn_is_bptree ||
+           (BP_GET_LEVEL(bp) == 0 && BP_GET_TYPE(bp) != DMU_OT_OBJSET)) {
+               if (dsl_scan_free_should_pause(scn))
+                       return (SET_ERROR(ERESTART));
+       }
+
+       zio_nowait(zio_free_sync(scn->scn_zio_root, scn->scn_dp->dp_spa,
+           dmu_tx_get_txg(tx), bp, 0));
+       dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, DD_USED_HEAD,
+           -bp_get_dsize_sync(scn->scn_dp->dp_spa, bp),
+           -BP_GET_PSIZE(bp), -BP_GET_UCSIZE(bp), tx);
+       scn->scn_visited_this_txg++;
+       return (0);
+}
+
+boolean_t
+dsl_scan_active(dsl_scan_t *scn)
+{
+       spa_t *spa = scn->scn_dp->dp_spa;
+       uint64_t used = 0, comp, uncomp;
+
+       if (spa->spa_load_state != SPA_LOAD_NONE)
+               return (B_FALSE);
+       if (spa_shutting_down(spa))
+               return (B_FALSE);
+       if (scn->scn_phys.scn_state == DSS_SCANNING ||
+           (scn->scn_async_destroying && !scn->scn_async_stalled))
+               return (B_TRUE);
+
+       if (spa_version(scn->scn_dp->dp_spa) >= SPA_VERSION_DEADLISTS) {
+               (void) bpobj_space(&scn->scn_dp->dp_free_bpobj,
+                   &used, &comp, &uncomp);
+       }
+       return (used != 0);
+}
+
+void
+dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
+{
+       dsl_scan_t *scn = dp->dp_scan;
+       spa_t *spa = dp->dp_spa;
+       int err = 0;
+
+       /*
+        * Check for scn_restart_txg before checking spa_load_state, so
+        * 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) {
+               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))
+                       func = POOL_SCAN_RESILVER;
+               zfs_dbgmsg("restarting scan func=%u txg=%llu",
+                   func, tx->tx_txg);
+               dsl_scan_setup_sync(&func, tx);
+       }
+
+       /*
+        * 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)
+               return;
+
+       scn->scn_visited_this_txg = 0;
+       scn->scn_pausing = B_FALSE;
+       scn->scn_sync_start_time = gethrtime();
+       spa->spa_scrub_active = B_TRUE;
+
+       /*
+        * First process the async destroys.  If we pause, don't do
+        * any scrubbing or resilvering.  This ensures that there are no
+        * async destroys while we are scanning, so the scan code doesn't
+        * 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) {
+               scn->scn_is_bptree = B_FALSE;
+               scn->scn_zio_root = zio_root(dp->dp_spa, NULL,
+                   NULL, ZIO_FLAG_MUSTSUCCEED);
+               err = bpobj_iterate(&dp->dp_free_bpobj,
+                   dsl_scan_free_block_cb, scn, tx);
+               VERIFY3U(0, ==, zio_wait(scn->scn_zio_root));
+
+               if (err != 0 && err != ERESTART)
+                       zfs_panic_recover("error %u from bpobj_iterate()", err);
+       }
+
+       if (err == 0 && spa_feature_is_active(spa, SPA_FEATURE_ASYNC_DESTROY)) {
+               ASSERT(scn->scn_async_destroying);
+               scn->scn_is_bptree = B_TRUE;
+               scn->scn_zio_root = zio_root(dp->dp_spa, NULL,
+                   NULL, ZIO_FLAG_MUSTSUCCEED);
+               err = bptree_iterate(dp->dp_meta_objset,
+                   dp->dp_bptree_obj, B_TRUE, dsl_scan_free_block_cb, scn, tx);
+               VERIFY0(zio_wait(scn->scn_zio_root));
+
+               if (err == EIO || err == ECKSUM) {
+                       err = 0;
+               } else if (err != 0 && err != ERESTART) {
+                       zfs_panic_recover("error %u from "
+                           "traverse_dataset_destroyed()", err);
+               }
+
+               if (bptree_is_empty(dp->dp_meta_objset, dp->dp_bptree_obj)) {
+                       /* finished; deactivate async destroy feature */
+                       spa_feature_decr(spa, SPA_FEATURE_ASYNC_DESTROY, tx);
+                       ASSERT(!spa_feature_is_active(spa,
+                           SPA_FEATURE_ASYNC_DESTROY));
+                       VERIFY0(zap_remove(dp->dp_meta_objset,
+                           DMU_POOL_DIRECTORY_OBJECT,
+                           DMU_POOL_BPTREE_OBJ, tx));
+                       VERIFY0(bptree_free(dp->dp_meta_objset,
+                           dp->dp_bptree_obj, tx));
+                       dp->dp_bptree_obj = 0;
+                       scn->scn_async_destroying = B_FALSE;
+                       scn->scn_async_stalled = B_FALSE;
+               } else {
+                       /*
+                        * If we didn't make progress, mark the async
+                        * destroy as stalled, so that we will not initiate
+                        * a spa_sync() on its behalf.  Note that we only
+                        * check this if we are not finished, because if the
+                        * bptree had no blocks for us to visit, we can
+                        * finish without "making progress".
+                        */
+                       scn->scn_async_stalled =
+                           (scn->scn_visited_this_txg == 0);
+               }
+       }
+       if (scn->scn_visited_this_txg) {
+               zfs_dbgmsg("freed %llu blocks in %llums from "
+                   "free_bpobj/bptree txg %llu; err=%u",
+                   (longlong_t)scn->scn_visited_this_txg,
+                   (longlong_t)
+                   NSEC2MSEC(gethrtime() - scn->scn_sync_start_time),
+                   (longlong_t)tx->tx_txg, err);
+               scn->scn_visited_this_txg = 0;
+
+               /*
+                * Write out changes to the DDT that may be required as a
+                * result of the blocks freed.  This ensures that the DDT
+                * is clean when a scrub/resilver runs.
+                */
+               ddt_sync(spa, tx->tx_txg);
+       }
+       if (err != 0)
+               return;
+       if (!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)) {
+               /*
+                * We have finished background destroying, but there is still
+                * some space left in the dp_free_dir. Transfer this leaked
+                * space to the dp_leak_dir.
+                */
+               if (dp->dp_leak_dir == NULL) {
+                       rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
+                       (void) dsl_dir_create_sync(dp, dp->dp_root_dir,
+                           LEAK_DIR_NAME, tx);
+                       VERIFY0(dsl_pool_open_special_dir(dp,
+                           LEAK_DIR_NAME, &dp->dp_leak_dir));
+                       rrw_exit(&dp->dp_config_rwlock, FTAG);
+               }
+               dsl_dir_diduse_space(dp->dp_leak_dir, DD_USED_HEAD,
+                   dsl_dir_phys(dp->dp_free_dir)->dd_used_bytes,
+                   dsl_dir_phys(dp->dp_free_dir)->dd_compressed_bytes,
+                   dsl_dir_phys(dp->dp_free_dir)->dd_uncompressed_bytes, tx);
+               dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD,
+                   -dsl_dir_phys(dp->dp_free_dir)->dd_used_bytes,
+                   -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) {
+               /* 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);
+               ASSERT0(dsl_dir_phys(dp->dp_free_dir)->dd_uncompressed_bytes);
+       }
+
+       if (scn->scn_phys.scn_state != DSS_SCANNING)
+               return;
+
+       if (scn->scn_done_txg == tx->tx_txg) {
+               ASSERT(!scn->scn_pausing);
+               /* finished with scan. */
+               zfs_dbgmsg("txg %llu scan complete", tx->tx_txg);
+               dsl_scan_done(scn, B_TRUE, tx);
+               ASSERT3U(spa->spa_scrub_inflight, ==, 0);
+               dsl_scan_sync_state(scn, tx);
+               return;
+       }
+
+       if (scn->scn_phys.scn_ddt_bookmark.ddb_class <=
+           scn->scn_phys.scn_ddt_class_max) {
+               zfs_dbgmsg("doing scan sync txg %llu; "
+                   "ddt bm=%llu/%llu/%llu/%llx",
+                   (longlong_t)tx->tx_txg,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_class,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_type,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_checksum,
+                   (longlong_t)scn->scn_phys.scn_ddt_bookmark.ddb_cursor);
+               ASSERT(scn->scn_phys.scn_bookmark.zb_objset == 0);
+               ASSERT(scn->scn_phys.scn_bookmark.zb_object == 0);
+               ASSERT(scn->scn_phys.scn_bookmark.zb_level == 0);
+               ASSERT(scn->scn_phys.scn_bookmark.zb_blkid == 0);
+       } else {
+               zfs_dbgmsg("doing scan sync txg %llu; bm=%llu/%llu/%llu/%llu",
+                   (longlong_t)tx->tx_txg,
+                   (longlong_t)scn->scn_phys.scn_bookmark.zb_objset,
+                   (longlong_t)scn->scn_phys.scn_bookmark.zb_object,
+                   (longlong_t)scn->scn_phys.scn_bookmark.zb_level,
+                   (longlong_t)scn->scn_phys.scn_bookmark.zb_blkid);
+       }
+
+       scn->scn_zio_root = zio_root(dp->dp_spa, NULL,
+           NULL, ZIO_FLAG_CANFAIL);
+       dsl_pool_config_enter(dp, FTAG);
+       dsl_scan_visit(scn, tx);
+       dsl_pool_config_exit(dp, FTAG);
+       (void) zio_wait(scn->scn_zio_root);
+       scn->scn_zio_root = NULL;
+
+       zfs_dbgmsg("visited %llu blocks in %llums",
+           (longlong_t)scn->scn_visited_this_txg,
+           (longlong_t)NSEC2MSEC(gethrtime() - scn->scn_sync_start_time));
+
+       if (!scn->scn_pausing) {
+               scn->scn_done_txg = tx->tx_txg + 1;
+               zfs_dbgmsg("txg %llu traversal complete, waiting till txg %llu",
+                   tx->tx_txg, scn->scn_done_txg);
+       }
+
+       if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
+               mutex_enter(&spa->spa_scrub_lock);
+               while (spa->spa_scrub_inflight > 0) {
+                       cv_wait(&spa->spa_scrub_io_cv,
+                           &spa->spa_scrub_lock);
+               }
+               mutex_exit(&spa->spa_scrub_lock);
+       }
+
+       dsl_scan_sync_state(scn, tx);
+}
+
+/*
+ * This will start a new scan, or restart an existing one.
+ */
+void
+dsl_resilver_restart(dsl_pool_t *dp, uint64_t txg)
+{
+       if (txg == 0) {
+               dmu_tx_t *tx;
+               tx = dmu_tx_create_dd(dp->dp_mos_dir);
+               VERIFY(0 == dmu_tx_assign(tx, TXG_WAIT));
+
+               txg = dmu_tx_get_txg(tx);
+               dp->dp_scan->scn_restart_txg = txg;
+               dmu_tx_commit(tx);
+       } else {
+               dp->dp_scan->scn_restart_txg = txg;
+       }
+       zfs_dbgmsg("restarting resilver txg=%llu", txg);
+}
+
+boolean_t
+dsl_scan_resilvering(dsl_pool_t *dp)
+{
+       return (dp->dp_scan->scn_phys.scn_state == DSS_SCANNING &&
+           dp->dp_scan->scn_phys.scn_func == POOL_SCAN_RESILVER);
+}
+
+/*
+ * scrub consumers
+ */
+
+static void
+count_block(zfs_all_blkstats_t *zab, const blkptr_t *bp)
+{
+       int i;
+
+       /*
+        * If we resume after a reboot, zab will be NULL; don't record
+        * incomplete stats in that case.
+        */
+       if (zab == NULL)
+               return;
+
+       for (i = 0; i < 4; i++) {
+               int l = (i < 2) ? BP_GET_LEVEL(bp) : DN_MAX_LEVELS;
+               int t = (i & 1) ? BP_GET_TYPE(bp) : DMU_OT_TOTAL;
+               int equal;
+               zfs_blkstat_t *zb;
+
+               if (t & DMU_OT_NEWTYPE)
+                       t = DMU_OT_OTHER;
+
+               zb = &zab->zab_type[l][t];
+               zb->zb_count++;
+               zb->zb_asize += BP_GET_ASIZE(bp);
+               zb->zb_lsize += BP_GET_LSIZE(bp);
+               zb->zb_psize += BP_GET_PSIZE(bp);
+               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_2_of_2_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 == 1)
+                               zb->zb_ditto_2_of_3_samevdev++;
+                       else if (equal == 3)
+                               zb->zb_ditto_3_of_3_samevdev++;
+                       break;
+               }
+       }
+}
+
+static void
+dsl_scan_scrub_done(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+
+       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 (zio->io_error && (zio->io_error != ECKSUM ||
+           !(zio->io_flags & ZIO_FLAG_SPECULATIVE))) {
+               spa->spa_dsl_pool->dp_scan->scn_phys.scn_errors++;
+       }
+       mutex_exit(&spa->spa_scrub_lock);
+}
+
+static int
+dsl_scan_scrub_cb(dsl_pool_t *dp,
+    const blkptr_t *bp, const zbookmark_phys_t *zb)
+{
+       dsl_scan_t *scn = dp->dp_scan;
+       size_t size = BP_GET_PSIZE(bp);
+       spa_t *spa = dp->dp_spa;
+       uint64_t phys_birth = BP_PHYSICAL_BIRTH(bp);
+       boolean_t needs_io = B_FALSE;
+       int zio_flags = ZIO_FLAG_SCAN_THREAD | ZIO_FLAG_RAW | ZIO_FLAG_CANFAIL;
+       int scan_delay = 0;
+       int d;
+
+       if (phys_birth <= scn->scn_phys.scn_min_txg ||
+           phys_birth >= scn->scn_phys.scn_max_txg)
+               return (0);
+
+       count_block(dp->dp_blkstats, bp);
+
+       if (BP_IS_EMBEDDED(bp))
+               return (0);
+
+       ASSERT(DSL_SCAN_IS_SCRUB_RESILVER(scn));
+       if (scn->scn_phys.scn_func == POOL_SCAN_SCRUB) {
+               zio_flags |= ZIO_FLAG_SCRUB;
+               needs_io = B_TRUE;
+               scan_delay = zfs_scrub_delay;
+       } else {
+               ASSERT3U(scn->scn_phys.scn_func, ==, POOL_SCAN_RESILVER);
+               zio_flags |= ZIO_FLAG_RESILVER;
+               needs_io = B_FALSE;
+               scan_delay = zfs_resilver_delay;
+       }
+
+       /* If it's an intent log block, failure is expected. */
+       if (zb->zb_level == ZB_ZIL_LEVEL)
+               zio_flags |= ZIO_FLAG_SPECULATIVE;
+
+       for (d = 0; d < BP_GET_NDVAS(bp); d++) {
+               vdev_t *vd = vdev_lookup_top(spa,
+                   DVA_GET_VDEV(&bp->blk_dva[d]));
+
+               /*
+                * Keep track of how much data we've examined so that
+                * zpool(1M) status can make useful progress reports.
+                */
+               scn->scn_phys.scn_examined += DVA_GET_ASIZE(&bp->blk_dva[d]);
+               spa->spa_scan_pass_exam += DVA_GET_ASIZE(&bp->blk_dva[d]);
+
+               /* if it's a resilver, this may not be in the target range */
+               if (!needs_io) {
+                       if (DVA_GET_GANG(&bp->blk_dva[d])) {
+                               /*
+                                * Gang members may be spread across multiple
+                                * vdevs, so the best estimate we have is the
+                                * scrub range, which has already been checked.
+                                * XXX -- it would be better to change our
+                                * allocation policy to ensure that all
+                                * gang members reside on the same vdev.
+                                */
+                               needs_io = B_TRUE;
+                       } else {
+                               needs_io = vdev_dtl_contains(vd, DTL_PARTIAL,
+                                   phys_birth, 1);
+                       }
+               }
+       }
+
+       if (needs_io && !zfs_no_scrub_io) {
+               vdev_t *rvd = spa->spa_root_vdev;
+               uint64_t maxinflight = rvd->vdev_children * zfs_top_maxinflight;
+               void *data = zio_data_buf_alloc(size);
+
+               mutex_enter(&spa->spa_scrub_lock);
+               while (spa->spa_scrub_inflight >= maxinflight)
+                       cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock);
+               spa->spa_scrub_inflight++;
+               mutex_exit(&spa->spa_scrub_lock);
+
+               /*
+                * If we're seeing recent (zfs_scan_idle) "important" I/Os
+                * then throttle our workload to limit the impact of a scan.
+                */
+               if (ddi_get_lbolt64() - spa->spa_last_io <= zfs_scan_idle)
+                       delay(scan_delay);
+
+               zio_nowait(zio_read(NULL, spa, bp, data, size,
+                   dsl_scan_scrub_done, NULL, ZIO_PRIORITY_SCRUB,
+                   zio_flags, zb));
+       }
+
+       /* do not relocate this block */
+       return (0);
+}
+
+int
+dsl_scan(dsl_pool_t *dp, pool_scan_func_t func)
+{
+       spa_t *spa = dp->dp_spa;
+
+       /*
+        * Purge all vdev caches and probe all devices.  We do this here
+        * rather than in sync context because this requires a writer lock
+        * on the spa_config lock, which we can't do from sync context.  The
+        * spa_scrub_reopen flag indicates that vdev_open() should not
+        * attempt to start another scrub.
+        */
+       spa_vdev_state_enter(spa, SCL_NONE);
+       spa->spa_scrub_reopen = B_TRUE;
+       vdev_reopen(spa->spa_root_vdev);
+       spa->spa_scrub_reopen = B_FALSE;
+       (void) spa_vdev_state_exit(spa, NULL, 0);
+
+       return (dsl_sync_task(spa_name(spa), dsl_scan_setup_check,
+           dsl_scan_setup_sync, &func, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+#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");
+
+module_param(zfs_resilver_delay, int, 0644);
+MODULE_PARM_DESC(zfs_resilver_delay, "Number of ticks to delay resilver");
+
+module_param(zfs_scrub_delay, int, 0644);
+MODULE_PARM_DESC(zfs_scrub_delay, "Number of ticks to delay scrub");
+
+module_param(zfs_scan_idle, int, 0644);
+MODULE_PARM_DESC(zfs_scan_idle, "Idle window in clock ticks");
+
+module_param(zfs_scan_min_time_ms, int, 0644);
+MODULE_PARM_DESC(zfs_scan_min_time_ms, "Min millisecs to scrub per txg");
+
+module_param(zfs_free_min_time_ms, int, 0644);
+MODULE_PARM_DESC(zfs_free_min_time_ms, "Min millisecs to free per txg");
+
+module_param(zfs_resilver_min_time_ms, int, 0644);
+MODULE_PARM_DESC(zfs_resilver_min_time_ms, "Min millisecs to resilver per txg");
+
+module_param(zfs_no_scrub_io, int, 0644);
+MODULE_PARM_DESC(zfs_no_scrub_io, "Set to disable scrub I/O");
+
+module_param(zfs_no_scrub_prefetch, int, 0644);
+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");
+#endif
diff --git a/zfs/module/zfs/dsl_synctask.c b/zfs/module/zfs/dsl_synctask.c
new file mode 100644 (file)
index 0000000..28130d2
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_synctask.h>
+#include <sys/metaslab.h>
+
+#define        DST_AVG_BLKSHIFT 14
+
+/* ARGSUSED */
+static int
+dsl_null_checkfunc(void *arg, dmu_tx_t *tx)
+{
+       return (0);
+}
+
+/*
+ * Called from open context to perform a callback in syncing context.  Waits
+ * for the operation to complete.
+ *
+ * The checkfunc will be called from open context as a preliminary check
+ * which can quickly fail.  If it succeeds, it will be called again from
+ * syncing context.  The checkfunc should generally be designed to work
+ * properly in either context, but if necessary it can check
+ * dmu_tx_is_syncing(tx).
+ *
+ * The synctask infrastructure enforces proper locking strategy with respect
+ * to the dp_config_rwlock -- the lock will always be held when the callbacks
+ * are called.  It will be held for read during the open-context (preliminary)
+ * call to the checkfunc, and then held for write from syncing context during
+ * the calls to the check and sync funcs.
+ *
+ * A dataset or pool name can be passed as the first argument.  Typically,
+ * the check func will hold, check the return value of the hold, and then
+ * release the dataset.  The sync func will VERIFYO(hold()) the dataset.
+ * This is safe because no changes can be made between the check and sync funcs,
+ * and the sync func will only be called if the check func successfully opened
+ * the dataset.
+ */
+int
+dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
+    dsl_syncfunc_t *syncfunc, void *arg,
+    int blocks_modified, zfs_space_check_t space_check)
+{
+       spa_t *spa;
+       dmu_tx_t *tx;
+       int err;
+       dsl_sync_task_t dst = { { { NULL } } };
+       dsl_pool_t *dp;
+
+       err = spa_open(pool, &spa, FTAG);
+       if (err != 0)
+               return (err);
+       dp = spa_get_dsl(spa);
+
+top:
+       tx = dmu_tx_create_dd(dp->dp_mos_dir);
+       VERIFY0(dmu_tx_assign(tx, TXG_WAIT));
+
+       dst.dst_pool = dp;
+       dst.dst_txg = dmu_tx_get_txg(tx);
+       dst.dst_space = blocks_modified << DST_AVG_BLKSHIFT;
+       dst.dst_space_check = space_check;
+       dst.dst_checkfunc = checkfunc != NULL ? checkfunc : dsl_null_checkfunc;
+       dst.dst_syncfunc = syncfunc;
+       dst.dst_arg = arg;
+       dst.dst_error = 0;
+       dst.dst_nowaiter = B_FALSE;
+
+       dsl_pool_config_enter(dp, FTAG);
+       err = dst.dst_checkfunc(arg, tx);
+       dsl_pool_config_exit(dp, FTAG);
+
+       if (err != 0) {
+               dmu_tx_commit(tx);
+               spa_close(spa, FTAG);
+               return (err);
+       }
+
+       VERIFY(txg_list_add_tail(&dp->dp_sync_tasks, &dst, dst.dst_txg));
+
+       dmu_tx_commit(tx);
+
+       txg_wait_synced(dp, dst.dst_txg);
+
+       if (dst.dst_error == EAGAIN) {
+               txg_wait_synced(dp, dst.dst_txg + TXG_DEFER_SIZE);
+               goto top;
+       }
+
+       spa_close(spa, FTAG);
+       return (dst.dst_error);
+}
+
+void
+dsl_sync_task_nowait(dsl_pool_t *dp, dsl_syncfunc_t *syncfunc, void *arg,
+    int blocks_modified, zfs_space_check_t space_check, dmu_tx_t *tx)
+{
+       dsl_sync_task_t *dst = kmem_zalloc(sizeof (*dst), KM_SLEEP);
+
+       dst->dst_pool = dp;
+       dst->dst_txg = dmu_tx_get_txg(tx);
+       dst->dst_space = blocks_modified << DST_AVG_BLKSHIFT;
+       dst->dst_space_check = space_check;
+       dst->dst_checkfunc = dsl_null_checkfunc;
+       dst->dst_syncfunc = syncfunc;
+       dst->dst_arg = arg;
+       dst->dst_error = 0;
+       dst->dst_nowaiter = B_TRUE;
+
+       VERIFY(txg_list_add_tail(&dp->dp_sync_tasks, dst, dst->dst_txg));
+}
+
+/*
+ * Called in syncing context to execute the synctask.
+ */
+void
+dsl_sync_task_sync(dsl_sync_task_t *dst, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dst->dst_pool;
+
+       ASSERT0(dst->dst_error);
+
+       /*
+        * Check for sufficient space.
+        *
+        * When the sync task was created, the caller specified the
+        * type of space checking required.  See the comment in
+        * zfs_space_check_t for details on the semantics of each
+        * type of space checking.
+        *
+        * We just check against what's on-disk; we don't want any
+        * in-flight accounting to get in our way, because open context
+        * may have already used up various in-core limits
+        * (arc_tempreserve, dsl_pool_tempreserve).
+        */
+       if (dst->dst_space_check != ZFS_SPACE_CHECK_NONE) {
+               uint64_t quota = dsl_pool_adjustedsize(dp,
+                   dst->dst_space_check == ZFS_SPACE_CHECK_RESERVED) -
+                   metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
+               uint64_t used = dsl_dir_phys(dp->dp_root_dir)->dd_used_bytes;
+               /* MOS space is triple-dittoed, so we multiply by 3. */
+               if (dst->dst_space > 0 && used + dst->dst_space * 3 > quota) {
+                       dst->dst_error = SET_ERROR(ENOSPC);
+                       if (dst->dst_nowaiter)
+                               kmem_free(dst, sizeof (*dst));
+                       return;
+               }
+       }
+
+       /*
+        * Check for errors by calling checkfunc.
+        */
+       rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
+       dst->dst_error = dst->dst_checkfunc(dst->dst_arg, tx);
+       if (dst->dst_error == 0)
+               dst->dst_syncfunc(dst->dst_arg, tx);
+       rrw_exit(&dp->dp_config_rwlock, FTAG);
+       if (dst->dst_nowaiter)
+               kmem_free(dst, sizeof (*dst));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_sync_task);
+EXPORT_SYMBOL(dsl_sync_task_nowait);
+#endif
diff --git a/zfs/module/zfs/dsl_userhold.c b/zfs/module/zfs/dsl_userhold.c
new file mode 100644 (file)
index 0000000..1b234ed
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dsl_userhold.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_destroy.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dmu_tx.h>
+#include <sys/zfs_onexit.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dir.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zap.h>
+
+typedef struct dsl_dataset_user_hold_arg {
+       nvlist_t *dduha_holds;
+       nvlist_t *dduha_chkholds;
+       nvlist_t *dduha_errlist;
+       minor_t dduha_minor;
+} dsl_dataset_user_hold_arg_t;
+
+/*
+ * If you add new checks here, you may need to add additional checks to the
+ * "temporary" case in snapshot_check() in dmu_objset.c.
+ */
+int
+dsl_dataset_user_hold_check_one(dsl_dataset_t *ds, const char *htag,
+    boolean_t temphold, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
+       int error = 0;
+
+       ASSERT(dsl_pool_config_held(dp));
+
+       if (strlen(htag) > MAXNAMELEN)
+               return (SET_ERROR(E2BIG));
+       /* Tempholds have a more restricted length */
+       if (temphold && strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
+               return (SET_ERROR(E2BIG));
+
+       /* tags must be unique (if ds already exists) */
+       if (ds != NULL && dsl_dataset_phys(ds)->ds_userrefs_obj != 0) {
+               uint64_t value;
+
+               error = zap_lookup(mos, dsl_dataset_phys(ds)->ds_userrefs_obj,
+                   htag, 8, 1, &value);
+               if (error == 0)
+                       error = SET_ERROR(EEXIST);
+               else if (error == ENOENT)
+                       error = 0;
+       }
+
+       return (error);
+}
+
+static int
+dsl_dataset_user_hold_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_user_hold_arg_t *dduha = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvpair_t *pair;
+
+       if (spa_version(dp->dp_spa) < SPA_VERSION_USERREFS)
+               return (SET_ERROR(ENOTSUP));
+
+       if (!dmu_tx_is_syncing(tx))
+               return (0);
+
+       for (pair = nvlist_next_nvpair(dduha->dduha_holds, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(dduha->dduha_holds, pair)) {
+               dsl_dataset_t *ds;
+               int error = 0;
+               char *htag, *name;
+
+               /* must be a snapshot */
+               name = nvpair_name(pair);
+               if (strchr(name, '@') == NULL)
+                       error = SET_ERROR(EINVAL);
+
+               if (error == 0)
+                       error = nvpair_value_string(pair, &htag);
+
+               if (error == 0)
+                       error = dsl_dataset_hold(dp, name, FTAG, &ds);
+
+               if (error == 0) {
+                       error = dsl_dataset_user_hold_check_one(ds, htag,
+                           dduha->dduha_minor != 0, tx);
+                       dsl_dataset_rele(ds, FTAG);
+               }
+
+               if (error == 0) {
+                       fnvlist_add_string(dduha->dduha_chkholds, name, htag);
+               } else {
+                       /*
+                        * We register ENOENT errors so they can be correctly
+                        * reported if needed, such as when all holds fail.
+                        */
+                       fnvlist_add_int32(dduha->dduha_errlist, name, error);
+                       if (error != ENOENT)
+                               return (error);
+               }
+       }
+
+       return (0);
+}
+
+
+static void
+dsl_dataset_user_hold_sync_one_impl(nvlist_t *tmpholds, dsl_dataset_t *ds,
+    const char *htag, minor_t minor, uint64_t now, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       objset_t *mos = dp->dp_meta_objset;
+       uint64_t zapobj;
+
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+
+       if (dsl_dataset_phys(ds)->ds_userrefs_obj == 0) {
+               /*
+                * This is the first user hold for this dataset.  Create
+                * the userrefs zap object.
+                */
+               dmu_buf_will_dirty(ds->ds_dbuf, tx);
+               zapobj = dsl_dataset_phys(ds)->ds_userrefs_obj =
+                   zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx);
+       } else {
+               zapobj = dsl_dataset_phys(ds)->ds_userrefs_obj;
+       }
+       ds->ds_userrefs++;
+
+       VERIFY0(zap_add(mos, zapobj, htag, 8, 1, &now, tx));
+
+       if (minor != 0) {
+               char name[MAXNAMELEN];
+               nvlist_t *tags;
+
+               VERIFY0(dsl_pool_user_hold(dp, ds->ds_object,
+                   htag, now, tx));
+               (void) snprintf(name, sizeof (name), "%llx",
+                   (u_longlong_t)ds->ds_object);
+
+               if (nvlist_lookup_nvlist(tmpholds, name, &tags) != 0) {
+                       tags = fnvlist_alloc();
+                       fnvlist_add_boolean(tags, htag);
+                       fnvlist_add_nvlist(tmpholds, name, tags);
+                       fnvlist_free(tags);
+               } else {
+                       fnvlist_add_boolean(tags, htag);
+               }
+       }
+
+       spa_history_log_internal_ds(ds, "hold", tx,
+           "tag=%s temp=%d refs=%llu",
+           htag, minor != 0, ds->ds_userrefs);
+}
+
+typedef struct zfs_hold_cleanup_arg {
+       char zhca_spaname[MAXNAMELEN];
+       uint64_t zhca_spa_load_guid;
+       nvlist_t *zhca_holds;
+} zfs_hold_cleanup_arg_t;
+
+static void
+dsl_dataset_user_release_onexit(void *arg)
+{
+       zfs_hold_cleanup_arg_t *ca = arg;
+       spa_t *spa;
+       int error;
+
+       error = spa_open(ca->zhca_spaname, &spa, FTAG);
+       if (error != 0) {
+               zfs_dbgmsg("couldn't release holds on pool=%s "
+                   "because pool is no longer loaded",
+                   ca->zhca_spaname);
+               return;
+       }
+       if (spa_load_guid(spa) != ca->zhca_spa_load_guid) {
+               zfs_dbgmsg("couldn't release holds on pool=%s "
+                   "because pool is no longer loaded (guid doesn't match)",
+                   ca->zhca_spaname);
+               spa_close(spa, FTAG);
+               return;
+       }
+
+       (void) dsl_dataset_user_release_tmp(spa_get_dsl(spa), ca->zhca_holds);
+       fnvlist_free(ca->zhca_holds);
+       kmem_free(ca, sizeof (zfs_hold_cleanup_arg_t));
+       spa_close(spa, FTAG);
+}
+
+static void
+dsl_onexit_hold_cleanup(spa_t *spa, nvlist_t *holds, minor_t minor)
+{
+       zfs_hold_cleanup_arg_t *ca;
+
+       if (minor == 0 || nvlist_empty(holds)) {
+               fnvlist_free(holds);
+               return;
+       }
+
+       ASSERT(spa != NULL);
+       ca = kmem_alloc(sizeof (*ca), KM_SLEEP);
+
+       (void) strlcpy(ca->zhca_spaname, spa_name(spa),
+           sizeof (ca->zhca_spaname));
+       ca->zhca_spa_load_guid = spa_load_guid(spa);
+       ca->zhca_holds = holds;
+       VERIFY0(zfs_onexit_add_cb(minor,
+           dsl_dataset_user_release_onexit, ca, NULL));
+}
+
+void
+dsl_dataset_user_hold_sync_one(dsl_dataset_t *ds, const char *htag,
+    minor_t minor, uint64_t now, dmu_tx_t *tx)
+{
+       nvlist_t *tmpholds;
+
+       if (minor != 0)
+               tmpholds = fnvlist_alloc();
+       else
+               tmpholds = NULL;
+       dsl_dataset_user_hold_sync_one_impl(tmpholds, ds, htag, minor, now, tx);
+       dsl_onexit_hold_cleanup(dsl_dataset_get_spa(ds), tmpholds, minor);
+}
+
+static void
+dsl_dataset_user_hold_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_user_hold_arg_t *dduha = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvlist_t *tmpholds;
+       nvpair_t *pair;
+       uint64_t now = gethrestime_sec();
+
+       if (dduha->dduha_minor != 0)
+               tmpholds = fnvlist_alloc();
+       else
+               tmpholds = NULL;
+       for (pair = nvlist_next_nvpair(dduha->dduha_chkholds, NULL);
+           pair != NULL;
+           pair = nvlist_next_nvpair(dduha->dduha_chkholds, pair)) {
+               dsl_dataset_t *ds;
+
+               VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
+               dsl_dataset_user_hold_sync_one_impl(tmpholds, ds,
+                   fnvpair_value_string(pair), dduha->dduha_minor, now, tx);
+               dsl_dataset_rele(ds, FTAG);
+       }
+       dsl_onexit_hold_cleanup(dp->dp_spa, tmpholds, dduha->dduha_minor);
+}
+
+/*
+ * The full semantics of this function are described in the comment above
+ * lzc_hold().
+ *
+ * To summarize:
+ * holds is nvl of snapname -> holdname
+ * errlist will be filled in with snapname -> error
+ *
+ * The snaphosts must all be in the same pool.
+ *
+ * Holds for snapshots that don't exist will be skipped.
+ *
+ * If none of the snapshots for requested holds exist then ENOENT will be
+ * returned.
+ *
+ * If cleanup_minor is not 0, the holds will be temporary, which will be cleaned
+ * up when the process exits.
+ *
+ * On success all the holds, for snapshots that existed, will be created and 0
+ * will be returned.
+ *
+ * On failure no holds will be created, the errlist will be filled in,
+ * and an errno will returned.
+ *
+ * In all cases the errlist will contain entries for holds where the snapshot
+ * didn't exist.
+ */
+int
+dsl_dataset_user_hold(nvlist_t *holds, minor_t cleanup_minor, nvlist_t *errlist)
+{
+       dsl_dataset_user_hold_arg_t dduha;
+       nvpair_t *pair;
+       int ret;
+
+       pair = nvlist_next_nvpair(holds, NULL);
+       if (pair == NULL)
+               return (0);
+
+       dduha.dduha_holds = holds;
+       dduha.dduha_chkholds = fnvlist_alloc();
+       dduha.dduha_errlist = errlist;
+       dduha.dduha_minor = cleanup_minor;
+
+       ret = dsl_sync_task(nvpair_name(pair), dsl_dataset_user_hold_check,
+           dsl_dataset_user_hold_sync, &dduha,
+           fnvlist_num_pairs(holds), ZFS_SPACE_CHECK_RESERVED);
+       fnvlist_free(dduha.dduha_chkholds);
+
+       return (ret);
+}
+
+typedef int (dsl_holdfunc_t)(dsl_pool_t *dp, const char *name, void *tag,
+    dsl_dataset_t **dsp);
+
+typedef struct dsl_dataset_user_release_arg {
+       dsl_holdfunc_t *ddura_holdfunc;
+       nvlist_t *ddura_holds;
+       nvlist_t *ddura_todelete;
+       nvlist_t *ddura_errlist;
+       nvlist_t *ddura_chkholds;
+} dsl_dataset_user_release_arg_t;
+
+/* Place a dataset hold on the snapshot identified by passed dsobj string */
+static int
+dsl_dataset_hold_obj_string(dsl_pool_t *dp, const char *dsobj, void *tag,
+    dsl_dataset_t **dsp)
+{
+       return (dsl_dataset_hold_obj(dp, strtonum(dsobj, NULL), tag, dsp));
+}
+
+static int
+dsl_dataset_user_release_check_one(dsl_dataset_user_release_arg_t *ddura,
+    dsl_dataset_t *ds, nvlist_t *holds, const char *snapname)
+{
+       uint64_t zapobj;
+       nvlist_t *holds_found;
+       nvpair_t *pair;
+       objset_t *mos;
+       int numholds;
+
+       if (!ds->ds_is_snapshot)
+               return (SET_ERROR(EINVAL));
+
+       if (nvlist_empty(holds))
+               return (0);
+
+       numholds = 0;
+       mos = ds->ds_dir->dd_pool->dp_meta_objset;
+       zapobj = dsl_dataset_phys(ds)->ds_userrefs_obj;
+       VERIFY0(nvlist_alloc(&holds_found, NV_UNIQUE_NAME, KM_SLEEP));
+
+       for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(holds, pair)) {
+               uint64_t tmp;
+               int error;
+               const char *holdname = nvpair_name(pair);
+
+               if (zapobj != 0)
+                       error = zap_lookup(mos, zapobj, holdname, 8, 1, &tmp);
+               else
+                       error = SET_ERROR(ENOENT);
+
+               /*
+                * Non-existent holds are put on the errlist, but don't
+                * cause an overall failure.
+                */
+               if (error == ENOENT) {
+                       if (ddura->ddura_errlist != NULL) {
+                               char *errtag = kmem_asprintf("%s#%s",
+                                   snapname, holdname);
+                               fnvlist_add_int32(ddura->ddura_errlist, errtag,
+                                   ENOENT);
+                               strfree(errtag);
+                       }
+                       continue;
+               }
+
+               if (error != 0) {
+                       fnvlist_free(holds_found);
+                       return (error);
+               }
+
+               fnvlist_add_boolean(holds_found, holdname);
+               numholds++;
+       }
+
+       if (DS_IS_DEFER_DESTROY(ds) &&
+           dsl_dataset_phys(ds)->ds_num_children == 1 &&
+           ds->ds_userrefs == numholds) {
+               /* we need to destroy the snapshot as well */
+               if (dsl_dataset_long_held(ds)) {
+                       fnvlist_free(holds_found);
+                       return (SET_ERROR(EBUSY));
+               }
+               fnvlist_add_boolean(ddura->ddura_todelete, snapname);
+       }
+
+       if (numholds != 0) {
+               fnvlist_add_nvlist(ddura->ddura_chkholds, snapname,
+                   holds_found);
+       }
+       fnvlist_free(holds_found);
+
+       return (0);
+}
+
+static int
+dsl_dataset_user_release_check(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_user_release_arg_t *ddura;
+       dsl_holdfunc_t *holdfunc;
+       dsl_pool_t *dp;
+       nvpair_t *pair;
+
+       if (!dmu_tx_is_syncing(tx))
+               return (0);
+
+       dp = dmu_tx_pool(tx);
+
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+
+       ddura = arg;
+       holdfunc = ddura->ddura_holdfunc;
+
+       for (pair = nvlist_next_nvpair(ddura->ddura_holds, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(ddura->ddura_holds, pair)) {
+               int error;
+               dsl_dataset_t *ds;
+               nvlist_t *holds;
+               const char *snapname = nvpair_name(pair);
+
+               error = nvpair_value_nvlist(pair, &holds);
+               if (error != 0)
+                       error = (SET_ERROR(EINVAL));
+               else
+                       error = holdfunc(dp, snapname, FTAG, &ds);
+               if (error == 0) {
+                       error = dsl_dataset_user_release_check_one(ddura, ds,
+                           holds, snapname);
+                       dsl_dataset_rele(ds, FTAG);
+               }
+               if (error != 0) {
+                       if (ddura->ddura_errlist != NULL) {
+                               fnvlist_add_int32(ddura->ddura_errlist,
+                                   snapname, error);
+                       }
+                       /*
+                        * Non-existent snapshots are put on the errlist,
+                        * but don't cause an overall failure.
+                        */
+                       if (error != ENOENT)
+                               return (error);
+               }
+       }
+
+       return (0);
+}
+
+static void
+dsl_dataset_user_release_sync_one(dsl_dataset_t *ds, nvlist_t *holds,
+    dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+       objset_t *mos = dp->dp_meta_objset;
+       nvpair_t *pair;
+
+       for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(holds, pair)) {
+               int error;
+               const char *holdname = nvpair_name(pair);
+
+               /* Remove temporary hold if one exists. */
+               error = dsl_pool_user_release(dp, ds->ds_object, holdname, tx);
+               VERIFY(error == 0 || error == ENOENT);
+
+               VERIFY0(zap_remove(mos, dsl_dataset_phys(ds)->ds_userrefs_obj,
+                   holdname, tx));
+               ds->ds_userrefs--;
+
+               spa_history_log_internal_ds(ds, "release", tx,
+                   "tag=%s refs=%lld", holdname, (longlong_t)ds->ds_userrefs);
+       }
+}
+
+static void
+dsl_dataset_user_release_sync(void *arg, dmu_tx_t *tx)
+{
+       dsl_dataset_user_release_arg_t *ddura = arg;
+       dsl_holdfunc_t *holdfunc = ddura->ddura_holdfunc;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       nvpair_t *pair;
+
+       ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
+
+       for (pair = nvlist_next_nvpair(ddura->ddura_chkholds, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(ddura->ddura_chkholds,
+           pair)) {
+               dsl_dataset_t *ds;
+               const char *name = nvpair_name(pair);
+
+               VERIFY0(holdfunc(dp, name, FTAG, &ds));
+
+               dsl_dataset_user_release_sync_one(ds,
+                   fnvpair_value_nvlist(pair), tx);
+               if (nvlist_exists(ddura->ddura_todelete, name)) {
+                       ASSERT(ds->ds_userrefs == 0 &&
+                           dsl_dataset_phys(ds)->ds_num_children == 1 &&
+                           DS_IS_DEFER_DESTROY(ds));
+                       dsl_destroy_snapshot_sync_impl(ds, B_FALSE, tx);
+               }
+               dsl_dataset_rele(ds, FTAG);
+       }
+}
+
+/*
+ * The full semantics of this function are described in the comment above
+ * lzc_release().
+ *
+ * To summarize:
+ * Releases holds specified in the nvl holds.
+ *
+ * holds is nvl of snapname -> { holdname, ... }
+ * errlist will be filled in with snapname -> error
+ *
+ * If tmpdp is not NULL the names for holds should be the dsobj's of snapshots,
+ * otherwise they should be the names of shapshots.
+ *
+ * As a release may cause snapshots to be destroyed this trys to ensure they
+ * aren't mounted.
+ *
+ * The release of non-existent holds are skipped.
+ *
+ * At least one hold must have been released for the this function to succeed
+ * and return 0.
+ */
+static int
+dsl_dataset_user_release_impl(nvlist_t *holds, nvlist_t *errlist,
+    dsl_pool_t *tmpdp)
+{
+       dsl_dataset_user_release_arg_t ddura;
+       nvpair_t *pair;
+       char *pool;
+       int error;
+
+       pair = nvlist_next_nvpair(holds, NULL);
+       if (pair == NULL)
+               return (0);
+
+       /*
+        * The release may cause snapshots to be destroyed; make sure they
+        * are not mounted.
+        */
+       if (tmpdp != NULL) {
+               /* Temporary holds are specified by dsobj string. */
+               ddura.ddura_holdfunc = dsl_dataset_hold_obj_string;
+               pool = spa_name(tmpdp->dp_spa);
+#ifdef _KERNEL
+               for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
+                   pair = nvlist_next_nvpair(holds, pair)) {
+                       dsl_dataset_t *ds;
+
+                       dsl_pool_config_enter(tmpdp, FTAG);
+                       error = dsl_dataset_hold_obj_string(tmpdp,
+                           nvpair_name(pair), FTAG, &ds);
+                       if (error == 0) {
+                               char name[MAXNAMELEN];
+                               dsl_dataset_name(ds, name);
+                               dsl_pool_config_exit(tmpdp, FTAG);
+                               dsl_dataset_rele(ds, FTAG);
+                               (void) zfs_unmount_snap(name);
+                       } else {
+                               dsl_pool_config_exit(tmpdp, FTAG);
+                       }
+               }
+#endif
+       } else {
+               /* Non-temporary holds are specified by name. */
+               ddura.ddura_holdfunc = dsl_dataset_hold;
+               pool = nvpair_name(pair);
+#ifdef _KERNEL
+               for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
+                   pair = nvlist_next_nvpair(holds, pair)) {
+                       (void) zfs_unmount_snap(nvpair_name(pair));
+               }
+#endif
+       }
+
+       ddura.ddura_holds = holds;
+       ddura.ddura_errlist = errlist;
+       VERIFY0(nvlist_alloc(&ddura.ddura_todelete, NV_UNIQUE_NAME,
+           KM_SLEEP));
+       VERIFY0(nvlist_alloc(&ddura.ddura_chkholds, NV_UNIQUE_NAME,
+           KM_SLEEP));
+
+       error = dsl_sync_task(pool, dsl_dataset_user_release_check,
+           dsl_dataset_user_release_sync, &ddura, 0, ZFS_SPACE_CHECK_NONE);
+       fnvlist_free(ddura.ddura_todelete);
+       fnvlist_free(ddura.ddura_chkholds);
+
+       return (error);
+}
+
+/*
+ * holds is nvl of snapname -> { holdname, ... }
+ * errlist will be filled in with snapname -> error
+ */
+int
+dsl_dataset_user_release(nvlist_t *holds, nvlist_t *errlist)
+{
+       return (dsl_dataset_user_release_impl(holds, errlist, NULL));
+}
+
+/*
+ * holds is nvl of snapdsobj -> { holdname, ... }
+ */
+void
+dsl_dataset_user_release_tmp(struct dsl_pool *dp, nvlist_t *holds)
+{
+       ASSERT(dp != NULL);
+       (void) dsl_dataset_user_release_impl(holds, NULL, dp);
+}
+
+int
+dsl_dataset_get_holds(const char *dsname, nvlist_t *nvl)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       int err;
+
+       err = dsl_pool_hold(dsname, FTAG, &dp);
+       if (err != 0)
+               return (err);
+       err = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+       if (err != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (err);
+       }
+
+       if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0) {
+               zap_attribute_t *za;
+               zap_cursor_t zc;
+
+               za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+               for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset,
+                   dsl_dataset_phys(ds)->ds_userrefs_obj);
+                   zap_cursor_retrieve(&zc, za) == 0;
+                   zap_cursor_advance(&zc)) {
+                       fnvlist_add_uint64(nvl, za->za_name,
+                           za->za_first_integer);
+               }
+               zap_cursor_fini(&zc);
+               kmem_free(za, sizeof (zap_attribute_t));
+       }
+       dsl_dataset_rele(ds, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (0);
+}
diff --git a/zfs/module/zfs/fm.c b/zfs/module/zfs/fm.c
new file mode 100644 (file)
index 0000000..999bd8a
--- /dev/null
@@ -0,0 +1,1660 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/*
+ * Fault Management Architecture (FMA) Resource and Protocol Support
+ *
+ * The routines contained herein provide services to support kernel subsystems
+ * in publishing fault management telemetry (see PSARC 2002/412 and 2003/089).
+ *
+ * Name-Value Pair Lists
+ *
+ * The embodiment of an FMA protocol element (event, fmri or authority) is a
+ * name-value pair list (nvlist_t).  FMA-specific nvlist construtor and
+ * destructor functions, fm_nvlist_create() and fm_nvlist_destroy(), are used
+ * to create an nvpair list using custom allocators.  Callers may choose to
+ * allocate either from the kernel memory allocator, or from a preallocated
+ * buffer, useful in constrained contexts like high-level interrupt routines.
+ *
+ * Protocol Event and FMRI Construction
+ *
+ * Convenience routines are provided to construct nvlist events according to
+ * the FMA Event Protocol and Naming Schema specification for ereports and
+ * FMRIs for the dev, cpu, hc, mem, legacy hc and de schemes.
+ *
+ * ENA Manipulation
+ *
+ * Routines to generate ENA formats 0, 1 and 2 are available as well as
+ * routines to increment formats 1 and 2.  Individual fields within the
+ * ENA are extractable via fm_ena_time_get(), fm_ena_id_get(),
+ * fm_ena_format_get() and fm_ena_gen_get().
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/list.h>
+#include <sys/nvpair.h>
+#include <sys/cmn_err.h>
+#include <sys/sysmacros.h>
+#include <sys/compress.h>
+#include <sys/sunddi.h>
+#include <sys/systeminfo.h>
+#include <sys/fm/util.h>
+#include <sys/fm/protocol.h>
+#include <sys/kstat.h>
+#include <sys/zfs_context.h>
+#ifdef _KERNEL
+#include <sys/atomic.h>
+#include <sys/condvar.h>
+#include <sys/cpuvar.h>
+#include <sys/systm.h>
+#include <sys/dumphdr.h>
+#include <sys/cpuvar.h>
+#include <sys/console.h>
+#include <sys/kobj.h>
+#include <sys/time.h>
+#include <sys/zfs_ioctl.h>
+
+int zfs_zevent_len_max = 0;
+int zfs_zevent_cols = 80;
+int zfs_zevent_console = 0;
+
+static int zevent_len_cur = 0;
+static int zevent_waiters = 0;
+static int zevent_flags = 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.
+ * They will be reset to the initial value (1) each time the kernel module is
+ * loaded.
+ */
+static uint64_t zevent_eid = 0;
+
+static kmutex_t zevent_lock;
+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
+ */
+
+struct erpt_kstat {
+       kstat_named_t   erpt_dropped;           /* num erpts dropped on post */
+       kstat_named_t   erpt_set_failed;        /* num erpt set failures */
+       kstat_named_t   fmri_set_failed;        /* num fmri set failures */
+       kstat_named_t   payload_set_failed;     /* num payload set failures */
+};
+
+static struct erpt_kstat erpt_kstat_data = {
+       { "erpt-dropped", KSTAT_DATA_UINT64 },
+       { "erpt-set-failed", KSTAT_DATA_UINT64 },
+       { "fmri-set-failed", KSTAT_DATA_UINT64 },
+       { "payload-set-failed", KSTAT_DATA_UINT64 }
+};
+
+kstat_t *fm_ksp;
+
+#ifdef _KERNEL
+
+/*
+ * Formatting utility function for fm_nvprintr.  We attempt to wrap chunks of
+ * output so they aren't split across console lines, and return the end column.
+ */
+/*PRINTFLIKE4*/
+static int
+fm_printf(int depth, int c, int cols, const char *format, ...)
+{
+       va_list ap;
+       int width;
+       char c1;
+
+       va_start(ap, format);
+       width = vsnprintf(&c1, sizeof (c1), format, ap);
+       va_end(ap);
+
+       if (c + width >= cols) {
+               console_printf("\n");
+               c = 0;
+               if (format[0] != ' ' && depth > 0) {
+                       console_printf(" ");
+                       c++;
+               }
+       }
+
+       va_start(ap, format);
+       console_vprintf(format, ap);
+       va_end(ap);
+
+       return ((c + width) % cols);
+}
+
+/*
+ * Recursively print a 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
+ * used for cache dumps right now, so we suppress them so as not to overwhelm
+ * the amount of console output we produce at panic time.  This can be further
+ * enhanced as FMA technology grows based upon the needs of consumers.  All
+ * FMA telemetry is logged using the dump device transport, so the console
+ * output serves only as a fallback in case this procedure is unsuccessful.
+ */
+static int
+fm_nvprintr(nvlist_t *nvl, int d, int c, int cols)
+{
+       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;
+
+               if (strcmp(name, FM_CLASS) == 0)
+                       continue; /* already printed by caller */
+
+               c = fm_printf(d, c, cols, " %s=", name);
+
+               switch (type) {
+               case DATA_TYPE_BOOLEAN:
+                       c = fm_printf(d + 1, c, cols, " 1");
+                       break;
+
+               case DATA_TYPE_BOOLEAN_VALUE:
+                       (void) nvpair_value_boolean_value(nvp, &b);
+                       c = fm_printf(d + 1, c, cols, b ? "1" : "0");
+                       break;
+
+               case DATA_TYPE_BYTE:
+                       (void) nvpair_value_byte(nvp, &i8);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i8);
+                       break;
+
+               case DATA_TYPE_INT8:
+                       (void) nvpair_value_int8(nvp, (void *)&i8);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i8);
+                       break;
+
+               case DATA_TYPE_UINT8:
+                       (void) nvpair_value_uint8(nvp, &i8);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i8);
+                       break;
+
+               case DATA_TYPE_INT16:
+                       (void) nvpair_value_int16(nvp, (void *)&i16);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i16);
+                       break;
+
+               case DATA_TYPE_UINT16:
+                       (void) nvpair_value_uint16(nvp, &i16);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i16);
+                       break;
+
+               case DATA_TYPE_INT32:
+                       (void) nvpair_value_int32(nvp, (void *)&i32);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i32);
+                       break;
+
+               case DATA_TYPE_UINT32:
+                       (void) nvpair_value_uint32(nvp, &i32);
+                       c = fm_printf(d + 1, c, cols, "0x%x", i32);
+                       break;
+
+               case DATA_TYPE_INT64:
+                       (void) nvpair_value_int64(nvp, (void *)&i64);
+                       c = fm_printf(d + 1, c, cols, "0x%llx",
+                           (u_longlong_t)i64);
+                       break;
+
+               case DATA_TYPE_UINT64:
+                       (void) nvpair_value_uint64(nvp, &i64);
+                       c = fm_printf(d + 1, c, cols, "0x%llx",
+                           (u_longlong_t)i64);
+                       break;
+
+               case DATA_TYPE_HRTIME:
+                       (void) nvpair_value_hrtime(nvp, (void *)&i64);
+                       c = fm_printf(d + 1, c, cols, "0x%llx",
+                           (u_longlong_t)i64);
+                       break;
+
+               case DATA_TYPE_STRING:
+                       (void) nvpair_value_string(nvp, &str);
+                       c = fm_printf(d + 1, c, cols, "\"%s\"",
+                           str ? str : "<NULL>");
+                       break;
+
+               case DATA_TYPE_NVLIST:
+                       c = fm_printf(d + 1, c, cols, "[");
+                       (void) nvpair_value_nvlist(nvp, &cnv);
+                       c = fm_nvprintr(cnv, d + 1, c, cols);
+                       c = fm_printf(d + 1, c, cols, " ]");
+                       break;
+
+               case DATA_TYPE_NVLIST_ARRAY: {
+                       nvlist_t **val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[");
+                       (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++) {
+                               c = fm_nvprintr(val[i], d + 1, c, cols);
+                       }
+                       c = fm_printf(d + 1, c, cols, " ]");
+                       }
+                       break;
+
+               case DATA_TYPE_INT8_ARRAY: {
+                       int8_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_int8_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_UINT8_ARRAY: {
+                       uint8_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_uint8_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_INT16_ARRAY: {
+                       int16_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_int16_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_UINT16_ARRAY: {
+                       uint16_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_uint16_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_INT32_ARRAY: {
+                       int32_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_int32_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                       c = fm_printf(d + 1, c, cols, "0x%llx ",
+                           (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_UINT32_ARRAY: {
+                       uint32_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_uint32_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_INT64_ARRAY: {
+                       int64_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_int64_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_UINT64_ARRAY: {
+                       uint64_t *val;
+                       uint_t i, nelem;
+
+                       c = fm_printf(d + 1, c, cols, "[ ");
+                       (void) nvpair_value_uint64_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               c = fm_printf(d + 1, c, cols, "0x%llx ",
+                                   (u_longlong_t)val[i]);
+
+                       c = fm_printf(d + 1, c, cols, "]");
+                       break;
+                       }
+
+               case DATA_TYPE_STRING_ARRAY:
+               case DATA_TYPE_BOOLEAN_ARRAY:
+               case DATA_TYPE_BYTE_ARRAY:
+                       c = fm_printf(d + 1, c, cols, "[...]");
+                       break;
+
+               case DATA_TYPE_UNKNOWN:
+                       c = fm_printf(d + 1, c, cols, "<unknown>");
+                       break;
+               }
+       }
+
+       return (c);
+}
+
+void
+fm_nvprint(nvlist_t *nvl)
+{
+       char *class;
+       int c = 0;
+
+       console_printf("\n");
+
+       if (nvlist_lookup_string(nvl, FM_CLASS, &class) == 0)
+               c = fm_printf(0, c, zfs_zevent_cols, "%s", class);
+
+       if (fm_nvprintr(nvl, 0, c, zfs_zevent_cols) != 0)
+               console_printf("\n");
+
+       console_printf("\n");
+}
+
+static zevent_t *
+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));
+       list_link_init(&ev->ev_node);
+
+       return (ev);
+}
+
+static void
+zfs_zevent_free(zevent_t *ev)
+{
+       /* Run provided cleanup callback */
+       ev->ev_cb(ev->ev_nvl, ev->ev_detector);
+
+       list_destroy(&ev->ev_ze_list);
+       kmem_free(ev, sizeof (zevent_t));
+}
+
+static void
+zfs_zevent_drain(zevent_t *ev)
+{
+       zfs_zevent_t *ze;
+
+       ASSERT(MUTEX_HELD(&zevent_lock));
+       list_remove(&zevent_list, ev);
+
+       /* Remove references to this event in all private file data */
+       while ((ze = list_head(&ev->ev_ze_list)) != NULL) {
+               list_remove(&ev->ev_ze_list, ze);
+               ze->ze_zevent = NULL;
+               ze->ze_dropped++;
+       }
+
+       zfs_zevent_free(ev);
+}
+
+void
+zfs_zevent_drain_all(int *count)
+{
+       zevent_t *ev;
+
+       mutex_enter(&zevent_lock);
+       while ((ev = list_head(&zevent_list)) != NULL)
+               zfs_zevent_drain(ev);
+
+       *count = zevent_len_cur;
+       zevent_len_cur = 0;
+       mutex_exit(&zevent_lock);
+}
+
+/*
+ * New zevents are inserted at the head.  If the maximum queue
+ * length is exceeded a zevent will be drained from the tail.
+ * As part of this any user space processes which currently have
+ * a reference to this zevent_t in their private data will have
+ * this reference set to NULL.
+ */
+static void
+zfs_zevent_insert(zevent_t *ev)
+{
+       ASSERT(MUTEX_HELD(&zevent_lock));
+       list_insert_head(&zevent_list, ev);
+
+       if (zevent_len_cur >= zfs_zevent_len_max)
+               zfs_zevent_drain(list_tail(&zevent_list));
+       else
+               zevent_len_cur++;
+}
+
+/*
+ * Post a zevent. The cb will be called when nvl and detector are no longer
+ * needed, i.e.:
+ * - An error happened and a zevent can't be posted. In this case, cb is called
+ *   before zfs_zevent_post() returns.
+ * - The event is being drained and freed.
+ */
+int
+zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
+{
+       int64_t tv_array[2];
+       timestruc_t tv;
+       uint64_t eid;
+       size_t nvl_size = 0;
+       zevent_t *ev;
+       int error;
+
+       ASSERT(cb != NULL);
+
+       gethrestime(&tv);
+       tv_array[0] = tv.tv_sec;
+       tv_array[1] = tv.tv_nsec;
+
+       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);
+               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);
+               goto out;
+       }
+
+       error = nvlist_size(nvl, &nvl_size, NV_ENCODE_NATIVE);
+       if (error) {
+               atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
+               goto out;
+       }
+
+       if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) {
+               atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
+               error = EOVERFLOW;
+               goto out;
+       }
+
+       if (zfs_zevent_console)
+               fm_nvprint(nvl);
+
+       ev = zfs_zevent_alloc();
+       if (ev == NULL) {
+               atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
+               error = ENOMEM;
+               goto out;
+       }
+
+       ev->ev_nvl = nvl;
+       ev->ev_detector = detector;
+       ev->ev_cb = cb;
+       ev->ev_eid = eid;
+
+       mutex_enter(&zevent_lock);
+       zfs_zevent_insert(ev);
+       cv_broadcast(&zevent_cv);
+       mutex_exit(&zevent_lock);
+
+out:
+       if (error)
+               cb(nvl, detector);
+
+       return (error);
+}
+
+static int
+zfs_zevent_minor_to_state(minor_t minor, zfs_zevent_t **ze)
+{
+       *ze = zfsdev_get_state(minor, ZST_ZEVENT);
+       if (*ze == NULL)
+               return (EBADF);
+
+       return (0);
+}
+
+int
+zfs_zevent_fd_hold(int fd, minor_t *minorp, zfs_zevent_t **ze)
+{
+       file_t *fp;
+       int error;
+
+       fp = getf(fd);
+       if (fp == NULL)
+               return (EBADF);
+
+       error = zfsdev_getminor(fp->f_file, minorp);
+       if (error == 0)
+               error = zfs_zevent_minor_to_state(*minorp, ze);
+
+       if (error)
+               zfs_zevent_fd_rele(fd);
+
+       return (error);
+}
+
+void
+zfs_zevent_fd_rele(int fd)
+{
+       releasef(fd);
+}
+
+/*
+ * Get the next zevent in the stream and place a copy in 'event'.  This
+ * may fail with ENOMEM if the encoded nvlist size exceeds the passed
+ * 'event_size'.  In this case the stream pointer is not advanced and
+ * and 'event_size' is set to the minimum required buffer size.
+ */
+int
+zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *event_size,
+    uint64_t *dropped)
+{
+       zevent_t *ev;
+       size_t size;
+       int error = 0;
+
+       mutex_enter(&zevent_lock);
+       if (ze->ze_zevent == NULL) {
+               /* New stream start at the beginning/tail */
+               ev = list_tail(&zevent_list);
+               if (ev == NULL) {
+                       error = ENOENT;
+                       goto out;
+               }
+       } else {
+               /*
+                * Existing stream continue with the next element and remove
+                * ourselves from the wait queue for the previous element
+                */
+               ev = list_prev(&zevent_list, ze->ze_zevent);
+               if (ev == NULL) {
+                       error = ENOENT;
+                       goto out;
+               }
+       }
+
+       VERIFY(nvlist_size(ev->ev_nvl, &size, NV_ENCODE_NATIVE) == 0);
+       if (size > *event_size) {
+               *event_size = size;
+               error = ENOMEM;
+               goto out;
+       }
+
+       if (ze->ze_zevent)
+               list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
+       ze->ze_zevent = ev;
+       list_insert_head(&ev->ev_ze_list, ze);
+       nvlist_dup(ev->ev_nvl, event, KM_SLEEP);
+       *dropped = ze->ze_dropped;
+       ze->ze_dropped = 0;
+out:
+       mutex_exit(&zevent_lock);
+
+       return (error);
+}
+
+int
+zfs_zevent_wait(zfs_zevent_t *ze)
+{
+       int error = 0;
+
+       mutex_enter(&zevent_lock);
+
+       if (zevent_flags & ZEVENT_SHUTDOWN) {
+               error = ESHUTDOWN;
+               goto out;
+       }
+
+       zevent_waiters++;
+       cv_wait_sig(&zevent_cv, &zevent_lock);
+       if (issig(JUSTLOOKING))
+               error = EINTR;
+
+       zevent_waiters--;
+out:
+       mutex_exit(&zevent_lock);
+
+       return (error);
+}
+
+/*
+ * The caller may seek to a specific EID by passing that EID.  If the EID
+ * is still available in the posted list of events the cursor is positioned
+ * there.  Otherwise ENOENT is returned and the cursor is not moved.
+ *
+ * There are two reserved EIDs which may be passed and will never fail.
+ * ZEVENT_SEEK_START positions the cursor at the start of the list, and
+ * ZEVENT_SEEK_END positions the cursor at the end of the list.
+ */
+int
+zfs_zevent_seek(zfs_zevent_t *ze, uint64_t eid)
+{
+       zevent_t *ev;
+       int error = 0;
+
+       mutex_enter(&zevent_lock);
+
+       if (eid == ZEVENT_SEEK_START) {
+               if (ze->ze_zevent)
+                       list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
+               ze->ze_zevent = NULL;
+               goto out;
+       }
+
+       if (eid == ZEVENT_SEEK_END) {
+               if (ze->ze_zevent)
+                       list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
+               ev = list_head(&zevent_list);
+               if (ev) {
+                       ze->ze_zevent = ev;
+                       list_insert_head(&ev->ev_ze_list, ze);
+               } else {
+                       ze->ze_zevent = NULL;
+               }
+
+               goto out;
+       }
+
+       for (ev = list_tail(&zevent_list); ev != NULL;
+           ev = list_prev(&zevent_list, ev)) {
+               if (ev->ev_eid == eid) {
+                       if (ze->ze_zevent)
+                               list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
+                       ze->ze_zevent = ev;
+                       list_insert_head(&ev->ev_ze_list, ze);
+                       break;
+               }
+       }
+
+       if (ev == NULL)
+               error = ENOENT;
+
+out:
+       mutex_exit(&zevent_lock);
+
+       return (error);
+}
+
+void
+zfs_zevent_init(zfs_zevent_t **zep)
+{
+       zfs_zevent_t *ze;
+
+       ze = *zep = kmem_zalloc(sizeof (zfs_zevent_t), KM_SLEEP);
+       list_link_init(&ze->ze_node);
+}
+
+void
+zfs_zevent_destroy(zfs_zevent_t *ze)
+{
+       mutex_enter(&zevent_lock);
+       if (ze->ze_zevent)
+               list_remove(&ze->ze_zevent->ev_ze_list, ze);
+       mutex_exit(&zevent_lock);
+
+       kmem_free(ze, sizeof (zfs_zevent_t));
+}
+#endif /* _KERNEL */
+
+/*
+ * Wrapppers for FM nvlist allocators
+ */
+/* ARGSUSED */
+static void *
+i_fm_alloc(nv_alloc_t *nva, size_t size)
+{
+       return (kmem_zalloc(size, KM_SLEEP));
+}
+
+/* ARGSUSED */
+static void
+i_fm_free(nv_alloc_t *nva, void *buf, size_t size)
+{
+       kmem_free(buf, size);
+}
+
+const nv_alloc_ops_t fm_mem_alloc_ops = {
+       NULL,
+       NULL,
+       i_fm_alloc,
+       i_fm_free,
+       NULL
+};
+
+/*
+ * Create and initialize a new nv_alloc_t for a fixed buffer, buf.  A pointer
+ * to the newly allocated nv_alloc_t structure is returned upon success or NULL
+ * is returned to indicate that the nv_alloc structure could not be created.
+ */
+nv_alloc_t *
+fm_nva_xcreate(char *buf, size_t bufsz)
+{
+       nv_alloc_t *nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
+
+       if (bufsz == 0 || nv_alloc_init(nvhdl, nv_fixed_ops, buf, bufsz) != 0) {
+               kmem_free(nvhdl, sizeof (nv_alloc_t));
+               return (NULL);
+       }
+
+       return (nvhdl);
+}
+
+/*
+ * Destroy a previously allocated nv_alloc structure.  The fixed buffer
+ * associated with nva must be freed by the caller.
+ */
+void
+fm_nva_xdestroy(nv_alloc_t *nva)
+{
+       nv_alloc_fini(nva);
+       kmem_free(nva, sizeof (nv_alloc_t));
+}
+
+/*
+ * Create a new nv list.  A pointer to a new nv list structure is returned
+ * upon success or NULL is returned to indicate that the structure could
+ * not be created.  The newly created nv list is created and managed by the
+ * operations installed in nva.   If nva is NULL, the default FMA nva
+ * operations are installed and used.
+ *
+ * When called from the kernel and nva == NULL, this function must be called
+ * from passive kernel context with no locks held that can prevent a
+ * sleeping memory allocation from occurring.  Otherwise, this function may
+ * be called from other kernel contexts as long a valid nva created via
+ * fm_nva_create() is supplied.
+ */
+nvlist_t *
+fm_nvlist_create(nv_alloc_t *nva)
+{
+       int hdl_alloced = 0;
+       nvlist_t *nvl;
+       nv_alloc_t *nvhdl;
+
+       if (nva == NULL) {
+               nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
+
+               if (nv_alloc_init(nvhdl, &fm_mem_alloc_ops, NULL, 0) != 0) {
+                       kmem_free(nvhdl, sizeof (nv_alloc_t));
+                       return (NULL);
+               }
+               hdl_alloced = 1;
+       } else {
+               nvhdl = nva;
+       }
+
+       if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nvhdl) != 0) {
+               if (hdl_alloced) {
+                       nv_alloc_fini(nvhdl);
+                       kmem_free(nvhdl, sizeof (nv_alloc_t));
+               }
+               return (NULL);
+       }
+
+       return (nvl);
+}
+
+/*
+ * Destroy a previously allocated nvlist structure.  flag indicates whether
+ * or not the associated nva structure should be freed (FM_NVA_FREE) or
+ * retained (FM_NVA_RETAIN).  Retaining the nv alloc structure allows
+ * it to be re-used for future nvlist creation operations.
+ */
+void
+fm_nvlist_destroy(nvlist_t *nvl, int flag)
+{
+       nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl);
+
+       nvlist_free(nvl);
+
+       if (nva != NULL) {
+               if (flag == FM_NVA_FREE)
+                       fm_nva_xdestroy(nva);
+       }
+}
+
+int
+i_fm_payload_set(nvlist_t *payload, const char *name, va_list ap)
+{
+       int nelem, ret = 0;
+       data_type_t type;
+
+       while (ret == 0 && name != NULL) {
+               type = va_arg(ap, data_type_t);
+               switch (type) {
+               case DATA_TYPE_BYTE:
+                       ret = nvlist_add_byte(payload, name,
+                           va_arg(ap, uint_t));
+                       break;
+               case DATA_TYPE_BYTE_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_byte_array(payload, name,
+                           va_arg(ap, uchar_t *), nelem);
+                       break;
+               case DATA_TYPE_BOOLEAN_VALUE:
+                       ret = nvlist_add_boolean_value(payload, name,
+                           va_arg(ap, boolean_t));
+                       break;
+               case DATA_TYPE_BOOLEAN_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_boolean_array(payload, name,
+                           va_arg(ap, boolean_t *), nelem);
+                       break;
+               case DATA_TYPE_INT8:
+                       ret = nvlist_add_int8(payload, name,
+                           va_arg(ap, int));
+                       break;
+               case DATA_TYPE_INT8_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_int8_array(payload, name,
+                           va_arg(ap, int8_t *), nelem);
+                       break;
+               case DATA_TYPE_UINT8:
+                       ret = nvlist_add_uint8(payload, name,
+                           va_arg(ap, uint_t));
+                       break;
+               case DATA_TYPE_UINT8_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_uint8_array(payload, name,
+                           va_arg(ap, uint8_t *), nelem);
+                       break;
+               case DATA_TYPE_INT16:
+                       ret = nvlist_add_int16(payload, name,
+                           va_arg(ap, int));
+                       break;
+               case DATA_TYPE_INT16_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_int16_array(payload, name,
+                           va_arg(ap, int16_t *), nelem);
+                       break;
+               case DATA_TYPE_UINT16:
+                       ret = nvlist_add_uint16(payload, name,
+                           va_arg(ap, uint_t));
+                       break;
+               case DATA_TYPE_UINT16_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_uint16_array(payload, name,
+                           va_arg(ap, uint16_t *), nelem);
+                       break;
+               case DATA_TYPE_INT32:
+                       ret = nvlist_add_int32(payload, name,
+                           va_arg(ap, int32_t));
+                       break;
+               case DATA_TYPE_INT32_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_int32_array(payload, name,
+                           va_arg(ap, int32_t *), nelem);
+                       break;
+               case DATA_TYPE_UINT32:
+                       ret = nvlist_add_uint32(payload, name,
+                           va_arg(ap, uint32_t));
+                       break;
+               case DATA_TYPE_UINT32_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_uint32_array(payload, name,
+                           va_arg(ap, uint32_t *), nelem);
+                       break;
+               case DATA_TYPE_INT64:
+                       ret = nvlist_add_int64(payload, name,
+                           va_arg(ap, int64_t));
+                       break;
+               case DATA_TYPE_INT64_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_int64_array(payload, name,
+                           va_arg(ap, int64_t *), nelem);
+                       break;
+               case DATA_TYPE_UINT64:
+                       ret = nvlist_add_uint64(payload, name,
+                           va_arg(ap, uint64_t));
+                       break;
+               case DATA_TYPE_UINT64_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_uint64_array(payload, name,
+                           va_arg(ap, uint64_t *), nelem);
+                       break;
+               case DATA_TYPE_STRING:
+                       ret = nvlist_add_string(payload, name,
+                           va_arg(ap, char *));
+                       break;
+               case DATA_TYPE_STRING_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_string_array(payload, name,
+                           va_arg(ap, char **), nelem);
+                       break;
+               case DATA_TYPE_NVLIST:
+                       ret = nvlist_add_nvlist(payload, name,
+                           va_arg(ap, nvlist_t *));
+                       break;
+               case DATA_TYPE_NVLIST_ARRAY:
+                       nelem = va_arg(ap, int);
+                       ret = nvlist_add_nvlist_array(payload, name,
+                           va_arg(ap, nvlist_t **), nelem);
+                       break;
+               default:
+                       ret = EINVAL;
+               }
+
+               name = va_arg(ap, char *);
+       }
+       return (ret);
+}
+
+void
+fm_payload_set(nvlist_t *payload, ...)
+{
+       int ret;
+       const char *name;
+       va_list ap;
+
+       va_start(ap, payload);
+       name = va_arg(ap, char *);
+       ret = i_fm_payload_set(payload, name, ap);
+       va_end(ap);
+
+       if (ret)
+               atomic_add_64(
+                   &erpt_kstat_data.payload_set_failed.value.ui64, 1);
+}
+
+/*
+ * Set-up and validate the members of an ereport event according to:
+ *
+ *     Member name             Type            Value
+ *     ====================================================
+ *     class                   string          ereport
+ *     version                 uint8_t         0
+ *     ena                     uint64_t        <ena>
+ *     detector                nvlist_t        <detector>
+ *     ereport-payload         nvlist_t        <var args>
+ *
+ * We don't actually add a 'version' member to the payload.  Really,
+ * the version quoted to us by our caller is that of the category 1
+ * "ereport" event class (and we require FM_EREPORT_VERS0) but
+ * the payload version of the actual leaf class event under construction
+ * may be something else.  Callers should supply a version in the varargs,
+ * or (better) we could take two version arguments - one for the
+ * ereport category 1 classification (expect FM_EREPORT_VERS0) and one
+ * for the leaf class.
+ */
+void
+fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
+    uint64_t ena, const nvlist_t *detector, ...)
+{
+       char ereport_class[FM_MAX_CLASS];
+       const char *name;
+       va_list ap;
+       int ret;
+
+       if (version != FM_EREPORT_VERS0) {
+               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               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);
+               return;
+       }
+
+       if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) {
+               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+       }
+
+       if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR,
+           (nvlist_t *)detector) != 0) {
+               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+       }
+
+       va_start(ap, detector);
+       name = va_arg(ap, const char *);
+       ret = i_fm_payload_set(ereport, name, ap);
+       va_end(ap);
+
+       if (ret)
+               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+}
+
+/*
+ * Set-up and validate the members of an hc fmri according to;
+ *
+ *     Member name             Type            Value
+ *     ===================================================
+ *     version                 uint8_t         0
+ *     auth                    nvlist_t        <auth>
+ *     hc-name                 string          <name>
+ *     hc-id                   string          <id>
+ *
+ * Note that auth and hc-id are optional members.
+ */
+
+#define        HC_MAXPAIRS     20
+#define        HC_MAXNAMELEN   50
+
+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);
+               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);
+               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);
+               return (0);
+       }
+
+       return (1);
+}
+
+void
+fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth,
+    nvlist_t *snvl, int npairs, ...)
+{
+       nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
+       nvlist_t *pairs[HC_MAXPAIRS];
+       va_list ap;
+       int i;
+
+       if (!fm_fmri_hc_set_common(fmri, version, auth))
+               return;
+
+       npairs = MIN(npairs, HC_MAXPAIRS);
+
+       va_start(ap, npairs);
+       for (i = 0; i < npairs; i++) {
+               const char *name = va_arg(ap, const char *);
+               uint32_t id = va_arg(ap, uint32_t);
+               char idstr[11];
+
+               (void) snprintf(idstr, sizeof (idstr), "%u", id);
+
+               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);
+               }
+       }
+       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);
+
+       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);
+               }
+       }
+}
+
+void
+fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
+    nvlist_t *snvl, nvlist_t *bboard, int npairs, ...)
+{
+       nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
+       nvlist_t *pairs[HC_MAXPAIRS];
+       nvlist_t **hcl;
+       uint_t n;
+       int i, j;
+       va_list ap;
+       char *hcname, *hcid;
+
+       if (!fm_fmri_hc_set_common(fmri, version, auth))
+               return;
+
+       /*
+        * copy the bboard nvpairs to the pairs array
+        */
+       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);
+               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);
+                       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);
+                       return;
+               }
+
+               pairs[i] = fm_nvlist_create(nva);
+               if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, hcname) != 0 ||
+                   nvlist_add_string(pairs[i], FM_FMRI_HC_ID, hcid) != 0) {
+                       for (j = 0; j <= i; j++) {
+                               if (pairs[j] != NULL)
+                                       fm_nvlist_destroy(pairs[j],
+                                           FM_NVA_RETAIN);
+                       }
+                       atomic_add_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       return;
+               }
+       }
+
+       /*
+        * create the pairs from passed in pairs
+        */
+       npairs = MIN(npairs, HC_MAXPAIRS);
+
+       va_start(ap, npairs);
+       for (i = n; i < npairs + n; i++) {
+               const char *name = va_arg(ap, const char *);
+               uint32_t id = va_arg(ap, uint32_t);
+               char idstr[11];
+               (void) snprintf(idstr, sizeof (idstr), "%u", id);
+               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) {
+                       for (j = 0; j <= i; j++) {
+                               if (pairs[j] != NULL)
+                                       fm_nvlist_destroy(pairs[j],
+                                           FM_NVA_RETAIN);
+                       }
+                       atomic_add_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       return;
+               }
+       }
+       va_end(ap);
+
+       /*
+        * Create the fmri hc list
+        */
+       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);
+               return;
+       }
+
+       for (i = 0; i < npairs + n; 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);
+                       return;
+               }
+       }
+}
+
+/*
+ * Set-up and validate the members of an dev fmri according to:
+ *
+ *     Member name             Type            Value
+ *     ====================================================
+ *     version                 uint8_t         0
+ *     auth                    nvlist_t        <auth>
+ *     devpath                 string          <devpath>
+ *     [devid]                 string          <devid>
+ *     [target-port-l0id]      string          <target-port-lun0-id>
+ *
+ * Note that auth and devid are optional members.
+ */
+void
+fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
+    const char *devpath, const char *devid, const char *tpl0)
+{
+       int err = 0;
+
+       if (version != DEV_SCHEME_VERSION0) {
+               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               return;
+       }
+
+       err |= nvlist_add_uint8(fmri_dev, FM_VERSION, version);
+       err |= nvlist_add_string(fmri_dev, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV);
+
+       if (auth != NULL) {
+               err |= nvlist_add_nvlist(fmri_dev, FM_FMRI_AUTHORITY,
+                   (nvlist_t *)auth);
+       }
+
+       err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_PATH, devpath);
+
+       if (devid != NULL)
+               err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_ID, devid);
+
+       if (tpl0 != NULL)
+               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);
+
+}
+
+/*
+ * Set-up and validate the members of an cpu fmri according to:
+ *
+ *     Member name             Type            Value
+ *     ====================================================
+ *     version                 uint8_t         0
+ *     auth                    nvlist_t        <auth>
+ *     cpuid                   uint32_t        <cpu_id>
+ *     cpumask                 uint8_t         <cpu_mask>
+ *     serial                  uint64_t        <serial_id>
+ *
+ * Note that auth, cpumask, serial are optional members.
+ *
+ */
+void
+fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth,
+    uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp)
+{
+       uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64;
+
+       if (version < CPU_SCHEME_VERSION1) {
+               atomic_add_64(failedp, 1);
+               return;
+       }
+
+       if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) {
+               atomic_add_64(failedp, 1);
+               return;
+       }
+
+       if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
+           FM_FMRI_SCHEME_CPU) != 0) {
+               atomic_add_64(failedp, 1);
+               return;
+       }
+
+       if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
+           (nvlist_t *)auth) != 0)
+               atomic_add_64(failedp, 1);
+
+       if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
+               atomic_add_64(failedp, 1);
+
+       if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK,
+           *cpu_maskp) != 0)
+               atomic_add_64(failedp, 1);
+
+       if (serial_idp == NULL || nvlist_add_string(fmri_cpu,
+           FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0)
+                       atomic_add_64(failedp, 1);
+}
+
+/*
+ * Set-up and validate the members of a mem according to:
+ *
+ *     Member name             Type            Value
+ *     ====================================================
+ *     version                 uint8_t         0
+ *     auth                    nvlist_t        <auth>          [optional]
+ *     unum                    string          <unum>
+ *     serial                  string          <serial>        [optional*]
+ *     offset                  uint64_t        <offset>        [optional]
+ *
+ *     * serial is required if offset is present
+ */
+void
+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);
+               return;
+       }
+
+       if (!serial && (offset != (uint64_t)-1)) {
+               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               return;
+       }
+
+       if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
+               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               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);
+               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);
+               }
+       }
+
+       if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) {
+               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+       }
+
+       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);
+               }
+               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);
+                       }
+               }
+       }
+}
+
+void
+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);
+               return;
+       }
+
+       if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
+               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               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);
+               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);
+       }
+
+       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);
+               }
+       }
+}
+
+uint64_t
+fm_ena_increment(uint64_t ena)
+{
+       uint64_t new_ena;
+
+       switch (ENA_FORMAT(ena)) {
+       case FM_ENA_FMT1:
+               new_ena = ena + (1 << ENA_FMT1_GEN_SHFT);
+               break;
+       case FM_ENA_FMT2:
+               new_ena = ena + (1 << ENA_FMT2_GEN_SHFT);
+               break;
+       default:
+               new_ena = 0;
+       }
+
+       return (new_ena);
+}
+
+uint64_t
+fm_ena_generate_cpu(uint64_t timestamp, processorid_t cpuid, uchar_t format)
+{
+       uint64_t ena = 0;
+
+       switch (format) {
+       case FM_ENA_FMT1:
+               if (timestamp) {
+                       ena = (uint64_t)((format & ENA_FORMAT_MASK) |
+                           ((cpuid << ENA_FMT1_CPUID_SHFT) &
+                           ENA_FMT1_CPUID_MASK) |
+                           ((timestamp << ENA_FMT1_TIME_SHFT) &
+                           ENA_FMT1_TIME_MASK));
+               } else {
+                       ena = (uint64_t)((format & ENA_FORMAT_MASK) |
+                           ((cpuid << ENA_FMT1_CPUID_SHFT) &
+                           ENA_FMT1_CPUID_MASK) |
+                           ((gethrtime() << ENA_FMT1_TIME_SHFT) &
+                           ENA_FMT1_TIME_MASK));
+               }
+               break;
+       case FM_ENA_FMT2:
+               ena = (uint64_t)((format & ENA_FORMAT_MASK) |
+                   ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK));
+               break;
+       default:
+               break;
+       }
+
+       return (ena);
+}
+
+uint64_t
+fm_ena_generate(uint64_t timestamp, uchar_t format)
+{
+       uint64_t ena;
+
+       kpreempt_disable();
+       ena = fm_ena_generate_cpu(timestamp, getcpuid(), format);
+       kpreempt_enable();
+
+       return (ena);
+}
+
+uint64_t
+fm_ena_generation_get(uint64_t ena)
+{
+       uint64_t gen;
+
+       switch (ENA_FORMAT(ena)) {
+       case FM_ENA_FMT1:
+               gen = (ena & ENA_FMT1_GEN_MASK) >> ENA_FMT1_GEN_SHFT;
+               break;
+       case FM_ENA_FMT2:
+               gen = (ena & ENA_FMT2_GEN_MASK) >> ENA_FMT2_GEN_SHFT;
+               break;
+       default:
+               gen = 0;
+               break;
+       }
+
+       return (gen);
+}
+
+uchar_t
+fm_ena_format_get(uint64_t ena)
+{
+
+       return (ENA_FORMAT(ena));
+}
+
+uint64_t
+fm_ena_id_get(uint64_t ena)
+{
+       uint64_t id;
+
+       switch (ENA_FORMAT(ena)) {
+       case FM_ENA_FMT1:
+               id = (ena & ENA_FMT1_ID_MASK) >> ENA_FMT1_ID_SHFT;
+               break;
+       case FM_ENA_FMT2:
+               id = (ena & ENA_FMT2_ID_MASK) >> ENA_FMT2_ID_SHFT;
+               break;
+       default:
+               id = 0;
+       }
+
+       return (id);
+}
+
+uint64_t
+fm_ena_time_get(uint64_t ena)
+{
+       uint64_t time;
+
+       switch (ENA_FORMAT(ena)) {
+       case FM_ENA_FMT1:
+               time = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT;
+               break;
+       case FM_ENA_FMT2:
+               time = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT;
+               break;
+       default:
+               time = 0;
+       }
+
+       return (time);
+}
+
+#ifdef _KERNEL
+void
+fm_init(void)
+{
+       zevent_len_cur = 0;
+       zevent_flags = 0;
+
+       if (zfs_zevent_len_max == 0)
+               zfs_zevent_len_max = ERPT_MAX_ERRS * MAX(max_ncpus, 4);
+
+       /* Initialize zevent allocation and generation kstats */
+       fm_ksp = kstat_create("zfs", 0, "fm", "misc", KSTAT_TYPE_NAMED,
+           sizeof (struct erpt_kstat) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+
+       if (fm_ksp != NULL) {
+               fm_ksp->ks_data = &erpt_kstat_data;
+               kstat_install(fm_ksp);
+       } else {
+               cmn_err(CE_NOTE, "failed to create fm/misc kstat\n");
+       }
+
+       mutex_init(&zevent_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&zevent_list, sizeof (zevent_t),
+           offsetof(zevent_t, ev_node));
+       cv_init(&zevent_cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+fm_fini(void)
+{
+       int count;
+
+       zfs_zevent_drain_all(&count);
+
+       mutex_enter(&zevent_lock);
+       cv_broadcast(&zevent_cv);
+
+       zevent_flags |= ZEVENT_SHUTDOWN;
+       while (zevent_waiters > 0) {
+               mutex_exit(&zevent_lock);
+               schedule();
+               mutex_enter(&zevent_lock);
+       }
+       mutex_exit(&zevent_lock);
+
+       cv_destroy(&zevent_cv);
+       list_destroy(&zevent_list);
+       mutex_destroy(&zevent_lock);
+
+       if (fm_ksp != NULL) {
+               kstat_delete(fm_ksp);
+               fm_ksp = NULL;
+       }
+}
+
+module_param(zfs_zevent_len_max, int, 0644);
+MODULE_PARM_DESC(zfs_zevent_len_max, "Max event queue length");
+
+module_param(zfs_zevent_cols, int, 0644);
+MODULE_PARM_DESC(zfs_zevent_cols, "Max event column width");
+
+module_param(zfs_zevent_console, int, 0644);
+MODULE_PARM_DESC(zfs_zevent_console, "Log events to the console");
+
+#endif /* _KERNEL */
diff --git a/zfs/module/zfs/gzip.c b/zfs/module/zfs/gzip.c
new file mode 100644 (file)
index 0000000..011fb91
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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/debug.h>
+#include <sys/types.h>
+
+#ifdef _KERNEL
+
+#include <sys/systm.h>
+#include <sys/zmod.h>
+
+typedef size_t zlen_t;
+#define        compress_func   z_compress_level
+#define        uncompress_func z_uncompress
+
+#else /* _KERNEL */
+
+#include <strings.h>
+#include <zlib.h>
+
+typedef uLongf zlen_t;
+#define        compress_func   compress2
+#define        uncompress_func uncompress
+
+#endif
+
+size_t
+gzip_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+       zlen_t dstlen = d_len;
+
+       ASSERT(d_len <= s_len);
+
+       if (compress_func(d_start, &dstlen, s_start, s_len, n) != Z_OK) {
+               if (d_len != s_len)
+                       return (s_len);
+
+               bcopy(s_start, d_start, s_len);
+               return (s_len);
+       }
+
+       return ((size_t) dstlen);
+}
+
+/*ARGSUSED*/
+int
+gzip_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+       zlen_t dstlen = d_len;
+
+       ASSERT(d_len >= s_len);
+
+       if (uncompress_func(d_start, &dstlen, s_start, s_len) != Z_OK)
+               return (-1);
+
+       return (0);
+}
diff --git a/zfs/module/zfs/lz4.c b/zfs/module/zfs/lz4.c
new file mode 100644 (file)
index 0000000..cf406b9
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ * LZ4 - Fast LZ compression algorithm
+ * Header File
+ * Copyright (C) 2011-2013, Yann Collet.
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT
+ * OWNER 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.
+ *
+ * You can contact the author at :
+ * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
+ * - LZ4 source repository : http://code.google.com/p/lz4/
+ */
+
+#include <sys/zfs_context.h>
+
+static int real_LZ4_compress(const char *source, char *dest, int isize,
+    int osize);
+static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
+    int isize, int maxOutputSize);
+static int LZ4_compressCtx(void *ctx, const char *source, char *dest,
+    int isize, int osize);
+static int LZ4_compress64kCtx(void *ctx, const char *source, char *dest,
+    int isize, int osize);
+
+static kmem_cache_t *lz4_cache;
+
+/*ARGSUSED*/
+size_t
+lz4_compress_zfs(void *s_start, void *d_start, size_t s_len,
+    size_t d_len, int n)
+{
+       uint32_t bufsiz;
+       char *dest = d_start;
+
+       ASSERT(d_len >= sizeof (bufsiz));
+
+       bufsiz = real_LZ4_compress(s_start, &dest[sizeof (bufsiz)], s_len,
+           d_len - sizeof (bufsiz));
+
+       /* Signal an error if the compression routine returned zero. */
+       if (bufsiz == 0)
+               return (s_len);
+
+       /*
+        * Encode the compresed buffer size at the start. We'll need this in
+        * decompression to counter the effects of padding which might be
+        * added to the compressed buffer and which, if unhandled, would
+        * confuse the hell out of our decompression function.
+        */
+       *(uint32_t *)dest = BE_32(bufsiz);
+
+       return (bufsiz + sizeof (bufsiz));
+}
+
+/*ARGSUSED*/
+int
+lz4_decompress_zfs(void *s_start, void *d_start, size_t s_len,
+    size_t d_len, int n)
+{
+       const char *src = s_start;
+       uint32_t bufsiz = BE_IN32(src);
+
+       /* invalid compressed buffer size encoded at start */
+       if (bufsiz + sizeof (bufsiz) > s_len)
+               return (1);
+
+       /*
+        * Returns 0 on success (decompression function returned non-negative)
+        * and non-zero on failure (decompression function returned negative.
+        */
+       return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)],
+           d_start, bufsiz, d_len) < 0);
+}
+
+/*
+ * LZ4 API Description:
+ *
+ * Simple Functions:
+ * real_LZ4_compress() :
+ *     isize  : is the input size. Max supported value is ~1.9GB
+ *     return : the number of bytes written in buffer dest
+ *              or 0 if the compression fails (if LZ4_COMPRESSMIN is set).
+ *     note : destination buffer must be already allocated.
+ *             destination buffer must be sized to handle worst cases
+ *             situations (input data not compressible) worst case size
+ *             evaluation is provided by function LZ4_compressBound().
+ *
+ * real_LZ4_uncompress() :
+ *     osize  : is the output size, therefore the original size
+ *     return : the number of bytes read in the source buffer.
+ *             If the source stream is malformed, the function will stop
+ *             decoding and return a negative result, indicating the byte
+ *             position of the faulty instruction. This function never
+ *             writes beyond dest + osize, and is therefore protected
+ *             against malicious data packets.
+ *     note : destination buffer must be already allocated
+ *     note : real_LZ4_uncompress() is not used in ZFS so its code
+ *            is not present here.
+ *
+ * Advanced Functions
+ *
+ * LZ4_compressBound() :
+ *     Provides the maximum size that LZ4 may output in a "worst case"
+ *     scenario (input data not compressible) primarily useful for memory
+ *     allocation of output buffer.
+ *
+ *     isize  : is the input size. Max supported value is ~1.9GB
+ *     return : maximum output size in a "worst case" scenario
+ *     note : this function is limited by "int" range (2^31-1)
+ *
+ * LZ4_uncompress_unknownOutputSize() :
+ *     isize  : is the input size, therefore the compressed size
+ *     maxOutputSize : is the size of the destination buffer (which must be
+ *             already allocated)
+ *     return : the number of bytes decoded in the destination buffer
+ *             (necessarily <= maxOutputSize). If the source stream is
+ *             malformed, the function will stop decoding and return a
+ *             negative result, indicating the byte position of the faulty
+ *             instruction. This function never writes beyond dest +
+ *             maxOutputSize, and is therefore protected against malicious
+ *             data packets.
+ *     note   : Destination buffer must be already allocated.
+ *             This version is slightly slower than real_LZ4_uncompress()
+ *
+ * LZ4_compressCtx() :
+ *     This function explicitly handles the CTX memory structure.
+ *
+ *     ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated
+ *     by the caller (either on the stack or using kmem_cache_alloc). Passing
+ *     NULL isn't valid.
+ *
+ * LZ4_compress64kCtx() :
+ *     Same as LZ4_compressCtx(), but specific to small inputs (<64KB).
+ *     isize *Must* be <64KB, otherwise the output will be corrupted.
+ *
+ *     ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated
+ *     by the caller (either on the stack or using kmem_cache_alloc). Passing
+ *     NULL isn't valid.
+ */
+
+/*
+ * Tuning parameters
+ */
+
+/*
+ * COMPRESSIONLEVEL: Increasing this value improves compression ratio
+ *      Lowering this value reduces memory usage. Reduced memory usage
+ *     typically improves speed, due to cache effect (ex: L1 32KB for Intel,
+ *     L1 64KB for AMD). Memory usage formula : N->2^(N+2) Bytes
+ *     (examples : 12 -> 16KB ; 17 -> 512KB)
+ */
+#define        COMPRESSIONLEVEL 12
+
+/*
+ * NOTCOMPRESSIBLE_CONFIRMATION: Decreasing this value will make the
+ *     algorithm skip faster data segments considered "incompressible".
+ *     This may decrease compression ratio dramatically, but will be
+ *     faster on incompressible data. Increasing this value will make
+ *     the algorithm search more before declaring a segment "incompressible".
+ *     This could improve compression a bit, but will be slower on
+ *     incompressible data. The default value (6) is recommended.
+ */
+#define        NOTCOMPRESSIBLE_CONFIRMATION 6
+
+/*
+ * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE: This will provide a boost to
+ * performance for big endian cpu, but the resulting compressed stream
+ * will be incompatible with little-endian CPU. You can set this option
+ * to 1 in situations where data will stay within closed environment.
+ * This option is useless on Little_Endian CPU (such as x86).
+ */
+/* #define     BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */
+
+/*
+ * CPU Feature Detection
+ */
+
+/* 32 or 64 bits ? */
+#if defined(_LP64)
+#define        LZ4_ARCH64 1
+#else
+#define        LZ4_ARCH64 0
+#endif
+
+/*
+ * Little Endian or Big Endian?
+ * Note: overwrite the below #define if you know your architecture endianess.
+ */
+#if defined(_BIG_ENDIAN)
+#define        LZ4_BIG_ENDIAN 1
+#else
+/*
+ * Little Endian assumed. PDP Endian and other very rare endian format
+ * are unsupported.
+ */
+#undef LZ4_BIG_ENDIAN
+#endif
+
+/*
+ * Unaligned memory access is automatically enabled for "common" CPU,
+ * such as x86. For others CPU, the compiler will be more cautious, and
+ * insert extra code to ensure aligned access is respected. If you know
+ * your target CPU supports unaligned memory access, you may want to
+ * force this option manually to improve performance
+ */
+#if defined(__ARM_FEATURE_UNALIGNED)
+#define        LZ4_FORCE_UNALIGNED_ACCESS 1
+#endif
+
+/*
+ * Illumos : we can't use GCC's __builtin_ctz family of builtins in the
+ * kernel
+ * Linux : we can use GCC's __builtin_ctz family of builtins in the
+ * kernel
+ */
+#undef LZ4_FORCE_SW_BITCOUNT
+#if defined(__sparc)
+#define        LZ4_FORCE_SW_BITCOUNT
+#endif
+
+/*
+ * Compiler Options
+ */
+/* Disable restrict */
+#define        restrict
+
+/*
+ * Linux : GCC_VERSION is defined as of 3.9-rc1, so undefine it.
+ * torvalds/linux@3f3f8d2f48acfd8ed3b8e6b7377935da57b27b16
+ */
+#ifdef GCC_VERSION
+#undef GCC_VERSION
+#endif
+
+#define        GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+#define        expect(expr, value)    (__builtin_expect((expr), (value)))
+#else
+#define        expect(expr, value)    (expr)
+#endif
+
+#ifndef likely
+#define        likely(expr)    expect((expr) != 0, 1)
+#endif
+
+#ifndef unlikely
+#define        unlikely(expr)  expect((expr) != 0, 0)
+#endif
+
+#define        lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | \
+       (((x) & 0xffu) << 8)))
+
+/* Basic types */
+#define        BYTE    uint8_t
+#define        U16     uint16_t
+#define        U32     uint32_t
+#define        S32     int32_t
+#define        U64     uint64_t
+
+#ifndef LZ4_FORCE_UNALIGNED_ACCESS
+#pragma pack(1)
+#endif
+
+typedef struct _U16_S {
+       U16 v;
+} U16_S;
+typedef struct _U32_S {
+       U32 v;
+} U32_S;
+typedef struct _U64_S {
+       U64 v;
+} U64_S;
+
+#ifndef LZ4_FORCE_UNALIGNED_ACCESS
+#pragma pack()
+#endif
+
+#define        A64(x) (((U64_S *)(x))->v)
+#define        A32(x) (((U32_S *)(x))->v)
+#define        A16(x) (((U16_S *)(x))->v)
+
+/*
+ * Constants
+ */
+#define        MINMATCH 4
+
+#define        HASH_LOG COMPRESSIONLEVEL
+#define        HASHTABLESIZE (1 << HASH_LOG)
+#define        HASH_MASK (HASHTABLESIZE - 1)
+
+#define        SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? \
+       NOTCOMPRESSIBLE_CONFIRMATION : 2)
+
+#define        COPYLENGTH 8
+#define        LASTLITERALS 5
+#define        MFLIMIT (COPYLENGTH + MINMATCH)
+#define        MINLENGTH (MFLIMIT + 1)
+
+#define        MAXD_LOG 16
+#define        MAX_DISTANCE ((1 << MAXD_LOG) - 1)
+
+#define        ML_BITS 4
+#define        ML_MASK ((1U<<ML_BITS)-1)
+#define        RUN_BITS (8-ML_BITS)
+#define        RUN_MASK ((1U<<RUN_BITS)-1)
+
+
+/*
+ * Architecture-specific macros
+ */
+#if LZ4_ARCH64
+#define        STEPSIZE 8
+#define        UARCH U64
+#define        AARCH A64
+#define        LZ4_COPYSTEP(s, d)      A64(d) = A64(s); d += 8; s += 8;
+#define        LZ4_COPYPACKET(s, d)    LZ4_COPYSTEP(s, d)
+#define        LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e)
+#define        HTYPE U32
+#define        INITBASE(base)          const BYTE* const base = ip
+#else /* !LZ4_ARCH64 */
+#define        STEPSIZE 4
+#define        UARCH U32
+#define        AARCH A32
+#define        LZ4_COPYSTEP(s, d)      A32(d) = A32(s); d += 4; s += 4;
+#define        LZ4_COPYPACKET(s, d)    LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
+#define        LZ4_SECURECOPY          LZ4_WILDCOPY
+#define        HTYPE const BYTE *
+#define        INITBASE(base)          const int base = 0
+#endif /* !LZ4_ARCH64 */
+
+#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
+#define        LZ4_READ_LITTLEENDIAN_16(d, s, p) \
+       { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
+#define        LZ4_WRITE_LITTLEENDIAN_16(p, i) \
+       { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; }
+#else
+#define        LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); }
+#define        LZ4_WRITE_LITTLEENDIAN_16(p, v)  { A16(p) = v; p += 2; }
+#endif
+
+
+/* Local structures */
+struct refTables {
+       HTYPE hashTable[HASHTABLESIZE];
+};
+
+
+/* Macros */
+#define        LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH * 8) - \
+       HASH_LOG))
+#define        LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p))
+#define        LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e);
+#define        LZ4_BLINDCOPY(s, d, l) { BYTE* e = (d) + l; LZ4_WILDCOPY(s, d, e); \
+       d = e; }
+
+
+/* Private functions */
+#if LZ4_ARCH64
+
+static inline int
+LZ4_NbCommonBytes(register U64 val)
+{
+#if defined(LZ4_BIG_ENDIAN)
+#if defined(__GNUC__) && (GCC_VERSION >= 304) && \
+       !defined(LZ4_FORCE_SW_BITCOUNT)
+       return (__builtin_clzll(val) >> 3);
+#else
+       int r;
+       if (!(val >> 32)) {
+               r = 4;
+       } else {
+               r = 0;
+               val >>= 32;
+       }
+       if (!(val >> 16)) {
+               r += 2;
+               val >>= 8;
+       } else {
+               val >>= 24;
+       }
+       r += (!val);
+       return (r);
+#endif
+#else
+#if defined(__GNUC__) && (GCC_VERSION >= 304) && \
+       !defined(LZ4_FORCE_SW_BITCOUNT)
+       return (__builtin_ctzll(val) >> 3);
+#else
+       static const int DeBruijnBytePos[64] =
+           { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5,
+               3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5,
+               5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4,
+               4, 5, 7, 2, 6, 5, 7, 6, 7, 7
+       };
+       return DeBruijnBytePos[((U64) ((val & -val) * 0x0218A392CDABBD3F)) >>
+           58];
+#endif
+#endif
+}
+
+#else
+
+static inline int
+LZ4_NbCommonBytes(register U32 val)
+{
+#if defined(LZ4_BIG_ENDIAN)
+#if defined(__GNUC__) && (GCC_VERSION >= 304) && \
+       !defined(LZ4_FORCE_SW_BITCOUNT)
+       return (__builtin_clz(val) >> 3);
+#else
+       int r;
+       if (!(val >> 16)) {
+               r = 2;
+               val >>= 8;
+       } else {
+               r = 0;
+               val >>= 24;
+       }
+       r += (!val);
+       return (r);
+#endif
+#else
+#if defined(__GNUC__) && (GCC_VERSION >= 304) && \
+       !defined(LZ4_FORCE_SW_BITCOUNT)
+       return (__builtin_ctz(val) >> 3);
+#else
+       static const int DeBruijnBytePos[32] = {
+               0, 0, 3, 0, 3, 1, 3, 0,
+               3, 2, 2, 1, 3, 2, 0, 1,
+               3, 3, 1, 2, 2, 2, 2, 0,
+               3, 1, 2, 0, 1, 0, 1, 1
+       };
+       return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >>
+           27];
+#endif
+#endif
+}
+
+#endif
+
+/* Compression functions */
+
+/*ARGSUSED*/
+static int
+LZ4_compressCtx(void *ctx, const char *source, char *dest, int isize,
+    int osize)
+{
+       struct refTables *srt = (struct refTables *)ctx;
+       HTYPE *HashTable = (HTYPE *) (srt->hashTable);
+
+       const BYTE *ip = (BYTE *) source;
+       INITBASE(base);
+       const BYTE *anchor = ip;
+       const BYTE *const iend = ip + isize;
+       const BYTE *const oend = (BYTE *) dest + osize;
+       const BYTE *const mflimit = iend - MFLIMIT;
+#define        matchlimit (iend - LASTLITERALS)
+
+       BYTE *op = (BYTE *) dest;
+
+       int len, length;
+       const int skipStrength = SKIPSTRENGTH;
+       U32 forwardH;
+
+
+       /* Init */
+       if (isize < MINLENGTH)
+               goto _last_literals;
+
+       /* First Byte */
+       HashTable[LZ4_HASH_VALUE(ip)] = ip - base;
+       ip++;
+       forwardH = LZ4_HASH_VALUE(ip);
+
+       /* Main Loop */
+       for (;;) {
+               int findMatchAttempts = (1U << skipStrength) + 3;
+               const BYTE *forwardIp = ip;
+               const BYTE *ref;
+               BYTE *token;
+
+               /* Find a match */
+               do {
+                       U32 h = forwardH;
+                       int step = findMatchAttempts++ >> skipStrength;
+                       ip = forwardIp;
+                       forwardIp = ip + step;
+
+                       if (unlikely(forwardIp > mflimit)) {
+                               goto _last_literals;
+                       }
+
+                       forwardH = LZ4_HASH_VALUE(forwardIp);
+                       ref = base + HashTable[h];
+                       HashTable[h] = ip - base;
+
+               } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip)));
+
+               /* Catch up */
+               while ((ip > anchor) && (ref > (BYTE *) source) &&
+                   unlikely(ip[-1] == ref[-1])) {
+                       ip--;
+                       ref--;
+               }
+
+               /* Encode Literal length */
+               length = ip - anchor;
+               token = op++;
+
+               /* Check output limit */
+               if (unlikely(op + length + (2 + 1 + LASTLITERALS) +
+                   (length >> 8) > oend))
+                       return (0);
+
+               if (length >= (int)RUN_MASK) {
+                       *token = (RUN_MASK << ML_BITS);
+                       len = length - RUN_MASK;
+                       for (; len > 254; len -= 255)
+                               *op++ = 255;
+                       *op++ = (BYTE)len;
+               } else
+                       *token = (length << ML_BITS);
+
+               /* Copy Literals */
+               LZ4_BLINDCOPY(anchor, op, length);
+
+               _next_match:
+               /* Encode Offset */
+               LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref);
+
+               /* Start Counting */
+               ip += MINMATCH;
+               ref += MINMATCH;        /* MinMatch verified */
+               anchor = ip;
+               while (likely(ip < matchlimit - (STEPSIZE - 1))) {
+                       UARCH diff = AARCH(ref) ^ AARCH(ip);
+                       if (!diff) {
+                               ip += STEPSIZE;
+                               ref += STEPSIZE;
+                               continue;
+                       }
+                       ip += LZ4_NbCommonBytes(diff);
+                       goto _endCount;
+               }
+#if LZ4_ARCH64
+               if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) {
+                       ip += 4;
+                       ref += 4;
+               }
+#endif
+               if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) {
+                       ip += 2;
+                       ref += 2;
+               }
+               if ((ip < matchlimit) && (*ref == *ip))
+                       ip++;
+               _endCount:
+
+               /* Encode MatchLength */
+               len = (ip - anchor);
+               /* Check output limit */
+               if (unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend))
+                       return (0);
+               if (len >= (int)ML_MASK) {
+                       *token += ML_MASK;
+                       len -= ML_MASK;
+                       for (; len > 509; len -= 510) {
+                               *op++ = 255;
+                               *op++ = 255;
+                       }
+                       if (len > 254) {
+                               len -= 255;
+                               *op++ = 255;
+                       }
+                       *op++ = (BYTE)len;
+               } else
+                       *token += len;
+
+               /* Test end of chunk */
+               if (ip > mflimit) {
+                       anchor = ip;
+                       break;
+               }
+               /* Fill table */
+               HashTable[LZ4_HASH_VALUE(ip - 2)] = ip - 2 - base;
+
+               /* Test next position */
+               ref = base + HashTable[LZ4_HASH_VALUE(ip)];
+               HashTable[LZ4_HASH_VALUE(ip)] = ip - base;
+               if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) {
+                       token = op++;
+                       *token = 0;
+                       goto _next_match;
+               }
+               /* Prepare next loop */
+               anchor = ip++;
+               forwardH = LZ4_HASH_VALUE(ip);
+       }
+
+       _last_literals:
+       /* Encode Last Literals */
+       {
+               int lastRun = iend - anchor;
+               if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) >
+                   oend)
+                       return (0);
+               if (lastRun >= (int)RUN_MASK) {
+                       *op++ = (RUN_MASK << ML_BITS);
+                       lastRun -= RUN_MASK;
+                       for (; lastRun > 254; lastRun -= 255) {
+                               *op++ = 255;
+                       }
+                       *op++ = (BYTE)lastRun;
+               } else
+                       *op++ = (lastRun << ML_BITS);
+               (void) memcpy(op, anchor, iend - anchor);
+               op += iend - anchor;
+       }
+
+       /* End */
+       return (int)(((char *)op) - dest);
+}
+
+
+
+/* Note : this function is valid only if isize < LZ4_64KLIMIT */
+#define        LZ4_64KLIMIT ((1 << 16) + (MFLIMIT - 1))
+#define        HASHLOG64K (HASH_LOG + 1)
+#define        HASH64KTABLESIZE (1U << HASHLOG64K)
+#define        LZ4_HASH64K_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8) - \
+       HASHLOG64K))
+#define        LZ4_HASH64K_VALUE(p)    LZ4_HASH64K_FUNCTION(A32(p))
+
+/*ARGSUSED*/
+static int
+LZ4_compress64kCtx(void *ctx, const char *source, char *dest, int isize,
+    int osize)
+{
+       struct refTables *srt = (struct refTables *)ctx;
+       U16 *HashTable = (U16 *) (srt->hashTable);
+
+       const BYTE *ip = (BYTE *) source;
+       const BYTE *anchor = ip;
+       const BYTE *const base = ip;
+       const BYTE *const iend = ip + isize;
+       const BYTE *const oend = (BYTE *) dest + osize;
+       const BYTE *const mflimit = iend - MFLIMIT;
+#define        matchlimit (iend - LASTLITERALS)
+
+       BYTE *op = (BYTE *) dest;
+
+       int len, length;
+       const int skipStrength = SKIPSTRENGTH;
+       U32 forwardH;
+
+       /* Init */
+       if (isize < MINLENGTH)
+               goto _last_literals;
+
+       /* First Byte */
+       ip++;
+       forwardH = LZ4_HASH64K_VALUE(ip);
+
+       /* Main Loop */
+       for (;;) {
+               int findMatchAttempts = (1U << skipStrength) + 3;
+               const BYTE *forwardIp = ip;
+               const BYTE *ref;
+               BYTE *token;
+
+               /* Find a match */
+               do {
+                       U32 h = forwardH;
+                       int step = findMatchAttempts++ >> skipStrength;
+                       ip = forwardIp;
+                       forwardIp = ip + step;
+
+                       if (forwardIp > mflimit) {
+                               goto _last_literals;
+                       }
+
+                       forwardH = LZ4_HASH64K_VALUE(forwardIp);
+                       ref = base + HashTable[h];
+                       HashTable[h] = ip - base;
+
+               } while (A32(ref) != A32(ip));
+
+               /* Catch up */
+               while ((ip > anchor) && (ref > (BYTE *) source) &&
+                   (ip[-1] == ref[-1])) {
+                       ip--;
+                       ref--;
+               }
+
+               /* Encode Literal length */
+               length = ip - anchor;
+               token = op++;
+
+               /* Check output limit */
+               if (unlikely(op + length + (2 + 1 + LASTLITERALS) +
+                   (length >> 8) > oend))
+                       return (0);
+
+               if (length >= (int)RUN_MASK) {
+                       *token = (RUN_MASK << ML_BITS);
+                       len = length - RUN_MASK;
+                       for (; len > 254; len -= 255)
+                               *op++ = 255;
+                       *op++ = (BYTE)len;
+               } else
+                       *token = (length << ML_BITS);
+
+               /* Copy Literals */
+               LZ4_BLINDCOPY(anchor, op, length);
+
+               _next_match:
+               /* Encode Offset */
+               LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref);
+
+               /* Start Counting */
+               ip += MINMATCH;
+               ref += MINMATCH;        /* MinMatch verified */
+               anchor = ip;
+               while (ip < matchlimit - (STEPSIZE - 1)) {
+                       UARCH diff = AARCH(ref) ^ AARCH(ip);
+                       if (!diff) {
+                               ip += STEPSIZE;
+                               ref += STEPSIZE;
+                               continue;
+                       }
+                       ip += LZ4_NbCommonBytes(diff);
+                       goto _endCount;
+               }
+#if LZ4_ARCH64
+               if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) {
+                       ip += 4;
+                       ref += 4;
+               }
+#endif
+               if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) {
+                       ip += 2;
+                       ref += 2;
+               }
+               if ((ip < matchlimit) && (*ref == *ip))
+                       ip++;
+               _endCount:
+
+               /* Encode MatchLength */
+               len = (ip - anchor);
+               /* Check output limit */
+               if (unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend))
+                       return (0);
+               if (len >= (int)ML_MASK) {
+                       *token += ML_MASK;
+                       len -= ML_MASK;
+                       for (; len > 509; len -= 510) {
+                               *op++ = 255;
+                               *op++ = 255;
+                       }
+                       if (len > 254) {
+                               len -= 255;
+                               *op++ = 255;
+                       }
+                       *op++ = (BYTE)len;
+               } else
+                       *token += len;
+
+               /* Test end of chunk */
+               if (ip > mflimit) {
+                       anchor = ip;
+                       break;
+               }
+               /* Fill table */
+               HashTable[LZ4_HASH64K_VALUE(ip - 2)] = ip - 2 - base;
+
+               /* Test next position */
+               ref = base + HashTable[LZ4_HASH64K_VALUE(ip)];
+               HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base;
+               if (A32(ref) == A32(ip)) {
+                       token = op++;
+                       *token = 0;
+                       goto _next_match;
+               }
+               /* Prepare next loop */
+               anchor = ip++;
+               forwardH = LZ4_HASH64K_VALUE(ip);
+       }
+
+       _last_literals:
+       /* Encode Last Literals */
+       {
+               int lastRun = iend - anchor;
+               if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) >
+                   oend)
+                       return (0);
+               if (lastRun >= (int)RUN_MASK) {
+                       *op++ = (RUN_MASK << ML_BITS);
+                       lastRun -= RUN_MASK;
+                       for (; lastRun > 254; lastRun -= 255)
+                               *op++ = 255;
+                       *op++ = (BYTE)lastRun;
+               } else
+                       *op++ = (lastRun << ML_BITS);
+               (void) memcpy(op, anchor, iend - anchor);
+               op += iend - anchor;
+       }
+
+       /* End */
+       return (int)(((char *)op) - dest);
+}
+
+static int
+real_LZ4_compress(const char *source, char *dest, int isize, int osize)
+{
+       void *ctx;
+       int result;
+
+       ASSERT(lz4_cache != NULL);
+       ctx = kmem_cache_alloc(lz4_cache, KM_SLEEP);
+
+       /*
+        * out of kernel memory, gently fall through - this will disable
+        * compression in zio_compress_data
+        */
+       if (ctx == NULL)
+               return (0);
+
+       memset(ctx, 0, sizeof (struct refTables));
+
+       if (isize < LZ4_64KLIMIT)
+               result = LZ4_compress64kCtx(ctx, source, dest, isize, osize);
+       else
+               result = LZ4_compressCtx(ctx, source, dest, isize, osize);
+
+       kmem_cache_free(lz4_cache, ctx);
+       return (result);
+}
+
+/* Decompression functions */
+
+/*
+ * Note: The decoding functions real_LZ4_uncompress() and
+ *     LZ4_uncompress_unknownOutputSize() are safe against "buffer overflow"
+ *     attack type. They will never write nor read outside of the provided
+ *     output buffers. LZ4_uncompress_unknownOutputSize() also insures that
+ *     it will never read outside of the input buffer. A corrupted input
+ *     will produce an error result, a negative int, indicating the position
+ *     of the error within input stream.
+ *
+ * Note[2]: real_LZ4_uncompress(), referred to above, is not used in ZFS so
+ *     its code is not present here.
+ */
+
+static int
+LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize,
+    int maxOutputSize)
+{
+       /* Local Variables */
+       const BYTE *restrict ip = (const BYTE *) source;
+       const BYTE *const iend = ip + isize;
+       const BYTE *ref;
+
+       BYTE *op = (BYTE *) dest;
+       BYTE *const oend = op + maxOutputSize;
+       BYTE *cpy;
+
+       size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};
+#if LZ4_ARCH64
+       size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+#endif
+
+       /* Main Loop */
+       while (ip < iend) {
+               unsigned token;
+               size_t length;
+
+               /* get runlength */
+               token = *ip++;
+               if ((length = (token >> ML_BITS)) == RUN_MASK) {
+                       int s = 255;
+                       while ((ip < iend) && (s == 255)) {
+                               s = *ip++;
+                               length += s;
+                       }
+               }
+               /* copy literals */
+               cpy = op + length;
+               /* CORNER-CASE: cpy might overflow. */
+               if (cpy < op)
+                       goto _output_error;     /* cpy was overflowed, bail! */
+               if ((cpy > oend - COPYLENGTH) ||
+                   (ip + length > iend - COPYLENGTH)) {
+                       if (cpy > oend)
+                               /* Error: writes beyond output buffer */
+                               goto _output_error;
+                       if (ip + length != iend)
+                               /*
+                                * Error: LZ4 format requires to consume all
+                                * input at this stage
+                                */
+                               goto _output_error;
+                       (void) memcpy(op, ip, length);
+                       op += length;
+                       /* Necessarily EOF, due to parsing restrictions */
+                       break;
+               }
+               LZ4_WILDCOPY(ip, op, cpy);
+               ip -= (op - cpy);
+               op = cpy;
+
+               /* get offset */
+               LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
+               ip += 2;
+               if (ref < (BYTE * const) dest)
+                       /*
+                        * Error: offset creates reference outside of
+                        * destination buffer
+                        */
+                       goto _output_error;
+
+               /* get matchlength */
+               if ((length = (token & ML_MASK)) == ML_MASK) {
+                       while (ip < iend) {
+                               int s = *ip++;
+                               length += s;
+                               if (s == 255)
+                                       continue;
+                               break;
+                       }
+               }
+               /* copy repeated sequence */
+               if (unlikely(op - ref < STEPSIZE)) {
+#if LZ4_ARCH64
+                       size_t dec64 = dec64table[op-ref];
+#else
+                       const int dec64 = 0;
+#endif
+                       op[0] = ref[0];
+                       op[1] = ref[1];
+                       op[2] = ref[2];
+                       op[3] = ref[3];
+                       op += 4;
+                       ref += 4;
+                       ref -= dec32table[op-ref];
+                       A32(op) = A32(ref);
+                       op += STEPSIZE - 4;
+                       ref -= dec64;
+               } else {
+                       LZ4_COPYSTEP(ref, op);
+               }
+               cpy = op + length - (STEPSIZE - 4);
+               if (cpy > oend - COPYLENGTH) {
+                       if (cpy > oend)
+                               /*
+                                * Error: request to write outside of
+                                * destination buffer
+                                */
+                               goto _output_error;
+                       LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
+                       while (op < cpy)
+                               *op++ = *ref++;
+                       op = cpy;
+                       if (op == oend)
+                               /*
+                                * Check EOF (should never happen, since
+                                * last 5 bytes are supposed to be literals)
+                                */
+                               goto _output_error;
+                       continue;
+               }
+               LZ4_SECURECOPY(ref, op, cpy);
+               op = cpy;       /* correction */
+       }
+
+       /* end of decoding */
+       return (int)(((char *)op) - dest);
+
+       /* write overflow error detected */
+       _output_error:
+       return (int)(-(((char *)ip) - source));
+}
+
+void
+lz4_init(void)
+{
+       lz4_cache = kmem_cache_create("lz4_cache",
+               sizeof (struct refTables), 0, NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+void
+lz4_fini(void)
+{
+       if (lz4_cache) {
+               kmem_cache_destroy(lz4_cache);
+               lz4_cache = NULL;
+       }
+}
diff --git a/zfs/module/zfs/lzjb.c b/zfs/module/zfs/lzjb.c
new file mode 100644 (file)
index 0000000..ae18467
--- /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 (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/*
+ * We keep our own copy of this algorithm for 3 main reasons:
+ *     1. If we didn't, anyone modifying common/os/compress.c would
+ *         directly break our on disk format
+ *     2. Our version of lzjb does not have a number of checks that the
+ *         common/os version needs and uses
+ *     3. We initialize the lempel to ensure deterministic results,
+ *        so that identical blocks can always be deduplicated.
+ * In particular, we are adding the "feature" that compress() can
+ * take a destination buffer size and returns the compressed length, or the
+ * source length if compression would overflow the destination buffer.
+ */
+
+#include <sys/zfs_context.h>
+
+#define        MATCH_BITS      6
+#define        MATCH_MIN       3
+#define        MATCH_MAX       ((1 << MATCH_BITS) + (MATCH_MIN - 1))
+#define        OFFSET_MASK     ((1 << (16 - MATCH_BITS)) - 1)
+#define        LEMPEL_SIZE     1024
+
+/*ARGSUSED*/
+size_t
+lzjb_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+       uchar_t *src = s_start;
+       uchar_t *dst = d_start;
+       uchar_t *cpy;
+       uchar_t *copymap = NULL;
+       int copymask = 1 << (NBBY - 1);
+       int mlen, offset, hash;
+       uint16_t *hp;
+       uint16_t *lempel;
+
+       lempel = kmem_zalloc(LEMPEL_SIZE * sizeof (uint16_t), KM_SLEEP);
+       while (src < (uchar_t *)s_start + s_len) {
+               if ((copymask <<= 1) == (1 << NBBY)) {
+                       if (dst >= (uchar_t *)d_start + d_len - 1 - 2 * NBBY) {
+                               kmem_free(lempel,
+                                   LEMPEL_SIZE*sizeof (uint16_t));
+                               return (s_len);
+                       }
+                       copymask = 1;
+                       copymap = dst;
+                       *dst++ = 0;
+               }
+               if (src > (uchar_t *)s_start + s_len - MATCH_MAX) {
+                       *dst++ = *src++;
+                       continue;
+               }
+               hash = (src[0] << 16) + (src[1] << 8) + src[2];
+               hash += hash >> 9;
+               hash += hash >> 5;
+               hp = &lempel[hash & (LEMPEL_SIZE - 1)];
+               offset = (intptr_t)(src - *hp) & OFFSET_MASK;
+               *hp = (uint16_t)(uintptr_t)src;
+               cpy = src - offset;
+               if (cpy >= (uchar_t *)s_start && cpy != src &&
+                   src[0] == cpy[0] && src[1] == cpy[1] && src[2] == cpy[2]) {
+                       *copymap |= copymask;
+                       for (mlen = MATCH_MIN; mlen < MATCH_MAX; mlen++)
+                               if (src[mlen] != cpy[mlen])
+                                       break;
+                       *dst++ = ((mlen - MATCH_MIN) << (NBBY - MATCH_BITS)) |
+                           (offset >> NBBY);
+                       *dst++ = (uchar_t)offset;
+                       src += mlen;
+               } else {
+                       *dst++ = *src++;
+               }
+       }
+
+       kmem_free(lempel, LEMPEL_SIZE * sizeof (uint16_t));
+       return (dst - (uchar_t *)d_start);
+}
+
+/*ARGSUSED*/
+int
+lzjb_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+       uchar_t *src = s_start;
+       uchar_t *dst = d_start;
+       uchar_t *d_end = (uchar_t *)d_start + d_len;
+       uchar_t *cpy;
+       uchar_t copymap = 0;
+       int copymask = 1 << (NBBY - 1);
+
+       while (dst < d_end) {
+               if ((copymask <<= 1) == (1 << NBBY)) {
+                       copymask = 1;
+                       copymap = *src++;
+               }
+               if (copymap & copymask) {
+                       int mlen = (src[0] >> (NBBY - MATCH_BITS)) + MATCH_MIN;
+                       int offset = ((src[0] << NBBY) | src[1]) & OFFSET_MASK;
+                       src += 2;
+                       if ((cpy = dst - offset) < (uchar_t *)d_start)
+                               return (-1);
+                       while (--mlen >= 0 && dst < d_end)
+                               *dst++ = *cpy++;
+               } else {
+                       *dst++ = *src++;
+               }
+       }
+       return (0);
+}
diff --git a/zfs/module/zfs/metaslab.c b/zfs/module/zfs/metaslab.c
new file mode 100644 (file)
index 0000000..59bcefd
--- /dev/null
@@ -0,0 +1,2745 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/space_map.h>
+#include <sys/metaslab_impl.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/spa_impl.h>
+#include <sys/zfeature.h>
+
+#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        METASLAB_WEIGHT_PRIMARY         (1ULL << 63)
+#define        METASLAB_WEIGHT_SECONDARY       (1ULL << 62)
+#define        METASLAB_ACTIVE_MASK            \
+       (METASLAB_WEIGHT_PRIMARY | METASLAB_WEIGHT_SECONDARY)
+
+/*
+ * 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, we will try to write this amount of data to a top-level vdev
+ * before moving on to the next one.
+ */
+unsigned long metaslab_aliquot = 512 << 10;
+
+uint64_t metaslab_gang_bang = SPA_MAXBLOCKSIZE + 1;    /* force gang blocks */
+
+/*
+ * The in-core space map representation is more compact than its on-disk form.
+ * The zfs_condense_pct determines how much more compact the in-core
+ * space_map representation must be before we compact it on-disk.
+ * Values should be greater than or equal to 100.
+ */
+int zfs_condense_pct = 200;
+
+/*
+ * Condensing a metaslab is not guaranteed to actually reduce the amount of
+ * space used on disk. In particular, a space map uses data in increments of
+ * MAX(1 << ashift, space_map_blksz), so a metaslab might use the
+ * same number of blocks after condensing. Since the goal of condensing is to
+ * reduce the number of IOPs required to read the space map, we only want to
+ * condense when we can be sure we will reduce the number of blocks used by the
+ * space map. Unfortunately, we cannot precisely compute whether or not this is
+ * the case in metaslab_should_condense since we are holding ms_lock. Instead,
+ * we apply the following heuristic: do not condense a spacemap unless the
+ * uncondensed size consumes greater than zfs_metaslab_condense_block_threshold
+ * blocks.
+ */
+int zfs_metaslab_condense_block_threshold = 4;
+
+/*
+ * The zfs_mg_noalloc_threshold defines which metaslab groups should
+ * be eligible for allocation. The value is defined as a percentage of
+ * free space. Metaslab groups that have more free space than
+ * zfs_mg_noalloc_threshold are always eligible for allocations. Once
+ * a metaslab group's free space is less than or equal to the
+ * zfs_mg_noalloc_threshold the allocator will avoid allocating to that
+ * group unless all groups in the pool have reached zfs_mg_noalloc_threshold.
+ * Once all groups in the pool reach zfs_mg_noalloc_threshold then all
+ * groups are allowed to accept allocations. Gang blocks are always
+ * eligible to allocate on any metaslab group. The default value of 0 means
+ * no metaslab group will be excluded based on this criterion.
+ */
+int zfs_mg_noalloc_threshold = 0;
+
+/*
+ * Metaslab groups are considered eligible for allocations if their
+ * fragmenation metric (measured as a percentage) is less than or equal to
+ * zfs_mg_fragmentation_threshold. 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.
+ */
+int zfs_mg_fragmentation_threshold = 85;
+
+/*
+ * Allow metaslabs to keep their active state as long as their fragmentation
+ * percentage is less than or equal to zfs_metaslab_fragmentation_threshold. An
+ * active metaslab that exceeds this threshold will no longer keep its active
+ * status allowing better metaslabs to be selected.
+ */
+int zfs_metaslab_fragmentation_threshold = 70;
+
+/*
+ * When set will load all metaslabs when pool is first opened.
+ */
+int metaslab_debug_load = 0;
+
+/*
+ * When set will prevent metaslabs from being unloaded.
+ */
+int metaslab_debug_unload = 0;
+
+/*
+ * Minimum size which forces the dynamic allocator to change
+ * it's allocation strategy.  Once the space map cannot satisfy
+ * an allocation of this size then it switches to using more
+ * aggressive strategy (i.e search by size rather than offset).
+ */
+uint64_t metaslab_df_alloc_threshold = SPA_MAXBLOCKSIZE;
+
+/*
+ * The minimum free space, in percent, which must be available
+ * in a space map to continue allocations in a first-fit fashion.
+ * Once the space_map's free space drops below this level we dynamically
+ * switch to using best-fit allocations.
+ */
+int metaslab_df_free_pct = 4;
+
+/*
+ * Percentage of all cpus that can be used by the metaslab taskq.
+ */
+int metaslab_load_pct = 50;
+
+/*
+ * Determines how many txgs a metaslab may remain loaded without having any
+ * allocations from it. As long as a metaslab continues to be used we will
+ * keep it loaded.
+ */
+int metaslab_unload_delay = TXG_SIZE * 2;
+
+/*
+ * Max number of metaslabs per group to preload.
+ */
+int metaslab_preload_limit = SPA_DVAS_PER_BP;
+
+/*
+ * Enable/disable preloading of metaslab.
+ */
+int metaslab_preload_enabled = B_TRUE;
+
+/*
+ * Enable/disable fragmentation weighting on metaslabs.
+ */
+int metaslab_fragmentation_factor_enabled = B_TRUE;
+
+/*
+ * Enable/disable lba weighting (i.e. outer tracks are given preference).
+ */
+int metaslab_lba_weighting_enabled = B_TRUE;
+
+/*
+ * Enable/disable metaslab group biasing.
+ */
+int metaslab_bias_enabled = B_TRUE;
+
+static uint64_t metaslab_fragmentation(metaslab_t *);
+
+/*
+ * ==========================================================================
+ * Metaslab classes
+ * ==========================================================================
+ */
+metaslab_class_t *
+metaslab_class_create(spa_t *spa, metaslab_ops_t *ops)
+{
+       metaslab_class_t *mc;
+
+       mc = kmem_zalloc(sizeof (metaslab_class_t), KM_SLEEP);
+
+       mc->mc_spa = spa;
+       mc->mc_rotor = NULL;
+       mc->mc_ops = ops;
+       mutex_init(&mc->mc_fastwrite_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       return (mc);
+}
+
+void
+metaslab_class_destroy(metaslab_class_t *mc)
+{
+       ASSERT(mc->mc_rotor == NULL);
+       ASSERT(mc->mc_alloc == 0);
+       ASSERT(mc->mc_deferred == 0);
+       ASSERT(mc->mc_space == 0);
+       ASSERT(mc->mc_dspace == 0);
+
+       mutex_destroy(&mc->mc_fastwrite_lock);
+       kmem_free(mc, sizeof (metaslab_class_t));
+}
+
+int
+metaslab_class_validate(metaslab_class_t *mc)
+{
+       metaslab_group_t *mg;
+       vdev_t *vd;
+
+       /*
+        * Must hold one of the spa_config locks.
+        */
+       ASSERT(spa_config_held(mc->mc_spa, SCL_ALL, RW_READER) ||
+           spa_config_held(mc->mc_spa, SCL_ALL, RW_WRITER));
+
+       if ((mg = mc->mc_rotor) == NULL)
+               return (0);
+
+       do {
+               vd = mg->mg_vd;
+               ASSERT(vd->vdev_mg != NULL);
+               ASSERT3P(vd->vdev_top, ==, vd);
+               ASSERT3P(mg->mg_class, ==, mc);
+               ASSERT3P(vd->vdev_ops, !=, &vdev_hole_ops);
+       } while ((mg = mg->mg_next) != mc->mc_rotor);
+
+       return (0);
+}
+
+void
+metaslab_class_space_update(metaslab_class_t *mc, int64_t alloc_delta,
+    int64_t defer_delta, int64_t space_delta, int64_t dspace_delta)
+{
+       atomic_add_64(&mc->mc_alloc, alloc_delta);
+       atomic_add_64(&mc->mc_deferred, defer_delta);
+       atomic_add_64(&mc->mc_space, space_delta);
+       atomic_add_64(&mc->mc_dspace, dspace_delta);
+}
+
+uint64_t
+metaslab_class_get_alloc(metaslab_class_t *mc)
+{
+       return (mc->mc_alloc);
+}
+
+uint64_t
+metaslab_class_get_deferred(metaslab_class_t *mc)
+{
+       return (mc->mc_deferred);
+}
+
+uint64_t
+metaslab_class_get_space(metaslab_class_t *mc)
+{
+       return (mc->mc_space);
+}
+
+uint64_t
+metaslab_class_get_dspace(metaslab_class_t *mc)
+{
+       return (spa_deflate(mc->mc_spa) ? mc->mc_dspace : mc->mc_space);
+}
+
+void
+metaslab_class_histogram_verify(metaslab_class_t *mc)
+{
+       vdev_t *rvd = mc->mc_spa->spa_root_vdev;
+       uint64_t *mc_hist;
+       int i, c;
+
+       if ((zfs_flags & ZFS_DEBUG_HISTOGRAM_VERIFY) == 0)
+               return;
+
+       mc_hist = kmem_zalloc(sizeof (uint64_t) * RANGE_TREE_HISTOGRAM_SIZE,
+           KM_SLEEP);
+
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               /*
+                * Skip any holes, uninitialized top-levels, or
+                * vdevs that are not in this metalab class.
+                */
+               if (tvd->vdev_ishole || tvd->vdev_ms_shift == 0 ||
+                   mg->mg_class != mc) {
+                       continue;
+               }
+
+               for (i = 0; i < RANGE_TREE_HISTOGRAM_SIZE; i++)
+                       mc_hist[i] += mg->mg_histogram[i];
+       }
+
+       for (i = 0; i < RANGE_TREE_HISTOGRAM_SIZE; i++)
+               VERIFY3U(mc_hist[i], ==, mc->mc_histogram[i]);
+
+       kmem_free(mc_hist, sizeof (uint64_t) * RANGE_TREE_HISTOGRAM_SIZE);
+}
+
+/*
+ * Calculate the metaslab class's fragmentation metric. The metric
+ * is weighted based on the space contribution of each metaslab group.
+ * The return value will be a number between 0 and 100 (inclusive), or
+ * ZFS_FRAG_INVALID if the metric has not been set. See comment above the
+ * zfs_frag_table for more information about the metric.
+ */
+uint64_t
+metaslab_class_fragmentation(metaslab_class_t *mc)
+{
+       vdev_t *rvd = mc->mc_spa->spa_root_vdev;
+       uint64_t fragmentation = 0;
+       int c;
+
+       spa_config_enter(mc->mc_spa, SCL_VDEV, FTAG, RW_READER);
+
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               /*
+                * Skip any holes, uninitialized top-levels, or
+                * vdevs that are not in this metalab class.
+                */
+               if (tvd->vdev_ishole || tvd->vdev_ms_shift == 0 ||
+                   mg->mg_class != mc) {
+                       continue;
+               }
+
+               /*
+                * If a metaslab group does not contain a fragmentation
+                * metric then just bail out.
+                */
+               if (mg->mg_fragmentation == ZFS_FRAG_INVALID) {
+                       spa_config_exit(mc->mc_spa, SCL_VDEV, FTAG);
+                       return (ZFS_FRAG_INVALID);
+               }
+
+               /*
+                * Determine how much this metaslab_group is contributing
+                * to the overall pool fragmentation metric.
+                */
+               fragmentation += mg->mg_fragmentation *
+                   metaslab_group_get_space(mg);
+       }
+       fragmentation /= metaslab_class_get_space(mc);
+
+       ASSERT3U(fragmentation, <=, 100);
+       spa_config_exit(mc->mc_spa, SCL_VDEV, FTAG);
+       return (fragmentation);
+}
+
+/*
+ * Calculate the amount of expandable space that is available in
+ * this metaslab class. If a device is expanded then its expandable
+ * space will be the amount of allocatable space that is currently not
+ * part of this metaslab class.
+ */
+uint64_t
+metaslab_class_expandable_space(metaslab_class_t *mc)
+{
+       vdev_t *rvd = mc->mc_spa->spa_root_vdev;
+       uint64_t space = 0;
+       int c;
+
+       spa_config_enter(mc->mc_spa, SCL_VDEV, FTAG, RW_READER);
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               if (tvd->vdev_ishole || tvd->vdev_ms_shift == 0 ||
+                   mg->mg_class != mc) {
+                       continue;
+               }
+
+               space += tvd->vdev_max_asize - tvd->vdev_asize;
+       }
+       spa_config_exit(mc->mc_spa, SCL_VDEV, FTAG);
+       return (space);
+}
+
+/*
+ * ==========================================================================
+ * Metaslab groups
+ * ==========================================================================
+ */
+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);
+
+       /*
+        * 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);
+
+       ASSERT3P(m1, ==, m2);
+
+       return (0);
+}
+
+/*
+ * 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.
+ */
+static void
+metaslab_group_alloc_update(metaslab_group_t *mg)
+{
+       vdev_t *vd = mg->mg_vd;
+       metaslab_class_t *mc = mg->mg_class;
+       vdev_stat_t *vs = &vd->vdev_stat;
+       boolean_t was_allocatable;
+
+       ASSERT(vd == vd->vdev_top);
+
+       mutex_enter(&mg->mg_lock);
+       was_allocatable = mg->mg_allocatable;
+
+       mg->mg_free_capacity = ((vs->vs_space - vs->vs_alloc) * 100) /
+           (vs->vs_space + 1);
+
+       /*
+        * 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_fragmentation == ZFS_FRAG_INVALID ||
+           mg->mg_fragmentation <= zfs_mg_fragmentation_threshold));
+
+       /*
+        * The mc_alloc_groups maintains a count of the number of
+        * groups in this metaslab class that are still above the
+        * zfs_mg_noalloc_threshold. This is used by the allocating
+        * threads to determine if they should avoid allocations to
+        * a given group. The allocator will avoid allocations to a group
+        * if that group has reached or is below the zfs_mg_noalloc_threshold
+        * and there are still other groups that are above the threshold.
+        * When a group transitions from allocatable to non-allocatable or
+        * vice versa we update the metaslab class to reflect that change.
+        * When the mc_alloc_groups value drops to 0 that means that all
+        * groups have reached the zfs_mg_noalloc_threshold making all groups
+        * eligible for allocations. This effectively means that all devices
+        * are balanced again.
+        */
+       if (was_allocatable && !mg->mg_allocatable)
+               mc->mc_alloc_groups--;
+       else if (!was_allocatable && mg->mg_allocatable)
+               mc->mc_alloc_groups++;
+
+       mutex_exit(&mg->mg_lock);
+}
+
+metaslab_group_t *
+metaslab_group_create(metaslab_class_t *mc, vdev_t *vd)
+{
+       metaslab_group_t *mg;
+
+       mg = kmem_zalloc(sizeof (metaslab_group_t), KM_SLEEP);
+       mutex_init(&mg->mg_lock, NULL, MUTEX_DEFAULT, NULL);
+       avl_create(&mg->mg_metaslab_tree, metaslab_compare,
+           sizeof (metaslab_t), offsetof(struct metaslab, ms_group_node));
+       mg->mg_vd = vd;
+       mg->mg_class = mc;
+       mg->mg_activation_count = 0;
+
+       mg->mg_taskq = taskq_create("metaslab_group_taskq", metaslab_load_pct,
+           maxclsyspri, 10, INT_MAX, TASKQ_THREADS_CPU_PCT | TASKQ_DYNAMIC);
+
+       return (mg);
+}
+
+void
+metaslab_group_destroy(metaslab_group_t *mg)
+{
+       ASSERT(mg->mg_prev == NULL);
+       ASSERT(mg->mg_next == NULL);
+       /*
+        * We may have gone below zero with the activation count
+        * either because we never activated in the first place or
+        * because we're done, and possibly removing the vdev.
+        */
+       ASSERT(mg->mg_activation_count <= 0);
+
+       taskq_destroy(mg->mg_taskq);
+       avl_destroy(&mg->mg_metaslab_tree);
+       mutex_destroy(&mg->mg_lock);
+       kmem_free(mg, sizeof (metaslab_group_t));
+}
+
+void
+metaslab_group_activate(metaslab_group_t *mg)
+{
+       metaslab_class_t *mc = mg->mg_class;
+       metaslab_group_t *mgprev, *mgnext;
+
+       ASSERT(spa_config_held(mc->mc_spa, SCL_ALLOC, RW_WRITER));
+
+       ASSERT(mc->mc_rotor != mg);
+       ASSERT(mg->mg_prev == NULL);
+       ASSERT(mg->mg_next == NULL);
+       ASSERT(mg->mg_activation_count <= 0);
+
+       if (++mg->mg_activation_count <= 0)
+               return;
+
+       mg->mg_aliquot = metaslab_aliquot * MAX(1, mg->mg_vd->vdev_children);
+       metaslab_group_alloc_update(mg);
+
+       if ((mgprev = mc->mc_rotor) == NULL) {
+               mg->mg_prev = mg;
+               mg->mg_next = mg;
+       } else {
+               mgnext = mgprev->mg_next;
+               mg->mg_prev = mgprev;
+               mg->mg_next = mgnext;
+               mgprev->mg_next = mg;
+               mgnext->mg_prev = mg;
+       }
+       mc->mc_rotor = mg;
+}
+
+void
+metaslab_group_passivate(metaslab_group_t *mg)
+{
+       metaslab_class_t *mc = mg->mg_class;
+       metaslab_group_t *mgprev, *mgnext;
+
+       ASSERT(spa_config_held(mc->mc_spa, SCL_ALLOC, RW_WRITER));
+
+       if (--mg->mg_activation_count != 0) {
+               ASSERT(mc->mc_rotor != mg);
+               ASSERT(mg->mg_prev == NULL);
+               ASSERT(mg->mg_next == NULL);
+               ASSERT(mg->mg_activation_count < 0);
+               return;
+       }
+
+       taskq_wait_outstanding(mg->mg_taskq, 0);
+       metaslab_group_alloc_update(mg);
+
+       mgprev = mg->mg_prev;
+       mgnext = mg->mg_next;
+
+       if (mg == mgnext) {
+               mc->mc_rotor = NULL;
+       } else {
+               mc->mc_rotor = mgnext;
+               mgprev->mg_next = mgnext;
+               mgnext->mg_prev = mgprev;
+       }
+
+       mg->mg_prev = NULL;
+       mg->mg_next = NULL;
+}
+
+uint64_t
+metaslab_group_get_space(metaslab_group_t *mg)
+{
+       return ((1ULL << mg->mg_vd->vdev_ms_shift) * mg->mg_vd->vdev_ms_count);
+}
+
+void
+metaslab_group_histogram_verify(metaslab_group_t *mg)
+{
+       uint64_t *mg_hist;
+       vdev_t *vd = mg->mg_vd;
+       uint64_t ashift = vd->vdev_ashift;
+       int i, m;
+
+       if ((zfs_flags & ZFS_DEBUG_HISTOGRAM_VERIFY) == 0)
+               return;
+
+       mg_hist = kmem_zalloc(sizeof (uint64_t) * RANGE_TREE_HISTOGRAM_SIZE,
+           KM_SLEEP);
+
+       ASSERT3U(RANGE_TREE_HISTOGRAM_SIZE, >=,
+           SPACE_MAP_HISTOGRAM_SIZE + ashift);
+
+       for (m = 0; m < vd->vdev_ms_count; m++) {
+               metaslab_t *msp = vd->vdev_ms[m];
+
+               if (msp->ms_sm == NULL)
+                       continue;
+
+               for (i = 0; i < SPACE_MAP_HISTOGRAM_SIZE; i++)
+                       mg_hist[i + ashift] +=
+                           msp->ms_sm->sm_phys->smp_histogram[i];
+       }
+
+       for (i = 0; i < RANGE_TREE_HISTOGRAM_SIZE; i ++)
+               VERIFY3U(mg_hist[i], ==, mg->mg_histogram[i]);
+
+       kmem_free(mg_hist, sizeof (uint64_t) * RANGE_TREE_HISTOGRAM_SIZE);
+}
+
+static void
+metaslab_group_histogram_add(metaslab_group_t *mg, metaslab_t *msp)
+{
+       metaslab_class_t *mc = mg->mg_class;
+       uint64_t ashift = mg->mg_vd->vdev_ashift;
+       int i;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       if (msp->ms_sm == NULL)
+               return;
+
+       mutex_enter(&mg->mg_lock);
+       for (i = 0; i < SPACE_MAP_HISTOGRAM_SIZE; i++) {
+               mg->mg_histogram[i + ashift] +=
+                   msp->ms_sm->sm_phys->smp_histogram[i];
+               mc->mc_histogram[i + ashift] +=
+                   msp->ms_sm->sm_phys->smp_histogram[i];
+       }
+       mutex_exit(&mg->mg_lock);
+}
+
+void
+metaslab_group_histogram_remove(metaslab_group_t *mg, metaslab_t *msp)
+{
+       metaslab_class_t *mc = mg->mg_class;
+       uint64_t ashift = mg->mg_vd->vdev_ashift;
+       int i;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       if (msp->ms_sm == NULL)
+               return;
+
+       mutex_enter(&mg->mg_lock);
+       for (i = 0; i < SPACE_MAP_HISTOGRAM_SIZE; i++) {
+               ASSERT3U(mg->mg_histogram[i + ashift], >=,
+                   msp->ms_sm->sm_phys->smp_histogram[i]);
+               ASSERT3U(mc->mc_histogram[i + ashift], >=,
+                   msp->ms_sm->sm_phys->smp_histogram[i]);
+
+               mg->mg_histogram[i + ashift] -=
+                   msp->ms_sm->sm_phys->smp_histogram[i];
+               mc->mc_histogram[i + ashift] -=
+                   msp->ms_sm->sm_phys->smp_histogram[i];
+       }
+       mutex_exit(&mg->mg_lock);
+}
+
+static void
+metaslab_group_add(metaslab_group_t *mg, metaslab_t *msp)
+{
+       ASSERT(msp->ms_group == NULL);
+       mutex_enter(&mg->mg_lock);
+       msp->ms_group = mg;
+       msp->ms_weight = 0;
+       avl_add(&mg->mg_metaslab_tree, msp);
+       mutex_exit(&mg->mg_lock);
+
+       mutex_enter(&msp->ms_lock);
+       metaslab_group_histogram_add(mg, msp);
+       mutex_exit(&msp->ms_lock);
+}
+
+static void
+metaslab_group_remove(metaslab_group_t *mg, metaslab_t *msp)
+{
+       mutex_enter(&msp->ms_lock);
+       metaslab_group_histogram_remove(mg, msp);
+       mutex_exit(&msp->ms_lock);
+
+       mutex_enter(&mg->mg_lock);
+       ASSERT(msp->ms_group == mg);
+       avl_remove(&mg->mg_metaslab_tree, msp);
+       msp->ms_group = NULL;
+       mutex_exit(&mg->mg_lock);
+}
+
+static void
+metaslab_group_sort(metaslab_group_t *mg, metaslab_t *msp, uint64_t weight)
+{
+       /*
+        * Although in principle the weight can be any value, in
+        * practice we do not use values in the range [1, 511].
+        */
+       ASSERT(weight >= SPA_MINBLOCKSIZE || weight == 0);
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+
+       mutex_enter(&mg->mg_lock);
+       ASSERT(msp->ms_group == mg);
+       avl_remove(&mg->mg_metaslab_tree, msp);
+       msp->ms_weight = weight;
+       avl_add(&mg->mg_metaslab_tree, msp);
+       mutex_exit(&mg->mg_lock);
+}
+
+/*
+ * Calculate the fragmentation for a given metaslab group. We can use
+ * a simple average here since all metaslabs within the group must have
+ * the same size. The return value will be a value between 0 and 100
+ * (inclusive), or ZFS_FRAG_INVALID if less than half of the metaslab in this
+ * group have a fragmentation metric.
+ */
+uint64_t
+metaslab_group_fragmentation(metaslab_group_t *mg)
+{
+       vdev_t *vd = mg->mg_vd;
+       uint64_t fragmentation = 0;
+       uint64_t valid_ms = 0;
+       int m;
+
+       for (m = 0; m < vd->vdev_ms_count; m++) {
+               metaslab_t *msp = vd->vdev_ms[m];
+
+               if (msp->ms_fragmentation == ZFS_FRAG_INVALID)
+                       continue;
+
+               valid_ms++;
+               fragmentation += msp->ms_fragmentation;
+       }
+
+       if (valid_ms <= vd->vdev_ms_count / 2)
+               return (ZFS_FRAG_INVALID);
+
+       fragmentation /= valid_ms;
+       ASSERT3U(fragmentation, <=, 100);
+       return (fragmentation);
+}
+
+/*
+ * Determine if a given metaslab group should skip allocations. A metaslab
+ * 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.
+ */
+static boolean_t
+metaslab_group_allocatable(metaslab_group_t *mg)
+{
+       vdev_t *vd = mg->mg_vd;
+       spa_t *spa = 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
+        * 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);
+}
+
+/*
+ * ==========================================================================
+ * Range tree callbacks
+ * ==========================================================================
+ */
+
+/*
+ * Comparison function for the private size-ordered tree. Tree is sorted
+ * by size, larger sizes at the end of the tree.
+ */
+static int
+metaslab_rangesize_compare(const void *x1, const void *x2)
+{
+       const range_seg_t *r1 = x1;
+       const range_seg_t *r2 = 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);
+
+       if (r1->rs_start > r2->rs_start)
+               return (1);
+
+       return (0);
+}
+
+/*
+ * Create any block allocator specific components. The current allocators
+ * rely on using both a size-ordered range_tree_t and an array of uint64_t's.
+ */
+static void
+metaslab_rt_create(range_tree_t *rt, void *arg)
+{
+       metaslab_t *msp = arg;
+
+       ASSERT3P(rt->rt_arg, ==, msp);
+       ASSERT(msp->ms_tree == NULL);
+
+       avl_create(&msp->ms_size_tree, metaslab_rangesize_compare,
+           sizeof (range_seg_t), offsetof(range_seg_t, rs_pp_node));
+}
+
+/*
+ * Destroy the block allocator specific components.
+ */
+static void
+metaslab_rt_destroy(range_tree_t *rt, void *arg)
+{
+       metaslab_t *msp = arg;
+
+       ASSERT3P(rt->rt_arg, ==, msp);
+       ASSERT3P(msp->ms_tree, ==, rt);
+       ASSERT0(avl_numnodes(&msp->ms_size_tree));
+
+       avl_destroy(&msp->ms_size_tree);
+}
+
+static void
+metaslab_rt_add(range_tree_t *rt, range_seg_t *rs, void *arg)
+{
+       metaslab_t *msp = arg;
+
+       ASSERT3P(rt->rt_arg, ==, msp);
+       ASSERT3P(msp->ms_tree, ==, rt);
+       VERIFY(!msp->ms_condensing);
+       avl_add(&msp->ms_size_tree, rs);
+}
+
+static void
+metaslab_rt_remove(range_tree_t *rt, range_seg_t *rs, void *arg)
+{
+       metaslab_t *msp = arg;
+
+       ASSERT3P(rt->rt_arg, ==, msp);
+       ASSERT3P(msp->ms_tree, ==, rt);
+       VERIFY(!msp->ms_condensing);
+       avl_remove(&msp->ms_size_tree, rs);
+}
+
+static void
+metaslab_rt_vacate(range_tree_t *rt, void *arg)
+{
+       metaslab_t *msp = arg;
+
+       ASSERT3P(rt->rt_arg, ==, msp);
+       ASSERT3P(msp->ms_tree, ==, rt);
+
+       /*
+        * Normally one would walk the tree freeing nodes along the way.
+        * Since the nodes are shared with the range trees we can avoid
+        * walking all nodes and just reinitialize the avl tree. The nodes
+        * will be freed by the range tree, so we don't want to free them here.
+        */
+       avl_create(&msp->ms_size_tree, metaslab_rangesize_compare,
+           sizeof (range_seg_t), offsetof(range_seg_t, rs_pp_node));
+}
+
+static range_tree_ops_t metaslab_rt_ops = {
+       metaslab_rt_create,
+       metaslab_rt_destroy,
+       metaslab_rt_add,
+       metaslab_rt_remove,
+       metaslab_rt_vacate
+};
+
+/*
+ * ==========================================================================
+ * Metaslab block operations
+ * ==========================================================================
+ */
+
+/*
+ * Return the maximum contiguous segment within the metaslab.
+ */
+uint64_t
+metaslab_block_maxsize(metaslab_t *msp)
+{
+       avl_tree_t *t = &msp->ms_size_tree;
+       range_seg_t *rs;
+
+       if (t == NULL || (rs = avl_last(t)) == NULL)
+               return (0ULL);
+
+       return (rs->rs_end - rs->rs_start);
+}
+
+uint64_t
+metaslab_block_alloc(metaslab_t *msp, uint64_t size)
+{
+       uint64_t start;
+       range_tree_t *rt = msp->ms_tree;
+
+       VERIFY(!msp->ms_condensing);
+
+       start = msp->ms_ops->msop_alloc(msp, size);
+       if (start != -1ULL) {
+               vdev_t *vd = msp->ms_group->mg_vd;
+
+               VERIFY0(P2PHASE(start, 1ULL << vd->vdev_ashift));
+               VERIFY0(P2PHASE(size, 1ULL << vd->vdev_ashift));
+               VERIFY3U(range_tree_space(rt) - size, <=, msp->ms_size);
+               range_tree_remove(rt, start, size);
+       }
+       return (start);
+}
+
+/*
+ * ==========================================================================
+ * Common allocator routines
+ * ==========================================================================
+ */
+
+#if defined(WITH_FF_BLOCK_ALLOCATOR) || \
+    defined(WITH_DF_BLOCK_ALLOCATOR) || \
+    defined(WITH_CF_BLOCK_ALLOCATOR)
+/*
+ * This is a helper function that can be used by the allocator to find
+ * a suitable block to allocate. This will search the specified AVL
+ * tree looking for a block that matches the specified criteria.
+ */
+static uint64_t
+metaslab_block_picker(avl_tree_t *t, uint64_t *cursor, uint64_t size,
+    uint64_t align)
+{
+       range_seg_t *rs, rsearch;
+       avl_index_t where;
+
+       rsearch.rs_start = *cursor;
+       rsearch.rs_end = *cursor + size;
+
+       rs = avl_find(t, &rsearch, &where);
+       if (rs == NULL)
+               rs = avl_nearest(t, where, AVL_AFTER);
+
+       while (rs != NULL) {
+               uint64_t offset = P2ROUNDUP(rs->rs_start, align);
+
+               if (offset + size <= rs->rs_end) {
+                       *cursor = offset + size;
+                       return (offset);
+               }
+               rs = AVL_NEXT(t, rs);
+       }
+
+       /*
+        * If we know we've searched the whole map (*cursor == 0), give up.
+        * Otherwise, reset the cursor to the beginning and try again.
+        */
+       if (*cursor == 0)
+               return (-1ULL);
+
+       *cursor = 0;
+       return (metaslab_block_picker(t, cursor, size, align));
+}
+#endif /* WITH_FF/DF/CF_BLOCK_ALLOCATOR */
+
+#if defined(WITH_FF_BLOCK_ALLOCATOR)
+/*
+ * ==========================================================================
+ * The first-fit block allocator
+ * ==========================================================================
+ */
+static uint64_t
+metaslab_ff_alloc(metaslab_t *msp, uint64_t size)
+{
+       /*
+        * Find the largest power of 2 block size that evenly divides the
+        * requested size. This is used to try to allocate blocks with similar
+        * alignment from the same area of the metaslab (i.e. same cursor
+        * bucket) but it does not guarantee that other allocations sizes
+        * may exist in the same region.
+        */
+       uint64_t align = size & -size;
+       uint64_t *cursor = &msp->ms_lbas[highbit64(align) - 1];
+       avl_tree_t *t = &msp->ms_tree->rt_root;
+
+       return (metaslab_block_picker(t, cursor, size, align));
+}
+
+static metaslab_ops_t metaslab_ff_ops = {
+       metaslab_ff_alloc
+};
+
+metaslab_ops_t *zfs_metaslab_ops = &metaslab_ff_ops;
+#endif /* WITH_FF_BLOCK_ALLOCATOR */
+
+#if defined(WITH_DF_BLOCK_ALLOCATOR)
+/*
+ * ==========================================================================
+ * Dynamic block allocator -
+ * Uses the first fit allocation scheme until space get low and then
+ * adjusts to a best fit allocation method. Uses metaslab_df_alloc_threshold
+ * and metaslab_df_free_pct to determine when to switch the allocation scheme.
+ * ==========================================================================
+ */
+static uint64_t
+metaslab_df_alloc(metaslab_t *msp, uint64_t size)
+{
+       /*
+        * Find the largest power of 2 block size that evenly divides the
+        * requested size. This is used to try to allocate blocks with similar
+        * alignment from the same area of the metaslab (i.e. same cursor
+        * bucket) but it does not guarantee that other allocations sizes
+        * may exist in the same region.
+        */
+       uint64_t align = size & -size;
+       uint64_t *cursor = &msp->ms_lbas[highbit64(align) - 1];
+       range_tree_t *rt = msp->ms_tree;
+       avl_tree_t *t = &rt->rt_root;
+       uint64_t max_size = metaslab_block_maxsize(msp);
+       int free_pct = range_tree_space(rt) * 100 / msp->ms_size;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       ASSERT3U(avl_numnodes(t), ==, avl_numnodes(&msp->ms_size_tree));
+
+       if (max_size < size)
+               return (-1ULL);
+
+       /*
+        * If we're running low on space switch to using the size
+        * sorted AVL tree (best-fit).
+        */
+       if (max_size < metaslab_df_alloc_threshold ||
+           free_pct < metaslab_df_free_pct) {
+               t = &msp->ms_size_tree;
+               *cursor = 0;
+       }
+
+       return (metaslab_block_picker(t, cursor, size, 1ULL));
+}
+
+static metaslab_ops_t metaslab_df_ops = {
+       metaslab_df_alloc
+};
+
+metaslab_ops_t *zfs_metaslab_ops = &metaslab_df_ops;
+#endif /* WITH_DF_BLOCK_ALLOCATOR */
+
+#if defined(WITH_CF_BLOCK_ALLOCATOR)
+/*
+ * ==========================================================================
+ * Cursor fit block allocator -
+ * Select the largest region in the metaslab, set the cursor to the beginning
+ * of the range and the cursor_end to the end of the range. As allocations
+ * are made advance the cursor. Continue allocating from the cursor until
+ * the range is exhausted and then find a new range.
+ * ==========================================================================
+ */
+static uint64_t
+metaslab_cf_alloc(metaslab_t *msp, uint64_t size)
+{
+       range_tree_t *rt = msp->ms_tree;
+       avl_tree_t *t = &msp->ms_size_tree;
+       uint64_t *cursor = &msp->ms_lbas[0];
+       uint64_t *cursor_end = &msp->ms_lbas[1];
+       uint64_t offset = 0;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       ASSERT3U(avl_numnodes(t), ==, avl_numnodes(&rt->rt_root));
+
+       ASSERT3U(*cursor_end, >=, *cursor);
+
+       if ((*cursor + size) > *cursor_end) {
+               range_seg_t *rs;
+
+               rs = avl_last(&msp->ms_size_tree);
+               if (rs == NULL || (rs->rs_end - rs->rs_start) < size)
+                       return (-1ULL);
+
+               *cursor = rs->rs_start;
+               *cursor_end = rs->rs_end;
+       }
+
+       offset = *cursor;
+       *cursor += size;
+
+       return (offset);
+}
+
+static metaslab_ops_t metaslab_cf_ops = {
+       metaslab_cf_alloc
+};
+
+metaslab_ops_t *zfs_metaslab_ops = &metaslab_cf_ops;
+#endif /* WITH_CF_BLOCK_ALLOCATOR */
+
+#if defined(WITH_NDF_BLOCK_ALLOCATOR)
+/*
+ * ==========================================================================
+ * New dynamic fit allocator -
+ * Select a region that is large enough to allocate 2^metaslab_ndf_clump_shift
+ * contiguous blocks. If no region is found then just use the largest segment
+ * that remains.
+ * ==========================================================================
+ */
+
+/*
+ * Determines desired number of contiguous blocks (2^metaslab_ndf_clump_shift)
+ * to request from the allocator.
+ */
+uint64_t metaslab_ndf_clump_shift = 4;
+
+static uint64_t
+metaslab_ndf_alloc(metaslab_t *msp, uint64_t size)
+{
+       avl_tree_t *t = &msp->ms_tree->rt_root;
+       avl_index_t where;
+       range_seg_t *rs, rsearch;
+       uint64_t hbit = highbit64(size);
+       uint64_t *cursor = &msp->ms_lbas[hbit - 1];
+       uint64_t max_size = metaslab_block_maxsize(msp);
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       ASSERT3U(avl_numnodes(t), ==, avl_numnodes(&msp->ms_size_tree));
+
+       if (max_size < size)
+               return (-1ULL);
+
+       rsearch.rs_start = *cursor;
+       rsearch.rs_end = *cursor + size;
+
+       rs = avl_find(t, &rsearch, &where);
+       if (rs == NULL || (rs->rs_end - rs->rs_start) < size) {
+               t = &msp->ms_size_tree;
+
+               rsearch.rs_start = 0;
+               rsearch.rs_end = MIN(max_size,
+                   1ULL << (hbit + metaslab_ndf_clump_shift));
+               rs = avl_find(t, &rsearch, &where);
+               if (rs == NULL)
+                       rs = avl_nearest(t, where, AVL_AFTER);
+               ASSERT(rs != NULL);
+       }
+
+       if ((rs->rs_end - rs->rs_start) >= size) {
+               *cursor = rs->rs_start + size;
+               return (rs->rs_start);
+       }
+       return (-1ULL);
+}
+
+static metaslab_ops_t metaslab_ndf_ops = {
+       metaslab_ndf_alloc
+};
+
+metaslab_ops_t *zfs_metaslab_ops = &metaslab_ndf_ops;
+#endif /* WITH_NDF_BLOCK_ALLOCATOR */
+
+
+/*
+ * ==========================================================================
+ * Metaslabs
+ * ==========================================================================
+ */
+
+/*
+ * Wait for any in-progress metaslab loads to complete.
+ */
+void
+metaslab_load_wait(metaslab_t *msp)
+{
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+
+       while (msp->ms_loading) {
+               ASSERT(!msp->ms_loaded);
+               cv_wait(&msp->ms_load_cv, &msp->ms_lock);
+       }
+}
+
+int
+metaslab_load(metaslab_t *msp)
+{
+       int error = 0;
+       int t;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       ASSERT(!msp->ms_loaded);
+       ASSERT(!msp->ms_loading);
+
+       msp->ms_loading = B_TRUE;
+
+       /*
+        * If the space map has not been allocated yet, then treat
+        * all the space in the metaslab as free and add it to the
+        * ms_tree.
+        */
+       if (msp->ms_sm != NULL)
+               error = space_map_load(msp->ms_sm, msp->ms_tree, SM_FREE);
+       else
+               range_tree_add(msp->ms_tree, msp->ms_start, msp->ms_size);
+
+       msp->ms_loaded = (error == 0);
+       msp->ms_loading = B_FALSE;
+
+       if (msp->ms_loaded) {
+               for (t = 0; t < TXG_DEFER_SIZE; t++) {
+                       range_tree_walk(msp->ms_defertree[t],
+                           range_tree_remove, msp->ms_tree);
+               }
+       }
+       cv_broadcast(&msp->ms_load_cv);
+       return (error);
+}
+
+void
+metaslab_unload(metaslab_t *msp)
+{
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       range_tree_vacate(msp->ms_tree, NULL, NULL);
+       msp->ms_loaded = B_FALSE;
+       msp->ms_weight &= ~METASLAB_ACTIVE_MASK;
+}
+
+int
+metaslab_init(metaslab_group_t *mg, uint64_t id, uint64_t object, uint64_t txg,
+    metaslab_t **msp)
+{
+       vdev_t *vd = mg->mg_vd;
+       objset_t *mos = vd->vdev_spa->spa_meta_objset;
+       metaslab_t *ms;
+       int error;
+
+       ms = kmem_zalloc(sizeof (metaslab_t), KM_SLEEP);
+       mutex_init(&ms->ms_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&ms->ms_load_cv, NULL, CV_DEFAULT, NULL);
+       ms->ms_id = id;
+       ms->ms_start = id << vd->vdev_ms_shift;
+       ms->ms_size = 1ULL << vd->vdev_ms_shift;
+
+       /*
+        * We only open space map objects that already exist. All others
+        * will be opened when we finally allocate an object for it.
+        */
+       if (object != 0) {
+               error = space_map_open(&ms->ms_sm, mos, object, ms->ms_start,
+                   ms->ms_size, vd->vdev_ashift, &ms->ms_lock);
+
+               if (error != 0) {
+                       kmem_free(ms, sizeof (metaslab_t));
+                       return (error);
+               }
+
+               ASSERT(ms->ms_sm != NULL);
+       }
+
+       /*
+        * We create the main range tree here, but we don't create the
+        * alloctree and freetree until metaslab_sync_done().  This serves
+        * two purposes: it allows metaslab_sync_done() to detect the
+        * addition of new space; and for debugging, it ensures that we'd
+        * data fault on any attempt to use this metaslab before it's ready.
+        */
+       ms->ms_tree = range_tree_create(&metaslab_rt_ops, ms, &ms->ms_lock);
+       metaslab_group_add(mg, ms);
+
+       ms->ms_fragmentation = metaslab_fragmentation(ms);
+       ms->ms_ops = mg->mg_class->mc_ops;
+
+       /*
+        * If we're opening an existing pool (txg == 0) or creating
+        * a new one (txg == TXG_INITIAL), all space is available now.
+        * If we're adding space to an existing pool, the new space
+        * does not become available until after this txg has synced.
+        */
+       if (txg <= TXG_INITIAL)
+               metaslab_sync_done(ms, 0);
+
+       /*
+        * If metaslab_debug_load is set and we're initializing a metaslab
+        * that has an allocated space_map object then load the its space
+        * map so that can verify frees.
+        */
+       if (metaslab_debug_load && ms->ms_sm != NULL) {
+               mutex_enter(&ms->ms_lock);
+               VERIFY0(metaslab_load(ms));
+               mutex_exit(&ms->ms_lock);
+       }
+
+       if (txg != 0) {
+               vdev_dirty(vd, 0, NULL, txg);
+               vdev_dirty(vd, VDD_METASLAB, ms, txg);
+       }
+
+       *msp = ms;
+
+       return (0);
+}
+
+void
+metaslab_fini(metaslab_t *msp)
+{
+       int t;
+
+       metaslab_group_t *mg = msp->ms_group;
+
+       metaslab_group_remove(mg, msp);
+
+       mutex_enter(&msp->ms_lock);
+
+       VERIFY(msp->ms_group == NULL);
+       vdev_space_update(mg->mg_vd, -space_map_allocated(msp->ms_sm),
+           0, -msp->ms_size);
+       space_map_close(msp->ms_sm);
+
+       metaslab_unload(msp);
+       range_tree_destroy(msp->ms_tree);
+
+       for (t = 0; t < TXG_SIZE; t++) {
+               range_tree_destroy(msp->ms_alloctree[t]);
+               range_tree_destroy(msp->ms_freetree[t]);
+       }
+
+       for (t = 0; t < TXG_DEFER_SIZE; t++) {
+               range_tree_destroy(msp->ms_defertree[t]);
+       }
+
+       ASSERT0(msp->ms_deferspace);
+
+       mutex_exit(&msp->ms_lock);
+       cv_destroy(&msp->ms_load_cv);
+       mutex_destroy(&msp->ms_lock);
+
+       kmem_free(msp, sizeof (metaslab_t));
+}
+
+#define        FRAGMENTATION_TABLE_SIZE        17
+
+/*
+ * This table defines a segment size based fragmentation metric that will
+ * allow each metaslab to derive its own fragmentation value. This is done
+ * by calculating the space in each bucket of the spacemap histogram and
+ * multiplying that by the fragmetation metric in this table. Doing
+ * this for all buckets and dividing it by the total amount of free
+ * space in this metaslab (i.e. the total free space in all buckets) gives
+ * us the fragmentation metric. This means that a high fragmentation metric
+ * equates to most of the free space being comprised of small segments.
+ * Conversely, if the metric is low, then most of the free space is in
+ * large segments. A 10% change in fragmentation equates to approximately
+ * double the number of segments.
+ *
+ * This table defines 0% fragmented space using 16MB segments. Testing has
+ * shown that segments that are greater than or equal to 16MB do not suffer
+ * from drastic performance problems. Using this value, we derive the rest
+ * of the table. Since the fragmentation value is never stored on disk, it
+ * is possible to change these calculations in the future.
+ */
+int zfs_frag_table[FRAGMENTATION_TABLE_SIZE] = {
+       100,    /* 512B */
+       100,    /* 1K   */
+       98,     /* 2K   */
+       95,     /* 4K   */
+       90,     /* 8K   */
+       80,     /* 16K  */
+       70,     /* 32K  */
+       60,     /* 64K  */
+       50,     /* 128K */
+       40,     /* 256K */
+       30,     /* 512K */
+       20,     /* 1M   */
+       15,     /* 2M   */
+       10,     /* 4M   */
+       5,      /* 8M   */
+       0       /* 16M  */
+};
+
+/*
+ * Calclate the metaslab's fragmentation metric. A return value
+ * of ZFS_FRAG_INVALID means that the metaslab has not been upgraded and does
+ * not support this metric. Otherwise, the return value should be in the
+ * range [0, 100].
+ */
+static uint64_t
+metaslab_fragmentation(metaslab_t *msp)
+{
+       spa_t *spa = msp->ms_group->mg_vd->vdev_spa;
+       uint64_t fragmentation = 0;
+       uint64_t total = 0;
+       boolean_t feature_enabled = spa_feature_is_enabled(spa,
+           SPA_FEATURE_SPACEMAP_HISTOGRAM);
+       int i;
+
+       if (!feature_enabled)
+               return (ZFS_FRAG_INVALID);
+
+       /*
+        * A null space map means that the entire metaslab is free
+        * and thus is not fragmented.
+        */
+       if (msp->ms_sm == NULL)
+               return (0);
+
+       /*
+        * If this metaslab's space_map has not been upgraded, flag it
+        * so that we upgrade next time we encounter it.
+        */
+       if (msp->ms_sm->sm_dbuf->db_size != sizeof (space_map_phys_t)) {
+               vdev_t *vd = msp->ms_group->mg_vd;
+
+               if (spa_writeable(vd->vdev_spa)) {
+                       uint64_t txg = spa_syncing_txg(spa);
+
+                       msp->ms_condense_wanted = B_TRUE;
+                       vdev_dirty(vd, VDD_METASLAB, msp, txg + 1);
+                       spa_dbgmsg(spa, "txg %llu, requesting force condense: "
+                           "msp %p, vd %p", txg, msp, vd);
+               }
+               return (ZFS_FRAG_INVALID);
+       }
+
+       for (i = 0; i < SPACE_MAP_HISTOGRAM_SIZE; i++) {
+               uint64_t space = 0;
+               uint8_t shift = msp->ms_sm->sm_shift;
+               int idx = MIN(shift - SPA_MINBLOCKSHIFT + i,
+                   FRAGMENTATION_TABLE_SIZE - 1);
+
+               if (msp->ms_sm->sm_phys->smp_histogram[i] == 0)
+                       continue;
+
+               space = msp->ms_sm->sm_phys->smp_histogram[i] << (i + shift);
+               total += space;
+
+               ASSERT3U(idx, <, FRAGMENTATION_TABLE_SIZE);
+               fragmentation += space * zfs_frag_table[idx];
+       }
+
+       if (total > 0)
+               fragmentation /= total;
+       ASSERT3U(fragmentation, <=, 100);
+       return (fragmentation);
+}
+
+/*
+ * Compute a weight -- a selection preference value -- for the given metaslab.
+ * This is based on the amount of free space, the level of fragmentation,
+ * the LBA range, and whether the metaslab is loaded.
+ */
+static uint64_t
+metaslab_weight(metaslab_t *msp)
+{
+       metaslab_group_t *mg = msp->ms_group;
+       vdev_t *vd = mg->mg_vd;
+       uint64_t weight, space;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+
+       /*
+        * This vdev is in the process of being removed so there is nothing
+        * for us to do here.
+        */
+       if (vd->vdev_removing) {
+               ASSERT0(space_map_allocated(msp->ms_sm));
+               ASSERT0(vd->vdev_ms_shift);
+               return (0);
+       }
+
+       /*
+        * The baseline weight is the metaslab's free space.
+        */
+       space = msp->ms_size - space_map_allocated(msp->ms_sm);
+
+       msp->ms_fragmentation = metaslab_fragmentation(msp);
+       if (metaslab_fragmentation_factor_enabled &&
+           msp->ms_fragmentation != ZFS_FRAG_INVALID) {
+               /*
+                * Use the fragmentation information to inversely scale
+                * down the baseline weight. We need to ensure that we
+                * don't exclude this metaslab completely when it's 100%
+                * fragmented. To avoid this we reduce the fragmented value
+                * by 1.
+                */
+               space = (space * (100 - (msp->ms_fragmentation - 1))) / 100;
+
+               /*
+                * If space < SPA_MINBLOCKSIZE, then we will not allocate from
+                * this metaslab again. The fragmentation metric may have
+                * decreased the space to something smaller than
+                * SPA_MINBLOCKSIZE, so reset the space to SPA_MINBLOCKSIZE
+                * so that we can consume any remaining space.
+                */
+               if (space > 0 && space < SPA_MINBLOCKSIZE)
+                       space = SPA_MINBLOCKSIZE;
+       }
+       weight = space;
+
+       /*
+        * Modern disks have uniform bit density and constant angular velocity.
+        * Therefore, the outer recording zones are faster (higher bandwidth)
+        * than the inner zones by the ratio of outer to inner track diameter,
+        * which is typically around 2:1.  We account for this by assigning
+        * higher weight to lower metaslabs (multiplier ranging from 2x to 1x).
+        * In effect, this means that we'll select the metaslab with the most
+        * free bandwidth rather than simply the one with the most free space.
+        */
+       if (!vd->vdev_nonrot && metaslab_lba_weighting_enabled) {
+               weight = 2 * weight - (msp->ms_id * weight) / vd->vdev_ms_count;
+               ASSERT(weight >= space && weight <= 2 * space);
+       }
+
+       /*
+        * If this metaslab is one we're actively using, adjust its
+        * weight to make it preferable to any inactive metaslab so
+        * we'll polish it off. If the fragmentation on this metaslab
+        * has exceed our threshold, then don't mark it active.
+        */
+       if (msp->ms_loaded && msp->ms_fragmentation != ZFS_FRAG_INVALID &&
+           msp->ms_fragmentation <= zfs_metaslab_fragmentation_threshold) {
+               weight |= (msp->ms_weight & METASLAB_ACTIVE_MASK);
+       }
+
+       return (weight);
+}
+
+static int
+metaslab_activate(metaslab_t *msp, uint64_t activation_weight)
+{
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+
+       if ((msp->ms_weight & METASLAB_ACTIVE_MASK) == 0) {
+               metaslab_load_wait(msp);
+               if (!msp->ms_loaded) {
+                       int error = metaslab_load(msp);
+                       if (error) {
+                               metaslab_group_sort(msp->ms_group, msp, 0);
+                               return (error);
+                       }
+               }
+
+               metaslab_group_sort(msp->ms_group, msp,
+                   msp->ms_weight | activation_weight);
+       }
+       ASSERT(msp->ms_loaded);
+       ASSERT(msp->ms_weight & METASLAB_ACTIVE_MASK);
+
+       return (0);
+}
+
+static void
+metaslab_passivate(metaslab_t *msp, uint64_t size)
+{
+       /*
+        * If size < SPA_MINBLOCKSIZE, then we will not allocate from
+        * this metaslab again.  In that case, it had better be empty,
+        * or we would be leaving space on the table.
+        */
+       ASSERT(size >= SPA_MINBLOCKSIZE || range_tree_space(msp->ms_tree) == 0);
+       metaslab_group_sort(msp->ms_group, msp, MIN(msp->ms_weight, size));
+       ASSERT((msp->ms_weight & METASLAB_ACTIVE_MASK) == 0);
+}
+
+static void
+metaslab_preload(void *arg)
+{
+       metaslab_t *msp = arg;
+       spa_t *spa = msp->ms_group->mg_vd->vdev_spa;
+       fstrans_cookie_t cookie = spl_fstrans_mark();
+
+       ASSERT(!MUTEX_HELD(&msp->ms_group->mg_lock));
+
+       mutex_enter(&msp->ms_lock);
+       metaslab_load_wait(msp);
+       if (!msp->ms_loaded)
+               (void) metaslab_load(msp);
+
+       /*
+        * Set the ms_access_txg value so that we don't unload it right away.
+        */
+       msp->ms_access_txg = spa_syncing_txg(spa) + metaslab_unload_delay + 1;
+       mutex_exit(&msp->ms_lock);
+       spl_fstrans_unmark(cookie);
+}
+
+static void
+metaslab_group_preload(metaslab_group_t *mg)
+{
+       spa_t *spa = mg->mg_vd->vdev_spa;
+       metaslab_t *msp;
+       avl_tree_t *t = &mg->mg_metaslab_tree;
+       int m = 0;
+
+       if (spa_shutting_down(spa) || !metaslab_preload_enabled) {
+               taskq_wait_outstanding(mg->mg_taskq, 0);
+               return;
+       }
+
+       mutex_enter(&mg->mg_lock);
+       /*
+        * Load the next potential metaslabs
+        */
+       msp = avl_first(t);
+       while (msp != NULL) {
+               metaslab_t *msp_next = AVL_NEXT(t, msp);
+
+               /*
+                * We preload only the maximum number of metaslabs specified
+                * by metaslab_preload_limit. If a metaslab is being forced
+                * to condense then we preload it too. This will ensure
+                * that force condensing happens in the next txg.
+                */
+               if (++m > metaslab_preload_limit && !msp->ms_condense_wanted) {
+                       msp = msp_next;
+                       continue;
+               }
+
+               /*
+                * We must drop the metaslab group lock here to preserve
+                * lock ordering with the ms_lock (when grabbing both
+                * the mg_lock and the ms_lock, the ms_lock must be taken
+                * first).  As a result, it is possible that the ordering
+                * of the metaslabs within the avl tree may change before
+                * we reacquire the lock. The metaslab cannot be removed from
+                * the tree while we're in syncing context so it is safe to
+                * drop the mg_lock here. If the metaslabs are reordered
+                * nothing will break -- we just may end up loading a
+                * less than optimal one.
+                */
+               mutex_exit(&mg->mg_lock);
+               VERIFY(taskq_dispatch(mg->mg_taskq, metaslab_preload,
+                   msp, TQ_SLEEP) != 0);
+               mutex_enter(&mg->mg_lock);
+               msp = msp_next;
+       }
+       mutex_exit(&mg->mg_lock);
+}
+
+/*
+ * Determine if the space map's on-disk footprint is past our tolerance
+ * for inefficiency. We would like to use the following criteria to make
+ * our decision:
+ *
+ * 1. The size of the space map object should not dramatically increase as a
+ * result of writing out the free space range tree.
+ *
+ * 2. The minimal on-disk space map representation is zfs_condense_pct/100
+ * times the size than the free space range tree representation
+ * (i.e. zfs_condense_pct = 110 and in-core = 1MB, minimal = 1.1.MB).
+ *
+ * 3. The on-disk size of the space map should actually decrease.
+ *
+ * Checking the first condition is tricky since we don't want to walk
+ * the entire AVL tree calculating the estimated on-disk size. Instead we
+ * use the size-ordered range tree in the metaslab and calculate the
+ * size required to write out the largest segment in our free tree. If the
+ * size required to represent that segment on disk is larger than the space
+ * map object then we avoid condensing this map.
+ *
+ * To determine the second criterion we use a best-case estimate and assume
+ * each segment can be represented on-disk as a single 64-bit entry. We refer
+ * to this best-case estimate as the space map's minimal form.
+ *
+ * Unfortunately, we cannot compute the on-disk size of the space map in this
+ * context because we cannot accurately compute the effects of compression, etc.
+ * Instead, we apply the heuristic described in the block comment for
+ * zfs_metaslab_condense_block_threshold - we only condense if the space used
+ * is greater than a threshold number of blocks.
+ */
+static boolean_t
+metaslab_should_condense(metaslab_t *msp)
+{
+       space_map_t *sm = msp->ms_sm;
+       range_seg_t *rs;
+       uint64_t size, entries, segsz, object_size, optimal_size, record_size;
+       dmu_object_info_t doi;
+       uint64_t vdev_blocksize = 1 << msp->ms_group->mg_vd->vdev_ashift;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       ASSERT(msp->ms_loaded);
+
+       /*
+        * Use the ms_size_tree range tree, which is ordered by size, to
+        * obtain the largest segment in the free tree. We always condense
+        * metaslabs that are empty and metaslabs for which a condense
+        * request has been made.
+        */
+       rs = avl_last(&msp->ms_size_tree);
+       if (rs == NULL || msp->ms_condense_wanted)
+               return (B_TRUE);
+
+       /*
+        * Calculate the number of 64-bit entries this segment would
+        * require when written to disk. If this single segment would be
+        * larger on-disk than the entire current on-disk structure, then
+        * clearly condensing will increase the on-disk structure size.
+        */
+       size = (rs->rs_end - rs->rs_start) >> sm->sm_shift;
+       entries = size / (MIN(size, SM_RUN_MAX));
+       segsz = entries * sizeof (uint64_t);
+
+       optimal_size = sizeof (uint64_t) * avl_numnodes(&msp->ms_tree->rt_root);
+       object_size = space_map_length(msp->ms_sm);
+
+       dmu_object_info_from_db(sm->sm_dbuf, &doi);
+       record_size = MAX(doi.doi_data_block_size, vdev_blocksize);
+
+       return (segsz <= object_size &&
+           object_size >= (optimal_size * zfs_condense_pct / 100) &&
+           object_size > zfs_metaslab_condense_block_threshold * record_size);
+}
+
+/*
+ * Condense the on-disk space map representation to its minimized form.
+ * The minimized form consists of a small number of allocations followed by
+ * the entries of the free range tree.
+ */
+static void
+metaslab_condense(metaslab_t *msp, uint64_t txg, dmu_tx_t *tx)
+{
+       spa_t *spa = msp->ms_group->mg_vd->vdev_spa;
+       range_tree_t *freetree = msp->ms_freetree[txg & TXG_MASK];
+       range_tree_t *condense_tree;
+       space_map_t *sm = msp->ms_sm;
+       int t;
+
+       ASSERT(MUTEX_HELD(&msp->ms_lock));
+       ASSERT3U(spa_sync_pass(spa), ==, 1);
+       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),
+           msp->ms_condense_wanted ? "TRUE" : "FALSE");
+
+       msp->ms_condense_wanted = B_FALSE;
+
+       /*
+        * Create an range tree that is 100% allocated. We remove segments
+        * that have been freed in this txg, any deferred frees that exist,
+        * and any allocation in the future. Removing segments should be
+        * a relatively inexpensive operation since we expect these trees to
+        * have a small number of nodes.
+        */
+       condense_tree = range_tree_create(NULL, NULL, &msp->ms_lock);
+       range_tree_add(condense_tree, msp->ms_start, msp->ms_size);
+
+       /*
+        * Remove what's been freed in this txg from the condense_tree.
+        * Since we're in sync_pass 1, we know that all the frees from
+        * this txg are in the freetree.
+        */
+       range_tree_walk(freetree, range_tree_remove, condense_tree);
+
+       for (t = 0; t < TXG_DEFER_SIZE; t++) {
+               range_tree_walk(msp->ms_defertree[t],
+                   range_tree_remove, condense_tree);
+       }
+
+       for (t = 1; t < TXG_CONCURRENT_STATES; t++) {
+               range_tree_walk(msp->ms_alloctree[(txg + t) & TXG_MASK],
+                   range_tree_remove, condense_tree);
+       }
+
+       /*
+        * We're about to drop the metaslab's lock thus allowing
+        * other consumers to change it's content. Set the
+        * metaslab's ms_condensing flag to ensure that
+        * allocations on this metaslab do not occur while we're
+        * in the middle of committing it to disk. This is only critical
+        * for the ms_tree as all other range trees use per txg
+        * views of their content.
+        */
+       msp->ms_condensing = B_TRUE;
+
+       mutex_exit(&msp->ms_lock);
+       space_map_truncate(sm, tx);
+       mutex_enter(&msp->ms_lock);
+
+       /*
+        * While we would ideally like to create a space_map representation
+        * that consists only of allocation records, doing so can be
+        * prohibitively expensive because the in-core free tree can be
+        * large, and therefore computationally expensive to subtract
+        * from the condense_tree. Instead we sync out two trees, a cheap
+        * allocation only tree followed by the in-core free tree. While not
+        * optimal, this is typically close to optimal, and much cheaper to
+        * compute.
+        */
+       space_map_write(sm, condense_tree, SM_ALLOC, tx);
+       range_tree_vacate(condense_tree, NULL, NULL);
+       range_tree_destroy(condense_tree);
+
+       space_map_write(sm, msp->ms_tree, SM_FREE, tx);
+       msp->ms_condensing = B_FALSE;
+}
+
+/*
+ * Write a metaslab to disk in the context of the specified transaction group.
+ */
+void
+metaslab_sync(metaslab_t *msp, uint64_t txg)
+{
+       metaslab_group_t *mg = msp->ms_group;
+       vdev_t *vd = mg->mg_vd;
+       spa_t *spa = vd->vdev_spa;
+       objset_t *mos = spa_meta_objset(spa);
+       range_tree_t *alloctree = msp->ms_alloctree[txg & TXG_MASK];
+       range_tree_t **freetree = &msp->ms_freetree[txg & TXG_MASK];
+       range_tree_t **freed_tree =
+           &msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK];
+       dmu_tx_t *tx;
+       uint64_t object = space_map_object(msp->ms_sm);
+
+       ASSERT(!vd->vdev_ishole);
+
+       /*
+        * This metaslab has just been added so there's no work to do now.
+        */
+       if (*freetree == NULL) {
+               ASSERT3P(alloctree, ==, NULL);
+               return;
+       }
+
+       ASSERT3P(alloctree, !=, NULL);
+       ASSERT3P(*freetree, !=, NULL);
+       ASSERT3P(*freed_tree, !=, NULL);
+
+       /*
+        * Normally, we don't want to process a metaslab if there
+        * are no allocations or frees to perform. However, if the metaslab
+        * is being forced to condense we need to let it through.
+        */
+       if (range_tree_space(alloctree) == 0 &&
+           range_tree_space(*freetree) == 0 &&
+           !msp->ms_condense_wanted)
+               return;
+
+       /*
+        * The only state that can actually be changing concurrently with
+        * metaslab_sync() is the metaslab's ms_tree.  No other thread can
+        * be modifying this txg's alloctree, freetree, freed_tree, or
+        * space_map_phys_t. Therefore, we only hold ms_lock to satify
+        * space_map ASSERTs. We drop it whenever we call into the DMU,
+        * because the DMU can call down to us (e.g. via zio_free()) at
+        * any time.
+        */
+
+       tx = dmu_tx_create_assigned(spa_get_dsl(spa), txg);
+
+       if (msp->ms_sm == NULL) {
+               uint64_t new_object;
+
+               new_object = space_map_alloc(mos, tx);
+               VERIFY3U(new_object, !=, 0);
+
+               VERIFY0(space_map_open(&msp->ms_sm, mos, new_object,
+                   msp->ms_start, msp->ms_size, vd->vdev_ashift,
+                   &msp->ms_lock));
+               ASSERT(msp->ms_sm != NULL);
+       }
+
+       mutex_enter(&msp->ms_lock);
+
+       /*
+        * Note: metaslab_condense() clears the space_map's histogram.
+        * Therefore we muse verify and remove this histogram before
+        * condensing.
+        */
+       metaslab_group_histogram_verify(mg);
+       metaslab_class_histogram_verify(mg->mg_class);
+       metaslab_group_histogram_remove(mg, msp);
+
+       if (msp->ms_loaded && spa_sync_pass(spa) == 1 &&
+           metaslab_should_condense(msp)) {
+               metaslab_condense(msp, txg, tx);
+       } else {
+               space_map_write(msp->ms_sm, alloctree, SM_ALLOC, tx);
+               space_map_write(msp->ms_sm, *freetree, SM_FREE, tx);
+       }
+
+       if (msp->ms_loaded) {
+               /*
+                * When the space map is loaded, we have an accruate
+                * histogram in the range tree. This gives us an opportunity
+                * to bring the space map's histogram up-to-date so we clear
+                * it first before updating it.
+                */
+               space_map_histogram_clear(msp->ms_sm);
+               space_map_histogram_add(msp->ms_sm, msp->ms_tree, tx);
+       } else {
+               /*
+                * Since the space map is not loaded we simply update the
+                * exisiting histogram with what was freed in this txg. This
+                * means that the on-disk histogram may not have an accurate
+                * view of the free space but it's close enough to allow
+                * us to make allocation decisions.
+                */
+               space_map_histogram_add(msp->ms_sm, *freetree, tx);
+       }
+       metaslab_group_histogram_add(mg, msp);
+       metaslab_group_histogram_verify(mg);
+       metaslab_class_histogram_verify(mg->mg_class);
+
+       /*
+        * For sync pass 1, we avoid traversing this txg's free range tree
+        * and instead will just swap the pointers for freetree and
+        * freed_tree. We can safely do this since the freed_tree is
+        * guaranteed to be empty on the initial pass.
+        */
+       if (spa_sync_pass(spa) == 1) {
+               range_tree_swap(freetree, freed_tree);
+       } else {
+               range_tree_vacate(*freetree, range_tree_add, *freed_tree);
+       }
+       range_tree_vacate(alloctree, NULL, NULL);
+
+       ASSERT0(range_tree_space(msp->ms_alloctree[txg & TXG_MASK]));
+       ASSERT0(range_tree_space(msp->ms_freetree[txg & TXG_MASK]));
+
+       mutex_exit(&msp->ms_lock);
+
+       if (object != space_map_object(msp->ms_sm)) {
+               object = space_map_object(msp->ms_sm);
+               dmu_write(mos, vd->vdev_ms_array, sizeof (uint64_t) *
+                   msp->ms_id, sizeof (uint64_t), &object, tx);
+       }
+       dmu_tx_commit(tx);
+}
+
+/*
+ * Called after a transaction group has completely synced to mark
+ * all of the metaslab's free space as usable.
+ */
+void
+metaslab_sync_done(metaslab_t *msp, uint64_t txg)
+{
+       metaslab_group_t *mg = msp->ms_group;
+       vdev_t *vd = mg->mg_vd;
+       range_tree_t **freed_tree;
+       range_tree_t **defer_tree;
+       int64_t alloc_delta, defer_delta;
+       int t;
+
+       ASSERT(!vd->vdev_ishole);
+
+       mutex_enter(&msp->ms_lock);
+
+       /*
+        * If this metaslab is just becoming available, initialize its
+        * alloctrees, freetrees, and defertree and add its capacity to
+        * the vdev.
+        */
+       if (msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK] == NULL) {
+               for (t = 0; t < TXG_SIZE; t++) {
+                       ASSERT(msp->ms_alloctree[t] == NULL);
+                       ASSERT(msp->ms_freetree[t] == NULL);
+
+                       msp->ms_alloctree[t] = range_tree_create(NULL, msp,
+                           &msp->ms_lock);
+                       msp->ms_freetree[t] = range_tree_create(NULL, msp,
+                           &msp->ms_lock);
+               }
+
+               for (t = 0; t < TXG_DEFER_SIZE; t++) {
+                       ASSERT(msp->ms_defertree[t] == NULL);
+
+                       msp->ms_defertree[t] = range_tree_create(NULL, msp,
+                           &msp->ms_lock);
+               }
+
+               vdev_space_update(vd, 0, 0, msp->ms_size);
+       }
+
+       freed_tree = &msp->ms_freetree[TXG_CLEAN(txg) & TXG_MASK];
+       defer_tree = &msp->ms_defertree[txg % TXG_DEFER_SIZE];
+
+       alloc_delta = space_map_alloc_delta(msp->ms_sm);
+       defer_delta = range_tree_space(*freed_tree) -
+           range_tree_space(*defer_tree);
+
+       vdev_space_update(vd, alloc_delta + defer_delta, defer_delta, 0);
+
+       ASSERT0(range_tree_space(msp->ms_alloctree[txg & TXG_MASK]));
+       ASSERT0(range_tree_space(msp->ms_freetree[txg & TXG_MASK]));
+
+       /*
+        * If there's a metaslab_load() in progress, wait for it to complete
+        * so that we have a consistent view of the in-core space map.
+        */
+       metaslab_load_wait(msp);
+
+       /*
+        * Move the frees from the defer_tree back to the free
+        * range tree (if it's loaded). Swap the freed_tree and the
+        * defer_tree -- this is safe to do because we've just emptied out
+        * the defer_tree.
+        */
+       range_tree_vacate(*defer_tree,
+           msp->ms_loaded ? range_tree_add : NULL, msp->ms_tree);
+       range_tree_swap(freed_tree, defer_tree);
+
+       space_map_update(msp->ms_sm);
+
+       msp->ms_deferspace += defer_delta;
+       ASSERT3S(msp->ms_deferspace, >=, 0);
+       ASSERT3S(msp->ms_deferspace, <=, msp->ms_size);
+       if (msp->ms_deferspace != 0) {
+               /*
+                * Keep syncing this metaslab until all deferred frees
+                * are back in circulation.
+                */
+               vdev_dirty(vd, VDD_METASLAB, msp, txg + 1);
+       }
+
+       if (msp->ms_loaded && msp->ms_access_txg < txg) {
+               for (t = 1; t < TXG_CONCURRENT_STATES; t++) {
+                       VERIFY0(range_tree_space(
+                           msp->ms_alloctree[(txg + t) & TXG_MASK]));
+               }
+
+               if (!metaslab_debug_unload)
+                       metaslab_unload(msp);
+       }
+
+       metaslab_group_sort(mg, msp, metaslab_weight(msp));
+       mutex_exit(&msp->ms_lock);
+}
+
+void
+metaslab_sync_reassess(metaslab_group_t *mg)
+{
+       metaslab_group_alloc_update(mg);
+       mg->mg_fragmentation = metaslab_group_fragmentation(mg);
+
+       /*
+        * Preload the next potential metaslabs
+        */
+       metaslab_group_preload(mg);
+}
+
+static uint64_t
+metaslab_distance(metaslab_t *msp, dva_t *dva)
+{
+       uint64_t ms_shift = msp->ms_group->mg_vd->vdev_ms_shift;
+       uint64_t offset = DVA_GET_OFFSET(dva) >> ms_shift;
+       uint64_t start = msp->ms_id;
+
+       if (msp->ms_group->mg_vd->vdev_id != DVA_GET_VDEV(dva))
+               return (1ULL << 63);
+
+       if (offset < start)
+               return ((start - offset) << ms_shift);
+       if (offset > start)
+               return ((offset - start) << ms_shift);
+       return (0);
+}
+
+static uint64_t
+metaslab_group_alloc(metaslab_group_t *mg, uint64_t psize, uint64_t asize,
+    uint64_t txg, uint64_t min_distance, dva_t *dva, int d)
+{
+       spa_t *spa = mg->mg_vd->vdev_spa;
+       metaslab_t *msp = NULL;
+       uint64_t offset = -1ULL;
+       avl_tree_t *t = &mg->mg_metaslab_tree;
+       uint64_t activation_weight;
+       uint64_t target_distance;
+       int i;
+
+       activation_weight = METASLAB_WEIGHT_PRIMARY;
+       for (i = 0; i < d; i++) {
+               if (DVA_GET_VDEV(&dva[i]) == mg->mg_vd->vdev_id) {
+                       activation_weight = METASLAB_WEIGHT_SECONDARY;
+                       break;
+               }
+       }
+
+       for (;;) {
+               boolean_t was_active;
+
+               mutex_enter(&mg->mg_lock);
+               for (msp = avl_first(t); msp; msp = AVL_NEXT(t, msp)) {
+                       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, "
+                                   "weight %llu", spa_name(spa),
+                                   mg->mg_vd->vdev_id, txg,
+                                   mg, msp, psize, asize, msp->ms_weight);
+                               mutex_exit(&mg->mg_lock);
+                               return (-1ULL);
+                       }
+
+                       /*
+                        * If the selected metaslab is condensing, skip it.
+                        */
+                       if (msp->ms_condensing)
+                               continue;
+
+                       was_active = msp->ms_weight & METASLAB_ACTIVE_MASK;
+                       if (activation_weight == METASLAB_WEIGHT_PRIMARY)
+                               break;
+
+                       target_distance = min_distance +
+                           (space_map_allocated(msp->ms_sm) != 0 ? 0 :
+                           min_distance >> 1);
+
+                       for (i = 0; i < d; i++)
+                               if (metaslab_distance(msp, &dva[i]) <
+                                   target_distance)
+                                       break;
+                       if (i == d)
+                               break;
+               }
+               mutex_exit(&mg->mg_lock);
+               if (msp == NULL)
+                       return (-1ULL);
+
+               mutex_enter(&msp->ms_lock);
+
+               /*
+                * Ensure that the metaslab we have selected is still
+                * capable of handling our request. It's possible that
+                * another thread may have changed the weight while we
+                * were blocked on the metaslab lock.
+                */
+               if (msp->ms_weight < asize || (was_active &&
+                   !(msp->ms_weight & METASLAB_ACTIVE_MASK) &&
+                   activation_weight == METASLAB_WEIGHT_PRIMARY)) {
+                       mutex_exit(&msp->ms_lock);
+                       continue;
+               }
+
+               if ((msp->ms_weight & METASLAB_WEIGHT_SECONDARY) &&
+                   activation_weight == METASLAB_WEIGHT_PRIMARY) {
+                       metaslab_passivate(msp,
+                           msp->ms_weight & ~METASLAB_ACTIVE_MASK);
+                       mutex_exit(&msp->ms_lock);
+                       continue;
+               }
+
+               if (metaslab_activate(msp, activation_weight) != 0) {
+                       mutex_exit(&msp->ms_lock);
+                       continue;
+               }
+
+               /*
+                * If this metaslab is currently condensing then pick again as
+                * we can't manipulate this metaslab until it's committed
+                * to disk.
+                */
+               if (msp->ms_condensing) {
+                       mutex_exit(&msp->ms_lock);
+                       continue;
+               }
+
+               if ((offset = metaslab_block_alloc(msp, asize)) != -1ULL)
+                       break;
+
+               metaslab_passivate(msp, metaslab_block_maxsize(msp));
+               mutex_exit(&msp->ms_lock);
+       }
+
+       if (range_tree_space(msp->ms_alloctree[txg & TXG_MASK]) == 0)
+               vdev_dirty(mg->mg_vd, VDD_METASLAB, msp, txg);
+
+       range_tree_add(msp->ms_alloctree[txg & TXG_MASK], offset, asize);
+       msp->ms_access_txg = txg + metaslab_unload_delay;
+
+       mutex_exit(&msp->ms_lock);
+
+       return (offset);
+}
+
+/*
+ * Allocate a block for the specified i/o.
+ */
+static int
+metaslab_alloc_dva(spa_t *spa, metaslab_class_t *mc, uint64_t psize,
+    dva_t *dva, int d, dva_t *hintdva, uint64_t txg, int flags)
+{
+       metaslab_group_t *mg, *fast_mg, *rotor;
+       vdev_t *vd;
+       int dshift = 3;
+       int all_zero;
+       int zio_lock = B_FALSE;
+       boolean_t allocatable;
+       uint64_t offset = -1ULL;
+       uint64_t asize;
+       uint64_t distance;
+
+       ASSERT(!DVA_IS_VALID(&dva[d]));
+
+       /*
+        * For testing, make some blocks above a certain size be gang blocks.
+        */
+       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
+        * nothing actually breaks if we miss a few updates -- we just won't
+        * allocate quite as evenly.  It all balances out over time.
+        *
+        * If we are doing ditto or log blocks, try to spread them across
+        * consecutive vdevs.  If we're forced to reuse a vdev before we've
+        * allocated all of our ditto blocks, then try and spread them out on
+        * that vdev as much as possible.  If it turns out to not be possible,
+        * gradually lower our standards until anything becomes acceptable.
+        * Also, allocating on consecutive vdevs (as opposed to random vdevs)
+        * gives us hope of containing our fault domains to something we're
+        * able to reason about.  Otherwise, any two top-level vdev failures
+        * will guarantee the loss of data.  With consecutive allocation,
+        * only two adjacent top-level vdev failures will result in data loss.
+        *
+        * If we are doing gang blocks (hintdva is non-NULL), try to keep
+        * ourselves on the same vdev as our gang block header.  That
+        * way, we can hope for locality in vdev_cache, plus it makes our
+        * fault domains something tractable.
+        */
+       if (hintdva) {
+               vd = vdev_lookup_top(spa, DVA_GET_VDEV(&hintdva[d]));
+
+               /*
+                * It's possible the vdev we're using as the hint no
+                * longer exists (i.e. removed). Consult the rotor when
+                * all else fails.
+                */
+               if (vd != NULL) {
+                       mg = vd->vdev_mg;
+
+                       if (flags & METASLAB_HINTBP_AVOID &&
+                           mg->mg_next != NULL)
+                               mg = mg->mg_next;
+               } else {
+                       mg = mc->mc_rotor;
+               }
+       } else if (d != 0) {
+               vd = vdev_lookup_top(spa, DVA_GET_VDEV(&dva[d - 1]));
+               mg = vd->vdev_mg->mg_next;
+       } else if (flags & METASLAB_FASTWRITE) {
+               mg = fast_mg = mc->mc_rotor;
+
+               do {
+                       if (fast_mg->mg_vd->vdev_pending_fastwrite <
+                           mg->mg_vd->vdev_pending_fastwrite)
+                               mg = fast_mg;
+               } while ((fast_mg = fast_mg->mg_next) != mc->mc_rotor);
+
+       } else {
+               mg = mc->mc_rotor;
+       }
+
+       /*
+        * If the hint put us into the wrong metaslab class, or into a
+        * metaslab group that has been passivated, just follow the rotor.
+        */
+       if (mg->mg_class != mc || mg->mg_activation_count <= 0)
+               mg = mc->mc_rotor;
+
+       rotor = mg;
+top:
+       all_zero = B_TRUE;
+       do {
+               ASSERT(mg->mg_activation_count == 1);
+
+               vd = mg->mg_vd;
+
+               /*
+                * Don't allocate from faulted devices.
+                */
+               if (zio_lock) {
+                       spa_config_enter(spa, SCL_ZIO, FTAG, RW_READER);
+                       allocatable = vdev_allocatable(vd);
+                       spa_config_exit(spa, SCL_ZIO, FTAG);
+               } else {
+                       allocatable = vdev_allocatable(vd);
+               }
+
+               /*
+                * 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
+                * even though space is still available.
+                */
+               if (allocatable && CAN_FASTGANG(flags) &&
+                   psize > SPA_GANGBLOCKSIZE)
+                       allocatable = metaslab_group_allocatable(mg);
+
+               if (!allocatable)
+                       goto next;
+
+               /*
+                * Avoid writing single-copy data to a failing vdev
+                * unless the user instructs us that it is okay.
+                */
+               if ((vd->vdev_stat.vs_write_errors > 0 ||
+                   vd->vdev_state < VDEV_STATE_HEALTHY) &&
+                   d == 0 && dshift == 3 && vd->vdev_children == 0) {
+                       all_zero = B_FALSE;
+                       goto next;
+               }
+
+               ASSERT(mg->mg_class == mc);
+
+               distance = vd->vdev_asize >> dshift;
+               if (distance <= (1ULL << vd->vdev_ms_shift))
+                       distance = 0;
+               else
+                       all_zero = B_FALSE;
+
+               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);
+               if (offset != -1ULL) {
+                       /*
+                        * If we've just selected this metaslab group,
+                        * figure out whether the corresponding vdev is
+                        * over- or under-used relative to the pool,
+                        * and set an allocation bias to even it out.
+                        *
+                        * Bias is also used to compensate for unequally
+                        * sized vdevs so that space is allocated fairly.
+                        */
+                       if (mc->mc_aliquot == 0 && metaslab_bias_enabled) {
+                               vdev_stat_t *vs = &vd->vdev_stat;
+                               int64_t vs_free = vs->vs_space - vs->vs_alloc;
+                               int64_t mc_free = mc->mc_space - mc->mc_alloc;
+                               int64_t ratio;
+
+                               /*
+                                * Calculate how much more or less we should
+                                * try to allocate from this device during
+                                * this iteration around the rotor.
+                                *
+                                * This basically introduces a zero-centered
+                                * bias towards the devices with the most
+                                * free space, while compensating for vdev
+                                * size differences.
+                                *
+                                * Examples:
+                                *  vdev V1 = 16M/128M
+                                *  vdev V2 = 16M/128M
+                                *  ratio(V1) = 100% ratio(V2) = 100%
+                                *
+                                *  vdev V1 = 16M/128M
+                                *  vdev V2 = 64M/128M
+                                *  ratio(V1) = 127% ratio(V2) =  72%
+                                *
+                                *  vdev V1 = 16M/128M
+                                *  vdev V2 = 64M/512M
+                                *  ratio(V1) =  40% ratio(V2) = 160%
+                                */
+                               ratio = (vs_free * mc->mc_alloc_groups * 100) /
+                                   (mc_free + 1);
+                               mg->mg_bias = ((ratio - 100) *
+                                   (int64_t)mg->mg_aliquot) / 100;
+                       } else if (!metaslab_bias_enabled) {
+                               mg->mg_bias = 0;
+                       }
+
+                       if ((flags & METASLAB_FASTWRITE) ||
+                           atomic_add_64_nv(&mc->mc_aliquot, asize) >=
+                           mg->mg_aliquot + mg->mg_bias) {
+                               mc->mc_rotor = mg->mg_next;
+                               mc->mc_aliquot = 0;
+                       }
+
+                       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_ASIZE(&dva[d], asize);
+
+                       if (flags & METASLAB_FASTWRITE) {
+                               atomic_add_64(&vd->vdev_pending_fastwrite,
+                                   psize);
+                               mutex_exit(&mc->mc_fastwrite_lock);
+                       }
+
+                       return (0);
+               }
+next:
+               mc->mc_rotor = mg->mg_next;
+               mc->mc_aliquot = 0;
+       } while ((mg = mg->mg_next) != rotor);
+
+       if (!all_zero) {
+               dshift++;
+               ASSERT(dshift < 64);
+               goto top;
+       }
+
+       if (!allocatable && !zio_lock) {
+               dshift = 3;
+               zio_lock = B_TRUE;
+               goto top;
+       }
+
+       bzero(&dva[d], sizeof (dva_t));
+
+       if (flags & METASLAB_FASTWRITE)
+               mutex_exit(&mc->mc_fastwrite_lock);
+
+       return (SET_ERROR(ENOSPC));
+}
+
+/*
+ * Free the block represented by DVA in the context of the specified
+ * transaction group.
+ */
+static void
+metaslab_free_dva(spa_t *spa, const dva_t *dva, uint64_t txg, boolean_t now)
+{
+       uint64_t vdev = DVA_GET_VDEV(dva);
+       uint64_t offset = DVA_GET_OFFSET(dva);
+       uint64_t size = DVA_GET_ASIZE(dva);
+       vdev_t *vd;
+       metaslab_t *msp;
+
+       if (txg > spa_freeze_txg(spa))
+               return;
+
+       if ((vd = vdev_lookup_top(spa, vdev)) == NULL || !DVA_IS_VALID(dva) ||
+           (offset >> vd->vdev_ms_shift) >= vd->vdev_ms_count) {
+               zfs_panic_recover("metaslab_free_dva(): bad DVA %llu:%llu:%llu",
+                   (u_longlong_t)vdev, (u_longlong_t)offset,
+                   (u_longlong_t)size);
+               return;
+       }
+
+       msp = vd->vdev_ms[offset >> vd->vdev_ms_shift];
+
+       if (DVA_GET_GANG(dva))
+               size = vdev_psize_to_asize(vd, SPA_GANGBLOCKSIZE);
+
+       mutex_enter(&msp->ms_lock);
+
+       if (now) {
+               range_tree_remove(msp->ms_alloctree[txg & TXG_MASK],
+                   offset, size);
+
+               VERIFY(!msp->ms_condensing);
+               VERIFY3U(offset, >=, msp->ms_start);
+               VERIFY3U(offset + size, <=, msp->ms_start + msp->ms_size);
+               VERIFY3U(range_tree_space(msp->ms_tree) + size, <=,
+                   msp->ms_size);
+               VERIFY0(P2PHASE(offset, 1ULL << vd->vdev_ashift));
+               VERIFY0(P2PHASE(size, 1ULL << vd->vdev_ashift));
+               range_tree_add(msp->ms_tree, offset, size);
+       } else {
+               if (range_tree_space(msp->ms_freetree[txg & TXG_MASK]) == 0)
+                       vdev_dirty(vd, VDD_METASLAB, msp, txg);
+               range_tree_add(msp->ms_freetree[txg & TXG_MASK],
+                   offset, size);
+       }
+
+       mutex_exit(&msp->ms_lock);
+}
+
+/*
+ * Intent log support: upon opening the pool after a crash, notify the SPA
+ * of blocks that the intent log has allocated for immediate write, but
+ * which are still considered free by the SPA because the last transaction
+ * group didn't commit yet.
+ */
+static int
+metaslab_claim_dva(spa_t *spa, const dva_t *dva, uint64_t txg)
+{
+       uint64_t vdev = DVA_GET_VDEV(dva);
+       uint64_t offset = DVA_GET_OFFSET(dva);
+       uint64_t size = DVA_GET_ASIZE(dva);
+       vdev_t *vd;
+       metaslab_t *msp;
+       int error = 0;
+
+       ASSERT(DVA_IS_VALID(dva));
+
+       if ((vd = vdev_lookup_top(spa, vdev)) == NULL ||
+           (offset >> vd->vdev_ms_shift) >= vd->vdev_ms_count)
+               return (SET_ERROR(ENXIO));
+
+       msp = vd->vdev_ms[offset >> vd->vdev_ms_shift];
+
+       if (DVA_GET_GANG(dva))
+               size = vdev_psize_to_asize(vd, SPA_GANGBLOCKSIZE);
+
+       mutex_enter(&msp->ms_lock);
+
+       if ((txg != 0 && spa_writeable(spa)) || !msp->ms_loaded)
+               error = metaslab_activate(msp, METASLAB_WEIGHT_SECONDARY);
+
+       if (error == 0 && !range_tree_contains(msp->ms_tree, offset, size))
+               error = SET_ERROR(ENOENT);
+
+       if (error || txg == 0) {        /* txg == 0 indicates dry run */
+               mutex_exit(&msp->ms_lock);
+               return (error);
+       }
+
+       VERIFY(!msp->ms_condensing);
+       VERIFY0(P2PHASE(offset, 1ULL << vd->vdev_ashift));
+       VERIFY0(P2PHASE(size, 1ULL << vd->vdev_ashift));
+       VERIFY3U(range_tree_space(msp->ms_tree) - size, <=, msp->ms_size);
+       range_tree_remove(msp->ms_tree, offset, size);
+
+       if (spa_writeable(spa)) {       /* don't dirty if we're zdb(1M) */
+               if (range_tree_space(msp->ms_alloctree[txg & TXG_MASK]) == 0)
+                       vdev_dirty(vd, VDD_METASLAB, msp, txg);
+               range_tree_add(msp->ms_alloctree[txg & TXG_MASK], offset, size);
+       }
+
+       mutex_exit(&msp->ms_lock);
+
+       return (0);
+}
+
+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)
+{
+       dva_t *dva = bp->blk_dva;
+       dva_t *hintdva = hintbp->blk_dva;
+       int d, error = 0;
+
+       ASSERT(bp->blk_birth == 0);
+       ASSERT(BP_PHYSICAL_BIRTH(bp) == 0);
+
+       spa_config_enter(spa, SCL_ALLOC, FTAG, RW_READER);
+
+       if (mc->mc_rotor == NULL) {     /* no vdevs in this class */
+               spa_config_exit(spa, SCL_ALLOC, FTAG);
+               return (SET_ERROR(ENOSPC));
+       }
+
+       ASSERT(ndvas > 0 && ndvas <= spa_max_replication(spa));
+       ASSERT(BP_GET_NDVAS(bp) == 0);
+       ASSERT(hintbp == NULL || ndvas <= BP_GET_NDVAS(hintbp));
+
+       for (d = 0; d < ndvas; d++) {
+               error = metaslab_alloc_dva(spa, mc, psize, dva, d, hintdva,
+                   txg, flags);
+               if (error != 0) {
+                       for (d--; d >= 0; d--) {
+                               metaslab_free_dva(spa, &dva[d], txg, B_TRUE);
+                               bzero(&dva[d], sizeof (dva_t));
+                       }
+                       spa_config_exit(spa, SCL_ALLOC, FTAG);
+                       return (error);
+               }
+       }
+       ASSERT(error == 0);
+       ASSERT(BP_GET_NDVAS(bp) == ndvas);
+
+       spa_config_exit(spa, SCL_ALLOC, FTAG);
+
+       BP_SET_BIRTH(bp, txg, txg);
+
+       return (0);
+}
+
+void
+metaslab_free(spa_t *spa, const blkptr_t *bp, uint64_t txg, boolean_t now)
+{
+       const dva_t *dva = bp->blk_dva;
+       int d, ndvas = BP_GET_NDVAS(bp);
+
+       ASSERT(!BP_IS_HOLE(bp));
+       ASSERT(!now || bp->blk_birth >= spa_syncing_txg(spa));
+
+       spa_config_enter(spa, SCL_FREE, FTAG, RW_READER);
+
+       for (d = 0; d < ndvas; d++)
+               metaslab_free_dva(spa, &dva[d], txg, now);
+
+       spa_config_exit(spa, SCL_FREE, FTAG);
+}
+
+int
+metaslab_claim(spa_t *spa, const blkptr_t *bp, uint64_t txg)
+{
+       const dva_t *dva = bp->blk_dva;
+       int ndvas = BP_GET_NDVAS(bp);
+       int d, error = 0;
+
+       ASSERT(!BP_IS_HOLE(bp));
+
+       if (txg != 0) {
+               /*
+                * First do a dry run to make sure all DVAs are claimable,
+                * so we don't have to unwind from partial failures below.
+                */
+               if ((error = metaslab_claim(spa, bp, 0)) != 0)
+                       return (error);
+       }
+
+       spa_config_enter(spa, SCL_ALLOC, FTAG, RW_READER);
+
+       for (d = 0; d < ndvas; d++)
+               if ((error = metaslab_claim_dva(spa, &dva[d], txg)) != 0)
+                       break;
+
+       spa_config_exit(spa, SCL_ALLOC, FTAG);
+
+       ASSERT(error == 0 || txg == 0);
+
+       return (error);
+}
+
+void
+metaslab_fastwrite_mark(spa_t *spa, const blkptr_t *bp)
+{
+       const dva_t *dva = bp->blk_dva;
+       int ndvas = BP_GET_NDVAS(bp);
+       uint64_t psize = BP_GET_PSIZE(bp);
+       int d;
+       vdev_t *vd;
+
+       ASSERT(!BP_IS_HOLE(bp));
+       ASSERT(!BP_IS_EMBEDDED(bp));
+       ASSERT(psize > 0);
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       for (d = 0; d < ndvas; d++) {
+               if ((vd = vdev_lookup_top(spa, DVA_GET_VDEV(&dva[d]))) == NULL)
+                       continue;
+               atomic_add_64(&vd->vdev_pending_fastwrite, psize);
+       }
+
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+}
+
+void
+metaslab_fastwrite_unmark(spa_t *spa, const blkptr_t *bp)
+{
+       const dva_t *dva = bp->blk_dva;
+       int ndvas = BP_GET_NDVAS(bp);
+       uint64_t psize = BP_GET_PSIZE(bp);
+       int d;
+       vdev_t *vd;
+
+       ASSERT(!BP_IS_HOLE(bp));
+       ASSERT(!BP_IS_EMBEDDED(bp));
+       ASSERT(psize > 0);
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       for (d = 0; d < ndvas; d++) {
+               if ((vd = vdev_lookup_top(spa, DVA_GET_VDEV(&dva[d]))) == NULL)
+                       continue;
+               ASSERT3U(vd->vdev_pending_fastwrite, >=, psize);
+               atomic_sub_64(&vd->vdev_pending_fastwrite, psize);
+       }
+
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+}
+
+void
+metaslab_check_free(spa_t *spa, const blkptr_t *bp)
+{
+       int i, j;
+
+       if ((zfs_flags & ZFS_DEBUG_ZIO_FREE) == 0)
+               return;
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+       for (i = 0; i < BP_GET_NDVAS(bp); i++) {
+               uint64_t vdev = DVA_GET_VDEV(&bp->blk_dva[i]);
+               vdev_t *vd = vdev_lookup_top(spa, vdev);
+               uint64_t offset = DVA_GET_OFFSET(&bp->blk_dva[i]);
+               uint64_t size = DVA_GET_ASIZE(&bp->blk_dva[i]);
+               metaslab_t *msp = vd->vdev_ms[offset >> vd->vdev_ms_shift];
+
+               if (msp->ms_loaded)
+                       range_tree_verify(msp->ms_tree, offset, size);
+
+               for (j = 0; j < TXG_SIZE; j++)
+                       range_tree_verify(msp->ms_freetree[j], offset, size);
+               for (j = 0; j < TXG_DEFER_SIZE; j++)
+                       range_tree_verify(msp->ms_defertree[j], offset, size);
+       }
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(metaslab_aliquot, ulong, 0644);
+module_param(metaslab_debug_load, int, 0644);
+module_param(metaslab_debug_unload, int, 0644);
+module_param(metaslab_preload_enabled, int, 0644);
+module_param(zfs_mg_noalloc_threshold, int, 0644);
+module_param(zfs_mg_fragmentation_threshold, int, 0644);
+module_param(zfs_metaslab_fragmentation_threshold, int, 0644);
+module_param(metaslab_fragmentation_factor_enabled, int, 0644);
+module_param(metaslab_lba_weighting_enabled, int, 0644);
+module_param(metaslab_bias_enabled, int, 0644);
+
+MODULE_PARM_DESC(metaslab_aliquot,
+       "allocation granularity (a.k.a. stripe size)");
+MODULE_PARM_DESC(metaslab_debug_load,
+       "load all metaslabs when pool is first opened");
+MODULE_PARM_DESC(metaslab_debug_unload,
+       "prevent metaslabs from being unloaded");
+MODULE_PARM_DESC(metaslab_preload_enabled,
+       "preload potential metaslabs during reassessment");
+
+MODULE_PARM_DESC(zfs_mg_noalloc_threshold,
+       "percentage of free space for metaslab group to allow allocation");
+MODULE_PARM_DESC(zfs_mg_fragmentation_threshold,
+       "fragmentation for metaslab group to allow allocation");
+
+MODULE_PARM_DESC(zfs_metaslab_fragmentation_threshold,
+       "fragmentation for metaslab to allow allocation");
+MODULE_PARM_DESC(metaslab_fragmentation_factor_enabled,
+       "use the fragmentation metric to prefer less fragmented metaslabs");
+MODULE_PARM_DESC(metaslab_lba_weighting_enabled,
+       "prefer metaslabs with lower LBAs");
+MODULE_PARM_DESC(metaslab_bias_enabled,
+       "enable metaslab group biasing");
+#endif /* _KERNEL && HAVE_SPL */
diff --git a/zfs/module/zfs/multilist.c b/zfs/module/zfs/multilist.c
new file mode 100644 (file)
index 0000000..e4446de
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * 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) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/multilist.h>
+#include <sys/trace_multilist.h>
+
+/* needed for spa_get_random() */
+#include <sys/spa.h>
+
+/*
+ * Given the object contained on the list, return a pointer to the
+ * object's multilist_node_t structure it contains.
+ */
+#ifdef DEBUG
+static multilist_node_t *
+multilist_d2l(multilist_t *ml, void *obj)
+{
+       return ((multilist_node_t *)((char *)obj + ml->ml_offset));
+}
+#endif
+
+/*
+ * Initialize a new mutlilist using the parameters specified.
+ *
+ *  - 'size' denotes the size of the structure containing the
+ *     multilist_node_t.
+ *  - 'offset' denotes the byte offset of the mutlilist_node_t within
+ *     the structure that contains it.
+ *  - 'num' specifies the number of internal sublists to create.
+ *  - 'index_func' is used to determine which sublist to insert into
+ *     when the multilist_insert() function is called; as well as which
+ *     sublist to remove from when multilist_remove() is called. The
+ *     requirements this function must meet, are the following:
+ *
+ *      - It must always return the same value when called on the same
+ *        object (to ensure the object is removed from the list it was
+ *        inserted into).
+ *
+ *      - It must return a value in the range [0, number of sublists).
+ *        The multilist_get_num_sublists() function may be used to
+ *        determine the number of sublists in the multilist.
+ *
+ *     Also, in order to reduce internal contention between the sublists
+ *     during insertion and removal, this function should choose evenly
+ *     between all available sublists when inserting. This isn't a hard
+ *     requirement, but a general rule of thumb in order to garner the
+ *     best multi-threaded performance out of the data structure.
+ */
+void
+multilist_create(multilist_t *ml, size_t size, size_t offset, unsigned int num,
+    multilist_sublist_index_func_t *index_func)
+{
+       int i;
+
+       ASSERT3P(ml, !=, NULL);
+       ASSERT3U(size, >, 0);
+       ASSERT3U(size, >=, offset + sizeof (multilist_node_t));
+       ASSERT3U(num, >, 0);
+       ASSERT3P(index_func, !=, NULL);
+
+       ml->ml_offset = offset;
+       ml->ml_num_sublists = num;
+       ml->ml_index_func = index_func;
+
+       ml->ml_sublists = kmem_zalloc(sizeof (multilist_sublist_t) *
+           ml->ml_num_sublists, KM_SLEEP);
+
+       ASSERT3P(ml->ml_sublists, !=, NULL);
+
+       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);
+               list_create(&mls->mls_list, size, offset);
+       }
+}
+
+/*
+ * Destroy the given multilist object, and free up any memory it holds.
+ */
+void
+multilist_destroy(multilist_t *ml)
+{
+       int i;
+
+       ASSERT(multilist_is_empty(ml));
+
+       for (i = 0; i < ml->ml_num_sublists; i++) {
+               multilist_sublist_t *mls = &ml->ml_sublists[i];
+
+               ASSERT(list_is_empty(&mls->mls_list));
+
+               list_destroy(&mls->mls_list);
+               mutex_destroy(&mls->mls_lock);
+       }
+
+       ASSERT3P(ml->ml_sublists, !=, NULL);
+       kmem_free(ml->ml_sublists,
+           sizeof (multilist_sublist_t) * ml->ml_num_sublists);
+
+       ml->ml_num_sublists = 0;
+       ml->ml_offset = 0;
+}
+
+/*
+ * Insert the given object into the multilist.
+ *
+ * This function will insert the object specified into the sublist
+ * determined using the function given at multilist creation time.
+ *
+ * The sublist locks are automatically acquired if not already held, to
+ * ensure consistency when inserting and removing from multiple threads.
+ */
+void
+multilist_insert(multilist_t *ml, void *obj)
+{
+       unsigned int sublist_idx = ml->ml_index_func(ml, obj);
+       multilist_sublist_t *mls;
+       boolean_t need_lock;
+
+       DTRACE_PROBE3(multilist__insert, multilist_t *, ml,
+           unsigned int, sublist_idx, void *, obj);
+
+       ASSERT3U(sublist_idx, <, ml->ml_num_sublists);
+
+       mls = &ml->ml_sublists[sublist_idx];
+
+       /*
+        * Note: Callers may already hold the sublist lock by calling
+        * multilist_sublist_lock().  Here we rely on MUTEX_HELD()
+        * returning TRUE if and only if the current thread holds the
+        * lock.  While it's a little ugly to make the lock recursive in
+        * this way, it works and allows the calling code to be much
+        * simpler -- otherwise it would have to pass around a flag
+        * indicating that it already has the lock.
+        */
+       need_lock = !MUTEX_HELD(&mls->mls_lock);
+
+       if (need_lock)
+               mutex_enter(&mls->mls_lock);
+
+       ASSERT(!multilist_link_active(multilist_d2l(ml, obj)));
+
+       multilist_sublist_insert_head(mls, obj);
+
+       if (need_lock)
+               mutex_exit(&mls->mls_lock);
+}
+
+/*
+ * Remove the given object from the multilist.
+ *
+ * This function will remove the object specified from the sublist
+ * determined using the function given at multilist creation time.
+ *
+ * The necessary sublist locks are automatically acquired, to ensure
+ * consistency when inserting and removing from multiple threads.
+ */
+void
+multilist_remove(multilist_t *ml, void *obj)
+{
+       unsigned int sublist_idx = ml->ml_index_func(ml, obj);
+       multilist_sublist_t *mls;
+       boolean_t need_lock;
+
+       DTRACE_PROBE3(multilist__remove, multilist_t *, ml,
+           unsigned int, sublist_idx, void *, obj);
+
+       ASSERT3U(sublist_idx, <, ml->ml_num_sublists);
+
+       mls = &ml->ml_sublists[sublist_idx];
+       /* See comment in multilist_insert(). */
+       need_lock = !MUTEX_HELD(&mls->mls_lock);
+
+       if (need_lock)
+               mutex_enter(&mls->mls_lock);
+
+       ASSERT(multilist_link_active(multilist_d2l(ml, obj)));
+
+       multilist_sublist_remove(mls, obj);
+
+       if (need_lock)
+               mutex_exit(&mls->mls_lock);
+}
+
+/*
+ * Check to see if this multilist object is empty.
+ *
+ * This will return TRUE if it finds all of the sublists of this
+ * multilist to be empty, and FALSE otherwise. Each sublist lock will be
+ * automatically acquired as necessary.
+ *
+ * If concurrent insertions and removals are occurring, the semantics
+ * of this function become a little fuzzy. Instead of locking all
+ * sublists for the entire call time of the function, each sublist is
+ * only locked as it is individually checked for emptiness. Thus, it's
+ * possible for this function to return TRUE with non-empty sublists at
+ * the time the function returns. This would be due to another thread
+ * inserting into a given sublist, after that specific sublist was check
+ * and deemed empty, but before all sublists have been checked.
+ */
+int
+multilist_is_empty(multilist_t *ml)
+{
+       int i;
+
+       for (i = 0; i < ml->ml_num_sublists; i++) {
+               multilist_sublist_t *mls = &ml->ml_sublists[i];
+               /* See comment in multilist_insert(). */
+               boolean_t need_lock = !MUTEX_HELD(&mls->mls_lock);
+
+               if (need_lock)
+                       mutex_enter(&mls->mls_lock);
+
+               if (!list_is_empty(&mls->mls_list)) {
+                       if (need_lock)
+                               mutex_exit(&mls->mls_lock);
+
+                       return (FALSE);
+               }
+
+               if (need_lock)
+                       mutex_exit(&mls->mls_lock);
+       }
+
+       return (TRUE);
+}
+
+/* Return the number of sublists composing this multilist */
+unsigned int
+multilist_get_num_sublists(multilist_t *ml)
+{
+       return (ml->ml_num_sublists);
+}
+
+/* Return a randomly selected, valid sublist index for this multilist */
+unsigned int
+multilist_get_random_index(multilist_t *ml)
+{
+       return (spa_get_random(ml->ml_num_sublists));
+}
+
+/* Lock and return the sublist specified at the given index */
+multilist_sublist_t *
+multilist_sublist_lock(multilist_t *ml, unsigned int sublist_idx)
+{
+       multilist_sublist_t *mls;
+
+       ASSERT3U(sublist_idx, <, ml->ml_num_sublists);
+       mls = &ml->ml_sublists[sublist_idx];
+       mutex_enter(&mls->mls_lock);
+
+       return (mls);
+}
+
+void
+multilist_sublist_unlock(multilist_sublist_t *mls)
+{
+       mutex_exit(&mls->mls_lock);
+}
+
+/*
+ * We're allowing any object to be inserted into this specific sublist,
+ * but this can lead to trouble if multilist_remove() is called to
+ * remove this object. Specifically, if calling ml_index_func on this
+ * object returns an index for sublist different than what is passed as
+ * a parameter here, any call to multilist_remove() with this newly
+ * inserted object is undefined! (the call to multilist_remove() will
+ * remove the object from a list that it isn't contained in)
+ */
+void
+multilist_sublist_insert_head(multilist_sublist_t *mls, void *obj)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       list_insert_head(&mls->mls_list, obj);
+}
+
+/* please see comment above multilist_sublist_insert_head */
+void
+multilist_sublist_insert_tail(multilist_sublist_t *mls, void *obj)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       list_insert_tail(&mls->mls_list, obj);
+}
+
+/*
+ * Move the object one element forward in the list.
+ *
+ * This function will move the given object forward in the list (towards
+ * the head) by one object. So, in essence, it will swap its position in
+ * the list with its "prev" pointer. If the given object is already at the
+ * head of the list, it cannot be moved forward any more than it already
+ * is, so no action is taken.
+ *
+ * NOTE: This function **must not** remove any object from the list other
+ *       than the object given as the parameter. This is relied upon in
+ *       arc_evict_state_impl().
+ */
+void
+multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj)
+{
+       void *prev = list_prev(&mls->mls_list, obj);
+
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       ASSERT(!list_is_empty(&mls->mls_list));
+
+       /* 'obj' must be at the head of the list, nothing to do */
+       if (prev == NULL)
+               return;
+
+       list_remove(&mls->mls_list, obj);
+       list_insert_before(&mls->mls_list, prev, obj);
+}
+
+void
+multilist_sublist_remove(multilist_sublist_t *mls, void *obj)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       list_remove(&mls->mls_list, obj);
+}
+
+void *
+multilist_sublist_head(multilist_sublist_t *mls)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       return (list_head(&mls->mls_list));
+}
+
+void *
+multilist_sublist_tail(multilist_sublist_t *mls)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       return (list_tail(&mls->mls_list));
+}
+
+void *
+multilist_sublist_next(multilist_sublist_t *mls, void *obj)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       return (list_next(&mls->mls_list, obj));
+}
+
+void *
+multilist_sublist_prev(multilist_sublist_t *mls, void *obj)
+{
+       ASSERT(MUTEX_HELD(&mls->mls_lock));
+       return (list_prev(&mls->mls_list, obj));
+}
+
+void
+multilist_link_init(multilist_node_t *link)
+{
+       list_link_init(link);
+}
+
+int
+multilist_link_active(multilist_node_t *link)
+{
+       return (list_link_active(link));
+}
diff --git a/zfs/module/zfs/range_tree.c b/zfs/module/zfs/range_tree.c
new file mode 100644 (file)
index 0000000..6422fd1
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/dnode.h>
+#include <sys/zio.h>
+#include <sys/range_tree.h>
+
+kmem_cache_t *range_seg_cache;
+
+void
+range_tree_init(void)
+{
+       ASSERT(range_seg_cache == NULL);
+       range_seg_cache = kmem_cache_create("range_seg_cache",
+           sizeof (range_seg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+void
+range_tree_fini(void)
+{
+       kmem_cache_destroy(range_seg_cache);
+       range_seg_cache = NULL;
+}
+
+void
+range_tree_stat_verify(range_tree_t *rt)
+{
+       range_seg_t *rs;
+       uint64_t hist[RANGE_TREE_HISTOGRAM_SIZE] = { 0 };
+       int i;
+
+       for (rs = avl_first(&rt->rt_root); rs != NULL;
+           rs = AVL_NEXT(&rt->rt_root, rs)) {
+               uint64_t size = rs->rs_end - rs->rs_start;
+               int idx = highbit64(size) - 1;
+
+               hist[idx]++;
+               ASSERT3U(hist[idx], !=, 0);
+       }
+
+       for (i = 0; i < RANGE_TREE_HISTOGRAM_SIZE; i++) {
+               if (hist[i] != rt->rt_histogram[i]) {
+                       zfs_dbgmsg("i=%d, hist=%p, hist=%llu, rt_hist=%llu",
+                           i, hist, hist[i], rt->rt_histogram[i]);
+               }
+               VERIFY3U(hist[i], ==, rt->rt_histogram[i]);
+       }
+}
+
+static void
+range_tree_stat_incr(range_tree_t *rt, range_seg_t *rs)
+{
+       uint64_t size = rs->rs_end - rs->rs_start;
+       int idx = highbit64(size) - 1;
+
+       ASSERT(size != 0);
+       ASSERT3U(idx, <,
+           sizeof (rt->rt_histogram) / sizeof (*rt->rt_histogram));
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       rt->rt_histogram[idx]++;
+       ASSERT3U(rt->rt_histogram[idx], !=, 0);
+}
+
+static void
+range_tree_stat_decr(range_tree_t *rt, range_seg_t *rs)
+{
+       uint64_t size = rs->rs_end - rs->rs_start;
+       int idx = highbit64(size) - 1;
+
+       ASSERT(size != 0);
+       ASSERT3U(idx, <,
+           sizeof (rt->rt_histogram) / sizeof (*rt->rt_histogram));
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       ASSERT3U(rt->rt_histogram[idx], !=, 0);
+       rt->rt_histogram[idx]--;
+}
+
+/*
+ * NOTE: caller is responsible for all locking.
+ */
+static int
+range_tree_seg_compare(const void *x1, const void *x2)
+{
+       const range_seg_t *r1 = x1;
+       const range_seg_t *r2 = 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);
+}
+
+range_tree_t *
+range_tree_create(range_tree_ops_t *ops, void *arg, kmutex_t *lp)
+{
+       range_tree_t *rt;
+
+       rt = kmem_zalloc(sizeof (range_tree_t), KM_SLEEP);
+
+       avl_create(&rt->rt_root, range_tree_seg_compare,
+           sizeof (range_seg_t), offsetof(range_seg_t, rs_node));
+
+       rt->rt_lock = lp;
+       rt->rt_ops = ops;
+       rt->rt_arg = arg;
+
+       if (rt->rt_ops != NULL)
+               rt->rt_ops->rtop_create(rt, rt->rt_arg);
+
+       return (rt);
+}
+
+void
+range_tree_destroy(range_tree_t *rt)
+{
+       VERIFY0(rt->rt_space);
+
+       if (rt->rt_ops != NULL)
+               rt->rt_ops->rtop_destroy(rt, rt->rt_arg);
+
+       avl_destroy(&rt->rt_root);
+       kmem_free(rt, sizeof (*rt));
+}
+
+void
+range_tree_add(void *arg, uint64_t start, uint64_t size)
+{
+       range_tree_t *rt = arg;
+       avl_index_t where;
+       range_seg_t rsearch, *rs_before, *rs_after, *rs;
+       uint64_t end = start + size;
+       boolean_t merge_before, merge_after;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       VERIFY(size != 0);
+
+       rsearch.rs_start = start;
+       rsearch.rs_end = end;
+       rs = avl_find(&rt->rt_root, &rsearch, &where);
+
+       if (rs != NULL && rs->rs_start <= start && rs->rs_end >= end) {
+               zfs_panic_recover("zfs: allocating allocated segment"
+                   "(offset=%llu size=%llu)\n",
+                   (longlong_t)start, (longlong_t)size);
+               return;
+       }
+
+       /* Make sure we don't overlap with either of our neighbors */
+       VERIFY(rs == NULL);
+
+       rs_before = avl_nearest(&rt->rt_root, where, AVL_BEFORE);
+       rs_after = avl_nearest(&rt->rt_root, where, AVL_AFTER);
+
+       merge_before = (rs_before != NULL && rs_before->rs_end == start);
+       merge_after = (rs_after != NULL && rs_after->rs_start == end);
+
+       if (merge_before && merge_after) {
+               avl_remove(&rt->rt_root, rs_before);
+               if (rt->rt_ops != NULL) {
+                       rt->rt_ops->rtop_remove(rt, rs_before, rt->rt_arg);
+                       rt->rt_ops->rtop_remove(rt, rs_after, rt->rt_arg);
+               }
+
+               range_tree_stat_decr(rt, rs_before);
+               range_tree_stat_decr(rt, rs_after);
+
+               rs_after->rs_start = rs_before->rs_start;
+               kmem_cache_free(range_seg_cache, rs_before);
+               rs = rs_after;
+       } else if (merge_before) {
+               if (rt->rt_ops != NULL)
+                       rt->rt_ops->rtop_remove(rt, rs_before, rt->rt_arg);
+
+               range_tree_stat_decr(rt, rs_before);
+
+               rs_before->rs_end = end;
+               rs = rs_before;
+       } else if (merge_after) {
+               if (rt->rt_ops != NULL)
+                       rt->rt_ops->rtop_remove(rt, rs_after, rt->rt_arg);
+
+               range_tree_stat_decr(rt, rs_after);
+
+               rs_after->rs_start = start;
+               rs = rs_after;
+       } else {
+               rs = kmem_cache_alloc(range_seg_cache, KM_SLEEP);
+               rs->rs_start = start;
+               rs->rs_end = end;
+               avl_insert(&rt->rt_root, rs, where);
+       }
+
+       if (rt->rt_ops != NULL)
+               rt->rt_ops->rtop_add(rt, rs, rt->rt_arg);
+
+       range_tree_stat_incr(rt, rs);
+       rt->rt_space += size;
+}
+
+void
+range_tree_remove(void *arg, uint64_t start, uint64_t size)
+{
+       range_tree_t *rt = arg;
+       avl_index_t where;
+       range_seg_t rsearch, *rs, *newseg;
+       uint64_t end = start + size;
+       boolean_t left_over, right_over;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       VERIFY3U(size, !=, 0);
+       VERIFY3U(size, <=, rt->rt_space);
+
+       rsearch.rs_start = start;
+       rsearch.rs_end = end;
+       rs = avl_find(&rt->rt_root, &rsearch, &where);
+
+       /* Make sure we completely overlap with someone */
+       if (rs == NULL) {
+               zfs_panic_recover("zfs: freeing free segment "
+                   "(offset=%llu size=%llu)",
+                   (longlong_t)start, (longlong_t)size);
+               return;
+       }
+       VERIFY3U(rs->rs_start, <=, start);
+       VERIFY3U(rs->rs_end, >=, end);
+
+       left_over = (rs->rs_start != start);
+       right_over = (rs->rs_end != end);
+
+       range_tree_stat_decr(rt, rs);
+
+       if (rt->rt_ops != NULL)
+               rt->rt_ops->rtop_remove(rt, rs, rt->rt_arg);
+
+       if (left_over && right_over) {
+               newseg = kmem_cache_alloc(range_seg_cache, KM_SLEEP);
+               newseg->rs_start = end;
+               newseg->rs_end = rs->rs_end;
+               range_tree_stat_incr(rt, newseg);
+
+               rs->rs_end = start;
+
+               avl_insert_here(&rt->rt_root, newseg, rs, AVL_AFTER);
+               if (rt->rt_ops != NULL)
+                       rt->rt_ops->rtop_add(rt, newseg, rt->rt_arg);
+       } else if (left_over) {
+               rs->rs_end = start;
+       } else if (right_over) {
+               rs->rs_start = end;
+       } else {
+               avl_remove(&rt->rt_root, rs);
+               kmem_cache_free(range_seg_cache, rs);
+               rs = NULL;
+       }
+
+       if (rs != NULL) {
+               range_tree_stat_incr(rt, rs);
+
+               if (rt->rt_ops != NULL)
+                       rt->rt_ops->rtop_add(rt, rs, rt->rt_arg);
+       }
+
+       rt->rt_space -= size;
+}
+
+static range_seg_t *
+range_tree_find_impl(range_tree_t *rt, uint64_t start, uint64_t size)
+{
+       avl_index_t where;
+       range_seg_t rsearch;
+       uint64_t end = start + size;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       VERIFY(size != 0);
+
+       rsearch.rs_start = start;
+       rsearch.rs_end = end;
+       return (avl_find(&rt->rt_root, &rsearch, &where));
+}
+
+static range_seg_t *
+range_tree_find(range_tree_t *rt, uint64_t start, uint64_t size)
+{
+       range_seg_t *rs = range_tree_find_impl(rt, start, size);
+       if (rs != NULL && rs->rs_start <= start && rs->rs_end >= start + size)
+               return (rs);
+       return (NULL);
+}
+
+void
+range_tree_verify(range_tree_t *rt, uint64_t off, uint64_t size)
+{
+       range_seg_t *rs;
+
+       mutex_enter(rt->rt_lock);
+       rs = range_tree_find(rt, off, size);
+       if (rs != NULL)
+               panic("freeing free block; rs=%p", (void *)rs);
+       mutex_exit(rt->rt_lock);
+}
+
+boolean_t
+range_tree_contains(range_tree_t *rt, uint64_t start, uint64_t size)
+{
+       return (range_tree_find(rt, start, size) != NULL);
+}
+
+/*
+ * Ensure that this range is not in the tree, regardless of whether
+ * it is currently in the tree.
+ */
+void
+range_tree_clear(range_tree_t *rt, uint64_t start, uint64_t size)
+{
+       range_seg_t *rs;
+
+       while ((rs = range_tree_find_impl(rt, start, size)) != NULL) {
+               uint64_t free_start = MAX(rs->rs_start, start);
+               uint64_t free_end = MIN(rs->rs_end, start + size);
+               range_tree_remove(rt, free_start, free_end - free_start);
+       }
+}
+
+void
+range_tree_swap(range_tree_t **rtsrc, range_tree_t **rtdst)
+{
+       range_tree_t *rt;
+
+       ASSERT(MUTEX_HELD((*rtsrc)->rt_lock));
+       ASSERT0(range_tree_space(*rtdst));
+       ASSERT0(avl_numnodes(&(*rtdst)->rt_root));
+
+       rt = *rtsrc;
+       *rtsrc = *rtdst;
+       *rtdst = rt;
+}
+
+void
+range_tree_vacate(range_tree_t *rt, range_tree_func_t *func, void *arg)
+{
+       range_seg_t *rs;
+       void *cookie = NULL;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+
+       if (rt->rt_ops != NULL)
+               rt->rt_ops->rtop_vacate(rt, rt->rt_arg);
+
+       while ((rs = avl_destroy_nodes(&rt->rt_root, &cookie)) != NULL) {
+               if (func != NULL)
+                       func(arg, rs->rs_start, rs->rs_end - rs->rs_start);
+               kmem_cache_free(range_seg_cache, rs);
+       }
+
+       bzero(rt->rt_histogram, sizeof (rt->rt_histogram));
+       rt->rt_space = 0;
+}
+
+void
+range_tree_walk(range_tree_t *rt, range_tree_func_t *func, void *arg)
+{
+       range_seg_t *rs;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+
+       for (rs = avl_first(&rt->rt_root); rs; rs = AVL_NEXT(&rt->rt_root, rs))
+               func(arg, rs->rs_start, rs->rs_end - rs->rs_start);
+}
+
+uint64_t
+range_tree_space(range_tree_t *rt)
+{
+       return (rt->rt_space);
+}
diff --git a/zfs/module/zfs/refcount.c b/zfs/module/zfs/refcount.c
new file mode 100644 (file)
index 0000000..4c460a2
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+
+#ifdef ZFS_DEBUG
+
+#ifdef _KERNEL
+int reference_tracking_enable = FALSE; /* runs out of memory too easily */
+#else
+int reference_tracking_enable = TRUE;
+#endif
+int reference_history = 3; /* tunable */
+
+static kmem_cache_t *reference_cache;
+static kmem_cache_t *reference_history_cache;
+
+void
+refcount_init(void)
+{
+       reference_cache = kmem_cache_create("reference_cache",
+           sizeof (reference_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+
+       reference_history_cache = kmem_cache_create("reference_history_cache",
+           sizeof (uint64_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+void
+refcount_fini(void)
+{
+       kmem_cache_destroy(reference_cache);
+       kmem_cache_destroy(reference_history_cache);
+}
+
+void
+refcount_create(refcount_t *rc)
+{
+       mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&rc->rc_list, sizeof (reference_t),
+           offsetof(reference_t, ref_link));
+       list_create(&rc->rc_removed, sizeof (reference_t),
+           offsetof(reference_t, ref_link));
+       rc->rc_count = 0;
+       rc->rc_removed_count = 0;
+       rc->rc_tracked = reference_tracking_enable;
+}
+
+void
+refcount_create_untracked(refcount_t *rc)
+{
+       refcount_create(rc);
+       rc->rc_tracked = B_FALSE;
+}
+
+void
+refcount_destroy_many(refcount_t *rc, uint64_t number)
+{
+       reference_t *ref;
+
+       ASSERT(rc->rc_count == number);
+       while ((ref = list_head(&rc->rc_list))) {
+               list_remove(&rc->rc_list, ref);
+               kmem_cache_free(reference_cache, ref);
+       }
+       list_destroy(&rc->rc_list);
+
+       while ((ref = list_head(&rc->rc_removed))) {
+               list_remove(&rc->rc_removed, ref);
+               kmem_cache_free(reference_history_cache, ref->ref_removed);
+               kmem_cache_free(reference_cache, ref);
+       }
+       list_destroy(&rc->rc_removed);
+       mutex_destroy(&rc->rc_mtx);
+}
+
+void
+refcount_destroy(refcount_t *rc)
+{
+       refcount_destroy_many(rc, 0);
+}
+
+int
+refcount_is_zero(refcount_t *rc)
+{
+       return (rc->rc_count == 0);
+}
+
+int64_t
+refcount_count(refcount_t *rc)
+{
+       return (rc->rc_count);
+}
+
+int64_t
+refcount_add_many(refcount_t *rc, uint64_t number, void *holder)
+{
+       reference_t *ref = NULL;
+       int64_t count;
+
+       if (rc->rc_tracked) {
+               ref = kmem_cache_alloc(reference_cache, KM_SLEEP);
+               ref->ref_holder = holder;
+               ref->ref_number = number;
+       }
+       mutex_enter(&rc->rc_mtx);
+       ASSERT(rc->rc_count >= 0);
+       if (rc->rc_tracked)
+               list_insert_head(&rc->rc_list, ref);
+       rc->rc_count += number;
+       count = rc->rc_count;
+       mutex_exit(&rc->rc_mtx);
+
+       return (count);
+}
+
+int64_t
+refcount_add(refcount_t *rc, void *holder)
+{
+       return (refcount_add_many(rc, 1, holder));
+}
+
+int64_t
+refcount_remove_many(refcount_t *rc, uint64_t number, void *holder)
+{
+       reference_t *ref;
+       int64_t count;
+
+       mutex_enter(&rc->rc_mtx);
+       ASSERT(rc->rc_count >= number);
+
+       if (!rc->rc_tracked) {
+               rc->rc_count -= number;
+               count = rc->rc_count;
+               mutex_exit(&rc->rc_mtx);
+               return (count);
+       }
+
+       for (ref = list_head(&rc->rc_list); ref;
+           ref = list_next(&rc->rc_list, ref)) {
+               if (ref->ref_holder == holder && ref->ref_number == number) {
+                       list_remove(&rc->rc_list, ref);
+                       if (reference_history > 0) {
+                               ref->ref_removed =
+                                   kmem_cache_alloc(reference_history_cache,
+                                   KM_SLEEP);
+                               list_insert_head(&rc->rc_removed, ref);
+                               rc->rc_removed_count++;
+                               if (rc->rc_removed_count > reference_history) {
+                                       ref = list_tail(&rc->rc_removed);
+                                       list_remove(&rc->rc_removed, ref);
+                                       kmem_cache_free(reference_history_cache,
+                                           ref->ref_removed);
+                                       kmem_cache_free(reference_cache, ref);
+                                       rc->rc_removed_count--;
+                               }
+                       } else {
+                               kmem_cache_free(reference_cache, ref);
+                       }
+                       rc->rc_count -= number;
+                       count = rc->rc_count;
+                       mutex_exit(&rc->rc_mtx);
+                       return (count);
+               }
+       }
+       panic("No such hold %p on refcount %llx", holder,
+           (u_longlong_t)(uintptr_t)rc);
+       return (-1);
+}
+
+int64_t
+refcount_remove(refcount_t *rc, void *holder)
+{
+       return (refcount_remove_many(rc, 1, holder));
+}
+
+void
+refcount_transfer(refcount_t *dst, refcount_t *src)
+{
+       int64_t count, removed_count;
+       list_t list, removed;
+
+       list_create(&list, sizeof (reference_t),
+           offsetof(reference_t, ref_link));
+       list_create(&removed, sizeof (reference_t),
+           offsetof(reference_t, ref_link));
+
+       mutex_enter(&src->rc_mtx);
+       count = src->rc_count;
+       removed_count = src->rc_removed_count;
+       src->rc_count = 0;
+       src->rc_removed_count = 0;
+       list_move_tail(&list, &src->rc_list);
+       list_move_tail(&removed, &src->rc_removed);
+       mutex_exit(&src->rc_mtx);
+
+       mutex_enter(&dst->rc_mtx);
+       dst->rc_count += count;
+       dst->rc_removed_count += removed_count;
+       list_move_tail(&dst->rc_list, &list);
+       list_move_tail(&dst->rc_removed, &removed);
+       mutex_exit(&dst->rc_mtx);
+
+       list_destroy(&list);
+       list_destroy(&removed);
+}
+
+#endif /* ZFS_DEBUG */
diff --git a/zfs/module/zfs/rrwlock.c b/zfs/module/zfs/rrwlock.c
new file mode 100644 (file)
index 0000000..51394c0
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+#include <sys/refcount.h>
+#include <sys/rrwlock.h>
+
+/*
+ * This file contains the implementation of a re-entrant read
+ * reader/writer lock (aka "rrwlock").
+ *
+ * This is a normal reader/writer lock with the additional feature
+ * of allowing threads who have already obtained a read lock to
+ * re-enter another read lock (re-entrant read) - even if there are
+ * waiting writers.
+ *
+ * Callers who have not obtained a read lock give waiting writers priority.
+ *
+ * The rrwlock_t lock does not allow re-entrant writers, nor does it
+ * allow a re-entrant mix of reads and writes (that is, it does not
+ * allow a caller who has already obtained a read lock to be able to
+ * then grab a write lock without first dropping all read locks, and
+ * vice versa).
+ *
+ * The rrwlock_t uses tsd (thread specific data) to keep a list of
+ * nodes (rrw_node_t), where each node keeps track of which specific
+ * lock (rrw_node_t::rn_rrl) the thread has grabbed.  Since re-entering
+ * should be rare, a thread that grabs multiple reads on the same rrwlock_t
+ * will store multiple rrw_node_ts of the same 'rrn_rrl'. Nodes on the
+ * tsd list can represent a different rrwlock_t.  This allows a thread
+ * to enter multiple and unique rrwlock_ts for read locks at the same time.
+ *
+ * Since using tsd exposes some overhead, the rrwlock_t only needs to
+ * keep tsd data when writers are waiting.  If no writers are waiting, then
+ * a reader just bumps the anonymous read count (rr_anon_rcount) - no tsd
+ * is needed.  Once a writer attempts to grab the lock, readers then
+ * keep tsd data and bump the linked readers count (rr_linked_rcount).
+ *
+ * If there are waiting writers and there are anonymous readers, then a
+ * reader doesn't know if it is a re-entrant lock. But since it may be one,
+ * we allow the read to proceed (otherwise it could deadlock).  Since once
+ * waiting writers are active, readers no longer bump the anonymous count,
+ * the anonymous readers will eventually flush themselves out.  At this point,
+ * readers will be able to tell if they are a re-entrant lock (have a
+ * rrw_node_t entry for the lock) or not. If they are a re-entrant lock, then
+ * we must let the proceed.  If they are not, then the reader blocks for the
+ * waiting writers.  Hence, we do not starve writers.
+ */
+
+/* global key for TSD */
+uint_t rrw_tsd_key;
+
+typedef struct rrw_node {
+       struct rrw_node *rn_next;
+       rrwlock_t *rn_rrl;
+       void *rn_tag;
+} rrw_node_t;
+
+static rrw_node_t *
+rrn_find(rrwlock_t *rrl)
+{
+       rrw_node_t *rn;
+
+       if (refcount_count(&rrl->rr_linked_rcount) == 0)
+               return (NULL);
+
+       for (rn = tsd_get(rrw_tsd_key); rn != NULL; rn = rn->rn_next) {
+               if (rn->rn_rrl == rrl)
+                       return (rn);
+       }
+       return (NULL);
+}
+
+/*
+ * Add a node to the head of the singly linked list.
+ */
+static void
+rrn_add(rrwlock_t *rrl, void *tag)
+{
+       rrw_node_t *rn;
+
+       rn = kmem_alloc(sizeof (*rn), KM_SLEEP);
+       rn->rn_rrl = rrl;
+       rn->rn_next = tsd_get(rrw_tsd_key);
+       rn->rn_tag = tag;
+       VERIFY(tsd_set(rrw_tsd_key, rn) == 0);
+}
+
+/*
+ * If a node is found for 'rrl', then remove the node from this
+ * thread's list and return TRUE; otherwise return FALSE.
+ */
+static boolean_t
+rrn_find_and_remove(rrwlock_t *rrl, void *tag)
+{
+       rrw_node_t *rn;
+       rrw_node_t *prev = NULL;
+
+       if (refcount_count(&rrl->rr_linked_rcount) == 0)
+               return (B_FALSE);
+
+       for (rn = tsd_get(rrw_tsd_key); rn != NULL; rn = rn->rn_next) {
+               if (rn->rn_rrl == rrl && rn->rn_tag == tag) {
+                       if (prev)
+                               prev->rn_next = rn->rn_next;
+                       else
+                               VERIFY(tsd_set(rrw_tsd_key, rn->rn_next) == 0);
+                       kmem_free(rn, sizeof (*rn));
+                       return (B_TRUE);
+               }
+               prev = rn;
+       }
+       return (B_FALSE);
+}
+
+void
+rrw_init(rrwlock_t *rrl, boolean_t track_all)
+{
+       mutex_init(&rrl->rr_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&rrl->rr_cv, NULL, CV_DEFAULT, NULL);
+       rrl->rr_writer = NULL;
+       refcount_create(&rrl->rr_anon_rcount);
+       refcount_create(&rrl->rr_linked_rcount);
+       rrl->rr_writer_wanted = B_FALSE;
+       rrl->rr_track_all = track_all;
+}
+
+void
+rrw_destroy(rrwlock_t *rrl)
+{
+       mutex_destroy(&rrl->rr_lock);
+       cv_destroy(&rrl->rr_cv);
+       ASSERT(rrl->rr_writer == NULL);
+       refcount_destroy(&rrl->rr_anon_rcount);
+       refcount_destroy(&rrl->rr_linked_rcount);
+}
+
+static void
+rrw_enter_read_impl(rrwlock_t *rrl, boolean_t prio, void *tag)
+{
+       mutex_enter(&rrl->rr_lock);
+#if !defined(DEBUG) && defined(_KERNEL)
+       if (rrl->rr_writer == NULL && !rrl->rr_writer_wanted &&
+           !rrl->rr_track_all) {
+               rrl->rr_anon_rcount.rc_count++;
+               mutex_exit(&rrl->rr_lock);
+               return;
+       }
+       DTRACE_PROBE(zfs__rrwfastpath__rdmiss);
+#endif
+       ASSERT(rrl->rr_writer != curthread);
+       ASSERT(refcount_count(&rrl->rr_anon_rcount) >= 0);
+
+       while (rrl->rr_writer != NULL || (rrl->rr_writer_wanted &&
+           refcount_is_zero(&rrl->rr_anon_rcount) && !prio &&
+           rrn_find(rrl) == NULL))
+               cv_wait(&rrl->rr_cv, &rrl->rr_lock);
+
+       if (rrl->rr_writer_wanted || rrl->rr_track_all) {
+               /* may or may not be a re-entrant enter */
+               rrn_add(rrl, tag);
+               (void) refcount_add(&rrl->rr_linked_rcount, tag);
+       } else {
+               (void) refcount_add(&rrl->rr_anon_rcount, tag);
+       }
+       ASSERT(rrl->rr_writer == NULL);
+       mutex_exit(&rrl->rr_lock);
+}
+
+void
+rrw_enter_read(rrwlock_t *rrl, void *tag)
+{
+       rrw_enter_read_impl(rrl, B_FALSE, tag);
+}
+
+/*
+ * take a read lock even if there are pending write lock requests. if we want
+ * to take a lock reentrantly, but from different threads (that have a
+ * relationship to each other), the normal detection mechanism to overrule
+ * the pending writer does not work, so we have to give an explicit hint here.
+ */
+void
+rrw_enter_read_prio(rrwlock_t *rrl, void *tag)
+{
+       rrw_enter_read_impl(rrl, B_TRUE, tag);
+}
+
+
+void
+rrw_enter_write(rrwlock_t *rrl)
+{
+       mutex_enter(&rrl->rr_lock);
+       ASSERT(rrl->rr_writer != curthread);
+
+       while (refcount_count(&rrl->rr_anon_rcount) > 0 ||
+           refcount_count(&rrl->rr_linked_rcount) > 0 ||
+           rrl->rr_writer != NULL) {
+               rrl->rr_writer_wanted = B_TRUE;
+               cv_wait(&rrl->rr_cv, &rrl->rr_lock);
+       }
+       rrl->rr_writer_wanted = B_FALSE;
+       rrl->rr_writer = curthread;
+       mutex_exit(&rrl->rr_lock);
+}
+
+void
+rrw_enter(rrwlock_t *rrl, krw_t rw, void *tag)
+{
+       if (rw == RW_READER)
+               rrw_enter_read(rrl, tag);
+       else
+               rrw_enter_write(rrl);
+}
+
+void
+rrw_exit(rrwlock_t *rrl, void *tag)
+{
+       mutex_enter(&rrl->rr_lock);
+#if !defined(DEBUG) && defined(_KERNEL)
+       if (!rrl->rr_writer && rrl->rr_linked_rcount.rc_count == 0) {
+               rrl->rr_anon_rcount.rc_count--;
+               if (rrl->rr_anon_rcount.rc_count == 0)
+                       cv_broadcast(&rrl->rr_cv);
+               mutex_exit(&rrl->rr_lock);
+               return;
+       }
+       DTRACE_PROBE(zfs__rrwfastpath__exitmiss);
+#endif
+       ASSERT(!refcount_is_zero(&rrl->rr_anon_rcount) ||
+           !refcount_is_zero(&rrl->rr_linked_rcount) ||
+           rrl->rr_writer != NULL);
+
+       if (rrl->rr_writer == NULL) {
+               int64_t count;
+               if (rrn_find_and_remove(rrl, tag)) {
+                       count = refcount_remove(&rrl->rr_linked_rcount, tag);
+               } else {
+                       ASSERT(!rrl->rr_track_all);
+                       count = refcount_remove(&rrl->rr_anon_rcount, tag);
+               }
+               if (count == 0)
+                       cv_broadcast(&rrl->rr_cv);
+       } else {
+               ASSERT(rrl->rr_writer == curthread);
+               ASSERT(refcount_is_zero(&rrl->rr_anon_rcount) &&
+                   refcount_is_zero(&rrl->rr_linked_rcount));
+               rrl->rr_writer = NULL;
+               cv_broadcast(&rrl->rr_cv);
+       }
+       mutex_exit(&rrl->rr_lock);
+}
+
+/*
+ * If the lock was created with track_all, rrw_held(RW_READER) will return
+ * B_TRUE iff the current thread has the lock for reader.  Otherwise it may
+ * return B_TRUE if any thread has the lock for reader.
+ */
+boolean_t
+rrw_held(rrwlock_t *rrl, krw_t rw)
+{
+       boolean_t held;
+
+       mutex_enter(&rrl->rr_lock);
+       if (rw == RW_WRITER) {
+               held = (rrl->rr_writer == curthread);
+       } else {
+               held = (!refcount_is_zero(&rrl->rr_anon_rcount) ||
+                   rrn_find(rrl) != NULL);
+       }
+       mutex_exit(&rrl->rr_lock);
+
+       return (held);
+}
+
+void
+rrw_tsd_destroy(void *arg)
+{
+       rrw_node_t *rn = arg;
+       if (rn != NULL) {
+               panic("thread %p terminating with rrw lock %p held",
+                   (void *)curthread, (void *)rn->rn_rrl);
+       }
+}
+
+/*
+ * A reader-mostly lock implementation, tuning above reader-writer locks
+ * for hightly parallel read acquisitions, while pessimizing writes.
+ *
+ * The idea is to split single busy lock into array of locks, so that
+ * each reader can lock only one of them for read, depending on result
+ * of simple hash function.  That proportionally reduces lock congestion.
+ * Writer same time has to sequentially aquire write on all the locks.
+ * That makes write aquisition proportionally slower, but in places where
+ * it is used (filesystem unmount) performance is not critical.
+ *
+ * All the functions below are direct wrappers around functions above.
+ */
+void
+rrm_init(rrmlock_t *rrl, boolean_t track_all)
+{
+       int i;
+
+       for (i = 0; i < RRM_NUM_LOCKS; i++)
+               rrw_init(&rrl->locks[i], track_all);
+}
+
+void
+rrm_destroy(rrmlock_t *rrl)
+{
+       int i;
+
+       for (i = 0; i < RRM_NUM_LOCKS; i++)
+               rrw_destroy(&rrl->locks[i]);
+}
+
+void
+rrm_enter(rrmlock_t *rrl, krw_t rw, void *tag)
+{
+       if (rw == RW_READER)
+               rrm_enter_read(rrl, tag);
+       else
+               rrm_enter_write(rrl);
+}
+
+/*
+ * This maps the current thread to a specific lock.  Note that the lock
+ * must be released by the same thread that acquired it.  We do this
+ * mapping by taking the thread pointer mod a prime number.  We examine
+ * only the low 32 bits of the thread pointer, because 32-bit division
+ * is faster than 64-bit division, and the high 32 bits have little
+ * entropy anyway.
+ */
+#define        RRM_TD_LOCK()   (((uint32_t)(uintptr_t)(curthread)) % RRM_NUM_LOCKS)
+
+void
+rrm_enter_read(rrmlock_t *rrl, void *tag)
+{
+       rrw_enter_read(&rrl->locks[RRM_TD_LOCK()], tag);
+}
+
+void
+rrm_enter_write(rrmlock_t *rrl)
+{
+       int i;
+
+       for (i = 0; i < RRM_NUM_LOCKS; i++)
+               rrw_enter_write(&rrl->locks[i]);
+}
+
+void
+rrm_exit(rrmlock_t *rrl, void *tag)
+{
+       int i;
+
+       if (rrl->locks[0].rr_writer == curthread) {
+               for (i = 0; i < RRM_NUM_LOCKS; i++)
+                       rrw_exit(&rrl->locks[i], tag);
+       } else {
+               rrw_exit(&rrl->locks[RRM_TD_LOCK()], tag);
+       }
+}
+
+boolean_t
+rrm_held(rrmlock_t *rrl, krw_t rw)
+{
+       if (rw == RW_WRITER) {
+               return (rrw_held(&rrl->locks[0], rw));
+       } else {
+               return (rrw_held(&rrl->locks[RRM_TD_LOCK()], rw));
+       }
+}
diff --git a/zfs/module/zfs/sa.c b/zfs/module/zfs/sa.c
new file mode 100644 (file)
index 0000000..d6ac5fc
--- /dev/null
@@ -0,0 +1,2071 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_objset.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/zap.h>
+#include <sys/sa.h>
+#include <sys/sunddi.h>
+#include <sys/sa_impl.h>
+#include <sys/dnode.h>
+#include <sys/errno.h>
+#include <sys/zfs_context.h>
+
+/*
+ * ZFS System attributes:
+ *
+ * A generic mechanism to allow for arbitrary attributes
+ * to be stored in a dnode.  The data will be stored in the bonus buffer of
+ * the dnode and if necessary a special "spill" block will be used to handle
+ * overflow situations.  The spill block will be sized to fit the data
+ * from 512 - 128K.  When a spill block is used the BP (blkptr_t) for the
+ * spill block is stored at the end of the current bonus buffer.  Any
+ * attributes that would be in the way of the blkptr_t will be relocated
+ * into the spill block.
+ *
+ * Attribute registration:
+ *
+ * Stored persistently on a per dataset basis
+ * a mapping between attribute "string" names and their actual attribute
+ * numeric values, length, and byteswap function.  The names are only used
+ * during registration.  All  attributes are known by their unique attribute
+ * id value.  If an attribute can have a variable size then the value
+ * 0 will be used to indicate this.
+ *
+ * Attribute Layout:
+ *
+ * Attribute layouts are a way to compactly store multiple attributes, but
+ * without taking the overhead associated with managing each attribute
+ * individually.  Since you will typically have the same set of attributes
+ * stored in the same order a single table will be used to represent that
+ * layout.  The ZPL for example will usually have only about 10 different
+ * layouts (regular files, device files, symlinks,
+ * regular files + scanstamp, files/dir with extended attributes, and then
+ * you have the possibility of all of those minus ACL, because it would
+ * be kicked out into the spill block)
+ *
+ * Layouts are simply an array of the attributes and their
+ * ordering i.e. [0, 1, 4, 5, 2]
+ *
+ * Each distinct layout is given a unique layout number and that is whats
+ * stored in the header at the beginning of the SA data buffer.
+ *
+ * A layout only covers a single dbuf (bonus or spill).  If a set of
+ * attributes is split up between the bonus buffer and a spill buffer then
+ * two different layouts will be used.  This allows us to byteswap the
+ * spill without looking at the bonus buffer and keeps the on disk format of
+ * the bonus and spill buffer the same.
+ *
+ * Adding a single attribute will cause the entire set of attributes to
+ * be rewritten and could result in a new layout number being constructed
+ * as part of the rewrite if no such layout exists for the new set of
+ * attribues.  The new attribute will be appended to the end of the already
+ * existing attributes.
+ *
+ * Both the attribute registration and attribute layout information are
+ * stored in normal ZAP attributes.  Their should be a small number of
+ * known layouts and the set of attributes is assumed to typically be quite
+ * small.
+ *
+ * The registered attributes and layout "table" information is maintained
+ * in core and a special "sa_os_t" is attached to the objset_t.
+ *
+ * A special interface is provided to allow for quickly applying
+ * a large set of attributes at once.  sa_replace_all_by_template() is
+ * used to set an array of attributes.  This is used by the ZPL when
+ * creating a brand new file.  The template that is passed into the function
+ * specifies the attribute, size for variable length attributes, location of
+ * data and special "data locator" function if the data isn't in a contiguous
+ * location.
+ *
+ * Byteswap implications:
+ *
+ * Since the SA attributes are not entirely self describing we can't do
+ * the normal byteswap processing.  The special ZAP layout attribute and
+ * attribute registration attributes define the byteswap function and the
+ * size of the attributes, unless it is variable sized.
+ * The normal ZFS byteswapping infrastructure assumes you don't need
+ * to read any objects in order to do the necessary byteswapping.  Whereas
+ * SA attributes can only be properly byteswapped if the dataset is opened
+ * and the layout/attribute ZAP attributes are available.  Because of this
+ * the SA attributes will be byteswapped when they are first accessed by
+ * the SA code that will read the SA data.
+ */
+
+typedef void (sa_iterfunc_t)(void *hdr, void *addr, sa_attr_type_t,
+    uint16_t length, int length_idx, boolean_t, void *userp);
+
+static int sa_build_index(sa_handle_t *hdl, sa_buf_type_t buftype);
+static void sa_idx_tab_hold(objset_t *os, sa_idx_tab_t *idx_tab);
+static void *sa_find_idx_tab(objset_t *os, dmu_object_type_t bonustype,
+    void *data);
+static void sa_idx_tab_rele(objset_t *os, void *arg);
+static void sa_copy_data(sa_data_locator_t *func, void *start, void *target,
+    int buflen);
+static int sa_modify_attrs(sa_handle_t *hdl, sa_attr_type_t newattr,
+    sa_data_op_t action, sa_data_locator_t *locator, void *datastart,
+    uint16_t buflen, dmu_tx_t *tx);
+
+arc_byteswap_func_t sa_bswap_table[] = {
+       byteswap_uint64_array,
+       byteswap_uint32_array,
+       byteswap_uint16_array,
+       byteswap_uint8_array,
+       zfs_acl_byteswap,
+};
+
+#define        SA_COPY_DATA(f, s, t, l) \
+       { \
+               if (f == NULL) { \
+                       if (l == 8) { \
+                               *(uint64_t *)t = *(uint64_t *)s; \
+                       } else if (l == 16) { \
+                               *(uint64_t *)t = *(uint64_t *)s; \
+                               *(uint64_t *)((uintptr_t)t + 8) = \
+                                   *(uint64_t *)((uintptr_t)s + 8); \
+                       } else { \
+                               bcopy(s, t, l); \
+                       } \
+               } else \
+                       sa_copy_data(f, s, t, l); \
+       }
+
+/*
+ * This table is fixed and cannot be changed.  Its purpose is to
+ * allow the SA code to work with both old/new ZPL file systems.
+ * It contains the list of legacy attributes.  These attributes aren't
+ * stored in the "attribute" registry zap objects, since older ZPL file systems
+ * won't have the registry.  Only objsets of type ZFS_TYPE_FILESYSTEM will
+ * use this static table.
+ */
+sa_attr_reg_t sa_legacy_attrs[] = {
+       {"ZPL_ATIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 0},
+       {"ZPL_MTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 1},
+       {"ZPL_CTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 2},
+       {"ZPL_CRTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 3},
+       {"ZPL_GEN", sizeof (uint64_t), SA_UINT64_ARRAY, 4},
+       {"ZPL_MODE", sizeof (uint64_t), SA_UINT64_ARRAY, 5},
+       {"ZPL_SIZE", sizeof (uint64_t), SA_UINT64_ARRAY, 6},
+       {"ZPL_PARENT", sizeof (uint64_t), SA_UINT64_ARRAY, 7},
+       {"ZPL_LINKS", sizeof (uint64_t), SA_UINT64_ARRAY, 8},
+       {"ZPL_XATTR", sizeof (uint64_t), SA_UINT64_ARRAY, 9},
+       {"ZPL_RDEV", sizeof (uint64_t), SA_UINT64_ARRAY, 10},
+       {"ZPL_FLAGS", sizeof (uint64_t), SA_UINT64_ARRAY, 11},
+       {"ZPL_UID", sizeof (uint64_t), SA_UINT64_ARRAY, 12},
+       {"ZPL_GID", sizeof (uint64_t), SA_UINT64_ARRAY, 13},
+       {"ZPL_PAD", sizeof (uint64_t) * 4, SA_UINT64_ARRAY, 14},
+       {"ZPL_ZNODE_ACL", 88, SA_UINT8_ARRAY, 15},
+};
+
+/*
+ * This is only used for objects of type DMU_OT_ZNODE
+ */
+sa_attr_type_t sa_legacy_zpl_layout[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+/*
+ * Special dummy layout used for buffers with no attributes.
+ */
+sa_attr_type_t sa_dummy_zpl_layout[] = { 0 };
+
+static int sa_legacy_attr_count = 16;
+static kmem_cache_t *sa_cache = NULL;
+
+/*ARGSUSED*/
+static int
+sa_cache_constructor(void *buf, void *unused, int kmflag)
+{
+       sa_handle_t *hdl = buf;
+
+       mutex_init(&hdl->sa_lock, NULL, MUTEX_DEFAULT, NULL);
+       return (0);
+}
+
+/*ARGSUSED*/
+static void
+sa_cache_destructor(void *buf, void *unused)
+{
+       sa_handle_t *hdl = buf;
+       mutex_destroy(&hdl->sa_lock);
+}
+
+void
+sa_cache_init(void)
+{
+       sa_cache = kmem_cache_create("sa_cache",
+           sizeof (sa_handle_t), 0, sa_cache_constructor,
+           sa_cache_destructor, NULL, NULL, NULL, 0);
+}
+
+void
+sa_cache_fini(void)
+{
+       if (sa_cache)
+               kmem_cache_destroy(sa_cache);
+}
+
+static int
+layout_num_compare(const void *arg1, const void *arg2)
+{
+       const sa_lot_t *node1 = arg1;
+       const sa_lot_t *node2 = arg2;
+
+       if (node1->lot_num > node2->lot_num)
+               return (1);
+       else if (node1->lot_num < node2->lot_num)
+               return (-1);
+       return (0);
+}
+
+static int
+layout_hash_compare(const void *arg1, const void *arg2)
+{
+       const sa_lot_t *node1 = arg1;
+       const sa_lot_t *node2 = 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);
+}
+
+boolean_t
+sa_layout_equal(sa_lot_t *tbf, sa_attr_type_t *attrs, int count)
+{
+       int i;
+
+       if (count != tbf->lot_attr_count)
+               return (1);
+
+       for (i = 0; i != count; i++) {
+               if (attrs[i] != tbf->lot_attrs[i])
+                       return (1);
+       }
+       return (0);
+}
+
+#define        SA_ATTR_HASH(attr) (zfs_crc64_table[(-1ULL ^ attr) & 0xFF])
+
+static uint64_t
+sa_layout_info_hash(sa_attr_type_t *attrs, int attr_count)
+{
+       int i;
+       uint64_t crc = -1ULL;
+
+       for (i = 0; i != attr_count; i++)
+               crc ^= SA_ATTR_HASH(attrs[i]);
+
+       return (crc);
+}
+
+static int
+sa_get_spill(sa_handle_t *hdl)
+{
+       int rc;
+       if (hdl->sa_spill == NULL) {
+               if ((rc = dmu_spill_hold_existing(hdl->sa_bonus, NULL,
+                   &hdl->sa_spill)) == 0)
+                       VERIFY(0 == sa_build_index(hdl, SA_SPILL));
+       } else {
+               rc = 0;
+       }
+
+       return (rc);
+}
+
+/*
+ * Main attribute lookup/update function
+ * returns 0 for success or non zero for failures
+ *
+ * Operates on bulk array, first failure will abort further processing
+ */
+int
+sa_attr_op(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count,
+    sa_data_op_t data_op, dmu_tx_t *tx)
+{
+       sa_os_t *sa = hdl->sa_os->os_sa;
+       int i;
+       int error = 0;
+       sa_buf_type_t buftypes;
+
+       buftypes = 0;
+
+       ASSERT(count > 0);
+       for (i = 0; i != count; i++) {
+               ASSERT(bulk[i].sa_attr <= hdl->sa_os->os_sa->sa_num_attrs);
+
+               bulk[i].sa_addr = NULL;
+               /* First check the bonus buffer */
+
+               if (hdl->sa_bonus_tab && TOC_ATTR_PRESENT(
+                   hdl->sa_bonus_tab->sa_idx_tab[bulk[i].sa_attr])) {
+                       SA_ATTR_INFO(sa, hdl->sa_bonus_tab,
+                           SA_GET_HDR(hdl, SA_BONUS),
+                           bulk[i].sa_attr, bulk[i], SA_BONUS, hdl);
+                       if (tx && !(buftypes & SA_BONUS)) {
+                               dmu_buf_will_dirty(hdl->sa_bonus, tx);
+                               buftypes |= SA_BONUS;
+                       }
+               }
+               if (bulk[i].sa_addr == NULL &&
+                   ((error = sa_get_spill(hdl)) == 0)) {
+                       if (TOC_ATTR_PRESENT(
+                           hdl->sa_spill_tab->sa_idx_tab[bulk[i].sa_attr])) {
+                               SA_ATTR_INFO(sa, hdl->sa_spill_tab,
+                                   SA_GET_HDR(hdl, SA_SPILL),
+                                   bulk[i].sa_attr, bulk[i], SA_SPILL, hdl);
+                               if (tx && !(buftypes & SA_SPILL) &&
+                                   bulk[i].sa_size == bulk[i].sa_length) {
+                                       dmu_buf_will_dirty(hdl->sa_spill, tx);
+                                       buftypes |= SA_SPILL;
+                               }
+                       }
+               }
+               if (error && error != ENOENT) {
+                       return ((error == ECKSUM) ? EIO : error);
+               }
+
+               switch (data_op) {
+               case SA_LOOKUP:
+                       if (bulk[i].sa_addr == NULL)
+                               return (SET_ERROR(ENOENT));
+                       if (bulk[i].sa_data) {
+                               SA_COPY_DATA(bulk[i].sa_data_func,
+                                   bulk[i].sa_addr, bulk[i].sa_data,
+                                   bulk[i].sa_size);
+                       }
+                       continue;
+
+               case SA_UPDATE:
+                       /* existing rewrite of attr */
+                       if (bulk[i].sa_addr &&
+                           bulk[i].sa_size == bulk[i].sa_length) {
+                               SA_COPY_DATA(bulk[i].sa_data_func,
+                                   bulk[i].sa_data, bulk[i].sa_addr,
+                                   bulk[i].sa_length);
+                               continue;
+                       } else if (bulk[i].sa_addr) { /* attr size change */
+                               error = sa_modify_attrs(hdl, bulk[i].sa_attr,
+                                   SA_REPLACE, bulk[i].sa_data_func,
+                                   bulk[i].sa_data, bulk[i].sa_length, tx);
+                       } else { /* adding new attribute */
+                               error = sa_modify_attrs(hdl, bulk[i].sa_attr,
+                                   SA_ADD, bulk[i].sa_data_func,
+                                   bulk[i].sa_data, bulk[i].sa_length, tx);
+                       }
+                       if (error)
+                               return (error);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return (error);
+}
+
+static sa_lot_t *
+sa_add_layout_entry(objset_t *os, sa_attr_type_t *attrs, int attr_count,
+    uint64_t lot_num, uint64_t hash, boolean_t zapadd, dmu_tx_t *tx)
+{
+       sa_os_t *sa = os->os_sa;
+       sa_lot_t *tb, *findtb;
+       int i;
+       avl_index_t loc;
+
+       ASSERT(MUTEX_HELD(&sa->sa_lock));
+       tb = kmem_zalloc(sizeof (sa_lot_t), KM_SLEEP);
+       tb->lot_attr_count = attr_count;
+       tb->lot_attrs = kmem_alloc(sizeof (sa_attr_type_t) * attr_count,
+           KM_SLEEP);
+       bcopy(attrs, tb->lot_attrs, sizeof (sa_attr_type_t) * attr_count);
+       tb->lot_num = lot_num;
+       tb->lot_hash = hash;
+       tb->lot_instance = 0;
+
+       if (zapadd) {
+               char attr_name[8];
+
+               if (sa->sa_layout_attr_obj == 0) {
+                       sa->sa_layout_attr_obj = zap_create_link(os,
+                           DMU_OT_SA_ATTR_LAYOUTS,
+                           sa->sa_master_obj, SA_LAYOUTS, tx);
+               }
+
+               (void) snprintf(attr_name, sizeof (attr_name),
+                   "%d", (int)lot_num);
+               VERIFY(0 == zap_update(os, os->os_sa->sa_layout_attr_obj,
+                   attr_name, 2, attr_count, attrs, tx));
+       }
+
+       list_create(&tb->lot_idx_tab, sizeof (sa_idx_tab_t),
+           offsetof(sa_idx_tab_t, sa_next));
+
+       for (i = 0; i != attr_count; i++) {
+               if (sa->sa_attr_table[tb->lot_attrs[i]].sa_length == 0)
+                       tb->lot_var_sizes++;
+       }
+
+       avl_add(&sa->sa_layout_num_tree, tb);
+
+       /* verify we don't have a hash collision */
+       if ((findtb = avl_find(&sa->sa_layout_hash_tree, tb, &loc)) != NULL) {
+               for (; findtb && findtb->lot_hash == hash;
+                   findtb = AVL_NEXT(&sa->sa_layout_hash_tree, findtb)) {
+                       if (findtb->lot_instance != tb->lot_instance)
+                               break;
+                       tb->lot_instance++;
+               }
+       }
+       avl_add(&sa->sa_layout_hash_tree, tb);
+       return (tb);
+}
+
+static void
+sa_find_layout(objset_t *os, uint64_t hash, sa_attr_type_t *attrs,
+    int count, dmu_tx_t *tx, sa_lot_t **lot)
+{
+       sa_lot_t *tb, tbsearch;
+       avl_index_t loc;
+       sa_os_t *sa = os->os_sa;
+       boolean_t found = B_FALSE;
+
+       mutex_enter(&sa->sa_lock);
+       tbsearch.lot_hash = hash;
+       tbsearch.lot_instance = 0;
+       tb = avl_find(&sa->sa_layout_hash_tree, &tbsearch, &loc);
+       if (tb) {
+               for (; tb && tb->lot_hash == hash;
+                   tb = AVL_NEXT(&sa->sa_layout_hash_tree, tb)) {
+                       if (sa_layout_equal(tb, attrs, count) == 0) {
+                               found = B_TRUE;
+                               break;
+                       }
+               }
+       }
+       if (!found) {
+               tb = sa_add_layout_entry(os, attrs, count,
+                   avl_numnodes(&sa->sa_layout_num_tree), hash, B_TRUE, tx);
+       }
+       mutex_exit(&sa->sa_lock);
+       *lot = tb;
+}
+
+static int
+sa_resize_spill(sa_handle_t *hdl, uint32_t size, dmu_tx_t *tx)
+{
+       int error;
+       uint32_t blocksize;
+
+       if (size == 0) {
+               blocksize = SPA_MINBLOCKSIZE;
+       } else if (size > SPA_OLD_MAXBLOCKSIZE) {
+               ASSERT(0);
+               return (SET_ERROR(EFBIG));
+       } else {
+               blocksize = P2ROUNDUP_TYPED(size, SPA_MINBLOCKSIZE, uint32_t);
+       }
+
+       error = dbuf_spill_set_blksz(hdl->sa_spill, blocksize, tx);
+       ASSERT(error == 0);
+       return (error);
+}
+
+static void
+sa_copy_data(sa_data_locator_t *func, void *datastart, void *target, int buflen)
+{
+       if (func == NULL) {
+               bcopy(datastart, target, buflen);
+       } else {
+               boolean_t start;
+               int bytes;
+               void *dataptr;
+               void *saptr = target;
+               uint32_t length;
+
+               start = B_TRUE;
+               bytes = 0;
+               while (bytes < buflen) {
+                       func(&dataptr, &length, buflen, start, datastart);
+                       bcopy(dataptr, saptr, length);
+                       saptr = (void *)((caddr_t)saptr + length);
+                       bytes += length;
+                       start = B_FALSE;
+               }
+       }
+}
+
+/*
+ * Determine several different values pertaining to system attribute
+ * buffers.
+ *
+ * Return the size of the sa_hdr_phys_t header for the buffer. Each
+ * variable length attribute except the first contributes two bytes to
+ * the header size, which is then rounded up to an 8-byte boundary.
+ *
+ * The following output parameters are also computed.
+ *
+ *  index - The index of the first attribute in attr_desc that will
+ *  spill over. Only valid if will_spill is set.
+ *
+ *  total - The total number of bytes of all system attributes described
+ *  in attr_desc.
+ *
+ *  will_spill - Set when spilling is necessary. It is only set when
+ *  the buftype is SA_BONUS.
+ */
+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)
+{
+       int var_size_count = 0;
+       int i;
+       int full_space;
+       int hdrsize;
+       int extra_hdrsize;
+
+       if (buftype == SA_BONUS && sa->sa_force_spill) {
+               *total = 0;
+               *index = 0;
+               *will_spill = B_TRUE;
+               return (0);
+       }
+
+       *index = -1;
+       *total = 0;
+       *will_spill = B_FALSE;
+
+       extra_hdrsize = 0;
+       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++) {
+               boolean_t is_var_sz, might_spill_here;
+               int tmp_hdrsize;
+
+               *total = P2ROUNDUP(*total, 8);
+               *total += attr_desc[i].sa_length;
+               if (*will_spill)
+                       continue;
+
+               is_var_sz = (SA_REGISTERED_LEN(sa, attr_desc[i].sa_attr) == 0);
+               if (is_var_sz)
+                       var_size_count++;
+
+               /*
+                * Calculate what the SA header size would be if this
+                * attribute doesn't spill.
+                */
+               tmp_hdrsize = hdrsize + ((is_var_sz && var_size_count > 1) ?
+                   sizeof (uint16_t) : 0);
+
+               /*
+                * Check whether this attribute spans into the space
+                * that would be used by the spill block pointer should
+                * a spill block be needed.
+                */
+               might_spill_here =
+                   buftype == SA_BONUS && *index == -1 &&
+                   (*total + P2ROUNDUP(tmp_hdrsize, 8)) >
+                   (full_space - sizeof (blkptr_t));
+
+               if (is_var_sz && var_size_count > 1) {
+                       if (buftype == SA_SPILL ||
+                           tmp_hdrsize + *total < full_space) {
+                               /*
+                                * Record the extra header size in case this
+                                * increase needs to be reversed due to
+                                * spill-over.
+                                */
+                               hdrsize = tmp_hdrsize;
+                               if (*index != -1 || might_spill_here)
+                                       extra_hdrsize += sizeof (uint16_t);
+                       } else {
+                               ASSERT(buftype == SA_BONUS);
+                               if (*index == -1)
+                                       *index = i;
+                               *will_spill = B_TRUE;
+                               continue;
+                       }
+               }
+
+               /*
+                * Store index of where spill *could* occur. Then
+                * continue to count the remaining attribute sizes. The
+                * sum is used later for sizing bonus and spill buffer.
+                */
+               if (might_spill_here)
+                       *index = i;
+
+               if ((*total + P2ROUNDUP(hdrsize, 8)) > full_space &&
+                   buftype == SA_BONUS)
+                       *will_spill = B_TRUE;
+       }
+
+       if (*will_spill)
+               hdrsize -= extra_hdrsize;
+
+       hdrsize = P2ROUNDUP(hdrsize, 8);
+       return (hdrsize);
+}
+
+#define        BUF_SPACE_NEEDED(total, header) (total + header)
+
+/*
+ * Find layout that corresponds to ordering of attributes
+ * If not found a new layout number is created and added to
+ * persistent layout tables.
+ */
+static int
+sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
+    dmu_tx_t *tx)
+{
+       sa_os_t *sa = hdl->sa_os->os_sa;
+       uint64_t hash;
+       sa_buf_type_t buftype;
+       sa_hdr_phys_t *sahdr;
+       void *data_start;
+       sa_attr_type_t *attrs, *attrs_start;
+       int i, lot_count;
+       int spill_idx;
+       int hdrsize;
+       int spillhdrsize = 0;
+       int used;
+       dmu_object_type_t bonustype;
+       sa_lot_t *lot;
+       int len_idx;
+       int spill_used;
+       boolean_t spilling;
+
+       dmu_buf_will_dirty(hdl->sa_bonus, tx);
+       bonustype = SA_BONUSTYPE_FROM_DB(hdl->sa_bonus);
+
+       /* 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);
+
+       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) :
+           used + hdrsize, tx));
+
+       ASSERT((bonustype == DMU_OT_ZNODE && spilling == 0) ||
+           bonustype == DMU_OT_SA);
+
+       /* setup and size spill buffer when needed */
+       if (spilling) {
+               boolean_t dummy;
+
+               if (hdl->sa_spill == NULL) {
+                       VERIFY(dmu_spill_hold_by_bonus(hdl->sa_bonus, NULL,
+                           &hdl->sa_spill) == 0);
+               }
+               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);
+
+               if (spill_used > SPA_OLD_MAXBLOCKSIZE)
+                       return (SET_ERROR(EFBIG));
+
+               if (BUF_SPACE_NEEDED(spill_used, spillhdrsize) >
+                   hdl->sa_spill->db_size)
+                       VERIFY(0 == sa_resize_spill(hdl,
+                           BUF_SPACE_NEEDED(spill_used, spillhdrsize), tx));
+       }
+
+       /* setup starting pointers to lay down data */
+       data_start = (void *)((uintptr_t)hdl->sa_bonus->db_data + hdrsize);
+       sahdr = (sa_hdr_phys_t *)hdl->sa_bonus->db_data;
+       buftype = SA_BONUS;
+
+       attrs_start = attrs = kmem_alloc(sizeof (sa_attr_type_t) * attr_count,
+           KM_SLEEP);
+       lot_count = 0;
+
+       for (i = 0, len_idx = 0, hash = -1ULL; i != attr_count; i++) {
+               uint16_t length;
+
+               ASSERT(IS_P2ALIGNED(data_start, 8));
+               attrs[i] = attr_desc[i].sa_attr;
+               length = SA_REGISTERED_LEN(sa, attrs[i]);
+               if (length == 0)
+                       length = attr_desc[i].sa_length;
+
+               if (spilling && i == spill_idx) { /* switch to spill buffer */
+                       VERIFY(bonustype == DMU_OT_SA);
+                       if (buftype == SA_BONUS && !sa->sa_force_spill) {
+                               sa_find_layout(hdl->sa_os, hash, attrs_start,
+                                   lot_count, tx, &lot);
+                               SA_SET_HDR(sahdr, lot->lot_num, hdrsize);
+                       }
+
+                       buftype = SA_SPILL;
+                       hash = -1ULL;
+                       len_idx = 0;
+
+                       sahdr = (sa_hdr_phys_t *)hdl->sa_spill->db_data;
+                       sahdr->sa_magic = SA_MAGIC;
+                       data_start = (void *)((uintptr_t)sahdr +
+                           spillhdrsize);
+                       attrs_start = &attrs[i];
+                       lot_count = 0;
+               }
+               hash ^= SA_ATTR_HASH(attrs[i]);
+               attr_desc[i].sa_addr = data_start;
+               attr_desc[i].sa_size = length;
+               SA_COPY_DATA(attr_desc[i].sa_data_func, attr_desc[i].sa_data,
+                   data_start, length);
+               if (sa->sa_attr_table[attrs[i]].sa_length == 0) {
+                       sahdr->sa_lengths[len_idx++] = length;
+               }
+               data_start = (void *)P2ROUNDUP(((uintptr_t)data_start +
+                   length), 8);
+               lot_count++;
+       }
+
+       sa_find_layout(hdl->sa_os, hash, attrs_start, lot_count, tx, &lot);
+
+       /*
+        * Verify that old znodes always have layout number 0.
+        * Must be DMU_OT_SA for arbitrary layouts
+        */
+       VERIFY((bonustype == DMU_OT_ZNODE && lot->lot_num == 0) ||
+           (bonustype == DMU_OT_SA && lot->lot_num > 1));
+
+       if (bonustype == DMU_OT_SA) {
+               SA_SET_HDR(sahdr, lot->lot_num,
+                   buftype == SA_BONUS ? hdrsize : spillhdrsize);
+       }
+
+       kmem_free(attrs, sizeof (sa_attr_type_t) * attr_count);
+       if (hdl->sa_bonus_tab) {
+               sa_idx_tab_rele(hdl->sa_os, hdl->sa_bonus_tab);
+               hdl->sa_bonus_tab = NULL;
+       }
+       if (!sa->sa_force_spill)
+               VERIFY(0 == sa_build_index(hdl, SA_BONUS));
+       if (hdl->sa_spill) {
+               sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab);
+               if (!spilling) {
+                       /*
+                        * remove spill block that is no longer needed.
+                        */
+                       dmu_buf_rele(hdl->sa_spill, NULL);
+                       hdl->sa_spill = NULL;
+                       hdl->sa_spill_tab = NULL;
+                       VERIFY(0 == dmu_rm_spill(hdl->sa_os,
+                           sa_handle_object(hdl), tx));
+               } else {
+                       VERIFY(0 == sa_build_index(hdl, SA_SPILL));
+               }
+       }
+
+       return (0);
+}
+
+static void
+sa_free_attr_table(sa_os_t *sa)
+{
+       int i;
+
+       if (sa->sa_attr_table == NULL)
+               return;
+
+       for (i = 0; i != sa->sa_num_attrs; i++) {
+               if (sa->sa_attr_table[i].sa_name)
+                       kmem_free(sa->sa_attr_table[i].sa_name,
+                           strlen(sa->sa_attr_table[i].sa_name) + 1);
+       }
+
+       kmem_free(sa->sa_attr_table,
+           sizeof (sa_attr_table_t) * sa->sa_num_attrs);
+
+       sa->sa_attr_table = NULL;
+}
+
+static int
+sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count)
+{
+       sa_os_t *sa = os->os_sa;
+       uint64_t sa_attr_count = 0;
+       uint64_t sa_reg_count = 0;
+       int error = 0;
+       uint64_t attr_value;
+       sa_attr_table_t *tb;
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int registered_count = 0;
+       int i;
+       dmu_objset_type_t ostype = dmu_objset_type(os);
+
+       sa->sa_user_table =
+           kmem_zalloc(count * sizeof (sa_attr_type_t), KM_SLEEP);
+       sa->sa_user_table_sz = count * sizeof (sa_attr_type_t);
+
+       if (sa->sa_reg_attr_obj != 0) {
+               error = zap_count(os, sa->sa_reg_attr_obj,
+                   &sa_attr_count);
+
+               /*
+                * Make sure we retrieved a count and that it isn't zero
+                */
+               if (error || (error == 0 && sa_attr_count == 0)) {
+                       if (error == 0)
+                               error = SET_ERROR(EINVAL);
+                       goto bail;
+               }
+               sa_reg_count = sa_attr_count;
+       }
+
+       if (ostype == DMU_OST_ZFS && sa_attr_count == 0)
+               sa_attr_count += sa_legacy_attr_count;
+
+       /* Allocate attribute numbers for attributes that aren't registered */
+       for (i = 0; i != count; i++) {
+               boolean_t found = B_FALSE;
+               int j;
+
+               if (ostype == DMU_OST_ZFS) {
+                       for (j = 0; j != sa_legacy_attr_count; j++) {
+                               if (strcmp(reg_attrs[i].sa_name,
+                                   sa_legacy_attrs[j].sa_name) == 0) {
+                                       sa->sa_user_table[i] =
+                                           sa_legacy_attrs[j].sa_attr;
+                                       found = B_TRUE;
+                               }
+                       }
+               }
+               if (found)
+                       continue;
+
+               if (sa->sa_reg_attr_obj)
+                       error = zap_lookup(os, sa->sa_reg_attr_obj,
+                           reg_attrs[i].sa_name, 8, 1, &attr_value);
+               else
+                       error = SET_ERROR(ENOENT);
+               switch (error) {
+               case ENOENT:
+                       sa->sa_user_table[i] = (sa_attr_type_t)sa_attr_count;
+                       sa_attr_count++;
+                       break;
+               case 0:
+                       sa->sa_user_table[i] = ATTR_NUM(attr_value);
+                       break;
+               default:
+                       goto bail;
+               }
+       }
+
+       sa->sa_num_attrs = sa_attr_count;
+       tb = sa->sa_attr_table =
+           kmem_zalloc(sizeof (sa_attr_table_t) * sa_attr_count, KM_SLEEP);
+
+       /*
+        * Attribute table is constructed from requested attribute list,
+        * previously foreign registered attributes, and also the legacy
+        * ZPL set of attributes.
+        */
+
+       if (sa->sa_reg_attr_obj) {
+               for (zap_cursor_init(&zc, os, sa->sa_reg_attr_obj);
+                   (error = zap_cursor_retrieve(&zc, &za)) == 0;
+                   zap_cursor_advance(&zc)) {
+                       uint64_t value;
+                       value  = za.za_first_integer;
+
+                       registered_count++;
+                       tb[ATTR_NUM(value)].sa_attr = ATTR_NUM(value);
+                       tb[ATTR_NUM(value)].sa_length = ATTR_LENGTH(value);
+                       tb[ATTR_NUM(value)].sa_byteswap = ATTR_BSWAP(value);
+                       tb[ATTR_NUM(value)].sa_registered = B_TRUE;
+
+                       if (tb[ATTR_NUM(value)].sa_name) {
+                               continue;
+                       }
+                       tb[ATTR_NUM(value)].sa_name =
+                           kmem_zalloc(strlen(za.za_name) +1, KM_SLEEP);
+                       (void) strlcpy(tb[ATTR_NUM(value)].sa_name, za.za_name,
+                           strlen(za.za_name) +1);
+               }
+               zap_cursor_fini(&zc);
+               /*
+                * Make sure we processed the correct number of registered
+                * attributes
+                */
+               if (registered_count != sa_reg_count) {
+                       ASSERT(error != 0);
+                       goto bail;
+               }
+
+       }
+
+       if (ostype == DMU_OST_ZFS) {
+               for (i = 0; i != sa_legacy_attr_count; i++) {
+                       if (tb[i].sa_name)
+                               continue;
+                       tb[i].sa_attr = sa_legacy_attrs[i].sa_attr;
+                       tb[i].sa_length = sa_legacy_attrs[i].sa_length;
+                       tb[i].sa_byteswap = sa_legacy_attrs[i].sa_byteswap;
+                       tb[i].sa_registered = B_FALSE;
+                       tb[i].sa_name =
+                           kmem_zalloc(strlen(sa_legacy_attrs[i].sa_name) +1,
+                           KM_SLEEP);
+                       (void) strlcpy(tb[i].sa_name,
+                           sa_legacy_attrs[i].sa_name,
+                           strlen(sa_legacy_attrs[i].sa_name) + 1);
+               }
+       }
+
+       for (i = 0; i != count; i++) {
+               sa_attr_type_t attr_id;
+
+               attr_id = sa->sa_user_table[i];
+               if (tb[attr_id].sa_name)
+                       continue;
+
+               tb[attr_id].sa_length = reg_attrs[i].sa_length;
+               tb[attr_id].sa_byteswap = reg_attrs[i].sa_byteswap;
+               tb[attr_id].sa_attr = attr_id;
+               tb[attr_id].sa_name =
+                   kmem_zalloc(strlen(reg_attrs[i].sa_name) + 1, KM_SLEEP);
+               (void) strlcpy(tb[attr_id].sa_name, reg_attrs[i].sa_name,
+                   strlen(reg_attrs[i].sa_name) + 1);
+       }
+
+       sa->sa_need_attr_registration =
+           (sa_attr_count != registered_count);
+
+       return (0);
+bail:
+       kmem_free(sa->sa_user_table, count * sizeof (sa_attr_type_t));
+       sa->sa_user_table = NULL;
+       sa_free_attr_table(sa);
+       return ((error != 0) ? error : EINVAL);
+}
+
+int
+sa_setup(objset_t *os, uint64_t sa_obj, sa_attr_reg_t *reg_attrs, int count,
+    sa_attr_type_t **user_table)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       sa_os_t *sa;
+       dmu_objset_type_t ostype = dmu_objset_type(os);
+       sa_attr_type_t *tb;
+       int error;
+
+       mutex_enter(&os->os_user_ptr_lock);
+       if (os->os_sa) {
+               mutex_enter(&os->os_sa->sa_lock);
+               mutex_exit(&os->os_user_ptr_lock);
+               tb = os->os_sa->sa_user_table;
+               mutex_exit(&os->os_sa->sa_lock);
+               *user_table = tb;
+               return (0);
+       }
+
+       sa = kmem_zalloc(sizeof (sa_os_t), KM_SLEEP);
+       mutex_init(&sa->sa_lock, NULL, MUTEX_DEFAULT, NULL);
+       sa->sa_master_obj = sa_obj;
+
+       os->os_sa = sa;
+       mutex_enter(&sa->sa_lock);
+       mutex_exit(&os->os_user_ptr_lock);
+       avl_create(&sa->sa_layout_num_tree, layout_num_compare,
+           sizeof (sa_lot_t), offsetof(sa_lot_t, lot_num_node));
+       avl_create(&sa->sa_layout_hash_tree, layout_hash_compare,
+           sizeof (sa_lot_t), offsetof(sa_lot_t, lot_hash_node));
+
+       if (sa_obj) {
+               error = zap_lookup(os, sa_obj, SA_LAYOUTS,
+                   8, 1, &sa->sa_layout_attr_obj);
+               if (error != 0 && error != ENOENT)
+                       goto fail;
+               error = zap_lookup(os, sa_obj, SA_REGISTRY,
+                   8, 1, &sa->sa_reg_attr_obj);
+               if (error != 0 && error != ENOENT)
+                       goto fail;
+       }
+
+       if ((error = sa_attr_table_setup(os, reg_attrs, count)) != 0)
+               goto fail;
+
+       if (sa->sa_layout_attr_obj != 0) {
+               uint64_t layout_count;
+
+               error = zap_count(os, sa->sa_layout_attr_obj,
+                   &layout_count);
+
+               /*
+                * Layout number count should be > 0
+                */
+               if (error || (error == 0 && layout_count == 0)) {
+                       if (error == 0)
+                               error = SET_ERROR(EINVAL);
+                       goto fail;
+               }
+
+               for (zap_cursor_init(&zc, os, sa->sa_layout_attr_obj);
+                   (error = zap_cursor_retrieve(&zc, &za)) == 0;
+                   zap_cursor_advance(&zc)) {
+                       sa_attr_type_t *lot_attrs;
+                       uint64_t lot_num;
+
+                       lot_attrs = kmem_zalloc(sizeof (sa_attr_type_t) *
+                           za.za_num_integers, KM_SLEEP);
+
+                       if ((error = (zap_lookup(os, sa->sa_layout_attr_obj,
+                           za.za_name, 2, za.za_num_integers,
+                           lot_attrs))) != 0) {
+                               kmem_free(lot_attrs, sizeof (sa_attr_type_t) *
+                                   za.za_num_integers);
+                               break;
+                       }
+                       VERIFY(ddi_strtoull(za.za_name, NULL, 10,
+                           (unsigned long long *)&lot_num) == 0);
+
+                       (void) sa_add_layout_entry(os, lot_attrs,
+                           za.za_num_integers, lot_num,
+                           sa_layout_info_hash(lot_attrs,
+                           za.za_num_integers), B_FALSE, NULL);
+                       kmem_free(lot_attrs, sizeof (sa_attr_type_t) *
+                           za.za_num_integers);
+               }
+               zap_cursor_fini(&zc);
+
+               /*
+                * Make sure layout count matches number of entries added
+                * to AVL tree
+                */
+               if (avl_numnodes(&sa->sa_layout_num_tree) != layout_count) {
+                       ASSERT(error != 0);
+                       goto fail;
+               }
+       }
+
+       /* Add special layout number for old ZNODES */
+       if (ostype == DMU_OST_ZFS) {
+               (void) sa_add_layout_entry(os, sa_legacy_zpl_layout,
+                   sa_legacy_attr_count, 0,
+                   sa_layout_info_hash(sa_legacy_zpl_layout,
+                   sa_legacy_attr_count), B_FALSE, NULL);
+
+               (void) sa_add_layout_entry(os, sa_dummy_zpl_layout, 0, 1,
+                   0, B_FALSE, NULL);
+       }
+       *user_table = os->os_sa->sa_user_table;
+       mutex_exit(&sa->sa_lock);
+       return (0);
+fail:
+       os->os_sa = NULL;
+       sa_free_attr_table(sa);
+       if (sa->sa_user_table)
+               kmem_free(sa->sa_user_table, sa->sa_user_table_sz);
+       mutex_exit(&sa->sa_lock);
+       avl_destroy(&sa->sa_layout_hash_tree);
+       avl_destroy(&sa->sa_layout_num_tree);
+       mutex_destroy(&sa->sa_lock);
+       kmem_free(sa, sizeof (sa_os_t));
+       return ((error == ECKSUM) ? EIO : error);
+}
+
+void
+sa_tear_down(objset_t *os)
+{
+       sa_os_t *sa = os->os_sa;
+       sa_lot_t *layout;
+       void *cookie;
+
+       kmem_free(sa->sa_user_table, sa->sa_user_table_sz);
+
+       /* Free up attr table */
+
+       sa_free_attr_table(sa);
+
+       cookie = NULL;
+       while ((layout =
+           avl_destroy_nodes(&sa->sa_layout_hash_tree, &cookie))) {
+               sa_idx_tab_t *tab;
+               while ((tab = list_head(&layout->lot_idx_tab))) {
+                       ASSERT(refcount_count(&tab->sa_refcount));
+                       sa_idx_tab_rele(os, tab);
+               }
+       }
+
+       cookie = NULL;
+       while ((layout = avl_destroy_nodes(&sa->sa_layout_num_tree, &cookie))) {
+               kmem_free(layout->lot_attrs,
+                   sizeof (sa_attr_type_t) * layout->lot_attr_count);
+               kmem_free(layout, sizeof (sa_lot_t));
+       }
+
+       avl_destroy(&sa->sa_layout_hash_tree);
+       avl_destroy(&sa->sa_layout_num_tree);
+       mutex_destroy(&sa->sa_lock);
+
+       kmem_free(sa, sizeof (sa_os_t));
+       os->os_sa = NULL;
+}
+
+void
+sa_build_idx_tab(void *hdr, void *attr_addr, sa_attr_type_t attr,
+    uint16_t length, int length_idx, boolean_t var_length, void *userp)
+{
+       sa_idx_tab_t *idx_tab = userp;
+
+       if (var_length) {
+               ASSERT(idx_tab->sa_variable_lengths);
+               idx_tab->sa_variable_lengths[length_idx] = length;
+       }
+       TOC_ATTR_ENCODE(idx_tab->sa_idx_tab[attr], length_idx,
+           (uint32_t)((uintptr_t)attr_addr - (uintptr_t)hdr));
+}
+
+static void
+sa_attr_iter(objset_t *os, sa_hdr_phys_t *hdr, dmu_object_type_t type,
+    sa_iterfunc_t func, sa_lot_t *tab, void *userp)
+{
+       void *data_start;
+       sa_lot_t *tb = tab;
+       sa_lot_t search;
+       avl_index_t loc;
+       sa_os_t *sa = os->os_sa;
+       int i;
+       uint16_t *length_start = NULL;
+       uint8_t length_idx = 0;
+
+       if (tab == NULL) {
+               search.lot_num = SA_LAYOUT_NUM(hdr, type);
+               tb = avl_find(&sa->sa_layout_num_tree, &search, &loc);
+               ASSERT(tb);
+       }
+
+       if (IS_SA_BONUSTYPE(type)) {
+               data_start = (void *)P2ROUNDUP(((uintptr_t)hdr +
+                   offsetof(sa_hdr_phys_t, sa_lengths) +
+                   (sizeof (uint16_t) * tb->lot_var_sizes)), 8);
+               length_start = hdr->sa_lengths;
+       } else {
+               data_start = hdr;
+       }
+
+       for (i = 0; i != tb->lot_attr_count; i++) {
+               int attr_length, reg_length;
+               uint8_t idx_len;
+
+               reg_length = sa->sa_attr_table[tb->lot_attrs[i]].sa_length;
+               if (reg_length) {
+                       attr_length = reg_length;
+                       idx_len = 0;
+               } else {
+                       attr_length = length_start[length_idx];
+                       idx_len = length_idx++;
+               }
+
+               func(hdr, data_start, tb->lot_attrs[i], attr_length,
+                   idx_len, reg_length == 0 ? B_TRUE : B_FALSE, userp);
+
+               data_start = (void *)P2ROUNDUP(((uintptr_t)data_start +
+                   attr_length), 8);
+       }
+}
+
+/*ARGSUSED*/
+void
+sa_byteswap_cb(void *hdr, void *attr_addr, sa_attr_type_t attr,
+    uint16_t length, int length_idx, boolean_t variable_length, void *userp)
+{
+       sa_handle_t *hdl = userp;
+       sa_os_t *sa = hdl->sa_os->os_sa;
+
+       sa_bswap_table[sa->sa_attr_table[attr].sa_byteswap](attr_addr, length);
+}
+
+void
+sa_byteswap(sa_handle_t *hdl, sa_buf_type_t buftype)
+{
+       sa_hdr_phys_t *sa_hdr_phys = SA_GET_HDR(hdl, buftype);
+       dmu_buf_impl_t *db;
+       int num_lengths = 1;
+       int i;
+       ASSERTV(sa_os_t *sa = hdl->sa_os->os_sa);
+
+       ASSERT(MUTEX_HELD(&sa->sa_lock));
+       if (sa_hdr_phys->sa_magic == SA_MAGIC)
+               return;
+
+       db = SA_GET_DB(hdl, buftype);
+
+       if (buftype == SA_SPILL) {
+               arc_release(db->db_buf, NULL);
+               arc_buf_thaw(db->db_buf);
+       }
+
+       sa_hdr_phys->sa_magic = BSWAP_32(sa_hdr_phys->sa_magic);
+       sa_hdr_phys->sa_layout_info = BSWAP_16(sa_hdr_phys->sa_layout_info);
+
+       /*
+        * Determine number of variable lenghts in header
+        * The standard 8 byte header has one for free and a
+        * 16 byte header would have 4 + 1;
+        */
+       if (SA_HDR_SIZE(sa_hdr_phys) > 8)
+               num_lengths += (SA_HDR_SIZE(sa_hdr_phys) - 8) >> 1;
+       for (i = 0; i != num_lengths; i++)
+               sa_hdr_phys->sa_lengths[i] =
+                   BSWAP_16(sa_hdr_phys->sa_lengths[i]);
+
+       sa_attr_iter(hdl->sa_os, sa_hdr_phys, DMU_OT_SA,
+           sa_byteswap_cb, NULL, hdl);
+
+       if (buftype == SA_SPILL)
+               arc_buf_freeze(((dmu_buf_impl_t *)hdl->sa_spill)->db_buf);
+}
+
+static int
+sa_build_index(sa_handle_t *hdl, sa_buf_type_t buftype)
+{
+       sa_hdr_phys_t *sa_hdr_phys;
+       dmu_buf_impl_t *db = SA_GET_DB(hdl, buftype);
+       dmu_object_type_t bonustype = SA_BONUSTYPE_FROM_DB(db);
+       sa_os_t *sa = hdl->sa_os->os_sa;
+       sa_idx_tab_t *idx_tab;
+
+       sa_hdr_phys = SA_GET_HDR(hdl, buftype);
+
+       mutex_enter(&sa->sa_lock);
+
+       /* Do we need to byteswap? */
+
+       /* only check if not old znode */
+       if (IS_SA_BONUSTYPE(bonustype) && sa_hdr_phys->sa_magic != SA_MAGIC &&
+           sa_hdr_phys->sa_magic != 0) {
+               VERIFY(BSWAP_32(sa_hdr_phys->sa_magic) == SA_MAGIC);
+               sa_byteswap(hdl, buftype);
+       }
+
+       idx_tab = sa_find_idx_tab(hdl->sa_os, bonustype, sa_hdr_phys);
+
+       if (buftype == SA_BONUS)
+               hdl->sa_bonus_tab = idx_tab;
+       else
+               hdl->sa_spill_tab = idx_tab;
+
+       mutex_exit(&sa->sa_lock);
+       return (0);
+}
+
+/*ARGSUSED*/
+static void
+sa_evict(void *dbu)
+{
+       panic("evicting sa dbuf\n");
+}
+
+static void
+sa_idx_tab_rele(objset_t *os, void *arg)
+{
+       sa_os_t *sa = os->os_sa;
+       sa_idx_tab_t *idx_tab = arg;
+
+       if (idx_tab == NULL)
+               return;
+
+       mutex_enter(&sa->sa_lock);
+       if (refcount_remove(&idx_tab->sa_refcount, NULL) == 0) {
+               list_remove(&idx_tab->sa_layout->lot_idx_tab, idx_tab);
+               if (idx_tab->sa_variable_lengths)
+                       kmem_free(idx_tab->sa_variable_lengths,
+                           sizeof (uint16_t) *
+                           idx_tab->sa_layout->lot_var_sizes);
+               refcount_destroy(&idx_tab->sa_refcount);
+               kmem_free(idx_tab->sa_idx_tab,
+                   sizeof (uint32_t) * sa->sa_num_attrs);
+               kmem_free(idx_tab, sizeof (sa_idx_tab_t));
+       }
+       mutex_exit(&sa->sa_lock);
+}
+
+static void
+sa_idx_tab_hold(objset_t *os, sa_idx_tab_t *idx_tab)
+{
+       ASSERTV(sa_os_t *sa = os->os_sa);
+
+       ASSERT(MUTEX_HELD(&sa->sa_lock));
+       (void) refcount_add(&idx_tab->sa_refcount, NULL);
+}
+
+void
+sa_spill_rele(sa_handle_t *hdl)
+{
+       mutex_enter(&hdl->sa_lock);
+       if (hdl->sa_spill) {
+               sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab);
+               dmu_buf_rele(hdl->sa_spill, NULL);
+               hdl->sa_spill = NULL;
+               hdl->sa_spill_tab = NULL;
+       }
+       mutex_exit(&hdl->sa_lock);
+}
+
+void
+sa_handle_destroy(sa_handle_t *hdl)
+{
+       dmu_buf_t *db = hdl->sa_bonus;
+
+       mutex_enter(&hdl->sa_lock);
+       (void) dmu_buf_remove_user(db, &hdl->sa_dbu);
+
+       if (hdl->sa_bonus_tab)
+               sa_idx_tab_rele(hdl->sa_os, hdl->sa_bonus_tab);
+
+       if (hdl->sa_spill_tab)
+               sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab);
+
+       dmu_buf_rele(hdl->sa_bonus, NULL);
+
+       if (hdl->sa_spill)
+               dmu_buf_rele((dmu_buf_t *)hdl->sa_spill, NULL);
+       mutex_exit(&hdl->sa_lock);
+
+       kmem_cache_free(sa_cache, hdl);
+}
+
+int
+sa_handle_get_from_db(objset_t *os, dmu_buf_t *db, void *userp,
+    sa_handle_type_t hdl_type, sa_handle_t **handlepp)
+{
+       int error = 0;
+       sa_handle_t *handle = NULL;
+#ifdef ZFS_DEBUG
+       dmu_object_info_t doi;
+
+       dmu_object_info_from_db(db, &doi);
+       ASSERT(doi.doi_bonus_type == DMU_OT_SA ||
+           doi.doi_bonus_type == DMU_OT_ZNODE);
+#endif
+       /* find handle, if it exists */
+       /* if one doesn't exist then create a new one, and initialize it */
+
+       if (hdl_type == SA_HDL_SHARED)
+               handle = dmu_buf_get_user(db);
+
+       if (handle == NULL) {
+               sa_handle_t *winner = NULL;
+
+               handle = kmem_cache_alloc(sa_cache, KM_SLEEP);
+               handle->sa_dbu.dbu_evict_func = NULL;
+               handle->sa_userp = userp;
+               handle->sa_bonus = db;
+               handle->sa_os = os;
+               handle->sa_spill = NULL;
+               handle->sa_bonus_tab = NULL;
+               handle->sa_spill_tab = NULL;
+
+               error = sa_build_index(handle, SA_BONUS);
+
+               if (hdl_type == SA_HDL_SHARED) {
+                       dmu_buf_init_user(&handle->sa_dbu, sa_evict, NULL);
+                       winner = dmu_buf_set_user_ie(db, &handle->sa_dbu);
+               }
+
+               if (winner != NULL) {
+                       kmem_cache_free(sa_cache, handle);
+                       handle = winner;
+               }
+       }
+       *handlepp = handle;
+
+       return (error);
+}
+
+int
+sa_handle_get(objset_t *objset, uint64_t objid, void *userp,
+    sa_handle_type_t hdl_type, sa_handle_t **handlepp)
+{
+       dmu_buf_t *db;
+       int error;
+
+       if ((error = dmu_bonus_hold(objset, objid, NULL, &db)))
+               return (error);
+
+       return (sa_handle_get_from_db(objset, db, userp, hdl_type,
+           handlepp));
+}
+
+int
+sa_buf_hold(objset_t *objset, uint64_t obj_num, void *tag, dmu_buf_t **db)
+{
+       return (dmu_bonus_hold(objset, obj_num, tag, db));
+}
+
+void
+sa_buf_rele(dmu_buf_t *db, void *tag)
+{
+       dmu_buf_rele(db, tag);
+}
+
+int
+sa_lookup_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count)
+{
+       ASSERT(hdl);
+       ASSERT(MUTEX_HELD(&hdl->sa_lock));
+       return (sa_attr_op(hdl, bulk, count, SA_LOOKUP, NULL));
+}
+
+int
+sa_lookup(sa_handle_t *hdl, sa_attr_type_t attr, void *buf, uint32_t buflen)
+{
+       int error;
+       sa_bulk_attr_t bulk;
+
+       VERIFY3U(buflen, <=, SA_ATTR_MAX_LEN);
+
+       bulk.sa_attr = attr;
+       bulk.sa_data = buf;
+       bulk.sa_length = buflen;
+       bulk.sa_data_func = NULL;
+
+       ASSERT(hdl);
+       mutex_enter(&hdl->sa_lock);
+       error = sa_lookup_impl(hdl, &bulk, 1);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+#ifdef _KERNEL
+int
+sa_lookup_uio(sa_handle_t *hdl, sa_attr_type_t attr, uio_t *uio)
+{
+       int error;
+       sa_bulk_attr_t bulk;
+
+       bulk.sa_data = NULL;
+       bulk.sa_attr = attr;
+       bulk.sa_data_func = NULL;
+
+       ASSERT(hdl);
+
+       mutex_enter(&hdl->sa_lock);
+       if ((error = sa_attr_op(hdl, &bulk, 1, SA_LOOKUP, NULL)) == 0) {
+               error = uiomove((void *)bulk.sa_addr, MIN(bulk.sa_size,
+                   uio->uio_resid), UIO_READ, uio);
+       }
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+#endif
+
+void *
+sa_find_idx_tab(objset_t *os, dmu_object_type_t bonustype, void *data)
+{
+       sa_idx_tab_t *idx_tab;
+       sa_hdr_phys_t *hdr = (sa_hdr_phys_t *)data;
+       sa_os_t *sa = os->os_sa;
+       sa_lot_t *tb, search;
+       avl_index_t loc;
+
+       /*
+        * Deterimine layout number.  If SA node and header == 0 then
+        * force the index table to the dummy "1" empty layout.
+        *
+        * The layout number would only be zero for a newly created file
+        * that has not added any attributes yet, or with crypto enabled which
+        * doesn't write any attributes to the bonus buffer.
+        */
+
+       search.lot_num = SA_LAYOUT_NUM(hdr, bonustype);
+
+       tb = avl_find(&sa->sa_layout_num_tree, &search, &loc);
+
+       /* Verify header size is consistent with layout information */
+       ASSERT(tb);
+       ASSERT((IS_SA_BONUSTYPE(bonustype) &&
+           SA_HDR_SIZE_MATCH_LAYOUT(hdr, tb)) || !IS_SA_BONUSTYPE(bonustype) ||
+           (IS_SA_BONUSTYPE(bonustype) && hdr->sa_layout_info == 0));
+
+       /*
+        * See if any of the already existing TOC entries can be reused?
+        */
+
+       for (idx_tab = list_head(&tb->lot_idx_tab); idx_tab;
+           idx_tab = list_next(&tb->lot_idx_tab, idx_tab)) {
+               boolean_t valid_idx = B_TRUE;
+               int i;
+
+               if (tb->lot_var_sizes != 0 &&
+                   idx_tab->sa_variable_lengths != NULL) {
+                       for (i = 0; i != tb->lot_var_sizes; i++) {
+                               if (hdr->sa_lengths[i] !=
+                                   idx_tab->sa_variable_lengths[i]) {
+                                       valid_idx = B_FALSE;
+                                       break;
+                               }
+                       }
+               }
+               if (valid_idx) {
+                       sa_idx_tab_hold(os, idx_tab);
+                       return (idx_tab);
+               }
+       }
+
+       /* No such luck, create a new entry */
+       idx_tab = kmem_zalloc(sizeof (sa_idx_tab_t), KM_SLEEP);
+       idx_tab->sa_idx_tab =
+           kmem_zalloc(sizeof (uint32_t) * sa->sa_num_attrs, KM_SLEEP);
+       idx_tab->sa_layout = tb;
+       refcount_create(&idx_tab->sa_refcount);
+       if (tb->lot_var_sizes)
+               idx_tab->sa_variable_lengths = kmem_alloc(sizeof (uint16_t) *
+                   tb->lot_var_sizes, KM_SLEEP);
+
+       sa_attr_iter(os, hdr, bonustype, sa_build_idx_tab,
+           tb, idx_tab);
+       sa_idx_tab_hold(os, idx_tab);   /* one hold for consumer */
+       sa_idx_tab_hold(os, idx_tab);   /* one for layout */
+       list_insert_tail(&tb->lot_idx_tab, idx_tab);
+       return (idx_tab);
+}
+
+void
+sa_default_locator(void **dataptr, uint32_t *len, uint32_t total_len,
+    boolean_t start, void *userdata)
+{
+       ASSERT(start);
+
+       *dataptr = userdata;
+       *len = total_len;
+}
+
+static void
+sa_attr_register_sync(sa_handle_t *hdl, dmu_tx_t *tx)
+{
+       uint64_t attr_value = 0;
+       sa_os_t *sa = hdl->sa_os->os_sa;
+       sa_attr_table_t *tb = sa->sa_attr_table;
+       int i;
+
+       mutex_enter(&sa->sa_lock);
+
+       if (!sa->sa_need_attr_registration || sa->sa_master_obj == 0) {
+               mutex_exit(&sa->sa_lock);
+               return;
+       }
+
+       if (sa->sa_reg_attr_obj == 0) {
+               sa->sa_reg_attr_obj = zap_create_link(hdl->sa_os,
+                   DMU_OT_SA_ATTR_REGISTRATION,
+                   sa->sa_master_obj, SA_REGISTRY, tx);
+       }
+       for (i = 0; i != sa->sa_num_attrs; i++) {
+               if (sa->sa_attr_table[i].sa_registered)
+                       continue;
+               ATTR_ENCODE(attr_value, tb[i].sa_attr, tb[i].sa_length,
+                   tb[i].sa_byteswap);
+               VERIFY(0 == zap_update(hdl->sa_os, sa->sa_reg_attr_obj,
+                   tb[i].sa_name, 8, 1, &attr_value, tx));
+               tb[i].sa_registered = B_TRUE;
+       }
+       sa->sa_need_attr_registration = B_FALSE;
+       mutex_exit(&sa->sa_lock);
+}
+
+/*
+ * Replace all attributes with attributes specified in template.
+ * If dnode had a spill buffer then those attributes will be
+ * also be replaced, possibly with just an empty spill block
+ *
+ * This interface is intended to only be used for bulk adding of
+ * attributes for a new file.  It will also be used by the ZPL
+ * when converting and old formatted znode to native SA support.
+ */
+int
+sa_replace_all_by_template_locked(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc,
+    int attr_count, dmu_tx_t *tx)
+{
+       sa_os_t *sa = hdl->sa_os->os_sa;
+
+       if (sa->sa_need_attr_registration)
+               sa_attr_register_sync(hdl, tx);
+       return (sa_build_layouts(hdl, attr_desc, attr_count, tx));
+}
+
+int
+sa_replace_all_by_template(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc,
+    int attr_count, dmu_tx_t *tx)
+{
+       int error;
+
+       mutex_enter(&hdl->sa_lock);
+       error = sa_replace_all_by_template_locked(hdl, attr_desc,
+           attr_count, tx);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+/*
+ * add/remove/replace a single attribute and then rewrite the entire set
+ * of attributes.
+ */
+static int
+sa_modify_attrs(sa_handle_t *hdl, sa_attr_type_t newattr,
+    sa_data_op_t action, sa_data_locator_t *locator, void *datastart,
+    uint16_t buflen, dmu_tx_t *tx)
+{
+       sa_os_t *sa = hdl->sa_os->os_sa;
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)hdl->sa_bonus;
+       dnode_t *dn;
+       sa_bulk_attr_t *attr_desc;
+       void *old_data[2];
+       int bonus_attr_count = 0;
+       int bonus_data_size = 0;
+       int spill_data_size = 0;
+       int spill_attr_count = 0;
+       int error;
+       uint16_t length;
+       int i, j, k, length_idx;
+       sa_hdr_phys_t *hdr;
+       sa_idx_tab_t *idx_tab;
+       int attr_count;
+       int count;
+
+       ASSERT(MUTEX_HELD(&hdl->sa_lock));
+
+       /* First make of copy of the old data */
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       if (dn->dn_bonuslen != 0) {
+               bonus_data_size = hdl->sa_bonus->db_size;
+               old_data[0] = kmem_alloc(bonus_data_size, KM_SLEEP);
+               bcopy(hdl->sa_bonus->db_data, old_data[0],
+                   hdl->sa_bonus->db_size);
+               bonus_attr_count = hdl->sa_bonus_tab->sa_layout->lot_attr_count;
+       } else {
+               old_data[0] = NULL;
+       }
+       DB_DNODE_EXIT(db);
+
+       /* Bring spill buffer online if it isn't currently */
+
+       if ((error = sa_get_spill(hdl)) == 0) {
+               spill_data_size = hdl->sa_spill->db_size;
+               old_data[1] = zio_buf_alloc(spill_data_size);
+               bcopy(hdl->sa_spill->db_data, old_data[1],
+                   hdl->sa_spill->db_size);
+               spill_attr_count =
+                   hdl->sa_spill_tab->sa_layout->lot_attr_count;
+       } else if (error && error != ENOENT) {
+               if (old_data[0])
+                       kmem_free(old_data[0], bonus_data_size);
+               return (error);
+       } else {
+               old_data[1] = NULL;
+       }
+
+       /* build descriptor of all attributes */
+
+       attr_count = bonus_attr_count + spill_attr_count;
+       if (action == SA_ADD)
+               attr_count++;
+       else if (action == SA_REMOVE)
+               attr_count--;
+
+       attr_desc = kmem_zalloc(sizeof (sa_bulk_attr_t) * attr_count, KM_SLEEP);
+
+       /*
+        * loop through bonus and spill buffer if it exists, and
+        * build up new attr_descriptor to reset the attributes
+        */
+       k = j = 0;
+       count = bonus_attr_count;
+       hdr = SA_GET_HDR(hdl, SA_BONUS);
+       idx_tab = SA_IDX_TAB_GET(hdl, SA_BONUS);
+       for (; k != 2; k++) {
+               /*
+                * Iterate over each attribute in layout.  Fetch the
+                * size of variable-length attributes needing rewrite
+                * from sa_lengths[].
+                */
+               for (i = 0, length_idx = 0; i != count; i++) {
+                       sa_attr_type_t attr;
+
+                       attr = idx_tab->sa_layout->lot_attrs[i];
+                       length = SA_REGISTERED_LEN(sa, attr);
+                       if (attr == newattr) {
+                               if (length == 0)
+                                       ++length_idx;
+                               if (action == SA_REMOVE)
+                                       continue;
+                               ASSERT(length == 0);
+                               ASSERT(action == SA_REPLACE);
+                               SA_ADD_BULK_ATTR(attr_desc, j, attr,
+                                   locator, datastart, buflen);
+                       } else {
+                               if (length == 0)
+                                       length = hdr->sa_lengths[length_idx++];
+
+                               SA_ADD_BULK_ATTR(attr_desc, j, attr,
+                                   NULL, (void *)
+                                   (TOC_OFF(idx_tab->sa_idx_tab[attr]) +
+                                   (uintptr_t)old_data[k]), length);
+                       }
+               }
+               if (k == 0 && hdl->sa_spill) {
+                       hdr = SA_GET_HDR(hdl, SA_SPILL);
+                       idx_tab = SA_IDX_TAB_GET(hdl, SA_SPILL);
+                       count = spill_attr_count;
+               } else {
+                       break;
+               }
+       }
+       if (action == SA_ADD) {
+               length = SA_REGISTERED_LEN(sa, newattr);
+               if (length == 0) {
+                       length = buflen;
+               }
+               SA_ADD_BULK_ATTR(attr_desc, j, newattr, locator,
+                   datastart, length);
+       }
+
+       error = sa_build_layouts(hdl, attr_desc, attr_count, tx);
+
+       if (old_data[0])
+               kmem_free(old_data[0], bonus_data_size);
+       if (old_data[1])
+               zio_buf_free(old_data[1], spill_data_size);
+       kmem_free(attr_desc, sizeof (sa_bulk_attr_t) * attr_count);
+
+       return (error);
+}
+
+static int
+sa_bulk_update_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count,
+    dmu_tx_t *tx)
+{
+       int error;
+       sa_os_t *sa = hdl->sa_os->os_sa;
+       dmu_object_type_t bonustype;
+       dmu_buf_t *saved_spill;
+
+       ASSERT(hdl);
+       ASSERT(MUTEX_HELD(&hdl->sa_lock));
+
+       bonustype = SA_BONUSTYPE_FROM_DB(SA_GET_DB(hdl, SA_BONUS));
+       saved_spill = hdl->sa_spill;
+
+       /* sync out registration table if necessary */
+       if (sa->sa_need_attr_registration)
+               sa_attr_register_sync(hdl, tx);
+
+       error = sa_attr_op(hdl, bulk, count, SA_UPDATE, tx);
+       if (error == 0 && !IS_SA_BONUSTYPE(bonustype) && sa->sa_update_cb)
+               sa->sa_update_cb(hdl, tx);
+
+       /*
+        * If saved_spill is NULL and current sa_spill is not NULL that
+        * means we increased the refcount of the spill buffer through
+        * sa_get_spill() or dmu_spill_hold_by_dnode().  Therefore we
+        * must release the hold before calling dmu_tx_commit() to avoid
+        * making a copy of this buffer in dbuf_sync_leaf() due to the
+        * reference count now being greater than 1.
+        */
+       if (!saved_spill && hdl->sa_spill) {
+               if (hdl->sa_spill_tab) {
+                       sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab);
+                       hdl->sa_spill_tab = NULL;
+               }
+
+               dmu_buf_rele((dmu_buf_t *)hdl->sa_spill, NULL);
+               hdl->sa_spill = NULL;
+       }
+
+       return (error);
+}
+
+/*
+ * update or add new attribute
+ */
+int
+sa_update(sa_handle_t *hdl, sa_attr_type_t type,
+    void *buf, uint32_t buflen, dmu_tx_t *tx)
+{
+       int error;
+       sa_bulk_attr_t bulk;
+
+       VERIFY3U(buflen, <=, SA_ATTR_MAX_LEN);
+
+       bulk.sa_attr = type;
+       bulk.sa_data_func = NULL;
+       bulk.sa_length = buflen;
+       bulk.sa_data = buf;
+
+       mutex_enter(&hdl->sa_lock);
+       error = sa_bulk_update_impl(hdl, &bulk, 1, tx);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+int
+sa_update_from_cb(sa_handle_t *hdl, sa_attr_type_t attr,
+    uint32_t buflen, sa_data_locator_t *locator, void *userdata, dmu_tx_t *tx)
+{
+       int error;
+       sa_bulk_attr_t bulk;
+
+       VERIFY3U(buflen, <=, SA_ATTR_MAX_LEN);
+
+       bulk.sa_attr = attr;
+       bulk.sa_data = userdata;
+       bulk.sa_data_func = locator;
+       bulk.sa_length = buflen;
+
+       mutex_enter(&hdl->sa_lock);
+       error = sa_bulk_update_impl(hdl, &bulk, 1, tx);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+/*
+ * Return size of an attribute
+ */
+
+int
+sa_size(sa_handle_t *hdl, sa_attr_type_t attr, int *size)
+{
+       sa_bulk_attr_t bulk;
+       int error;
+
+       bulk.sa_data = NULL;
+       bulk.sa_attr = attr;
+       bulk.sa_data_func = NULL;
+
+       ASSERT(hdl);
+       mutex_enter(&hdl->sa_lock);
+       if ((error = sa_attr_op(hdl, &bulk, 1, SA_LOOKUP, NULL)) != 0) {
+               mutex_exit(&hdl->sa_lock);
+               return (error);
+       }
+       *size = bulk.sa_size;
+
+       mutex_exit(&hdl->sa_lock);
+       return (0);
+}
+
+int
+sa_bulk_lookup_locked(sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count)
+{
+       ASSERT(hdl);
+       ASSERT(MUTEX_HELD(&hdl->sa_lock));
+       return (sa_lookup_impl(hdl, attrs, count));
+}
+
+int
+sa_bulk_lookup(sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count)
+{
+       int error;
+
+       ASSERT(hdl);
+       mutex_enter(&hdl->sa_lock);
+       error = sa_bulk_lookup_locked(hdl, attrs, count);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+int
+sa_bulk_update(sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count, dmu_tx_t *tx)
+{
+       int error;
+
+       ASSERT(hdl);
+       mutex_enter(&hdl->sa_lock);
+       error = sa_bulk_update_impl(hdl, attrs, count, tx);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+int
+sa_remove(sa_handle_t *hdl, sa_attr_type_t attr, dmu_tx_t *tx)
+{
+       int error;
+
+       mutex_enter(&hdl->sa_lock);
+       error = sa_modify_attrs(hdl, attr, SA_REMOVE, NULL,
+           NULL, 0, tx);
+       mutex_exit(&hdl->sa_lock);
+       return (error);
+}
+
+void
+sa_object_info(sa_handle_t *hdl, dmu_object_info_t *doi)
+{
+       dmu_object_info_from_db((dmu_buf_t *)hdl->sa_bonus, doi);
+}
+
+void
+sa_object_size(sa_handle_t *hdl, uint32_t *blksize, u_longlong_t *nblocks)
+{
+       dmu_object_size_from_db((dmu_buf_t *)hdl->sa_bonus,
+           blksize, nblocks);
+}
+
+void
+sa_set_userp(sa_handle_t *hdl, void *ptr)
+{
+       hdl->sa_userp = ptr;
+}
+
+dmu_buf_t *
+sa_get_db(sa_handle_t *hdl)
+{
+       return ((dmu_buf_t *)hdl->sa_bonus);
+}
+
+void *
+sa_get_userdata(sa_handle_t *hdl)
+{
+       return (hdl->sa_userp);
+}
+
+void
+sa_register_update_callback_locked(objset_t *os, sa_update_cb_t *func)
+{
+       ASSERT(MUTEX_HELD(&os->os_sa->sa_lock));
+       os->os_sa->sa_update_cb = func;
+}
+
+void
+sa_register_update_callback(objset_t *os, sa_update_cb_t *func)
+{
+
+       mutex_enter(&os->os_sa->sa_lock);
+       sa_register_update_callback_locked(os, func);
+       mutex_exit(&os->os_sa->sa_lock);
+}
+
+uint64_t
+sa_handle_object(sa_handle_t *hdl)
+{
+       return (hdl->sa_bonus->db_object);
+}
+
+boolean_t
+sa_enabled(objset_t *os)
+{
+       return (os->os_sa == NULL);
+}
+
+int
+sa_set_sa_object(objset_t *os, uint64_t sa_object)
+{
+       sa_os_t *sa = os->os_sa;
+
+       if (sa->sa_master_obj)
+               return (1);
+
+       sa->sa_master_obj = sa_object;
+
+       return (0);
+}
+
+int
+sa_hdrsize(void *arg)
+{
+       sa_hdr_phys_t *hdr = arg;
+
+       return (SA_HDR_SIZE(hdr));
+}
+
+void
+sa_handle_lock(sa_handle_t *hdl)
+{
+       ASSERT(hdl);
+       mutex_enter(&hdl->sa_lock);
+}
+
+void
+sa_handle_unlock(sa_handle_t *hdl)
+{
+       ASSERT(hdl);
+       mutex_exit(&hdl->sa_lock);
+}
+
+#ifdef _KERNEL
+EXPORT_SYMBOL(sa_handle_get);
+EXPORT_SYMBOL(sa_handle_get_from_db);
+EXPORT_SYMBOL(sa_handle_destroy);
+EXPORT_SYMBOL(sa_buf_hold);
+EXPORT_SYMBOL(sa_buf_rele);
+EXPORT_SYMBOL(sa_spill_rele);
+EXPORT_SYMBOL(sa_lookup);
+EXPORT_SYMBOL(sa_update);
+EXPORT_SYMBOL(sa_remove);
+EXPORT_SYMBOL(sa_bulk_lookup);
+EXPORT_SYMBOL(sa_bulk_lookup_locked);
+EXPORT_SYMBOL(sa_bulk_update);
+EXPORT_SYMBOL(sa_size);
+EXPORT_SYMBOL(sa_update_from_cb);
+EXPORT_SYMBOL(sa_object_info);
+EXPORT_SYMBOL(sa_object_size);
+EXPORT_SYMBOL(sa_get_userdata);
+EXPORT_SYMBOL(sa_set_userp);
+EXPORT_SYMBOL(sa_get_db);
+EXPORT_SYMBOL(sa_handle_object);
+EXPORT_SYMBOL(sa_register_update_callback);
+EXPORT_SYMBOL(sa_setup);
+EXPORT_SYMBOL(sa_replace_all_by_template);
+EXPORT_SYMBOL(sa_replace_all_by_template_locked);
+EXPORT_SYMBOL(sa_enabled);
+EXPORT_SYMBOL(sa_cache_init);
+EXPORT_SYMBOL(sa_cache_fini);
+EXPORT_SYMBOL(sa_set_sa_object);
+EXPORT_SYMBOL(sa_hdrsize);
+EXPORT_SYMBOL(sa_handle_lock);
+EXPORT_SYMBOL(sa_handle_unlock);
+EXPORT_SYMBOL(sa_lookup_uio);
+#endif /* _KERNEL */
diff --git a/zfs/module/zfs/sha256.c b/zfs/module/zfs/sha256.c
new file mode 100644 (file)
index 0000000..cf9dd8f
--- /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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+#include <sys/zio_checksum.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)
+{
+       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;
+}
+
+void
+zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+           0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
+       uint8_t pad[128];
+       int i, padsize;
+
+       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;
+
+       for (i = 0; i < padsize; i += 64)
+               SHA256Transform(H, pad + i);
+
+       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]);
+}
diff --git a/zfs/module/zfs/spa.c b/zfs/module/zfs/spa.c
new file mode 100644 (file)
index 0000000..dde909e
--- /dev/null
@@ -0,0 +1,6648 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2013, 2014, Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+/*
+ * SPA: Storage Pool Allocator
+ *
+ * This file contains all the routines used when modifying on-disk SPA state.
+ * This includes opening, importing, destroying, exporting a pool, and syncing a
+ * pool.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/fm/fs/zfs.h>
+#include <sys/spa_impl.h>
+#include <sys/zio.h>
+#include <sys/zio_checksum.h>
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/zap.h>
+#include <sys/zil.h>
+#include <sys/ddt.h>
+#include <sys/vdev_impl.h>
+#include <sys/vdev_disk.h>
+#include <sys/metaslab.h>
+#include <sys/metaslab_impl.h>
+#include <sys/uberblock_impl.h>
+#include <sys/txg.h>
+#include <sys/avl.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dmu_objset.h>
+#include <sys/unique.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/fs/zfs.h>
+#include <sys/arc.h>
+#include <sys/callb.h>
+#include <sys/systeminfo.h>
+#include <sys/spa_boot.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/dsl_scan.h>
+#include <sys/zfeature.h>
+#include <sys/dsl_destroy.h>
+#include <sys/zvol.h>
+
+#ifdef _KERNEL
+#include <sys/bootprops.h>
+#include <sys/callb.h>
+#include <sys/cpupart.h>
+#include <sys/pool.h>
+#include <sys/sysdc.h>
+#include <sys/zone.h>
+#endif /* _KERNEL */
+
+#include "zfs_prop.h"
+#include "zfs_comutil.h"
+
+typedef enum zti_modes {
+       ZTI_MODE_FIXED,                 /* value is # of threads (min 1) */
+       ZTI_MODE_BATCH,                 /* cpu-intensive; value is ignored */
+       ZTI_MODE_NULL,                  /* don't create a taskq */
+       ZTI_NMODES
+} zti_modes_t;
+
+#define        ZTI_P(n, q)     { ZTI_MODE_FIXED, (n), (q) }
+#define        ZTI_PCT(n)      { ZTI_MODE_ONLINE_PERCENT, (n), 1 }
+#define        ZTI_BATCH       { ZTI_MODE_BATCH, 0, 1 }
+#define        ZTI_NULL        { ZTI_MODE_NULL, 0, 0 }
+
+#define        ZTI_N(n)        ZTI_P(n, 1)
+#define        ZTI_ONE         ZTI_N(1)
+
+typedef struct zio_taskq_info {
+       zti_modes_t zti_mode;
+       uint_t zti_value;
+       uint_t zti_count;
+} zio_taskq_info_t;
+
+static const char *const zio_taskq_types[ZIO_TASKQ_TYPES] = {
+       "iss", "iss_h", "int", "int_h"
+};
+
+/*
+ * This table defines the taskq settings for each ZFS I/O type. When
+ * initializing a pool, we use this table to create an appropriately sized
+ * taskq. Some operations are low volume and therefore have a small, static
+ * number of threads assigned to their taskqs using the ZTI_N(#) or ZTI_ONE
+ * macros. Other operations process a large amount of data; the ZTI_BATCH
+ * macro causes us to create a taskq oriented for throughput. Some operations
+ * are so high frequency and short-lived that the taskq itself can become a a
+ * point of lock contention. The ZTI_P(#, #) macro indicates that we need an
+ * additional degree of parallelism specified by the number of threads per-
+ * taskq and the number of taskqs; when dispatching an event in this case, the
+ * particular taskq is chosen at random.
+ *
+ * The different taskq priorities are to handle the different contexts (issue
+ * and interrupt) and then to reserve threads for ZIO_PRIORITY_NOW I/Os that
+ * need to be handled with minimum delay.
+ */
+const zio_taskq_info_t zio_taskqs[ZIO_TYPES][ZIO_TASKQ_TYPES] = {
+       /* ISSUE        ISSUE_HIGH      INTR            INTR_HIGH */
+       { ZTI_ONE,      ZTI_NULL,       ZTI_ONE,        ZTI_NULL }, /* NULL */
+       { ZTI_N(8),     ZTI_NULL,       ZTI_P(12, 8),   ZTI_NULL }, /* READ */
+       { ZTI_BATCH,    ZTI_N(5),       ZTI_P(12, 8),   ZTI_N(5) }, /* WRITE */
+       { ZTI_P(12, 8), ZTI_NULL,       ZTI_ONE,        ZTI_NULL }, /* FREE */
+       { ZTI_ONE,      ZTI_NULL,       ZTI_ONE,        ZTI_NULL }, /* CLAIM */
+       { ZTI_ONE,      ZTI_NULL,       ZTI_ONE,        ZTI_NULL }, /* IOCTL */
+};
+
+static void spa_sync_version(void *arg, dmu_tx_t *tx);
+static void spa_sync_props(void *arg, dmu_tx_t *tx);
+static boolean_t spa_has_active_shared_spare(spa_t *spa);
+static inline int spa_load_impl(spa_t *spa, uint64_t, nvlist_t *config,
+    spa_load_state_t state, spa_import_type_t type, boolean_t mosconfig,
+    char **ereport);
+static void spa_vdev_resilver_done(spa_t *spa);
+
+uint_t         zio_taskq_batch_pct = 75;       /* 1 thread per cpu in pset */
+id_t           zio_taskq_psrset_bind = PS_NONE;
+boolean_t      zio_taskq_sysdc = B_TRUE;       /* use SDC scheduling class */
+uint_t         zio_taskq_basedc = 80;          /* base duty cycle */
+
+boolean_t      spa_create_process = B_TRUE;    /* no process ==> no sysdc */
+
+/*
+ * This (illegal) pool name is used when temporarily importing a spa_t in order
+ * to get the vdev stats associated with the imported devices.
+ */
+#define        TRYIMPORT_NAME  "$import"
+
+/*
+ * ==========================================================================
+ * SPA properties routines
+ * ==========================================================================
+ */
+
+/*
+ * Add a (source=src, propname=propval) list to an nvlist.
+ */
+static void
+spa_prop_add_list(nvlist_t *nvl, zpool_prop_t prop, char *strval,
+    uint64_t intval, zprop_source_t src)
+{
+       const char *propname = zpool_prop_to_name(prop);
+       nvlist_t *propval;
+
+       VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+       VERIFY(nvlist_add_uint64(propval, ZPROP_SOURCE, src) == 0);
+
+       if (strval != NULL)
+               VERIFY(nvlist_add_string(propval, ZPROP_VALUE, strval) == 0);
+       else
+               VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, intval) == 0);
+
+       VERIFY(nvlist_add_nvlist(nvl, propname, propval) == 0);
+       nvlist_free(propval);
+}
+
+/*
+ * Get property values from the spa configuration.
+ */
+static void
+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;
+       spa_config_dirent_t *dp;
+       metaslab_class_t *mc = spa_normal_class(spa);
+
+       ASSERT(MUTEX_HELD(&spa->spa_props_lock));
+
+       if (rvd != NULL) {
+               alloc = metaslab_class_get_alloc(spa_normal_class(spa));
+               size = metaslab_class_get_space(spa_normal_class(spa));
+               spa_prop_add_list(*nvp, ZPOOL_PROP_NAME, spa_name(spa), 0, src);
+               spa_prop_add_list(*nvp, ZPOOL_PROP_SIZE, NULL, size, src);
+               spa_prop_add_list(*nvp, ZPOOL_PROP_ALLOCATED, NULL, alloc, src);
+               spa_prop_add_list(*nvp, ZPOOL_PROP_FREE, NULL,
+                   size - alloc, src);
+
+               spa_prop_add_list(*nvp, ZPOOL_PROP_FRAGMENTATION, NULL,
+                   metaslab_class_fragmentation(mc), src);
+               spa_prop_add_list(*nvp, ZPOOL_PROP_EXPANDSZ, NULL,
+                   metaslab_class_expandable_space(mc), src);
+               spa_prop_add_list(*nvp, ZPOOL_PROP_READONLY, NULL,
+                   (spa_mode(spa) == FREAD), src);
+
+               cap = (size == 0) ? 0 : (alloc * 100 / size);
+               spa_prop_add_list(*nvp, ZPOOL_PROP_CAPACITY, NULL, cap, src);
+
+               spa_prop_add_list(*nvp, ZPOOL_PROP_DEDUPRATIO, NULL,
+                   ddt_get_pool_dedup_ratio(spa), src);
+
+               spa_prop_add_list(*nvp, ZPOOL_PROP_HEALTH, NULL,
+                   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 (pool != NULL) {
+               /*
+                * The $FREE directory was introduced in SPA_VERSION_DEADLISTS,
+                * when opening pools before this version freedir will be NULL.
+                */
+               if (pool->dp_free_dir != NULL) {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_FREEING, NULL,
+                           dsl_dir_phys(pool->dp_free_dir)->dd_used_bytes,
+                           src);
+               } else {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_FREEING,
+                           NULL, 0, src);
+               }
+
+               if (pool->dp_leak_dir != NULL) {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_LEAKED, NULL,
+                           dsl_dir_phys(pool->dp_leak_dir)->dd_used_bytes,
+                           src);
+               } else {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_LEAKED,
+                           NULL, 0, src);
+               }
+       }
+
+       spa_prop_add_list(*nvp, ZPOOL_PROP_GUID, NULL, spa_guid(spa), src);
+
+       if (spa->spa_comment != NULL) {
+               spa_prop_add_list(*nvp, ZPOOL_PROP_COMMENT, spa->spa_comment,
+                   0, ZPROP_SRC_LOCAL);
+       }
+
+       if (spa->spa_root != NULL)
+               spa_prop_add_list(*nvp, ZPOOL_PROP_ALTROOT, spa->spa_root,
+                   0, ZPROP_SRC_LOCAL);
+
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_BLOCKS)) {
+               spa_prop_add_list(*nvp, ZPOOL_PROP_MAXBLOCKSIZE, NULL,
+                   MIN(zfs_max_recordsize, SPA_MAXBLOCKSIZE), ZPROP_SRC_NONE);
+       } else {
+               spa_prop_add_list(*nvp, ZPOOL_PROP_MAXBLOCKSIZE, NULL,
+                   SPA_OLD_MAXBLOCKSIZE, 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,
+                           "none", 0, ZPROP_SRC_LOCAL);
+               } else if (strcmp(dp->scd_path, spa_config_path) != 0) {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_CACHEFILE,
+                           dp->scd_path, 0, ZPROP_SRC_LOCAL);
+               }
+       }
+}
+
+/*
+ * Get zpool property values.
+ */
+int
+spa_prop_get(spa_t *spa, nvlist_t **nvp)
+{
+       objset_t *mos = spa->spa_meta_objset;
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int err;
+
+       err = nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP);
+       if (err)
+               return (err);
+
+       mutex_enter(&spa->spa_props_lock);
+
+       /*
+        * Get properties from the spa config.
+        */
+       spa_prop_get_config(spa, nvp);
+
+       /* If no pool property object, no more prop to get. */
+       if (mos == NULL || spa->spa_pool_props_object == 0) {
+               mutex_exit(&spa->spa_props_lock);
+               goto out;
+       }
+
+       /*
+        * Get properties from the MOS pool property object.
+        */
+       for (zap_cursor_init(&zc, mos, spa->spa_pool_props_object);
+           (err = zap_cursor_retrieve(&zc, &za)) == 0;
+           zap_cursor_advance(&zc)) {
+               uint64_t intval = 0;
+               char *strval = NULL;
+               zprop_source_t src = ZPROP_SRC_DEFAULT;
+               zpool_prop_t prop;
+
+               if ((prop = zpool_name_to_prop(za.za_name)) == ZPROP_INVAL)
+                       continue;
+
+               switch (za.za_integer_length) {
+               case 8:
+                       /* integer property */
+                       if (za.za_first_integer !=
+                           zpool_prop_default_numeric(prop))
+                               src = ZPROP_SRC_LOCAL;
+
+                       if (prop == ZPOOL_PROP_BOOTFS) {
+                               dsl_pool_t *dp;
+                               dsl_dataset_t *ds = NULL;
+
+                               dp = spa_get_dsl(spa);
+                               dsl_pool_config_enter(dp, FTAG);
+                               if ((err = dsl_dataset_hold_obj(dp,
+                                   za.za_first_integer, FTAG, &ds))) {
+                                       dsl_pool_config_exit(dp, FTAG);
+                                       break;
+                               }
+
+                               strval = kmem_alloc(
+                                   MAXNAMELEN + strlen(MOS_DIR_NAME) + 1,
+                                   KM_SLEEP);
+                               dsl_dataset_name(ds, strval);
+                               dsl_dataset_rele(ds, FTAG);
+                               dsl_pool_config_exit(dp, FTAG);
+                       } else {
+                               strval = NULL;
+                               intval = za.za_first_integer;
+                       }
+
+                       spa_prop_add_list(*nvp, prop, strval, intval, src);
+
+                       if (strval != NULL)
+                               kmem_free(strval,
+                                   MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
+
+                       break;
+
+               case 1:
+                       /* string property */
+                       strval = kmem_alloc(za.za_num_integers, KM_SLEEP);
+                       err = zap_lookup(mos, spa->spa_pool_props_object,
+                           za.za_name, 1, za.za_num_integers, strval);
+                       if (err) {
+                               kmem_free(strval, za.za_num_integers);
+                               break;
+                       }
+                       spa_prop_add_list(*nvp, prop, strval, 0, src);
+                       kmem_free(strval, za.za_num_integers);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       zap_cursor_fini(&zc);
+       mutex_exit(&spa->spa_props_lock);
+out:
+       if (err && err != ENOENT) {
+               nvlist_free(*nvp);
+               *nvp = NULL;
+               return (err);
+       }
+
+       return (0);
+}
+
+/*
+ * Validate the given pool properties nvlist and modify the list
+ * for the property values to be set.
+ */
+static int
+spa_prop_validate(spa_t *spa, nvlist_t *props)
+{
+       nvpair_t *elem;
+       int error = 0, reset_bootfs = 0;
+       uint64_t objnum = 0;
+       boolean_t has_feature = B_FALSE;
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
+               uint64_t intval;
+               char *strval, *slash, *check, *fname;
+               const char *propname = nvpair_name(elem);
+               zpool_prop_t prop = zpool_name_to_prop(propname);
+
+               switch ((int)prop) {
+               case ZPROP_INVAL:
+                       if (!zpool_prop_feature(propname)) {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+
+                       /*
+                        * Sanitize the input.
+                        */
+                       if (nvpair_type(elem) != DATA_TYPE_UINT64) {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+
+                       if (nvpair_value_uint64(elem, &intval) != 0) {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+
+                       if (intval != 0) {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+
+                       fname = strchr(propname, '@') + 1;
+                       if (zfeature_lookup_name(fname, NULL) != 0) {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+
+                       has_feature = B_TRUE;
+                       break;
+
+               case ZPOOL_PROP_VERSION:
+                       error = nvpair_value_uint64(elem, &intval);
+                       if (!error &&
+                           (intval < spa_version(spa) ||
+                           intval > SPA_VERSION_BEFORE_FEATURES ||
+                           has_feature))
+                               error = SET_ERROR(EINVAL);
+                       break;
+
+               case ZPOOL_PROP_DELEGATION:
+               case ZPOOL_PROP_AUTOREPLACE:
+               case ZPOOL_PROP_LISTSNAPS:
+               case ZPOOL_PROP_AUTOEXPAND:
+                       error = nvpair_value_uint64(elem, &intval);
+                       if (!error && intval > 1)
+                               error = SET_ERROR(EINVAL);
+                       break;
+
+               case ZPOOL_PROP_BOOTFS:
+                       /*
+                        * If the pool version is less than SPA_VERSION_BOOTFS,
+                        * or the pool is still being created (version == 0),
+                        * the bootfs property cannot be set.
+                        */
+                       if (spa_version(spa) < SPA_VERSION_BOOTFS) {
+                               error = SET_ERROR(ENOTSUP);
+                               break;
+                       }
+
+                       /*
+                        * Make sure the vdev config is bootable
+                        */
+                       if (!vdev_is_bootable(spa->spa_root_vdev)) {
+                               error = SET_ERROR(ENOTSUP);
+                               break;
+                       }
+
+                       reset_bootfs = 1;
+
+                       error = nvpair_value_string(elem, &strval);
+
+                       if (!error) {
+                               objset_t *os;
+                               uint64_t propval;
+
+                               if (strval == NULL || strval[0] == '\0') {
+                                       objnum = zpool_prop_default_numeric(
+                                           ZPOOL_PROP_BOOTFS);
+                                       break;
+                               }
+
+                               error = dmu_objset_hold(strval, FTAG, &os);
+                               if (error)
+                                       break;
+
+                               /*
+                                * Must be ZPL, and its property settings
+                                * must be supported by GRUB (compression
+                                * is not gzip, and large blocks are not used).
+                                */
+
+                               if (dmu_objset_type(os) != DMU_OST_ZFS) {
+                                       error = SET_ERROR(ENOTSUP);
+                               } else if ((error =
+                                   dsl_prop_get_int_ds(dmu_objset_ds(os),
+                                   zfs_prop_to_name(ZFS_PROP_COMPRESSION),
+                                   &propval)) == 0 &&
+                                   !BOOTFS_COMPRESS_VALID(propval)) {
+                                       error = SET_ERROR(ENOTSUP);
+                               } else if ((error =
+                                   dsl_prop_get_int_ds(dmu_objset_ds(os),
+                                   zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
+                                   &propval)) == 0 &&
+                                   propval > SPA_OLD_MAXBLOCKSIZE) {
+                                       error = SET_ERROR(ENOTSUP);
+                               } else {
+                                       objnum = dmu_objset_id(os);
+                               }
+                               dmu_objset_rele(os, FTAG);
+                       }
+                       break;
+
+               case ZPOOL_PROP_FAILUREMODE:
+                       error = nvpair_value_uint64(elem, &intval);
+                       if (!error && (intval < ZIO_FAILURE_MODE_WAIT ||
+                           intval > ZIO_FAILURE_MODE_PANIC))
+                               error = SET_ERROR(EINVAL);
+
+                       /*
+                        * This is a special case which only occurs when
+                        * the pool has completely failed. This allows
+                        * the user to change the in-core failmode property
+                        * without syncing it out to disk (I/Os might
+                        * currently be blocked). We do this by returning
+                        * EIO to the caller (spa_prop_set) to trick it
+                        * into thinking we encountered a property validation
+                        * error.
+                        */
+                       if (!error && spa_suspended(spa)) {
+                               spa->spa_failmode = intval;
+                               error = SET_ERROR(EIO);
+                       }
+                       break;
+
+               case ZPOOL_PROP_CACHEFILE:
+                       if ((error = nvpair_value_string(elem, &strval)) != 0)
+                               break;
+
+                       if (strval[0] == '\0')
+                               break;
+
+                       if (strcmp(strval, "none") == 0)
+                               break;
+
+                       if (strval[0] != '/') {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+
+                       slash = strrchr(strval, '/');
+                       ASSERT(slash != NULL);
+
+                       if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
+                           strcmp(slash, "/..") == 0)
+                               error = SET_ERROR(EINVAL);
+                       break;
+
+               case ZPOOL_PROP_COMMENT:
+                       if ((error = nvpair_value_string(elem, &strval)) != 0)
+                               break;
+                       for (check = strval; *check != '\0'; check++) {
+                               if (!isprint(*check)) {
+                                       error = SET_ERROR(EINVAL);
+                                       break;
+                               }
+                               check++;
+                       }
+                       if (strlen(strval) > ZPROP_MAX_COMMENT)
+                               error = SET_ERROR(E2BIG);
+                       break;
+
+               case ZPOOL_PROP_DEDUPDITTO:
+                       if (spa_version(spa) < SPA_VERSION_DEDUP)
+                               error = SET_ERROR(ENOTSUP);
+                       else
+                               error = nvpair_value_uint64(elem, &intval);
+                       if (error == 0 &&
+                           intval != 0 && intval < ZIO_DEDUPDITTO_MIN)
+                               error = SET_ERROR(EINVAL);
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (error)
+                       break;
+       }
+
+       if (!error && reset_bootfs) {
+               error = nvlist_remove(props,
+                   zpool_prop_to_name(ZPOOL_PROP_BOOTFS), DATA_TYPE_STRING);
+
+               if (!error) {
+                       error = nvlist_add_uint64(props,
+                           zpool_prop_to_name(ZPOOL_PROP_BOOTFS), objnum);
+               }
+       }
+
+       return (error);
+}
+
+void
+spa_configfile_set(spa_t *spa, nvlist_t *nvp, boolean_t need_sync)
+{
+       char *cachefile;
+       spa_config_dirent_t *dp;
+
+       if (nvlist_lookup_string(nvp, zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
+           &cachefile) != 0)
+               return;
+
+       dp = kmem_alloc(sizeof (spa_config_dirent_t),
+           KM_SLEEP);
+
+       if (cachefile[0] == '\0')
+               dp->scd_path = spa_strdup(spa_config_path);
+       else if (strcmp(cachefile, "none") == 0)
+               dp->scd_path = NULL;
+       else
+               dp->scd_path = spa_strdup(cachefile);
+
+       list_insert_head(&spa->spa_config_list, dp);
+       if (need_sync)
+               spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
+}
+
+int
+spa_prop_set(spa_t *spa, nvlist_t *nvp)
+{
+       int error;
+       nvpair_t *elem = NULL;
+       boolean_t need_sync = B_FALSE;
+
+       if ((error = spa_prop_validate(spa, nvp)) != 0)
+               return (error);
+
+       while ((elem = nvlist_next_nvpair(nvp, elem)) != NULL) {
+               zpool_prop_t prop = zpool_name_to_prop(nvpair_name(elem));
+
+               if (prop == ZPOOL_PROP_CACHEFILE ||
+                   prop == ZPOOL_PROP_ALTROOT ||
+                   prop == ZPOOL_PROP_READONLY)
+                       continue;
+
+               if (prop == ZPOOL_PROP_VERSION || prop == ZPROP_INVAL) {
+                       uint64_t ver;
+
+                       if (prop == ZPOOL_PROP_VERSION) {
+                               VERIFY(nvpair_value_uint64(elem, &ver) == 0);
+                       } else {
+                               ASSERT(zpool_prop_feature(nvpair_name(elem)));
+                               ver = SPA_VERSION_FEATURES;
+                               need_sync = B_TRUE;
+                       }
+
+                       /* Save time if the version is already set. */
+                       if (ver == spa_version(spa))
+                               continue;
+
+                       /*
+                        * In addition to the pool directory object, we might
+                        * create the pool properties object, the features for
+                        * read object, the features for write object, or the
+                        * feature descriptions object.
+                        */
+                       error = dsl_sync_task(spa->spa_name, NULL,
+                           spa_sync_version, &ver,
+                           6, ZFS_SPACE_CHECK_RESERVED);
+                       if (error)
+                               return (error);
+                       continue;
+               }
+
+               need_sync = B_TRUE;
+               break;
+       }
+
+       if (need_sync) {
+               return (dsl_sync_task(spa->spa_name, NULL, spa_sync_props,
+                   nvp, 6, ZFS_SPACE_CHECK_RESERVED));
+       }
+
+       return (0);
+}
+
+/*
+ * If the bootfs property value is dsobj, clear it.
+ */
+void
+spa_prop_clear_bootfs(spa_t *spa, uint64_t dsobj, dmu_tx_t *tx)
+{
+       if (spa->spa_bootfs == dsobj && spa->spa_pool_props_object != 0) {
+               VERIFY(zap_remove(spa->spa_meta_objset,
+                   spa->spa_pool_props_object,
+                   zpool_prop_to_name(ZPOOL_PROP_BOOTFS), tx) == 0);
+               spa->spa_bootfs = 0;
+       }
+}
+
+/*ARGSUSED*/
+static int
+spa_change_guid_check(void *arg, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       uint64_t vdev_state;
+       ASSERTV(uint64_t *newguid = arg);
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+       vdev_state = rvd->vdev_state;
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       if (vdev_state != VDEV_STATE_HEALTHY)
+               return (SET_ERROR(ENXIO));
+
+       ASSERT3U(spa_guid(spa), !=, *newguid);
+
+       return (0);
+}
+
+static void
+spa_change_guid_sync(void *arg, dmu_tx_t *tx)
+{
+       uint64_t *newguid = arg;
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       uint64_t oldguid;
+       vdev_t *rvd = spa->spa_root_vdev;
+
+       oldguid = spa_guid(spa);
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+       rvd->vdev_guid = *newguid;
+       rvd->vdev_guid_sum += (*newguid - oldguid);
+       vdev_config_dirty(rvd);
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       spa_history_log_internal(spa, "guid change", tx, "old=%llu new=%llu",
+           oldguid, *newguid);
+}
+
+/*
+ * Change the GUID for the pool.  This is done so that we can later
+ * re-import a pool built from a clone of our own vdevs.  We will modify
+ * the root vdev's guid, our own pool guid, and then mark all of our
+ * vdevs dirty.  Note that we must make sure that all our vdevs are
+ * online when we do this, or else any vdevs that weren't present
+ * would be orphaned from our pool.  We are also going to issue a
+ * sysevent to update any watchers.
+ */
+int
+spa_change_guid(spa_t *spa)
+{
+       int error;
+       uint64_t guid;
+
+       mutex_enter(&spa->spa_vdev_top_lock);
+       mutex_enter(&spa_namespace_lock);
+       guid = spa_generate_guid(NULL);
+
+       error = dsl_sync_task(spa->spa_name, spa_change_guid_check,
+           spa_change_guid_sync, &guid, 5, ZFS_SPACE_CHECK_RESERVED);
+
+       if (error == 0) {
+               spa_config_sync(spa, B_FALSE, B_TRUE);
+               spa_event_notify(spa, NULL, FM_EREPORT_ZFS_POOL_REGUID);
+       }
+
+       mutex_exit(&spa_namespace_lock);
+       mutex_exit(&spa->spa_vdev_top_lock);
+
+       return (error);
+}
+
+/*
+ * ==========================================================================
+ * SPA state manipulation (open/create/destroy/import/export)
+ * ==========================================================================
+ */
+
+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;
+       int ret;
+
+       ret = bcmp(&sa->se_bookmark, &sb->se_bookmark,
+           sizeof (zbookmark_phys_t));
+
+       if (ret < 0)
+               return (-1);
+       else if (ret > 0)
+               return (1);
+       else
+               return (0);
+}
+
+/*
+ * Utility function which retrieves copies of the current logs and
+ * re-initializes them in the process.
+ */
+void
+spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub)
+{
+       ASSERT(MUTEX_HELD(&spa->spa_errlist_lock));
+
+       bcopy(&spa->spa_errlist_last, last, sizeof (avl_tree_t));
+       bcopy(&spa->spa_errlist_scrub, scrub, sizeof (avl_tree_t));
+
+       avl_create(&spa->spa_errlist_scrub,
+           spa_error_entry_compare, sizeof (spa_error_entry_t),
+           offsetof(spa_error_entry_t, se_avl));
+       avl_create(&spa->spa_errlist_last,
+           spa_error_entry_compare, sizeof (spa_error_entry_t),
+           offsetof(spa_error_entry_t, se_avl));
+}
+
+static void
+spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q)
+{
+       const zio_taskq_info_t *ztip = &zio_taskqs[t][q];
+       enum zti_modes mode = ztip->zti_mode;
+       uint_t value = ztip->zti_value;
+       uint_t count = ztip->zti_count;
+       spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
+       char name[32];
+       uint_t i, flags = 0;
+       boolean_t batch = B_FALSE;
+
+       if (mode == ZTI_MODE_NULL) {
+               tqs->stqs_count = 0;
+               tqs->stqs_taskq = NULL;
+               return;
+       }
+
+       ASSERT3U(count, >, 0);
+
+       tqs->stqs_count = count;
+       tqs->stqs_taskq = kmem_alloc(count * sizeof (taskq_t *), KM_SLEEP);
+
+       switch (mode) {
+       case ZTI_MODE_FIXED:
+               ASSERT3U(value, >=, 1);
+               value = MAX(value, 1);
+               flags |= TASKQ_DYNAMIC;
+               break;
+
+       case ZTI_MODE_BATCH:
+               batch = B_TRUE;
+               flags |= TASKQ_THREADS_CPU_PCT;
+               value = MIN(zio_taskq_batch_pct, 100);
+               break;
+
+       default:
+               panic("unrecognized mode for %s_%s taskq (%u:%u) in "
+                   "spa_activate()",
+                   zio_type_name[t], zio_taskq_types[q], mode, value);
+               break;
+       }
+
+       for (i = 0; i < count; i++) {
+               taskq_t *tq;
+
+               if (count > 1) {
+                       (void) snprintf(name, sizeof (name), "%s_%s_%u",
+                           zio_type_name[t], zio_taskq_types[q], i);
+               } else {
+                       (void) snprintf(name, sizeof (name), "%s_%s",
+                           zio_type_name[t], zio_taskq_types[q]);
+               }
+
+               if (zio_taskq_sysdc && spa->spa_proc != &p0) {
+                       if (batch)
+                               flags |= TASKQ_DC_BATCH;
+
+                       tq = taskq_create_sysdc(name, value, 50, INT_MAX,
+                           spa->spa_proc, zio_taskq_basedc, flags);
+               } else {
+                       pri_t pri = maxclsyspri;
+                       /*
+                        * The write issue taskq can be extremely CPU
+                        * intensive.  Run it at slightly less important
+                        * priority than the other taskqs.  Under Linux this
+                        * means incrementing the priority value on platforms
+                        * like illumos it should be decremented.
+                        */
+                       if (t == ZIO_TYPE_WRITE && q == ZIO_TASKQ_ISSUE)
+                               pri++;
+
+                       tq = taskq_create_proc(name, value, pri, 50,
+                           INT_MAX, spa->spa_proc, flags);
+               }
+
+               tqs->stqs_taskq[i] = tq;
+       }
+}
+
+static void
+spa_taskqs_fini(spa_t *spa, zio_type_t t, zio_taskq_type_t q)
+{
+       spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
+       uint_t i;
+
+       if (tqs->stqs_taskq == NULL) {
+               ASSERT3U(tqs->stqs_count, ==, 0);
+               return;
+       }
+
+       for (i = 0; i < tqs->stqs_count; i++) {
+               ASSERT3P(tqs->stqs_taskq[i], !=, NULL);
+               taskq_destroy(tqs->stqs_taskq[i]);
+       }
+
+       kmem_free(tqs->stqs_taskq, tqs->stqs_count * sizeof (taskq_t *));
+       tqs->stqs_taskq = NULL;
+}
+
+/*
+ * Dispatch a task to the appropriate taskq for the ZFS I/O type and priority.
+ * Note that a type may have multiple discrete taskqs to avoid lock contention
+ * on the taskq itself. In that case we choose which taskq at random by using
+ * the low bits of gethrtime().
+ */
+void
+spa_taskq_dispatch_ent(spa_t *spa, zio_type_t t, zio_taskq_type_t q,
+    task_func_t *func, void *arg, uint_t flags, taskq_ent_t *ent)
+{
+       spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
+       taskq_t *tq;
+
+       ASSERT3P(tqs->stqs_taskq, !=, NULL);
+       ASSERT3U(tqs->stqs_count, !=, 0);
+
+       if (tqs->stqs_count == 1) {
+               tq = tqs->stqs_taskq[0];
+       } else {
+               tq = tqs->stqs_taskq[((uint64_t)gethrtime()) % tqs->stqs_count];
+       }
+
+       taskq_dispatch_ent(tq, func, arg, flags, ent);
+}
+
+/*
+ * Same as spa_taskq_dispatch_ent() but block on the task until completion.
+ */
+void
+spa_taskq_dispatch_sync(spa_t *spa, zio_type_t t, zio_taskq_type_t q,
+    task_func_t *func, void *arg, uint_t flags)
+{
+       spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
+       taskq_t *tq;
+       taskqid_t id;
+
+       ASSERT3P(tqs->stqs_taskq, !=, NULL);
+       ASSERT3U(tqs->stqs_count, !=, 0);
+
+       if (tqs->stqs_count == 1) {
+               tq = tqs->stqs_taskq[0];
+       } else {
+               tq = tqs->stqs_taskq[((uint64_t)gethrtime()) % tqs->stqs_count];
+       }
+
+       id = taskq_dispatch(tq, func, arg, flags);
+       if (id)
+               taskq_wait_id(tq, id);
+}
+
+static void
+spa_create_zio_taskqs(spa_t *spa)
+{
+       int t, q;
+
+       for (t = 0; t < ZIO_TYPES; t++) {
+               for (q = 0; q < ZIO_TASKQ_TYPES; q++) {
+                       spa_taskqs_init(spa, t, q);
+               }
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPA_THREAD)
+static void
+spa_thread(void *arg)
+{
+       callb_cpr_t cprinfo;
+
+       spa_t *spa = arg;
+       user_t *pu = PTOU(curproc);
+
+       CALLB_CPR_INIT(&cprinfo, &spa->spa_proc_lock, callb_generic_cpr,
+           spa->spa_name);
+
+       ASSERT(curproc != &p0);
+       (void) snprintf(pu->u_psargs, sizeof (pu->u_psargs),
+           "zpool-%s", spa->spa_name);
+       (void) strlcpy(pu->u_comm, pu->u_psargs, sizeof (pu->u_comm));
+
+       /* bind this thread to the requested psrset */
+       if (zio_taskq_psrset_bind != PS_NONE) {
+               pool_lock();
+               mutex_enter(&cpu_lock);
+               mutex_enter(&pidlock);
+               mutex_enter(&curproc->p_lock);
+
+               if (cpupart_bind_thread(curthread, zio_taskq_psrset_bind,
+                   0, NULL, NULL) == 0)  {
+                       curthread->t_bind_pset = zio_taskq_psrset_bind;
+               } else {
+                       cmn_err(CE_WARN,
+                           "Couldn't bind process for zfs pool \"%s\" to "
+                           "pset %d\n", spa->spa_name, zio_taskq_psrset_bind);
+               }
+
+               mutex_exit(&curproc->p_lock);
+               mutex_exit(&pidlock);
+               mutex_exit(&cpu_lock);
+               pool_unlock();
+       }
+
+       if (zio_taskq_sysdc) {
+               sysdc_thread_enter(curthread, 100, 0);
+       }
+
+       spa->spa_proc = curproc;
+       spa->spa_did = curthread->t_did;
+
+       spa_create_zio_taskqs(spa);
+
+       mutex_enter(&spa->spa_proc_lock);
+       ASSERT(spa->spa_proc_state == SPA_PROC_CREATED);
+
+       spa->spa_proc_state = SPA_PROC_ACTIVE;
+       cv_broadcast(&spa->spa_proc_cv);
+
+       CALLB_CPR_SAFE_BEGIN(&cprinfo);
+       while (spa->spa_proc_state == SPA_PROC_ACTIVE)
+               cv_wait(&spa->spa_proc_cv, &spa->spa_proc_lock);
+       CALLB_CPR_SAFE_END(&cprinfo, &spa->spa_proc_lock);
+
+       ASSERT(spa->spa_proc_state == SPA_PROC_DEACTIVATE);
+       spa->spa_proc_state = SPA_PROC_GONE;
+       spa->spa_proc = &p0;
+       cv_broadcast(&spa->spa_proc_cv);
+       CALLB_CPR_EXIT(&cprinfo);       /* drops spa_proc_lock */
+
+       mutex_enter(&curproc->p_lock);
+       lwp_exit();
+}
+#endif
+
+/*
+ * Activate an uninitialized pool.
+ */
+static void
+spa_activate(spa_t *spa, int mode)
+{
+       ASSERT(spa->spa_state == POOL_STATE_UNINITIALIZED);
+
+       spa->spa_state = POOL_STATE_ACTIVE;
+       spa->spa_mode = mode;
+
+       spa->spa_normal_class = metaslab_class_create(spa, zfs_metaslab_ops);
+       spa->spa_log_class = metaslab_class_create(spa, zfs_metaslab_ops);
+
+       /* Try to create a covering process */
+       mutex_enter(&spa->spa_proc_lock);
+       ASSERT(spa->spa_proc_state == SPA_PROC_NONE);
+       ASSERT(spa->spa_proc == &p0);
+       spa->spa_did = 0;
+
+#ifdef HAVE_SPA_THREAD
+       /* Only create a process if we're going to be around a while. */
+       if (spa_create_process && strcmp(spa->spa_name, TRYIMPORT_NAME) != 0) {
+               if (newproc(spa_thread, (caddr_t)spa, syscid, maxclsyspri,
+                   NULL, 0) == 0) {
+                       spa->spa_proc_state = SPA_PROC_CREATED;
+                       while (spa->spa_proc_state == SPA_PROC_CREATED) {
+                               cv_wait(&spa->spa_proc_cv,
+                                   &spa->spa_proc_lock);
+                       }
+                       ASSERT(spa->spa_proc_state == SPA_PROC_ACTIVE);
+                       ASSERT(spa->spa_proc != &p0);
+                       ASSERT(spa->spa_did != 0);
+               } else {
+#ifdef _KERNEL
+                       cmn_err(CE_WARN,
+                           "Couldn't create process for zfs pool \"%s\"\n",
+                           spa->spa_name);
+#endif
+               }
+       }
+#endif /* HAVE_SPA_THREAD */
+       mutex_exit(&spa->spa_proc_lock);
+
+       /* If we didn't create a process, we need to create our taskqs. */
+       if (spa->spa_proc == &p0) {
+               spa_create_zio_taskqs(spa);
+       }
+
+       list_create(&spa->spa_config_dirty_list, sizeof (vdev_t),
+           offsetof(vdev_t, vdev_config_dirty_node));
+       list_create(&spa->spa_evicting_os_list, sizeof (objset_t),
+           offsetof(objset_t, os_evicting_node));
+       list_create(&spa->spa_state_dirty_list, sizeof (vdev_t),
+           offsetof(vdev_t, vdev_state_dirty_node));
+
+       txg_list_create(&spa->spa_vdev_txg_list,
+           offsetof(struct vdev, vdev_txg_node));
+
+       avl_create(&spa->spa_errlist_scrub,
+           spa_error_entry_compare, sizeof (spa_error_entry_t),
+           offsetof(spa_error_entry_t, se_avl));
+       avl_create(&spa->spa_errlist_last,
+           spa_error_entry_compare, sizeof (spa_error_entry_t),
+           offsetof(spa_error_entry_t, se_avl));
+
+       /*
+        * This taskq is used to perform zvol-minor-related tasks
+        * asynchronously. This has several advantages, including easy
+        * resolution of various deadlocks (zfsonlinux bug #3681).
+        *
+        * The taskq must be single threaded to ensure tasks are always
+        * processed in the order in which they were dispatched.
+        *
+        * A taskq per pool allows one to keep the pools independent.
+        * This way if one pool is suspended, it will not impact another.
+        *
+        * The preferred location to dispatch a zvol minor task is a sync
+        * task. In this context, there is easy access to the spa_t and minimal
+        * error handling is required because the sync task must succeed.
+        */
+       spa->spa_zvol_taskq = taskq_create("z_zvol", 1, defclsyspri,
+           1, INT_MAX, 0);
+}
+
+/*
+ * Opposite of spa_activate().
+ */
+static void
+spa_deactivate(spa_t *spa)
+{
+       int t, q;
+
+       ASSERT(spa->spa_sync_on == B_FALSE);
+       ASSERT(spa->spa_dsl_pool == NULL);
+       ASSERT(spa->spa_root_vdev == NULL);
+       ASSERT(spa->spa_async_zio_root == NULL);
+       ASSERT(spa->spa_state != POOL_STATE_UNINITIALIZED);
+
+       spa_evicting_os_wait(spa);
+
+       if (spa->spa_zvol_taskq) {
+               taskq_destroy(spa->spa_zvol_taskq);
+               spa->spa_zvol_taskq = NULL;
+       }
+
+       txg_list_destroy(&spa->spa_vdev_txg_list);
+
+       list_destroy(&spa->spa_config_dirty_list);
+       list_destroy(&spa->spa_evicting_os_list);
+       list_destroy(&spa->spa_state_dirty_list);
+
+       taskq_cancel_id(system_taskq, spa->spa_deadman_tqid);
+
+       for (t = 0; t < ZIO_TYPES; t++) {
+               for (q = 0; q < ZIO_TASKQ_TYPES; q++) {
+                       spa_taskqs_fini(spa, t, q);
+               }
+       }
+
+       metaslab_class_destroy(spa->spa_normal_class);
+       spa->spa_normal_class = NULL;
+
+       metaslab_class_destroy(spa->spa_log_class);
+       spa->spa_log_class = NULL;
+
+       /*
+        * If this was part of an import or the open otherwise failed, we may
+        * still have errors left in the queues.  Empty them just in case.
+        */
+       spa_errlog_drain(spa);
+
+       avl_destroy(&spa->spa_errlist_scrub);
+       avl_destroy(&spa->spa_errlist_last);
+
+       spa->spa_state = POOL_STATE_UNINITIALIZED;
+
+       mutex_enter(&spa->spa_proc_lock);
+       if (spa->spa_proc_state != SPA_PROC_NONE) {
+               ASSERT(spa->spa_proc_state == SPA_PROC_ACTIVE);
+               spa->spa_proc_state = SPA_PROC_DEACTIVATE;
+               cv_broadcast(&spa->spa_proc_cv);
+               while (spa->spa_proc_state == SPA_PROC_DEACTIVATE) {
+                       ASSERT(spa->spa_proc != &p0);
+                       cv_wait(&spa->spa_proc_cv, &spa->spa_proc_lock);
+               }
+               ASSERT(spa->spa_proc_state == SPA_PROC_GONE);
+               spa->spa_proc_state = SPA_PROC_NONE;
+       }
+       ASSERT(spa->spa_proc == &p0);
+       mutex_exit(&spa->spa_proc_lock);
+
+       /*
+        * We want to make sure spa_thread() has actually exited the ZFS
+        * module, so that the module can't be unloaded out from underneath
+        * it.
+        */
+       if (spa->spa_did != 0) {
+               thread_join(spa->spa_did);
+               spa->spa_did = 0;
+       }
+}
+
+/*
+ * Verify a pool configuration, and construct the vdev tree appropriately.  This
+ * will create all the necessary vdevs in the appropriate layout, with each vdev
+ * in the CLOSED state.  This will prep the pool before open/creation/import.
+ * All vdev validation is done by the vdev_alloc() routine.
+ */
+static int
+spa_config_parse(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent,
+    uint_t id, int atype)
+{
+       nvlist_t **child;
+       uint_t children;
+       int error;
+       int c;
+
+       if ((error = vdev_alloc(spa, vdp, nv, parent, id, atype)) != 0)
+               return (error);
+
+       if ((*vdp)->vdev_ops->vdev_op_leaf)
+               return (0);
+
+       error = nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children);
+
+       if (error == ENOENT)
+               return (0);
+
+       if (error) {
+               vdev_free(*vdp);
+               *vdp = NULL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       for (c = 0; c < children; c++) {
+               vdev_t *vd;
+               if ((error = spa_config_parse(spa, &vd, child[c], *vdp, c,
+                   atype)) != 0) {
+                       vdev_free(*vdp);
+                       *vdp = NULL;
+                       return (error);
+               }
+       }
+
+       ASSERT(*vdp != NULL);
+
+       return (0);
+}
+
+/*
+ * Opposite of spa_load().
+ */
+static void
+spa_unload(spa_t *spa)
+{
+       int i;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       /*
+        * Stop async tasks.
+        */
+       spa_async_suspend(spa);
+
+       /*
+        * Stop syncing.
+        */
+       if (spa->spa_sync_on) {
+               txg_sync_stop(spa->spa_dsl_pool);
+               spa->spa_sync_on = B_FALSE;
+       }
+
+       /*
+        * Wait for any outstanding async I/O to complete.
+        */
+       if (spa->spa_async_zio_root != NULL) {
+               for (i = 0; i < max_ncpus; i++)
+                       (void) zio_wait(spa->spa_async_zio_root[i]);
+               kmem_free(spa->spa_async_zio_root, max_ncpus * sizeof (void *));
+               spa->spa_async_zio_root = NULL;
+       }
+
+       bpobj_close(&spa->spa_deferred_bpobj);
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+       /*
+        * Close all vdevs.
+        */
+       if (spa->spa_root_vdev)
+               vdev_free(spa->spa_root_vdev);
+       ASSERT(spa->spa_root_vdev == NULL);
+
+       /*
+        * Close the dsl pool.
+        */
+       if (spa->spa_dsl_pool) {
+               dsl_pool_close(spa->spa_dsl_pool);
+               spa->spa_dsl_pool = NULL;
+               spa->spa_meta_objset = NULL;
+       }
+
+       ddt_unload(spa);
+
+
+       /*
+        * Drop and purge level 2 cache
+        */
+       spa_l2cache_drop(spa);
+
+       for (i = 0; i < spa->spa_spares.sav_count; i++)
+               vdev_free(spa->spa_spares.sav_vdevs[i]);
+       if (spa->spa_spares.sav_vdevs) {
+               kmem_free(spa->spa_spares.sav_vdevs,
+                   spa->spa_spares.sav_count * sizeof (void *));
+               spa->spa_spares.sav_vdevs = NULL;
+       }
+       if (spa->spa_spares.sav_config) {
+               nvlist_free(spa->spa_spares.sav_config);
+               spa->spa_spares.sav_config = NULL;
+       }
+       spa->spa_spares.sav_count = 0;
+
+       for (i = 0; i < spa->spa_l2cache.sav_count; i++) {
+               vdev_clear_stats(spa->spa_l2cache.sav_vdevs[i]);
+               vdev_free(spa->spa_l2cache.sav_vdevs[i]);
+       }
+       if (spa->spa_l2cache.sav_vdevs) {
+               kmem_free(spa->spa_l2cache.sav_vdevs,
+                   spa->spa_l2cache.sav_count * sizeof (void *));
+               spa->spa_l2cache.sav_vdevs = NULL;
+       }
+       if (spa->spa_l2cache.sav_config) {
+               nvlist_free(spa->spa_l2cache.sav_config);
+               spa->spa_l2cache.sav_config = NULL;
+       }
+       spa->spa_l2cache.sav_count = 0;
+
+       spa->spa_async_suspended = 0;
+
+       if (spa->spa_comment != NULL) {
+               spa_strfree(spa->spa_comment);
+               spa->spa_comment = NULL;
+       }
+
+       spa_config_exit(spa, SCL_ALL, FTAG);
+}
+
+/*
+ * Load (or re-load) the current list of vdevs describing the active spares for
+ * this pool.  When this is called, we have some form of basic information in
+ * 'spa_spares.sav_config'.  We parse this into vdevs, try to open them, and
+ * then re-generate a more complete list including status information.
+ */
+static void
+spa_load_spares(spa_t *spa)
+{
+       nvlist_t **spares;
+       uint_t nspares;
+       int i;
+       vdev_t *vd, *tvd;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       /*
+        * First, close and free any existing spare vdevs.
+        */
+       for (i = 0; i < spa->spa_spares.sav_count; i++) {
+               vd = spa->spa_spares.sav_vdevs[i];
+
+               /* Undo the call to spa_activate() below */
+               if ((tvd = spa_lookup_by_guid(spa, vd->vdev_guid,
+                   B_FALSE)) != NULL && tvd->vdev_isspare)
+                       spa_spare_remove(tvd);
+               vdev_close(vd);
+               vdev_free(vd);
+       }
+
+       if (spa->spa_spares.sav_vdevs)
+               kmem_free(spa->spa_spares.sav_vdevs,
+                   spa->spa_spares.sav_count * sizeof (void *));
+
+       if (spa->spa_spares.sav_config == NULL)
+               nspares = 0;
+       else
+               VERIFY(nvlist_lookup_nvlist_array(spa->spa_spares.sav_config,
+                   ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0);
+
+       spa->spa_spares.sav_count = (int)nspares;
+       spa->spa_spares.sav_vdevs = NULL;
+
+       if (nspares == 0)
+               return;
+
+       /*
+        * Construct the array of vdevs, opening them to get status in the
+        * process.   For each spare, there is potentially two different vdev_t
+        * structures associated with it: one in the list of spares (used only
+        * for basic validation purposes) and one in the active vdev
+        * configuration (if it's spared in).  During this phase we open and
+        * validate each vdev on the spare list.  If the vdev also exists in the
+        * active configuration, then we also mark this vdev as an active spare.
+        */
+       spa->spa_spares.sav_vdevs = kmem_zalloc(nspares * sizeof (void *),
+           KM_SLEEP);
+       for (i = 0; i < spa->spa_spares.sav_count; i++) {
+               VERIFY(spa_config_parse(spa, &vd, spares[i], NULL, 0,
+                   VDEV_ALLOC_SPARE) == 0);
+               ASSERT(vd != NULL);
+
+               spa->spa_spares.sav_vdevs[i] = vd;
+
+               if ((tvd = spa_lookup_by_guid(spa, vd->vdev_guid,
+                   B_FALSE)) != NULL) {
+                       if (!tvd->vdev_isspare)
+                               spa_spare_add(tvd);
+
+                       /*
+                        * We only mark the spare active if we were successfully
+                        * able to load the vdev.  Otherwise, importing a pool
+                        * with a bad active spare would result in strange
+                        * behavior, because multiple pool would think the spare
+                        * is actively in use.
+                        *
+                        * There is a vulnerability here to an equally bizarre
+                        * circumstance, where a dead active spare is later
+                        * brought back to life (onlined or otherwise).  Given
+                        * the rarity of this scenario, and the extra complexity
+                        * it adds, we ignore the possibility.
+                        */
+                       if (!vdev_is_dead(tvd))
+                               spa_spare_activate(tvd);
+               }
+
+               vd->vdev_top = vd;
+               vd->vdev_aux = &spa->spa_spares;
+
+               if (vdev_open(vd) != 0)
+                       continue;
+
+               if (vdev_validate_aux(vd) == 0)
+                       spa_spare_add(vd);
+       }
+
+       /*
+        * Recompute the stashed list of spares, with status information
+        * this time.
+        */
+       VERIFY(nvlist_remove(spa->spa_spares.sav_config, ZPOOL_CONFIG_SPARES,
+           DATA_TYPE_NVLIST_ARRAY) == 0);
+
+       spares = kmem_alloc(spa->spa_spares.sav_count * sizeof (void *),
+           KM_SLEEP);
+       for (i = 0; i < spa->spa_spares.sav_count; i++)
+               spares[i] = vdev_config_generate(spa,
+                   spa->spa_spares.sav_vdevs[i], B_TRUE, VDEV_CONFIG_SPARE);
+       VERIFY(nvlist_add_nvlist_array(spa->spa_spares.sav_config,
+           ZPOOL_CONFIG_SPARES, spares, spa->spa_spares.sav_count) == 0);
+       for (i = 0; i < spa->spa_spares.sav_count; i++)
+               nvlist_free(spares[i]);
+       kmem_free(spares, spa->spa_spares.sav_count * sizeof (void *));
+}
+
+/*
+ * Load (or re-load) the current list of vdevs describing the active l2cache for
+ * this pool.  When this is called, we have some form of basic information in
+ * 'spa_l2cache.sav_config'.  We parse this into vdevs, try to open them, and
+ * then re-generate a more complete list including status information.
+ * Devices which are already active have their details maintained, and are
+ * not re-opened.
+ */
+static void
+spa_load_l2cache(spa_t *spa)
+{
+       nvlist_t **l2cache;
+       uint_t nl2cache;
+       int i, j, oldnvdevs;
+       uint64_t guid;
+       vdev_t *vd, **oldvdevs, **newvdevs;
+       spa_aux_vdev_t *sav = &spa->spa_l2cache;
+
+       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;
+
+       /*
+        * Process new nvlist of vdevs.
+        */
+       for (i = 0; i < nl2cache; i++) {
+               VERIFY(nvlist_lookup_uint64(l2cache[i], ZPOOL_CONFIG_GUID,
+                   &guid) == 0);
+
+               newvdevs[i] = NULL;
+               for (j = 0; j < oldnvdevs; j++) {
+                       vd = oldvdevs[j];
+                       if (vd != NULL && guid == vd->vdev_guid) {
+                               /*
+                                * Retain previous vdev for add/remove ops.
+                                */
+                               newvdevs[i] = vd;
+                               oldvdevs[j] = NULL;
+                               break;
+                       }
+               }
+
+               if (newvdevs[i] == NULL) {
+                       /*
+                        * Create new vdev
+                        */
+                       VERIFY(spa_config_parse(spa, &vd, l2cache[i], NULL, 0,
+                           VDEV_ALLOC_L2CACHE) == 0);
+                       ASSERT(vd != NULL);
+                       newvdevs[i] = vd;
+
+                       /*
+                        * Commit this vdev as an l2cache device,
+                        * even if it fails to open.
+                        */
+                       spa_l2cache_add(vd);
+
+                       vd->vdev_top = vd;
+                       vd->vdev_aux = sav;
+
+                       spa_l2cache_activate(vd);
+
+                       if (vdev_open(vd) != 0)
+                               continue;
+
+                       (void) vdev_validate_aux(vd);
+
+                       if (!vdev_is_dead(vd))
+                               l2arc_add_vdev(spa, vd);
+               }
+       }
+
+       /*
+        * Purge vdevs that were dropped
+        */
+       for (i = 0; i < oldnvdevs; i++) {
+               uint64_t pool;
+
+               vd = oldvdevs[i];
+               if (vd != NULL) {
+                       ASSERT(vd->vdev_isl2cache);
+
+                       if (spa_l2cache_exists(vd->vdev_guid, &pool) &&
+                           pool != 0ULL && l2arc_vdev_present(vd))
+                               l2arc_remove_vdev(vd);
+                       vdev_clear_stats(vd);
+                       vdev_free(vd);
+               }
+       }
+
+       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)
+               kmem_free(l2cache, sav->sav_count * sizeof (void *));
+}
+
+static int
+load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value)
+{
+       dmu_buf_t *db;
+       char *packed = NULL;
+       size_t nvsize = 0;
+       int error;
+       *value = NULL;
+
+       error = dmu_bonus_hold(spa->spa_meta_objset, obj, FTAG, &db);
+       if (error)
+               return (error);
+
+       nvsize = *(uint64_t *)db->db_data;
+       dmu_buf_rele(db, FTAG);
+
+       packed = vmem_alloc(nvsize, KM_SLEEP);
+       error = dmu_read(spa->spa_meta_objset, obj, 0, nvsize, packed,
+           DMU_READ_PREFETCH);
+       if (error == 0)
+               error = nvlist_unpack(packed, nvsize, value, 0);
+       vmem_free(packed, nvsize);
+
+       return (error);
+}
+
+/*
+ * Checks to see if the given vdev could not be opened, in which case we post a
+ * sysevent to notify the autoreplace code that the device has been removed.
+ */
+static void
+spa_check_removed(vdev_t *vd)
+{
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               spa_check_removed(vd->vdev_child[c]);
+
+       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);
+       }
+}
+
+/*
+ * Validate the current config against the MOS config
+ */
+static boolean_t
+spa_config_valid(spa_t *spa, nvlist_t *config)
+{
+       vdev_t *mrvd, *rvd = spa->spa_root_vdev;
+       nvlist_t *nv;
+       int c, i;
+
+       VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) == 0);
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       VERIFY(spa_config_parse(spa, &mrvd, nv, NULL, 0, VDEV_ALLOC_LOAD) == 0);
+
+       ASSERT3U(rvd->vdev_children, ==, mrvd->vdev_children);
+
+       /*
+        * If we're doing a normal import, then build up any additional
+        * diagnostic information about missing devices in this config.
+        * We'll pass this up to the user for further processing.
+        */
+       if (!(spa->spa_import_flags & ZFS_IMPORT_MISSING_LOG)) {
+               nvlist_t **child, *nv;
+               uint64_t idx = 0;
+
+               child = kmem_alloc(rvd->vdev_children * sizeof (nvlist_t **),
+                   KM_SLEEP);
+               VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+               for (c = 0; c < rvd->vdev_children; c++) {
+                       vdev_t *tvd = rvd->vdev_child[c];
+                       vdev_t *mtvd  = mrvd->vdev_child[c];
+
+                       if (tvd->vdev_ops == &vdev_missing_ops &&
+                           mtvd->vdev_ops != &vdev_missing_ops &&
+                           mtvd->vdev_islog)
+                               child[idx++] = vdev_config_generate(spa, mtvd,
+                                   B_FALSE, 0);
+               }
+
+               if (idx) {
+                       VERIFY(nvlist_add_nvlist_array(nv,
+                           ZPOOL_CONFIG_CHILDREN, child, idx) == 0);
+                       VERIFY(nvlist_add_nvlist(spa->spa_load_info,
+                           ZPOOL_CONFIG_MISSING_DEVICES, nv) == 0);
+
+                       for (i = 0; i < idx; i++)
+                               nvlist_free(child[i]);
+               }
+               nvlist_free(nv);
+               kmem_free(child, rvd->vdev_children * sizeof (char **));
+       }
+
+       /*
+        * Compare the root vdev tree with the information we have
+        * from the MOS config (mrvd). Check each top-level vdev
+        * with the corresponding MOS config top-level (mtvd).
+        */
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               vdev_t *mtvd  = mrvd->vdev_child[c];
+
+               /*
+                * Resolve any "missing" vdevs in the current configuration.
+                * If we find that the MOS config has more accurate information
+                * about the top-level vdev then use that vdev instead.
+                */
+               if (tvd->vdev_ops == &vdev_missing_ops &&
+                   mtvd->vdev_ops != &vdev_missing_ops) {
+
+                       if (!(spa->spa_import_flags & ZFS_IMPORT_MISSING_LOG))
+                               continue;
+
+                       /*
+                        * Device specific actions.
+                        */
+                       if (mtvd->vdev_islog) {
+                               spa_set_log_state(spa, SPA_LOG_CLEAR);
+                       } else {
+                               /*
+                                * XXX - once we have 'readonly' pool
+                                * support we should be able to handle
+                                * missing data devices by transitioning
+                                * the pool to readonly.
+                                */
+                               continue;
+                       }
+
+                       /*
+                        * Swap the missing vdev with the data we were
+                        * able to obtain from the MOS config.
+                        */
+                       vdev_remove_child(rvd, tvd);
+                       vdev_remove_child(mrvd, mtvd);
+
+                       vdev_add_child(rvd, mtvd);
+                       vdev_add_child(mrvd, tvd);
+
+                       spa_config_exit(spa, SCL_ALL, FTAG);
+                       vdev_load(mtvd);
+                       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+                       vdev_reopen(rvd);
+               } 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);
+               }
+       }
+       vdev_free(mrvd);
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       /*
+        * Ensure we were able to validate the config.
+        */
+       return (rvd->vdev_guid_sum == spa->spa_uberblock.ub_guid_sum);
+}
+
+/*
+ * Check for missing log devices
+ */
+static boolean_t
+spa_check_logs(spa_t *spa)
+{
+       boolean_t rv = B_FALSE;
+       dsl_pool_t *dp = spa_get_dsl(spa);
+
+       switch (spa->spa_log_state) {
+       default:
+               break;
+       case SPA_LOG_MISSING:
+               /* need to recheck in case slog has been restored */
+       case SPA_LOG_UNKNOWN:
+               rv = (dmu_objset_find_dp(dp, dp->dp_root_dir_obj,
+                   zil_check_log_chain, NULL, DS_FIND_CHILDREN) != 0);
+               if (rv)
+                       spa_set_log_state(spa, SPA_LOG_MISSING);
+               break;
+       }
+       return (rv);
+}
+
+static boolean_t
+spa_passivate_log(spa_t *spa)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       boolean_t slog_found = B_FALSE;
+       int c;
+
+       ASSERT(spa_config_held(spa, SCL_ALLOC, RW_WRITER));
+
+       if (!spa_has_slogs(spa))
+               return (B_FALSE);
+
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               if (tvd->vdev_islog) {
+                       metaslab_group_passivate(mg);
+                       slog_found = B_TRUE;
+               }
+       }
+
+       return (slog_found);
+}
+
+static void
+spa_activate_log(spa_t *spa)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       int c;
+
+       ASSERT(spa_config_held(spa, SCL_ALLOC, RW_WRITER));
+
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               if (tvd->vdev_islog)
+                       metaslab_group_activate(mg);
+       }
+}
+
+int
+spa_offline_log(spa_t *spa)
+{
+       int error;
+
+       error = dmu_objset_find(spa_name(spa), zil_vdev_offline,
+           NULL, DS_FIND_CHILDREN);
+       if (error == 0) {
+               /*
+                * We successfully offlined the log device, sync out the
+                * current txg so that the "stubby" block can be removed
+                * by zil_sync().
+                */
+               txg_wait_synced(spa->spa_dsl_pool, 0);
+       }
+       return (error);
+}
+
+static void
+spa_aux_check_removed(spa_aux_vdev_t *sav)
+{
+       int i;
+
+       for (i = 0; i < sav->sav_count; i++)
+               spa_check_removed(sav->sav_vdevs[i]);
+}
+
+void
+spa_claim_notify(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+
+       if (zio->io_error)
+               return;
+
+       mutex_enter(&spa->spa_props_lock);      /* any mutex will do */
+       if (spa->spa_claim_max_txg < zio->io_bp->blk_birth)
+               spa->spa_claim_max_txg = zio->io_bp->blk_birth;
+       mutex_exit(&spa->spa_props_lock);
+}
+
+typedef struct spa_load_error {
+       uint64_t        sle_meta_count;
+       uint64_t        sle_data_count;
+} spa_load_error_t;
+
+static void
+spa_load_verify_done(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       spa_load_error_t *sle = zio->io_private;
+       dmu_object_type_t type = BP_GET_TYPE(bp);
+       int error = zio->io_error;
+       spa_t *spa = zio->io_spa;
+
+       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);
+               else
+                       atomic_add_64(&sle->sle_data_count, 1);
+       }
+       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);
+       mutex_exit(&spa->spa_scrub_lock);
+}
+
+/*
+ * Maximum number of concurrent scrub i/os to create while verifying
+ * a pool while importing it.
+ */
+int spa_load_verify_maxinflight = 10000;
+int spa_load_verify_metadata = B_TRUE;
+int spa_load_verify_data = B_TRUE;
+
+/*ARGSUSED*/
+static int
+spa_load_verify_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       zio_t *rio;
+       size_t size;
+       void *data;
+
+       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+               return (0);
+       /*
+        * Note: normally this routine will not be called if
+        * spa_load_verify_metadata is not set.  However, it may be useful
+        * to manually set the flag after the traversal has begun.
+        */
+       if (!spa_load_verify_metadata)
+               return (0);
+       if (BP_GET_BUFC_TYPE(bp) == ARC_BUFC_DATA && !spa_load_verify_data)
+               return (0);
+
+       rio = arg;
+       size = BP_GET_PSIZE(bp);
+       data = zio_data_buf_alloc(size);
+
+       mutex_enter(&spa->spa_scrub_lock);
+       while (spa->spa_scrub_inflight >= spa_load_verify_maxinflight)
+               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(rio, spa, bp, data, size,
+           spa_load_verify_done, rio->io_private, ZIO_PRIORITY_SCRUB,
+           ZIO_FLAG_SPECULATIVE | ZIO_FLAG_CANFAIL |
+           ZIO_FLAG_SCRUB | ZIO_FLAG_RAW, zb));
+       return (0);
+}
+
+/* ARGSUSED */
+int
+verify_dataset_name_len(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
+{
+       if (dsl_dataset_namelen(ds) >= ZFS_MAX_DATASET_NAME_LEN)
+               return (SET_ERROR(ENAMETOOLONG));
+
+       return (0);
+}
+
+static int
+spa_load_verify(spa_t *spa)
+{
+       zio_t *rio;
+       spa_load_error_t sle = { 0 };
+       zpool_rewind_policy_t policy;
+       boolean_t verify_ok = B_FALSE;
+       int error = 0;
+
+       zpool_get_rewind_policy(spa->spa_config, &policy);
+
+       if (policy.zrp_request & ZPOOL_NEVER_REWIND)
+               return (0);
+
+       dsl_pool_config_enter(spa->spa_dsl_pool, FTAG);
+       error = dmu_objset_find_dp(spa->spa_dsl_pool,
+           spa->spa_dsl_pool->dp_root_dir_obj, verify_dataset_name_len, NULL,
+           DS_FIND_CHILDREN);
+       dsl_pool_config_exit(spa->spa_dsl_pool, FTAG);
+       if (error != 0)
+               return (error);
+
+       rio = zio_root(spa, NULL, &sle,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE);
+
+       if (spa_load_verify_metadata) {
+               error = traverse_pool(spa, spa->spa_verify_min_txg,
+                   TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA,
+                   spa_load_verify_cb, rio);
+       }
+
+       (void) zio_wait(rio);
+
+       spa->spa_load_meta_errors = sle.sle_meta_count;
+       spa->spa_load_data_errors = sle.sle_data_count;
+
+       if (!error && sle.sle_meta_count <= policy.zrp_maxmeta &&
+           sle.sle_data_count <= policy.zrp_maxdata) {
+               int64_t loss = 0;
+
+               verify_ok = B_TRUE;
+               spa->spa_load_txg = spa->spa_uberblock.ub_txg;
+               spa->spa_load_txg_ts = spa->spa_uberblock.ub_timestamp;
+
+               loss = spa->spa_last_ubsync_txg_ts - spa->spa_load_txg_ts;
+               VERIFY(nvlist_add_uint64(spa->spa_load_info,
+                   ZPOOL_CONFIG_LOAD_TIME, spa->spa_load_txg_ts) == 0);
+               VERIFY(nvlist_add_int64(spa->spa_load_info,
+                   ZPOOL_CONFIG_REWIND_TIME, loss) == 0);
+               VERIFY(nvlist_add_uint64(spa->spa_load_info,
+                   ZPOOL_CONFIG_LOAD_DATA_ERRORS, sle.sle_data_count) == 0);
+       } else {
+               spa->spa_load_max_txg = spa->spa_uberblock.ub_txg;
+       }
+
+       if (error) {
+               if (error != ENXIO && error != EIO)
+                       error = SET_ERROR(EIO);
+               return (error);
+       }
+
+       return (verify_ok ? 0 : EIO);
+}
+
+/*
+ * Find a value in the pool props object.
+ */
+static void
+spa_prop_find(spa_t *spa, zpool_prop_t prop, uint64_t *val)
+{
+       (void) zap_lookup(spa->spa_meta_objset, spa->spa_pool_props_object,
+           zpool_prop_to_name(prop), sizeof (uint64_t), 1, val);
+}
+
+/*
+ * Find a value in the pool directory object.
+ */
+static int
+spa_dir_prop(spa_t *spa, const char *name, uint64_t *val)
+{
+       return (zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           name, sizeof (uint64_t), 1, val));
+}
+
+static int
+spa_vdev_err(vdev_t *vdev, vdev_aux_t aux, int err)
+{
+       vdev_set_state(vdev, B_TRUE, VDEV_STATE_CANT_OPEN, aux);
+       return (err);
+}
+
+/*
+ * Fix up config after a partly-completed split.  This is done with the
+ * ZPOOL_CONFIG_SPLIT nvlist.  Both the splitting pool and the split-off
+ * pool have that entry in their config, but only the splitting one contains
+ * a list of all the guids of the vdevs that are being split off.
+ *
+ * This function determines what to do with that list: either rejoin
+ * all the disks to the pool, or complete the splitting process.  To attempt
+ * the rejoin, each disk that is offlined is marked online again, and
+ * we do a reopen() call.  If the vdev label for every disk that was
+ * marked online indicates it was successfully split off (VDEV_AUX_SPLIT_POOL)
+ * then we call vdev_split() on each disk, and complete the split.
+ *
+ * Otherwise we leave the config alone, with all the vdevs in place in
+ * the original pool.
+ */
+static void
+spa_try_repair(spa_t *spa, nvlist_t *config)
+{
+       uint_t extracted;
+       uint64_t *glist;
+       uint_t i, gcount;
+       nvlist_t *nvl;
+       vdev_t **vd;
+       boolean_t attempt_reopen;
+
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_SPLIT, &nvl) != 0)
+               return;
+
+       /* check that the config is complete */
+       if (nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_SPLIT_LIST,
+           &glist, &gcount) != 0)
+               return;
+
+       vd = kmem_zalloc(gcount * sizeof (vdev_t *), KM_SLEEP);
+
+       /* attempt to online all the vdevs & validate */
+       attempt_reopen = B_TRUE;
+       for (i = 0; i < gcount; i++) {
+               if (glist[i] == 0)      /* vdev is hole */
+                       continue;
+
+               vd[i] = spa_lookup_by_guid(spa, glist[i], B_FALSE);
+               if (vd[i] == NULL) {
+                       /*
+                        * Don't bother attempting to reopen the disks;
+                        * just do the split.
+                        */
+                       attempt_reopen = B_FALSE;
+               } else {
+                       /* attempt to re-online it */
+                       vd[i]->vdev_offline = B_FALSE;
+               }
+       }
+
+       if (attempt_reopen) {
+               vdev_reopen(spa->spa_root_vdev);
+
+               /* check each device to see what state it's in */
+               for (extracted = 0, i = 0; i < gcount; i++) {
+                       if (vd[i] != NULL &&
+                           vd[i]->vdev_stat.vs_aux != VDEV_AUX_SPLIT_POOL)
+                               break;
+                       ++extracted;
+               }
+       }
+
+       /*
+        * If every disk has been moved to the new pool, or if we never
+        * even attempted to look at them, then we split them off for
+        * good.
+        */
+       if (!attempt_reopen || gcount == extracted) {
+               for (i = 0; i < gcount; i++)
+                       if (vd[i] != NULL)
+                               vdev_split(vd[i]);
+               vdev_reopen(spa->spa_root_vdev);
+       }
+
+       kmem_free(vd, gcount * sizeof (vdev_t *));
+}
+
+static int
+spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type,
+    boolean_t mosconfig)
+{
+       nvlist_t *config = spa->spa_config;
+       char *ereport = FM_EREPORT_ZFS_POOL;
+       char *comment;
+       int error;
+       uint64_t pool_guid;
+       nvlist_t *nvl;
+
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &pool_guid))
+               return (SET_ERROR(EINVAL));
+
+       ASSERT(spa->spa_comment == NULL);
+       if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
+               spa->spa_comment = spa_strdup(comment);
+
+       /*
+        * Versioning wasn't explicitly added to the label until later, so if
+        * it's not present treat it as the initial version.
+        */
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &spa->spa_ubsync.ub_version) != 0)
+               spa->spa_ubsync.ub_version = SPA_VERSION_INITIAL;
+
+       (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
+           &spa->spa_config_txg);
+
+       if ((state == SPA_LOAD_IMPORT || state == SPA_LOAD_TRYIMPORT) &&
+           spa_guid_exists(pool_guid, 0)) {
+               error = SET_ERROR(EEXIST);
+       } else {
+               spa->spa_config_guid = pool_guid;
+
+               if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_SPLIT,
+                   &nvl) == 0) {
+                       VERIFY(nvlist_dup(nvl, &spa->spa_config_splitting,
+                           KM_SLEEP) == 0);
+               }
+
+               nvlist_free(spa->spa_load_info);
+               spa->spa_load_info = fnvlist_alloc();
+
+               gethrestime(&spa->spa_loaded_ts);
+               error = spa_load_impl(spa, pool_guid, config, state, type,
+                   mosconfig, &ereport);
+       }
+
+       /*
+        * Don't count references from objsets that are already closed
+        * and are making their way through the eviction process.
+        */
+       spa_evicting_os_wait(spa);
+       spa->spa_minref = refcount_count(&spa->spa_refcount);
+       if (error) {
+               if (error != EEXIST) {
+                       spa->spa_loaded_ts.tv_sec = 0;
+                       spa->spa_loaded_ts.tv_nsec = 0;
+               }
+               if (error != EBADF) {
+                       zfs_ereport_post(ereport, spa, NULL, NULL, 0, 0);
+               }
+       }
+       spa->spa_load_state = error ? SPA_LOAD_ERROR : SPA_LOAD_NONE;
+       spa->spa_ena = 0;
+
+       return (error);
+}
+
+/*
+ * Load an existing storage pool, using the pool's builtin spa_config as a
+ * source of configuration information.
+ */
+__attribute__((always_inline))
+static inline int
+spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
+    spa_load_state_t state, spa_import_type_t type, boolean_t mosconfig,
+    char **ereport)
+{
+       int error = 0;
+       nvlist_t *nvroot = NULL;
+       nvlist_t *label;
+       vdev_t *rvd;
+       uberblock_t *ub = &spa->spa_uberblock;
+       uint64_t children, config_cache_txg = spa->spa_config_txg;
+       int orig_mode = spa->spa_mode;
+       int parse, i;
+       uint64_t obj;
+       boolean_t missing_feat_write = B_FALSE;
+
+       /*
+        * If this is an untrusted config, access the pool in read-only mode.
+        * This prevents things like resilvering recently removed devices.
+        */
+       if (!mosconfig)
+               spa->spa_mode = FREAD;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       spa->spa_load_state = state;
+
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot))
+               return (SET_ERROR(EINVAL));
+
+       parse = (type == SPA_IMPORT_EXISTING ?
+           VDEV_ALLOC_LOAD : VDEV_ALLOC_SPLIT);
+
+       /*
+        * Create "The Godfather" zio to hold all async IOs
+        */
+       spa->spa_async_zio_root = kmem_alloc(max_ncpus * sizeof (void *),
+           KM_SLEEP);
+       for (i = 0; i < max_ncpus; i++) {
+               spa->spa_async_zio_root[i] = zio_root(spa, NULL, NULL,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+                   ZIO_FLAG_GODFATHER);
+       }
+
+       /*
+        * Parse the configuration into a vdev tree.  We explicitly set the
+        * value that will be returned by spa_version() since parsing the
+        * configuration requires knowing the version number.
+        */
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       error = spa_config_parse(spa, &rvd, nvroot, NULL, 0, parse);
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       if (error != 0)
+               return (error);
+
+       ASSERT(spa->spa_root_vdev == rvd);
+       ASSERT3U(spa->spa_min_ashift, >=, SPA_MINBLOCKSHIFT);
+       ASSERT3U(spa->spa_max_ashift, <=, SPA_MAXBLOCKSHIFT);
+
+       if (type != SPA_IMPORT_ASSEMBLE) {
+               ASSERT(spa_guid(spa) == pool_guid);
+       }
+
+       /*
+        * Try to open all vdevs, loading each label in the process.
+        */
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       error = vdev_open(rvd);
+       spa_config_exit(spa, SCL_ALL, FTAG);
+       if (error != 0)
+               return (error);
+
+       /*
+        * We need to validate the vdev labels against the configuration that
+        * we have in hand, which is dependent on the setting of mosconfig. If
+        * mosconfig is true then we're validating the vdev labels based on
+        * that config.  Otherwise, we're validating against the cached config
+        * (zpool.cache) that was read when we loaded the zfs module, and then
+        * later we will recursively call spa_load() and validate against
+        * the vdev config.
+        *
+        * If we're assembling a new pool that's been split off from an
+        * existing pool, the labels haven't yet been updated so we skip
+        * validation for now.
+        */
+       if (type != SPA_IMPORT_ASSEMBLE) {
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               error = vdev_validate(rvd, mosconfig);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+
+               if (error != 0)
+                       return (error);
+
+               if (rvd->vdev_state <= VDEV_STATE_CANT_OPEN)
+                       return (SET_ERROR(ENXIO));
+       }
+
+       /*
+        * Find the best uberblock.
+        */
+       vdev_uberblock_load(rvd, ub, &label);
+
+       /*
+        * If we weren't able to find a single valid uberblock, return failure.
+        */
+       if (ub->ub_txg == 0) {
+               nvlist_free(label);
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, ENXIO));
+       }
+
+       /*
+        * If the pool has an unsupported version we can't open it.
+        */
+       if (!SPA_VERSION_IS_SUPPORTED(ub->ub_version)) {
+               nvlist_free(label);
+               return (spa_vdev_err(rvd, VDEV_AUX_VERSION_NEWER, ENOTSUP));
+       }
+
+       if (ub->ub_version >= SPA_VERSION_FEATURES) {
+               nvlist_t *features;
+
+               /*
+                * If we weren't able to find what's necessary for reading the
+                * MOS in the label, return failure.
+                */
+               if (label == NULL || nvlist_lookup_nvlist(label,
+                   ZPOOL_CONFIG_FEATURES_FOR_READ, &features) != 0) {
+                       nvlist_free(label);
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA,
+                           ENXIO));
+               }
+
+               /*
+                * Update our in-core representation with the definitive values
+                * from the label.
+                */
+               nvlist_free(spa->spa_label_features);
+               VERIFY(nvlist_dup(features, &spa->spa_label_features, 0) == 0);
+       }
+
+       nvlist_free(label);
+
+       /*
+        * Look through entries in the label nvlist's features_for_read. If
+        * there is a feature listed there which we don't understand then we
+        * cannot open a pool.
+        */
+       if (ub->ub_version >= SPA_VERSION_FEATURES) {
+               nvlist_t *unsup_feat;
+               nvpair_t *nvp;
+
+               VERIFY(nvlist_alloc(&unsup_feat, NV_UNIQUE_NAME, KM_SLEEP) ==
+                   0);
+
+               for (nvp = nvlist_next_nvpair(spa->spa_label_features, NULL);
+                   nvp != NULL;
+                   nvp = nvlist_next_nvpair(spa->spa_label_features, nvp)) {
+                       if (!zfeature_is_supported(nvpair_name(nvp))) {
+                               VERIFY(nvlist_add_string(unsup_feat,
+                                   nvpair_name(nvp), "") == 0);
+                       }
+               }
+
+               if (!nvlist_empty(unsup_feat)) {
+                       VERIFY(nvlist_add_nvlist(spa->spa_load_info,
+                           ZPOOL_CONFIG_UNSUP_FEAT, unsup_feat) == 0);
+                       nvlist_free(unsup_feat);
+                       return (spa_vdev_err(rvd, VDEV_AUX_UNSUP_FEAT,
+                           ENOTSUP));
+               }
+
+               nvlist_free(unsup_feat);
+       }
+
+       /*
+        * If the vdev guid sum doesn't match the uberblock, we have an
+        * incomplete configuration.  We first check to see if the pool
+        * is aware of the complete config (i.e ZPOOL_CONFIG_VDEV_CHILDREN).
+        * If it is, defer the vdev_guid_sum check till later so we
+        * can handle missing vdevs.
+        */
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_VDEV_CHILDREN,
+           &children) != 0 && mosconfig && type != SPA_IMPORT_ASSEMBLE &&
+           rvd->vdev_guid_sum != ub->ub_guid_sum)
+               return (spa_vdev_err(rvd, VDEV_AUX_BAD_GUID_SUM, ENXIO));
+
+       if (type != SPA_IMPORT_ASSEMBLE && spa->spa_config_splitting) {
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_try_repair(spa, config);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               nvlist_free(spa->spa_config_splitting);
+               spa->spa_config_splitting = NULL;
+       }
+
+       /*
+        * Initialize internal SPA structures.
+        */
+       spa->spa_state = POOL_STATE_ACTIVE;
+       spa->spa_ubsync = spa->spa_uberblock;
+       spa->spa_verify_min_txg = spa->spa_extreme_rewind ?
+           TXG_INITIAL - 1 : spa_last_synced_txg(spa) - TXG_DEFER_SIZE - 1;
+       spa->spa_first_txg = spa->spa_last_ubsync_txg ?
+           spa->spa_last_ubsync_txg : spa_last_synced_txg(spa) + 1;
+       spa->spa_claim_max_txg = spa->spa_first_txg;
+       spa->spa_prev_software_version = ub->ub_software_version;
+
+       error = dsl_pool_init(spa, spa->spa_first_txg, &spa->spa_dsl_pool);
+       if (error)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+       spa->spa_meta_objset = spa->spa_dsl_pool->dp_meta_objset;
+
+       if (spa_dir_prop(spa, DMU_POOL_CONFIG, &spa->spa_config_object) != 0)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       if (spa_version(spa) >= SPA_VERSION_FEATURES) {
+               boolean_t missing_feat_read = B_FALSE;
+               nvlist_t *unsup_feat, *enabled_feat;
+               spa_feature_t i;
+
+               if (spa_dir_prop(spa, DMU_POOL_FEATURES_FOR_READ,
+                   &spa->spa_feat_for_read_obj) != 0) {
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+               }
+
+               if (spa_dir_prop(spa, DMU_POOL_FEATURES_FOR_WRITE,
+                   &spa->spa_feat_for_write_obj) != 0) {
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+               }
+
+               if (spa_dir_prop(spa, DMU_POOL_FEATURE_DESCRIPTIONS,
+                   &spa->spa_feat_desc_obj) != 0) {
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+               }
+
+               enabled_feat = fnvlist_alloc();
+               unsup_feat = fnvlist_alloc();
+
+               if (!spa_features_check(spa, B_FALSE,
+                   unsup_feat, enabled_feat))
+                       missing_feat_read = B_TRUE;
+
+               if (spa_writeable(spa) || state == SPA_LOAD_TRYIMPORT) {
+                       if (!spa_features_check(spa, B_TRUE,
+                           unsup_feat, enabled_feat)) {
+                               missing_feat_write = B_TRUE;
+                       }
+               }
+
+               fnvlist_add_nvlist(spa->spa_load_info,
+                   ZPOOL_CONFIG_ENABLED_FEAT, enabled_feat);
+
+               if (!nvlist_empty(unsup_feat)) {
+                       fnvlist_add_nvlist(spa->spa_load_info,
+                           ZPOOL_CONFIG_UNSUP_FEAT, unsup_feat);
+               }
+
+               fnvlist_free(enabled_feat);
+               fnvlist_free(unsup_feat);
+
+               if (!missing_feat_read) {
+                       fnvlist_add_boolean(spa->spa_load_info,
+                           ZPOOL_CONFIG_CAN_RDONLY);
+               }
+
+               /*
+                * If the state is SPA_LOAD_TRYIMPORT, our objective is
+                * twofold: to determine whether the pool is available for
+                * import in read-write mode and (if it is not) whether the
+                * pool is available for import in read-only mode. If the pool
+                * is available for import in read-write mode, it is displayed
+                * as available in userland; if it is not available for import
+                * in read-only mode, it is displayed as unavailable in
+                * userland. If the pool is available for import in read-only
+                * mode but not read-write mode, it is displayed as unavailable
+                * in userland with a special note that the pool is actually
+                * available for open in read-only mode.
+                *
+                * As a result, if the state is SPA_LOAD_TRYIMPORT and we are
+                * missing a feature for write, we must first determine whether
+                * the pool can be opened read-only before returning to
+                * userland in order to know whether to display the
+                * abovementioned note.
+                */
+               if (missing_feat_read || (missing_feat_write &&
+                   spa_writeable(spa))) {
+                       return (spa_vdev_err(rvd, VDEV_AUX_UNSUP_FEAT,
+                           ENOTSUP));
+               }
+
+               /*
+                * Load refcounts for ZFS features from disk into an in-memory
+                * cache during SPA initialization.
+                */
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       uint64_t refcount;
+
+                       error = feature_get_refcount_from_disk(spa,
+                           &spa_feature_table[i], &refcount);
+                       if (error == 0) {
+                               spa->spa_feat_refcount_cache[i] = refcount;
+                       } else if (error == ENOTSUP) {
+                               spa->spa_feat_refcount_cache[i] =
+                                   SPA_FEATURE_DISABLED;
+                       } else {
+                               return (spa_vdev_err(rvd,
+                                   VDEV_AUX_CORRUPT_DATA, EIO));
+                       }
+               }
+       }
+
+       if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
+               if (spa_dir_prop(spa, DMU_POOL_FEATURE_ENABLED_TXG,
+                   &spa->spa_feat_enabled_txg_obj) != 0)
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+       }
+
+       spa->spa_is_initializing = B_TRUE;
+       error = dsl_pool_open(spa->spa_dsl_pool);
+       spa->spa_is_initializing = B_FALSE;
+       if (error != 0)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       if (!mosconfig) {
+               uint64_t hostid;
+               nvlist_t *policy = NULL, *nvconfig;
+
+               if (load_nvlist(spa, spa->spa_config_object, &nvconfig) != 0)
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+               if (!spa_is_root(spa) && nvlist_lookup_uint64(nvconfig,
+                   ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
+                       char *hostname;
+                       unsigned long myhostid = 0;
+
+                       VERIFY(nvlist_lookup_string(nvconfig,
+                           ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
+
+#ifdef _KERNEL
+                       myhostid = zone_get_hostid(NULL);
+#else  /* _KERNEL */
+                       /*
+                        * We're emulating the system's hostid in userland, so
+                        * we can't use zone_get_hostid().
+                        */
+                       (void) ddi_strtoul(hw_serial, NULL, 10, &myhostid);
+#endif /* _KERNEL */
+                       if (hostid != 0 && myhostid != 0 &&
+                           hostid != myhostid) {
+                               nvlist_free(nvconfig);
+                               cmn_err(CE_WARN, "pool '%s' could not be "
+                                   "loaded as it was last accessed by another "
+                                   "system (host: %s hostid: 0x%lx). See: "
+                                   "http://zfsonlinux.org/msg/ZFS-8000-EY",
+                                   spa_name(spa), hostname,
+                                   (unsigned long)hostid);
+                               return (SET_ERROR(EBADF));
+                       }
+               }
+               if (nvlist_lookup_nvlist(spa->spa_config,
+                   ZPOOL_REWIND_POLICY, &policy) == 0)
+                       VERIFY(nvlist_add_nvlist(nvconfig,
+                           ZPOOL_REWIND_POLICY, policy) == 0);
+
+               spa_config_set(spa, nvconfig);
+               spa_unload(spa);
+               spa_deactivate(spa);
+               spa_activate(spa, orig_mode);
+
+               return (spa_load(spa, state, SPA_IMPORT_EXISTING, B_TRUE));
+       }
+
+       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);
+       if (error != 0)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       /*
+        * Load the bit that tells us to use the new accounting function
+        * (raid-z deflation).  If we have an older pool, this will not
+        * be present.
+        */
+       error = spa_dir_prop(spa, DMU_POOL_DEFLATE, &spa->spa_deflate);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       error = spa_dir_prop(spa, DMU_POOL_CREATION_VERSION,
+           &spa->spa_creation_version);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       /*
+        * Load the persistent error log.  If we have an older pool, this will
+        * not be present.
+        */
+       error = spa_dir_prop(spa, DMU_POOL_ERRLOG_LAST, &spa->spa_errlog_last);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       error = spa_dir_prop(spa, DMU_POOL_ERRLOG_SCRUB,
+           &spa->spa_errlog_scrub);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       /*
+        * Load the history object.  If we have an older pool, this
+        * will not be present.
+        */
+       error = spa_dir_prop(spa, DMU_POOL_HISTORY, &spa->spa_history);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       /*
+        * If we're assembling the pool from the split-off vdevs of
+        * an existing pool, we don't want to attach the spares & cache
+        * devices.
+        */
+
+       /*
+        * Load any hot spares for this pool.
+        */
+       error = spa_dir_prop(spa, DMU_POOL_SPARES, &spa->spa_spares.sav_object);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+       if (error == 0 && type != SPA_IMPORT_ASSEMBLE) {
+               ASSERT(spa_version(spa) >= SPA_VERSION_SPARES);
+               if (load_nvlist(spa, spa->spa_spares.sav_object,
+                   &spa->spa_spares.sav_config) != 0)
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_load_spares(spa);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+       } else if (error == 0) {
+               spa->spa_spares.sav_sync = B_TRUE;
+       }
+
+       /*
+        * Load any level 2 ARC devices for this pool.
+        */
+       error = spa_dir_prop(spa, DMU_POOL_L2CACHE,
+           &spa->spa_l2cache.sav_object);
+       if (error != 0 && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+       if (error == 0 && type != SPA_IMPORT_ASSEMBLE) {
+               ASSERT(spa_version(spa) >= SPA_VERSION_L2CACHE);
+               if (load_nvlist(spa, spa->spa_l2cache.sav_object,
+                   &spa->spa_l2cache.sav_config) != 0)
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_load_l2cache(spa);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+       } else if (error == 0) {
+               spa->spa_l2cache.sav_sync = B_TRUE;
+       }
+
+       spa->spa_delegation = zpool_prop_default_numeric(ZPOOL_PROP_DELEGATION);
+
+       error = spa_dir_prop(spa, DMU_POOL_PROPS, &spa->spa_pool_props_object);
+       if (error && error != ENOENT)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       if (error == 0) {
+               uint64_t autoreplace = 0;
+
+               spa_prop_find(spa, ZPOOL_PROP_BOOTFS, &spa->spa_bootfs);
+               spa_prop_find(spa, ZPOOL_PROP_AUTOREPLACE, &autoreplace);
+               spa_prop_find(spa, ZPOOL_PROP_DELEGATION, &spa->spa_delegation);
+               spa_prop_find(spa, ZPOOL_PROP_FAILUREMODE, &spa->spa_failmode);
+               spa_prop_find(spa, ZPOOL_PROP_AUTOEXPAND, &spa->spa_autoexpand);
+               spa_prop_find(spa, ZPOOL_PROP_DEDUPDITTO,
+                   &spa->spa_dedup_ditto);
+
+               spa->spa_autoreplace = (autoreplace != 0);
+       }
+
+       /*
+        * If the 'autoreplace' property is set, then post a resource notifying
+        * the ZFS DE that it should not issue any faults for unopenable
+        * devices.  We also iterate over the vdevs, and post a sysevent for any
+        * unopenable vdevs so that the normal autoreplace handler can take
+        * over.
+        */
+       if (spa->spa_autoreplace && state != SPA_LOAD_TRYIMPORT) {
+               spa_check_removed(spa->spa_root_vdev);
+               /*
+                * For the import case, this is done in spa_import(), because
+                * at this point we're using the spare definitions from
+                * the MOS config, not necessarily from the userland config.
+                */
+               if (state != SPA_LOAD_IMPORT) {
+                       spa_aux_check_removed(&spa->spa_spares);
+                       spa_aux_check_removed(&spa->spa_l2cache);
+               }
+       }
+
+       /*
+        * Load the vdev state for all toplevel vdevs.
+        */
+       vdev_load(rvd);
+
+       /*
+        * Propagate the leaf DTLs we just loaded all the way up the tree.
+        */
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       vdev_dtl_reassess(rvd, 0, 0, B_FALSE);
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       /*
+        * Load the DDTs (dedup tables).
+        */
+       error = ddt_load(spa);
+       if (error != 0)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       spa_update_dspace(spa);
+
+       /*
+        * Validate the config, using the MOS config to fill in any
+        * information which might be missing.  If we fail to validate
+        * the config then declare the pool unfit for use. If we're
+        * assembling a pool from a split, the log is not transferred
+        * over.
+        */
+       if (type != SPA_IMPORT_ASSEMBLE) {
+               nvlist_t *nvconfig;
+
+               if (load_nvlist(spa, spa->spa_config_object, &nvconfig) != 0)
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+               if (!spa_config_valid(spa, nvconfig)) {
+                       nvlist_free(nvconfig);
+                       return (spa_vdev_err(rvd, VDEV_AUX_BAD_GUID_SUM,
+                           ENXIO));
+               }
+               nvlist_free(nvconfig);
+
+               /*
+                * Now that we've validated the config, check the state of the
+                * root vdev.  If it can't be opened, it indicates one or
+                * more toplevel vdevs are faulted.
+                */
+               if (rvd->vdev_state <= VDEV_STATE_CANT_OPEN)
+                       return (SET_ERROR(ENXIO));
+
+               if (spa_writeable(spa) && spa_check_logs(spa)) {
+                       *ereport = FM_EREPORT_ZFS_LOG_REPLAY;
+                       return (spa_vdev_err(rvd, VDEV_AUX_BAD_LOG, ENXIO));
+               }
+       }
+
+       if (missing_feat_write) {
+               ASSERT(state == SPA_LOAD_TRYIMPORT);
+
+               /*
+                * At this point, we know that we can open the pool in
+                * read-only mode but not read-write mode. We now have enough
+                * information and can return to userland.
+                */
+               return (spa_vdev_err(rvd, VDEV_AUX_UNSUP_FEAT, ENOTSUP));
+       }
+
+       /*
+        * We've successfully opened the pool, verify that we're ready
+        * to start pushing transactions.
+        */
+       if (state != SPA_LOAD_TRYIMPORT) {
+               if ((error = spa_load_verify(spa)))
+                       return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA,
+                           error));
+       }
+
+       if (spa_writeable(spa) && (state == SPA_LOAD_RECOVER ||
+           spa->spa_load_max_txg == UINT64_MAX)) {
+               dmu_tx_t *tx;
+               int need_update = B_FALSE;
+               dsl_pool_t *dp = spa_get_dsl(spa);
+               int c;
+
+               ASSERT(state != SPA_LOAD_TRYIMPORT);
+
+               /*
+                * Claim log blocks that haven't been committed yet.
+                * This must all happen in a single txg.
+                * Note: spa_claim_max_txg is updated by spa_claim_notify(),
+                * invoked from zil_claim_log_block()'s i/o done callback.
+                * Price of rollback is that we abandon the log.
+                */
+               spa->spa_claiming = B_TRUE;
+
+               tx = dmu_tx_create_assigned(dp, spa_first_txg(spa));
+               (void) dmu_objset_find_dp(dp, dp->dp_root_dir_obj,
+                   zil_claim, tx, DS_FIND_CHILDREN);
+               dmu_tx_commit(tx);
+
+               spa->spa_claiming = B_FALSE;
+
+               spa_set_log_state(spa, SPA_LOG_GOOD);
+               spa->spa_sync_on = B_TRUE;
+               txg_sync_start(spa->spa_dsl_pool);
+
+               /*
+                * Wait for all claims to sync.  We sync up to the highest
+                * claimed log block birth time so that claimed log blocks
+                * don't appear to be from the future.  spa_claim_max_txg
+                * will have been set for us by either zil_check_log_chain()
+                * (invoked from spa_check_logs()) or zil_claim() above.
+                */
+               txg_wait_synced(spa->spa_dsl_pool, spa->spa_claim_max_txg);
+
+               /*
+                * If the config cache is stale, or we have uninitialized
+                * metaslabs (see spa_vdev_add()), then update the config.
+                *
+                * If this is a verbatim import, trust the current
+                * in-core spa_config and update the disk labels.
+                */
+               if (config_cache_txg != spa->spa_config_txg ||
+                   state == SPA_LOAD_IMPORT ||
+                   state == SPA_LOAD_RECOVER ||
+                   (spa->spa_import_flags & ZFS_IMPORT_VERBATIM))
+                       need_update = B_TRUE;
+
+               for (c = 0; c < rvd->vdev_children; c++)
+                       if (rvd->vdev_child[c]->vdev_ms_array == 0)
+                               need_update = B_TRUE;
+
+               /*
+                * Update the config cache asychronously in case we're the
+                * root pool, in which case the config cache isn't writable yet.
+                */
+               if (need_update)
+                       spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
+
+               /*
+                * Check all DTLs to see if anything needs resilvering.
+                */
+               if (!dsl_scan_resilvering(spa->spa_dsl_pool) &&
+                   vdev_resilver_needed(rvd, NULL, NULL))
+                       spa_async_request(spa, SPA_ASYNC_RESILVER);
+
+               /*
+                * Log the fact that we booted up (so that we can detect if
+                * we rebooted in the middle of an operation).
+                */
+               spa_history_log_version(spa, "open");
+
+               /*
+                * Delete any inconsistent datasets.
+                */
+               (void) dmu_objset_find(spa_name(spa),
+                   dsl_destroy_inconsistent, NULL, DS_FIND_CHILDREN);
+
+               /*
+                * Clean up any stale temporary dataset userrefs.
+                */
+               dsl_pool_clean_tmp_userrefs(spa->spa_dsl_pool);
+       }
+
+       return (0);
+}
+
+static int
+spa_load_retry(spa_t *spa, spa_load_state_t state, int mosconfig)
+{
+       int mode = spa->spa_mode;
+
+       spa_unload(spa);
+       spa_deactivate(spa);
+
+       spa->spa_load_max_txg = spa->spa_uberblock.ub_txg - 1;
+
+       spa_activate(spa, mode);
+       spa_async_suspend(spa);
+
+       return (spa_load(spa, state, SPA_IMPORT_EXISTING, mosconfig));
+}
+
+/*
+ * If spa_load() fails this function will try loading prior txg's. If
+ * 'state' is SPA_LOAD_RECOVER and one of these loads succeeds the pool
+ * will be rewound to that txg. If 'state' is not SPA_LOAD_RECOVER this
+ * function will not rewind the pool and will return the same error as
+ * spa_load().
+ */
+static int
+spa_load_best(spa_t *spa, spa_load_state_t state, int mosconfig,
+    uint64_t max_request, int rewind_flags)
+{
+       nvlist_t *loadinfo = NULL;
+       nvlist_t *config = NULL;
+       int load_error, rewind_error;
+       uint64_t safe_rewind_txg;
+       uint64_t min_txg;
+
+       if (spa->spa_load_txg && state == SPA_LOAD_RECOVER) {
+               spa->spa_load_max_txg = spa->spa_load_txg;
+               spa_set_log_state(spa, SPA_LOG_CLEAR);
+       } else {
+               spa->spa_load_max_txg = max_request;
+               if (max_request != UINT64_MAX)
+                       spa->spa_extreme_rewind = B_TRUE;
+       }
+
+       load_error = rewind_error = spa_load(spa, state, SPA_IMPORT_EXISTING,
+           mosconfig);
+       if (load_error == 0)
+               return (0);
+
+       if (spa->spa_root_vdev != NULL)
+               config = spa_config_generate(spa, NULL, -1ULL, B_TRUE);
+
+       spa->spa_last_ubsync_txg = spa->spa_uberblock.ub_txg;
+       spa->spa_last_ubsync_txg_ts = spa->spa_uberblock.ub_timestamp;
+
+       if (rewind_flags & ZPOOL_NEVER_REWIND) {
+               nvlist_free(config);
+               return (load_error);
+       }
+
+       if (state == SPA_LOAD_RECOVER) {
+               /* Price of rolling back is discarding txgs, including log */
+               spa_set_log_state(spa, SPA_LOG_CLEAR);
+       } else {
+               /*
+                * If we aren't rolling back save the load info from our first
+                * import attempt so that we can restore it after attempting
+                * to rewind.
+                */
+               loadinfo = spa->spa_load_info;
+               spa->spa_load_info = fnvlist_alloc();
+       }
+
+       spa->spa_load_max_txg = spa->spa_last_ubsync_txg;
+       safe_rewind_txg = spa->spa_last_ubsync_txg - TXG_DEFER_SIZE;
+       min_txg = (rewind_flags & ZPOOL_EXTREME_REWIND) ?
+           TXG_INITIAL : safe_rewind_txg;
+
+       /*
+        * Continue as long as we're finding errors, we're still within
+        * the acceptable rewind range, and we're still finding uberblocks
+        */
+       while (rewind_error && spa->spa_uberblock.ub_txg >= min_txg &&
+           spa->spa_uberblock.ub_txg <= spa->spa_load_max_txg) {
+               if (spa->spa_load_max_txg < safe_rewind_txg)
+                       spa->spa_extreme_rewind = B_TRUE;
+               rewind_error = spa_load_retry(spa, state, mosconfig);
+       }
+
+       spa->spa_extreme_rewind = B_FALSE;
+       spa->spa_load_max_txg = UINT64_MAX;
+
+       if (config && (rewind_error || state != SPA_LOAD_RECOVER))
+               spa_config_set(spa, config);
+
+       if (state == SPA_LOAD_RECOVER) {
+               ASSERT3P(loadinfo, ==, NULL);
+               return (rewind_error);
+       } else {
+               /* Store the rewind info as part of the initial load info */
+               fnvlist_add_nvlist(loadinfo, ZPOOL_CONFIG_REWIND_INFO,
+                   spa->spa_load_info);
+
+               /* Restore the initial load info */
+               fnvlist_free(spa->spa_load_info);
+               spa->spa_load_info = loadinfo;
+
+               return (load_error);
+       }
+}
+
+/*
+ * Pool Open/Import
+ *
+ * The import case is identical to an open except that the configuration is sent
+ * down from userland, instead of grabbed from the configuration cache.  For the
+ * case of an open, the pool configuration will exist in the
+ * POOL_STATE_UNINITIALIZED state.
+ *
+ * The stats information (gen/count/ustats) is used to gather vdev statistics at
+ * the same time open the pool, without having to keep around the spa_t in some
+ * ambiguous state.
+ */
+static int
+spa_open_common(const char *pool, spa_t **spapp, void *tag, nvlist_t *nvpolicy,
+    nvlist_t **config)
+{
+       spa_t *spa;
+       spa_load_state_t state = SPA_LOAD_OPEN;
+       int error;
+       int locked = B_FALSE;
+       int firstopen = B_FALSE;
+
+       *spapp = NULL;
+
+       /*
+        * As disgusting as this is, we need to support recursive calls to this
+        * function because dsl_dir_open() is called during spa_load(), and ends
+        * up calling spa_open() again.  The real fix is to figure out how to
+        * avoid dsl_dir_open() calling this in the first place.
+        */
+       if (mutex_owner(&spa_namespace_lock) != curthread) {
+               mutex_enter(&spa_namespace_lock);
+               locked = B_TRUE;
+       }
+
+       if ((spa = spa_lookup(pool)) == NULL) {
+               if (locked)
+                       mutex_exit(&spa_namespace_lock);
+               return (SET_ERROR(ENOENT));
+       }
+
+       if (spa->spa_state == POOL_STATE_UNINITIALIZED) {
+               zpool_rewind_policy_t policy;
+
+               firstopen = B_TRUE;
+
+               zpool_get_rewind_policy(nvpolicy ? nvpolicy : spa->spa_config,
+                   &policy);
+               if (policy.zrp_request & ZPOOL_DO_REWIND)
+                       state = SPA_LOAD_RECOVER;
+
+               spa_activate(spa, spa_mode_global);
+
+               if (state != SPA_LOAD_RECOVER)
+                       spa->spa_last_ubsync_txg = spa->spa_load_txg = 0;
+
+               error = spa_load_best(spa, state, B_FALSE, policy.zrp_txg,
+                   policy.zrp_request);
+
+               if (error == EBADF) {
+                       /*
+                        * If vdev_validate() returns failure (indicated by
+                        * EBADF), it indicates that one of the vdevs indicates
+                        * that the pool has been exported or destroyed.  If
+                        * this is the case, the config cache is out of sync and
+                        * we should remove the pool from the namespace.
+                        */
+                       spa_unload(spa);
+                       spa_deactivate(spa);
+                       spa_config_sync(spa, B_TRUE, B_TRUE);
+                       spa_remove(spa);
+                       if (locked)
+                               mutex_exit(&spa_namespace_lock);
+                       return (SET_ERROR(ENOENT));
+               }
+
+               if (error) {
+                       /*
+                        * We can't open the pool, but we still have useful
+                        * information: the state of each vdev after the
+                        * attempted vdev_open().  Return this to the user.
+                        */
+                       if (config != NULL && spa->spa_config) {
+                               VERIFY(nvlist_dup(spa->spa_config, config,
+                                   KM_SLEEP) == 0);
+                               VERIFY(nvlist_add_nvlist(*config,
+                                   ZPOOL_CONFIG_LOAD_INFO,
+                                   spa->spa_load_info) == 0);
+                       }
+                       spa_unload(spa);
+                       spa_deactivate(spa);
+                       spa->spa_last_open_failed = error;
+                       if (locked)
+                               mutex_exit(&spa_namespace_lock);
+                       *spapp = NULL;
+                       return (error);
+               }
+       }
+
+       spa_open_ref(spa, tag);
+
+       if (config != NULL)
+               *config = spa_config_generate(spa, NULL, -1ULL, B_TRUE);
+
+       /*
+        * If we've recovered the pool, pass back any information we
+        * gathered while doing the load.
+        */
+       if (state == SPA_LOAD_RECOVER) {
+               VERIFY(nvlist_add_nvlist(*config, ZPOOL_CONFIG_LOAD_INFO,
+                   spa->spa_load_info) == 0);
+       }
+
+       if (locked) {
+               spa->spa_last_open_failed = 0;
+               spa->spa_last_ubsync_txg = 0;
+               spa->spa_load_txg = 0;
+               mutex_exit(&spa_namespace_lock);
+       }
+
+       if (firstopen)
+               zvol_create_minors(spa, spa_name(spa), B_TRUE);
+
+       *spapp = spa;
+
+       return (0);
+}
+
+int
+spa_open_rewind(const char *name, spa_t **spapp, void *tag, nvlist_t *policy,
+    nvlist_t **config)
+{
+       return (spa_open_common(name, spapp, tag, policy, config));
+}
+
+int
+spa_open(const char *name, spa_t **spapp, void *tag)
+{
+       return (spa_open_common(name, spapp, tag, NULL, NULL));
+}
+
+/*
+ * Lookup the given spa_t, incrementing the inject count in the process,
+ * preventing it from being exported or destroyed.
+ */
+spa_t *
+spa_inject_addref(char *name)
+{
+       spa_t *spa;
+
+       mutex_enter(&spa_namespace_lock);
+       if ((spa = spa_lookup(name)) == NULL) {
+               mutex_exit(&spa_namespace_lock);
+               return (NULL);
+       }
+       spa->spa_inject_ref++;
+       mutex_exit(&spa_namespace_lock);
+
+       return (spa);
+}
+
+void
+spa_inject_delref(spa_t *spa)
+{
+       mutex_enter(&spa_namespace_lock);
+       spa->spa_inject_ref--;
+       mutex_exit(&spa_namespace_lock);
+}
+
+/*
+ * Add spares device information to the nvlist.
+ */
+static void
+spa_add_spares(spa_t *spa, nvlist_t *config)
+{
+       nvlist_t **spares;
+       uint_t i, nspares;
+       nvlist_t *nvroot;
+       uint64_t guid;
+       vdev_stat_t *vs;
+       uint_t vsc;
+       uint64_t pool;
+
+       ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
+
+       if (spa->spa_spares.sav_count == 0)
+               return;
+
+       VERIFY(nvlist_lookup_nvlist(config,
+           ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+       VERIFY(nvlist_lookup_nvlist_array(spa->spa_spares.sav_config,
+           ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0);
+       if (nspares != 0) {
+               VERIFY(nvlist_add_nvlist_array(nvroot,
+                   ZPOOL_CONFIG_SPARES, spares, nspares) == 0);
+               VERIFY(nvlist_lookup_nvlist_array(nvroot,
+                   ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0);
+
+               /*
+                * Go through and find any spares which have since been
+                * repurposed as an active spare.  If this is the case, update
+                * their status appropriately.
+                */
+               for (i = 0; i < nspares; i++) {
+                       VERIFY(nvlist_lookup_uint64(spares[i],
+                           ZPOOL_CONFIG_GUID, &guid) == 0);
+                       if (spa_spare_exists(guid, &pool, NULL) &&
+                           pool != 0ULL) {
+                               VERIFY(nvlist_lookup_uint64_array(
+                                   spares[i], ZPOOL_CONFIG_VDEV_STATS,
+                                   (uint64_t **)&vs, &vsc) == 0);
+                               vs->vs_state = VDEV_STATE_CANT_OPEN;
+                               vs->vs_aux = VDEV_AUX_SPARED;
+                       }
+               }
+       }
+}
+
+/*
+ * Add l2cache device information to the nvlist, including vdev stats.
+ */
+static void
+spa_add_l2cache(spa_t *spa, nvlist_t *config)
+{
+       nvlist_t **l2cache;
+       uint_t i, j, nl2cache;
+       nvlist_t *nvroot;
+       uint64_t guid;
+       vdev_t *vd;
+       vdev_stat_t *vs;
+       uint_t vsc;
+
+       ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
+
+       if (spa->spa_l2cache.sav_count == 0)
+               return;
+
+       VERIFY(nvlist_lookup_nvlist(config,
+           ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+       VERIFY(nvlist_lookup_nvlist_array(spa->spa_l2cache.sav_config,
+           ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0);
+       if (nl2cache != 0) {
+               VERIFY(nvlist_add_nvlist_array(nvroot,
+                   ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache) == 0);
+               VERIFY(nvlist_lookup_nvlist_array(nvroot,
+                   ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0);
+
+               /*
+                * Update level 2 cache device stats.
+                */
+
+               for (i = 0; i < nl2cache; i++) {
+                       VERIFY(nvlist_lookup_uint64(l2cache[i],
+                           ZPOOL_CONFIG_GUID, &guid) == 0);
+
+                       vd = NULL;
+                       for (j = 0; j < spa->spa_l2cache.sav_count; j++) {
+                               if (guid ==
+                                   spa->spa_l2cache.sav_vdevs[j]->vdev_guid) {
+                                       vd = spa->spa_l2cache.sav_vdevs[j];
+                                       break;
+                               }
+                       }
+                       ASSERT(vd != NULL);
+
+                       VERIFY(nvlist_lookup_uint64_array(l2cache[i],
+                           ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
+                           == 0);
+                       vdev_get_stats(vd, vs);
+               }
+       }
+}
+
+static void
+spa_feature_stats_from_disk(spa_t *spa, nvlist_t *features)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+
+       if (spa->spa_feat_for_read_obj != 0) {
+               for (zap_cursor_init(&zc, spa->spa_meta_objset,
+                   spa->spa_feat_for_read_obj);
+                   zap_cursor_retrieve(&zc, &za) == 0;
+                   zap_cursor_advance(&zc)) {
+                       ASSERT(za.za_integer_length == sizeof (uint64_t) &&
+                           za.za_num_integers == 1);
+                       VERIFY0(nvlist_add_uint64(features, za.za_name,
+                           za.za_first_integer));
+               }
+               zap_cursor_fini(&zc);
+       }
+
+       if (spa->spa_feat_for_write_obj != 0) {
+               for (zap_cursor_init(&zc, spa->spa_meta_objset,
+                   spa->spa_feat_for_write_obj);
+                   zap_cursor_retrieve(&zc, &za) == 0;
+                   zap_cursor_advance(&zc)) {
+                       ASSERT(za.za_integer_length == sizeof (uint64_t) &&
+                           za.za_num_integers == 1);
+                       VERIFY0(nvlist_add_uint64(features, za.za_name,
+                           za.za_first_integer));
+               }
+               zap_cursor_fini(&zc);
+       }
+}
+
+static void
+spa_feature_stats_from_cache(spa_t *spa, nvlist_t *features)
+{
+       int i;
+
+       for (i = 0; i < SPA_FEATURES; i++) {
+               zfeature_info_t feature = spa_feature_table[i];
+               uint64_t refcount;
+
+               if (feature_get_refcount(spa, &feature, &refcount) != 0)
+                       continue;
+
+               VERIFY0(nvlist_add_uint64(features, feature.fi_guid, refcount));
+       }
+}
+
+/*
+ * Store a list of pool features and their reference counts in the
+ * config.
+ *
+ * The first time this is called on a spa, allocate a new nvlist, fetch
+ * the pool features and reference counts from disk, then save the list
+ * in the spa. In subsequent calls on the same spa use the saved nvlist
+ * and refresh its values from the cached reference counts.  This
+ * ensures we don't block here on I/O on a suspended pool so 'zpool
+ * clear' can resume the pool.
+ */
+static void
+spa_add_feature_stats(spa_t *spa, nvlist_t *config)
+{
+       nvlist_t *features;
+
+       ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
+
+       mutex_enter(&spa->spa_feat_stats_lock);
+       features = spa->spa_feat_stats;
+
+       if (features != NULL) {
+               spa_feature_stats_from_cache(spa, features);
+       } else {
+               VERIFY0(nvlist_alloc(&features, NV_UNIQUE_NAME, KM_SLEEP));
+               spa->spa_feat_stats = features;
+               spa_feature_stats_from_disk(spa, features);
+       }
+
+       VERIFY0(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
+           features));
+
+       mutex_exit(&spa->spa_feat_stats_lock);
+}
+
+int
+spa_get_stats(const char *name, nvlist_t **config,
+    char *altroot, size_t buflen)
+{
+       int error;
+       spa_t *spa;
+
+       *config = NULL;
+       error = spa_open_common(name, &spa, FTAG, NULL, config);
+
+       if (spa != NULL) {
+               /*
+                * This still leaves a window of inconsistency where the spares
+                * or l2cache devices could change and the config would be
+                * self-inconsistent.
+                */
+               spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+
+               if (*config != NULL) {
+                       uint64_t loadtimes[2];
+
+                       loadtimes[0] = spa->spa_loaded_ts.tv_sec;
+                       loadtimes[1] = spa->spa_loaded_ts.tv_nsec;
+                       VERIFY(nvlist_add_uint64_array(*config,
+                           ZPOOL_CONFIG_LOADED_TIME, loadtimes, 2) == 0);
+
+                       VERIFY(nvlist_add_uint64(*config,
+                           ZPOOL_CONFIG_ERRCOUNT,
+                           spa_get_errlog_size(spa)) == 0);
+
+                       if (spa_suspended(spa))
+                               VERIFY(nvlist_add_uint64(*config,
+                                   ZPOOL_CONFIG_SUSPENDED,
+                                   spa->spa_failmode) == 0);
+
+                       spa_add_spares(spa, *config);
+                       spa_add_l2cache(spa, *config);
+                       spa_add_feature_stats(spa, *config);
+               }
+       }
+
+       /*
+        * We want to get the alternate root even for faulted pools, so we cheat
+        * and call spa_lookup() directly.
+        */
+       if (altroot) {
+               if (spa == NULL) {
+                       mutex_enter(&spa_namespace_lock);
+                       spa = spa_lookup(name);
+                       if (spa)
+                               spa_altroot(spa, altroot, buflen);
+                       else
+                               altroot[0] = '\0';
+                       spa = NULL;
+                       mutex_exit(&spa_namespace_lock);
+               } else {
+                       spa_altroot(spa, altroot, buflen);
+               }
+       }
+
+       if (spa != NULL) {
+               spa_config_exit(spa, SCL_CONFIG, FTAG);
+               spa_close(spa, FTAG);
+       }
+
+       return (error);
+}
+
+/*
+ * Validate that the auxiliary device array is well formed.  We must have an
+ * array of nvlists, each which describes a valid leaf vdev.  If this is an
+ * import (mode is VDEV_ALLOC_SPARE), then we allow corrupted spares to be
+ * specified, as long as they are well-formed.
+ */
+static int
+spa_validate_aux_devs(spa_t *spa, nvlist_t *nvroot, uint64_t crtxg, int mode,
+    spa_aux_vdev_t *sav, const char *config, uint64_t version,
+    vdev_labeltype_t label)
+{
+       nvlist_t **dev;
+       uint_t i, ndev;
+       vdev_t *vd;
+       int error;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       /*
+        * It's acceptable to have no devs specified.
+        */
+       if (nvlist_lookup_nvlist_array(nvroot, config, &dev, &ndev) != 0)
+               return (0);
+
+       if (ndev == 0)
+               return (SET_ERROR(EINVAL));
+
+       /*
+        * Make sure the pool is formatted with a version that supports this
+        * device type.
+        */
+       if (spa_version(spa) < version)
+               return (SET_ERROR(ENOTSUP));
+
+       /*
+        * Set the pending device list so we correctly handle device in-use
+        * checking.
+        */
+       sav->sav_pending = dev;
+       sav->sav_npending = ndev;
+
+       for (i = 0; i < ndev; i++) {
+               if ((error = spa_config_parse(spa, &vd, dev[i], NULL, 0,
+                   mode)) != 0)
+                       goto out;
+
+               if (!vd->vdev_ops->vdev_op_leaf) {
+                       vdev_free(vd);
+                       error = SET_ERROR(EINVAL);
+                       goto out;
+               }
+
+               /*
+                * The L2ARC currently only supports disk devices in
+                * kernel context.  For user-level testing, we allow it.
+                */
+#ifdef _KERNEL
+               if ((strcmp(config, ZPOOL_CONFIG_L2CACHE) == 0) &&
+                   strcmp(vd->vdev_ops->vdev_op_type, VDEV_TYPE_DISK) != 0) {
+                       error = SET_ERROR(ENOTBLK);
+                       vdev_free(vd);
+                       goto out;
+               }
+#endif
+               vd->vdev_top = vd;
+
+               if ((error = vdev_open(vd)) == 0 &&
+                   (error = vdev_label_init(vd, crtxg, label)) == 0) {
+                       VERIFY(nvlist_add_uint64(dev[i], ZPOOL_CONFIG_GUID,
+                           vd->vdev_guid) == 0);
+               }
+
+               vdev_free(vd);
+
+               if (error &&
+                   (mode != VDEV_ALLOC_SPARE && mode != VDEV_ALLOC_L2CACHE))
+                       goto out;
+               else
+                       error = 0;
+       }
+
+out:
+       sav->sav_pending = NULL;
+       sav->sav_npending = 0;
+       return (error);
+}
+
+static int
+spa_validate_aux(spa_t *spa, nvlist_t *nvroot, uint64_t crtxg, int mode)
+{
+       int error;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       if ((error = spa_validate_aux_devs(spa, nvroot, crtxg, mode,
+           &spa->spa_spares, ZPOOL_CONFIG_SPARES, SPA_VERSION_SPARES,
+           VDEV_LABEL_SPARE)) != 0) {
+               return (error);
+       }
+
+       return (spa_validate_aux_devs(spa, nvroot, crtxg, mode,
+           &spa->spa_l2cache, ZPOOL_CONFIG_L2CACHE, SPA_VERSION_L2CACHE,
+           VDEV_LABEL_L2CACHE));
+}
+
+static void
+spa_set_aux_vdevs(spa_aux_vdev_t *sav, nvlist_t **devs, int ndevs,
+    const char *config)
+{
+       int i;
+
+       if (sav->sav_config != NULL) {
+               nvlist_t **olddevs;
+               uint_t oldndevs;
+               nvlist_t **newdevs;
+
+               /*
+                * Generate new dev list by concatentating with the
+                * current dev list.
+                */
+               VERIFY(nvlist_lookup_nvlist_array(sav->sav_config, config,
+                   &olddevs, &oldndevs) == 0);
+
+               newdevs = kmem_alloc(sizeof (void *) *
+                   (ndevs + oldndevs), KM_SLEEP);
+               for (i = 0; i < oldndevs; i++)
+                       VERIFY(nvlist_dup(olddevs[i], &newdevs[i],
+                           KM_SLEEP) == 0);
+               for (i = 0; i < ndevs; i++)
+                       VERIFY(nvlist_dup(devs[i], &newdevs[i + oldndevs],
+                           KM_SLEEP) == 0);
+
+               VERIFY(nvlist_remove(sav->sav_config, config,
+                   DATA_TYPE_NVLIST_ARRAY) == 0);
+
+               VERIFY(nvlist_add_nvlist_array(sav->sav_config,
+                   config, newdevs, ndevs + oldndevs) == 0);
+               for (i = 0; i < oldndevs + ndevs; i++)
+                       nvlist_free(newdevs[i]);
+               kmem_free(newdevs, (oldndevs + ndevs) * sizeof (void *));
+       } else {
+               /*
+                * Generate a new dev list.
+                */
+               VERIFY(nvlist_alloc(&sav->sav_config, NV_UNIQUE_NAME,
+                   KM_SLEEP) == 0);
+               VERIFY(nvlist_add_nvlist_array(sav->sav_config, config,
+                   devs, ndevs) == 0);
+       }
+}
+
+/*
+ * Stop and drop level 2 ARC devices
+ */
+void
+spa_l2cache_drop(spa_t *spa)
+{
+       vdev_t *vd;
+       int i;
+       spa_aux_vdev_t *sav = &spa->spa_l2cache;
+
+       for (i = 0; i < sav->sav_count; i++) {
+               uint64_t pool;
+
+               vd = sav->sav_vdevs[i];
+               ASSERT(vd != NULL);
+
+               if (spa_l2cache_exists(vd->vdev_guid, &pool) &&
+                   pool != 0ULL && l2arc_vdev_present(vd))
+                       l2arc_remove_vdev(vd);
+       }
+}
+
+/*
+ * Pool Creation
+ */
+int
+spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
+    nvlist_t *zplprops)
+{
+       spa_t *spa;
+       char *altroot = NULL;
+       vdev_t *rvd;
+       dsl_pool_t *dp;
+       dmu_tx_t *tx;
+       int error = 0;
+       uint64_t txg = TXG_INITIAL;
+       nvlist_t **spares, **l2cache;
+       uint_t nspares, nl2cache;
+       uint64_t version, obj;
+       boolean_t has_features;
+       nvpair_t *elem;
+       int c, i;
+       char *poolname;
+       nvlist_t *nvl;
+
+       if (nvlist_lookup_string(props, "tname", &poolname) != 0)
+               poolname = (char *)pool;
+
+       /*
+        * If this pool already exists, return failure.
+        */
+       mutex_enter(&spa_namespace_lock);
+       if (spa_lookup(poolname) != NULL) {
+               mutex_exit(&spa_namespace_lock);
+               return (SET_ERROR(EEXIST));
+       }
+
+       /*
+        * Allocate a new spa_t structure.
+        */
+       nvl = fnvlist_alloc();
+       fnvlist_add_string(nvl, ZPOOL_CONFIG_POOL_NAME, pool);
+       (void) nvlist_lookup_string(props,
+           zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
+       spa = spa_add(poolname, nvl, altroot);
+       fnvlist_free(nvl);
+       spa_activate(spa, spa_mode_global);
+
+       if (props && (error = spa_prop_validate(spa, props))) {
+               spa_deactivate(spa);
+               spa_remove(spa);
+               mutex_exit(&spa_namespace_lock);
+               return (error);
+       }
+
+       /*
+        * Temporary pool names should never be written to disk.
+        */
+       if (poolname != pool)
+               spa->spa_import_flags |= ZFS_IMPORT_TEMP_NAME;
+
+       has_features = B_FALSE;
+       for (elem = nvlist_next_nvpair(props, NULL);
+           elem != NULL; elem = nvlist_next_nvpair(props, elem)) {
+               if (zpool_prop_feature(nvpair_name(elem)))
+                       has_features = B_TRUE;
+       }
+
+       if (has_features || nvlist_lookup_uint64(props,
+           zpool_prop_to_name(ZPOOL_PROP_VERSION), &version) != 0) {
+               version = SPA_VERSION;
+       }
+       ASSERT(SPA_VERSION_IS_SUPPORTED(version));
+
+       spa->spa_first_txg = txg;
+       spa->spa_uberblock.ub_txg = txg - 1;
+       spa->spa_uberblock.ub_version = version;
+       spa->spa_ubsync = spa->spa_uberblock;
+
+       /*
+        * Create "The Godfather" zio to hold all async IOs
+        */
+       spa->spa_async_zio_root = kmem_alloc(max_ncpus * sizeof (void *),
+           KM_SLEEP);
+       for (i = 0; i < max_ncpus; i++) {
+               spa->spa_async_zio_root[i] = zio_root(spa, NULL, NULL,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+                   ZIO_FLAG_GODFATHER);
+       }
+
+       /*
+        * Create the root vdev.
+        */
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+       error = spa_config_parse(spa, &rvd, nvroot, NULL, 0, VDEV_ALLOC_ADD);
+
+       ASSERT(error != 0 || rvd != NULL);
+       ASSERT(error != 0 || spa->spa_root_vdev == rvd);
+
+       if (error == 0 && !zfs_allocatable_devs(nvroot))
+               error = SET_ERROR(EINVAL);
+
+       if (error == 0 &&
+           (error = vdev_create(rvd, txg, B_FALSE)) == 0 &&
+           (error = spa_validate_aux(spa, nvroot, txg,
+           VDEV_ALLOC_ADD)) == 0) {
+               for (c = 0; c < rvd->vdev_children; c++) {
+                       vdev_metaslab_set_size(rvd->vdev_child[c]);
+                       vdev_expand(rvd->vdev_child[c], txg);
+               }
+       }
+
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       if (error != 0) {
+               spa_unload(spa);
+               spa_deactivate(spa);
+               spa_remove(spa);
+               mutex_exit(&spa_namespace_lock);
+               return (error);
+       }
+
+       /*
+        * Get the list of spares, if specified.
+        */
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+           &spares, &nspares) == 0) {
+               VERIFY(nvlist_alloc(&spa->spa_spares.sav_config, NV_UNIQUE_NAME,
+                   KM_SLEEP) == 0);
+               VERIFY(nvlist_add_nvlist_array(spa->spa_spares.sav_config,
+                   ZPOOL_CONFIG_SPARES, spares, nspares) == 0);
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_load_spares(spa);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               spa->spa_spares.sav_sync = B_TRUE;
+       }
+
+       /*
+        * Get the list of level 2 cache devices, if specified.
+        */
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+           &l2cache, &nl2cache) == 0) {
+               VERIFY(nvlist_alloc(&spa->spa_l2cache.sav_config,
+                   NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               VERIFY(nvlist_add_nvlist_array(spa->spa_l2cache.sav_config,
+                   ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache) == 0);
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_load_l2cache(spa);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               spa->spa_l2cache.sav_sync = B_TRUE;
+       }
+
+       spa->spa_is_initializing = B_TRUE;
+       spa->spa_dsl_pool = dp = dsl_pool_create(spa, zplprops, txg);
+       spa->spa_meta_objset = dp->dp_meta_objset;
+       spa->spa_is_initializing = B_FALSE;
+
+       /*
+        * Create DDTs (dedup tables).
+        */
+       ddt_create(spa);
+
+       spa_update_dspace(spa);
+
+       tx = dmu_tx_create_assigned(dp, txg);
+
+       /*
+        * Create the pool config object.
+        */
+       spa->spa_config_object = dmu_object_alloc(spa->spa_meta_objset,
+           DMU_OT_PACKED_NVLIST, SPA_CONFIG_BLOCKSIZE,
+           DMU_OT_PACKED_NVLIST_SIZE, sizeof (uint64_t), tx);
+
+       if (zap_add(spa->spa_meta_objset,
+           DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_CONFIG,
+           sizeof (uint64_t), 1, &spa->spa_config_object, tx) != 0) {
+               cmn_err(CE_PANIC, "failed to add pool config");
+       }
+
+       if (spa_version(spa) >= SPA_VERSION_FEATURES)
+               spa_feature_create_zap_objects(spa, tx);
+
+       if (zap_add(spa->spa_meta_objset,
+           DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_CREATION_VERSION,
+           sizeof (uint64_t), 1, &version, tx) != 0) {
+               cmn_err(CE_PANIC, "failed to add pool version");
+       }
+
+       /* Newly created pools with the right version are always deflated. */
+       if (version >= SPA_VERSION_RAIDZ_DEFLATE) {
+               spa->spa_deflate = TRUE;
+               if (zap_add(spa->spa_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_DEFLATE,
+                   sizeof (uint64_t), 1, &spa->spa_deflate, tx) != 0) {
+                       cmn_err(CE_PANIC, "failed to add deflate");
+               }
+       }
+
+       /*
+        * Create the deferred-free bpobj.  Turn off compression
+        * because sync-to-convergence takes longer if the blocksize
+        * keeps changing.
+        */
+       obj = bpobj_alloc(spa->spa_meta_objset, 1 << 14, tx);
+       dmu_object_set_compress(spa->spa_meta_objset, obj,
+           ZIO_COMPRESS_OFF, tx);
+       if (zap_add(spa->spa_meta_objset,
+           DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SYNC_BPOBJ,
+           sizeof (uint64_t), 1, &obj, tx) != 0) {
+               cmn_err(CE_PANIC, "failed to add bpobj");
+       }
+       VERIFY3U(0, ==, bpobj_open(&spa->spa_deferred_bpobj,
+           spa->spa_meta_objset, obj));
+
+       /*
+        * Create the pool's history object.
+        */
+       if (version >= SPA_VERSION_ZPOOL_HISTORY)
+               spa_history_create_obj(spa, tx);
+
+       /*
+        * Set pool properties.
+        */
+       spa->spa_bootfs = zpool_prop_default_numeric(ZPOOL_PROP_BOOTFS);
+       spa->spa_delegation = zpool_prop_default_numeric(ZPOOL_PROP_DELEGATION);
+       spa->spa_failmode = zpool_prop_default_numeric(ZPOOL_PROP_FAILUREMODE);
+       spa->spa_autoexpand = zpool_prop_default_numeric(ZPOOL_PROP_AUTOEXPAND);
+
+       if (props != NULL) {
+               spa_configfile_set(spa, props, B_FALSE);
+               spa_sync_props(props, tx);
+       }
+
+       dmu_tx_commit(tx);
+
+       spa->spa_sync_on = B_TRUE;
+       txg_sync_start(spa->spa_dsl_pool);
+
+       /*
+        * We explicitly wait for the first transaction to complete so that our
+        * bean counters are appropriately updated.
+        */
+       txg_wait_synced(spa->spa_dsl_pool, txg);
+
+       spa_config_sync(spa, B_FALSE, B_TRUE);
+
+       spa_history_log_version(spa, "create");
+
+       /*
+        * Don't count references from objsets that are already closed
+        * and are making their way through the eviction process.
+        */
+       spa_evicting_os_wait(spa);
+       spa->spa_minref = refcount_count(&spa->spa_refcount);
+
+       mutex_exit(&spa_namespace_lock);
+
+       return (0);
+}
+
+/*
+ * Import a non-root pool into the system.
+ */
+int
+spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
+{
+       spa_t *spa;
+       char *altroot = NULL;
+       spa_load_state_t state = SPA_LOAD_IMPORT;
+       zpool_rewind_policy_t policy;
+       uint64_t mode = spa_mode_global;
+       uint64_t readonly = B_FALSE;
+       int error;
+       nvlist_t *nvroot;
+       nvlist_t **spares, **l2cache;
+       uint_t nspares, nl2cache;
+
+       /*
+        * If a pool with this name exists, return failure.
+        */
+       mutex_enter(&spa_namespace_lock);
+       if (spa_lookup(pool) != NULL) {
+               mutex_exit(&spa_namespace_lock);
+               return (SET_ERROR(EEXIST));
+       }
+
+       /*
+        * Create and initialize the spa structure.
+        */
+       (void) nvlist_lookup_string(props,
+           zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
+       (void) nvlist_lookup_uint64(props,
+           zpool_prop_to_name(ZPOOL_PROP_READONLY), &readonly);
+       if (readonly)
+               mode = FREAD;
+       spa = spa_add(pool, config, altroot);
+       spa->spa_import_flags = flags;
+
+       /*
+        * Verbatim import - Take a pool and insert it into the namespace
+        * as if it had been loaded at boot.
+        */
+       if (spa->spa_import_flags & ZFS_IMPORT_VERBATIM) {
+               if (props != NULL)
+                       spa_configfile_set(spa, props, B_FALSE);
+
+               spa_config_sync(spa, B_FALSE, B_TRUE);
+
+               mutex_exit(&spa_namespace_lock);
+               return (0);
+       }
+
+       spa_activate(spa, mode);
+
+       /*
+        * Don't start async tasks until we know everything is healthy.
+        */
+       spa_async_suspend(spa);
+
+       zpool_get_rewind_policy(config, &policy);
+       if (policy.zrp_request & ZPOOL_DO_REWIND)
+               state = SPA_LOAD_RECOVER;
+
+       /*
+        * Pass off the heavy lifting to spa_load().  Pass TRUE for mosconfig
+        * because the user-supplied config is actually the one to trust when
+        * doing an import.
+        */
+       if (state != SPA_LOAD_RECOVER)
+               spa->spa_last_ubsync_txg = spa->spa_load_txg = 0;
+
+       error = spa_load_best(spa, state, B_TRUE, policy.zrp_txg,
+           policy.zrp_request);
+
+       /*
+        * Propagate anything learned while loading the pool and pass it
+        * back to caller (i.e. rewind info, missing devices, etc).
+        */
+       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
+           spa->spa_load_info) == 0);
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       /*
+        * Toss any existing sparelist, as it doesn't have any validity
+        * anymore, and conflicts with spa_has_spare().
+        */
+       if (spa->spa_spares.sav_config) {
+               nvlist_free(spa->spa_spares.sav_config);
+               spa->spa_spares.sav_config = NULL;
+               spa_load_spares(spa);
+       }
+       if (spa->spa_l2cache.sav_config) {
+               nvlist_free(spa->spa_l2cache.sav_config);
+               spa->spa_l2cache.sav_config = NULL;
+               spa_load_l2cache(spa);
+       }
+
+       VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       if (error == 0)
+               error = spa_validate_aux(spa, nvroot, -1ULL,
+                   VDEV_ALLOC_SPARE);
+       if (error == 0)
+               error = spa_validate_aux(spa, nvroot, -1ULL,
+                   VDEV_ALLOC_L2CACHE);
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       if (props != NULL)
+               spa_configfile_set(spa, props, B_FALSE);
+
+       if (error != 0 || (props && spa_writeable(spa) &&
+           (error = spa_prop_set(spa, props)))) {
+               spa_unload(spa);
+               spa_deactivate(spa);
+               spa_remove(spa);
+               mutex_exit(&spa_namespace_lock);
+               return (error);
+       }
+
+       spa_async_resume(spa);
+
+       /*
+        * Override any spares and level 2 cache devices as specified by
+        * the user, as these may have correct device names/devids, etc.
+        */
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+           &spares, &nspares) == 0) {
+               if (spa->spa_spares.sav_config)
+                       VERIFY(nvlist_remove(spa->spa_spares.sav_config,
+                           ZPOOL_CONFIG_SPARES, DATA_TYPE_NVLIST_ARRAY) == 0);
+               else
+                       VERIFY(nvlist_alloc(&spa->spa_spares.sav_config,
+                           NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               VERIFY(nvlist_add_nvlist_array(spa->spa_spares.sav_config,
+                   ZPOOL_CONFIG_SPARES, spares, nspares) == 0);
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_load_spares(spa);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               spa->spa_spares.sav_sync = B_TRUE;
+       }
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+           &l2cache, &nl2cache) == 0) {
+               if (spa->spa_l2cache.sav_config)
+                       VERIFY(nvlist_remove(spa->spa_l2cache.sav_config,
+                           ZPOOL_CONFIG_L2CACHE, DATA_TYPE_NVLIST_ARRAY) == 0);
+               else
+                       VERIFY(nvlist_alloc(&spa->spa_l2cache.sav_config,
+                           NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               VERIFY(nvlist_add_nvlist_array(spa->spa_l2cache.sav_config,
+                   ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache) == 0);
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+               spa_load_l2cache(spa);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               spa->spa_l2cache.sav_sync = B_TRUE;
+       }
+
+       /*
+        * Check for any removed devices.
+        */
+       if (spa->spa_autoreplace) {
+               spa_aux_check_removed(&spa->spa_spares);
+               spa_aux_check_removed(&spa->spa_l2cache);
+       }
+
+       if (spa_writeable(spa)) {
+               /*
+                * Update the config cache to include the newly-imported pool.
+                */
+               spa_config_update(spa, SPA_CONFIG_UPDATE_POOL);
+       }
+
+       /*
+        * It's possible that the pool was expanded while it was exported.
+        * We kick off an async task to handle this for us.
+        */
+       spa_async_request(spa, SPA_ASYNC_AUTOEXPAND);
+
+       mutex_exit(&spa_namespace_lock);
+       spa_history_log_version(spa, "import");
+       zvol_create_minors(spa, pool, B_TRUE);
+
+       return (0);
+}
+
+nvlist_t *
+spa_tryimport(nvlist_t *tryconfig)
+{
+       nvlist_t *config = NULL;
+       char *poolname;
+       spa_t *spa;
+       uint64_t state;
+       int error;
+
+       if (nvlist_lookup_string(tryconfig, ZPOOL_CONFIG_POOL_NAME, &poolname))
+               return (NULL);
+
+       if (nvlist_lookup_uint64(tryconfig, ZPOOL_CONFIG_POOL_STATE, &state))
+               return (NULL);
+
+       /*
+        * Create and initialize the spa structure.
+        */
+       mutex_enter(&spa_namespace_lock);
+       spa = spa_add(TRYIMPORT_NAME, tryconfig, NULL);
+       spa_activate(spa, FREAD);
+
+       /*
+        * Pass off the heavy lifting to spa_load().
+        * Pass TRUE for mosconfig because the user-supplied config
+        * is actually the one to trust when doing an import.
+        */
+       error = spa_load(spa, SPA_LOAD_TRYIMPORT, SPA_IMPORT_EXISTING, B_TRUE);
+
+       /*
+        * If 'tryconfig' was at least parsable, return the current config.
+        */
+       if (spa->spa_root_vdev != NULL) {
+               config = spa_config_generate(spa, NULL, -1ULL, B_TRUE);
+               VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME,
+                   poolname) == 0);
+               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+                   state) == 0);
+               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_TIMESTAMP,
+                   spa->spa_uberblock.ub_timestamp) == 0);
+               VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
+                   spa->spa_load_info) == 0);
+               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA,
+                   spa->spa_errata) == 0);
+
+               /*
+                * If the bootfs property exists on this pool then we
+                * copy it out so that external consumers can tell which
+                * pools are bootable.
+                */
+               if ((!error || error == EEXIST) && spa->spa_bootfs) {
+                       char *tmpname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+                       /*
+                        * We have to play games with the name since the
+                        * pool was opened as TRYIMPORT_NAME.
+                        */
+                       if (dsl_dsobj_to_dsname(spa_name(spa),
+                           spa->spa_bootfs, tmpname) == 0) {
+                               char *cp;
+                               char *dsname;
+
+                               dsname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+                               cp = strchr(tmpname, '/');
+                               if (cp == NULL) {
+                                       (void) strlcpy(dsname, tmpname,
+                                           MAXPATHLEN);
+                               } else {
+                                       (void) snprintf(dsname, MAXPATHLEN,
+                                           "%s/%s", poolname, ++cp);
+                               }
+                               VERIFY(nvlist_add_string(config,
+                                   ZPOOL_CONFIG_BOOTFS, dsname) == 0);
+                               kmem_free(dsname, MAXPATHLEN);
+                       }
+                       kmem_free(tmpname, MAXPATHLEN);
+               }
+
+               /*
+                * Add the list of hot spares and level 2 cache devices.
+                */
+               spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+               spa_add_spares(spa, config);
+               spa_add_l2cache(spa, config);
+               spa_config_exit(spa, SCL_CONFIG, FTAG);
+       }
+
+       spa_unload(spa);
+       spa_deactivate(spa);
+       spa_remove(spa);
+       mutex_exit(&spa_namespace_lock);
+
+       return (config);
+}
+
+/*
+ * Pool export/destroy
+ *
+ * The act of destroying or exporting a pool is very simple.  We make sure there
+ * is no more pending I/O and any references to the pool are gone.  Then, we
+ * update the pool state and sync all the labels to disk, removing the
+ * configuration from the cache afterwards. If the 'hardforce' flag is set, then
+ * we don't sync the labels or remove the configuration cache.
+ */
+static int
+spa_export_common(char *pool, int new_state, nvlist_t **oldconfig,
+    boolean_t force, boolean_t hardforce)
+{
+       spa_t *spa;
+
+       if (oldconfig)
+               *oldconfig = NULL;
+
+       if (!(spa_mode_global & FWRITE))
+               return (SET_ERROR(EROFS));
+
+       mutex_enter(&spa_namespace_lock);
+       if ((spa = spa_lookup(pool)) == NULL) {
+               mutex_exit(&spa_namespace_lock);
+               return (SET_ERROR(ENOENT));
+       }
+
+       /*
+        * Put a hold on the pool, drop the namespace lock, stop async tasks,
+        * reacquire the namespace lock, and see if we can export.
+        */
+       spa_open_ref(spa, FTAG);
+       mutex_exit(&spa_namespace_lock);
+       spa_async_suspend(spa);
+       if (spa->spa_zvol_taskq) {
+               zvol_remove_minors(spa, spa_name(spa), B_TRUE);
+               taskq_wait(spa->spa_zvol_taskq);
+       }
+       mutex_enter(&spa_namespace_lock);
+       spa_close(spa, FTAG);
+
+       if (spa->spa_state == POOL_STATE_UNINITIALIZED)
+               goto export_spa;
+       /*
+        * The pool will be in core if it's openable, in which case we can
+        * modify its state.  Objsets may be open only because they're dirty,
+        * so we have to force it to sync before checking spa_refcnt.
+        */
+       if (spa->spa_sync_on) {
+               txg_wait_synced(spa->spa_dsl_pool, 0);
+               spa_evicting_os_wait(spa);
+       }
+
+       /*
+        * A pool cannot be exported or destroyed if there are active
+        * references.  If we are resetting a pool, allow references by
+        * fault injection handlers.
+        */
+       if (!spa_refcount_zero(spa) ||
+           (spa->spa_inject_ref != 0 &&
+           new_state != POOL_STATE_UNINITIALIZED)) {
+               spa_async_resume(spa);
+               mutex_exit(&spa_namespace_lock);
+               return (SET_ERROR(EBUSY));
+       }
+
+       if (spa->spa_sync_on) {
+               /*
+                * A pool cannot be exported if it has an active shared spare.
+                * This is to prevent other pools stealing the active spare
+                * from an exported pool. At user's own will, such pool can
+                * be forcedly exported.
+                */
+               if (!force && new_state == POOL_STATE_EXPORTED &&
+                   spa_has_active_shared_spare(spa)) {
+                       spa_async_resume(spa);
+                       mutex_exit(&spa_namespace_lock);
+                       return (SET_ERROR(EXDEV));
+               }
+
+               /*
+                * We want this to be reflected on every label,
+                * so mark them all dirty.  spa_unload() will do the
+                * final sync that pushes these changes out.
+                */
+               if (new_state != POOL_STATE_UNINITIALIZED && !hardforce) {
+                       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+                       spa->spa_state = new_state;
+                       spa->spa_final_txg = spa_last_synced_txg(spa) +
+                           TXG_DEFER_SIZE + 1;
+                       vdev_config_dirty(spa->spa_root_vdev);
+                       spa_config_exit(spa, SCL_ALL, FTAG);
+               }
+       }
+
+export_spa:
+       spa_event_notify(spa, NULL, FM_EREPORT_ZFS_POOL_DESTROY);
+
+       if (spa->spa_state != POOL_STATE_UNINITIALIZED) {
+               spa_unload(spa);
+               spa_deactivate(spa);
+       }
+
+       if (oldconfig && spa->spa_config)
+               VERIFY(nvlist_dup(spa->spa_config, oldconfig, 0) == 0);
+
+       if (new_state != POOL_STATE_UNINITIALIZED) {
+               if (!hardforce)
+                       spa_config_sync(spa, B_TRUE, B_TRUE);
+               spa_remove(spa);
+       }
+       mutex_exit(&spa_namespace_lock);
+
+       return (0);
+}
+
+/*
+ * Destroy a storage pool.
+ */
+int
+spa_destroy(char *pool)
+{
+       return (spa_export_common(pool, POOL_STATE_DESTROYED, NULL,
+           B_FALSE, B_FALSE));
+}
+
+/*
+ * Export a storage pool.
+ */
+int
+spa_export(char *pool, nvlist_t **oldconfig, boolean_t force,
+    boolean_t hardforce)
+{
+       return (spa_export_common(pool, POOL_STATE_EXPORTED, oldconfig,
+           force, hardforce));
+}
+
+/*
+ * Similar to spa_export(), this unloads the spa_t without actually removing it
+ * from the namespace in any way.
+ */
+int
+spa_reset(char *pool)
+{
+       return (spa_export_common(pool, POOL_STATE_UNINITIALIZED, NULL,
+           B_FALSE, B_FALSE));
+}
+
+/*
+ * ==========================================================================
+ * Device manipulation
+ * ==========================================================================
+ */
+
+/*
+ * Add a device to a storage pool.
+ */
+int
+spa_vdev_add(spa_t *spa, nvlist_t *nvroot)
+{
+       uint64_t txg, id;
+       int error;
+       vdev_t *rvd = spa->spa_root_vdev;
+       vdev_t *vd, *tvd;
+       nvlist_t **spares, **l2cache;
+       uint_t nspares, nl2cache;
+       int c;
+
+       ASSERT(spa_writeable(spa));
+
+       txg = spa_vdev_enter(spa);
+
+       if ((error = spa_config_parse(spa, &vd, nvroot, NULL, 0,
+           VDEV_ALLOC_ADD)) != 0)
+               return (spa_vdev_exit(spa, NULL, txg, error));
+
+       spa->spa_pending_vdev = vd;     /* spa_vdev_exit() will clear this */
+
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, &spares,
+           &nspares) != 0)
+               nspares = 0;
+
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, &l2cache,
+           &nl2cache) != 0)
+               nl2cache = 0;
+
+       if (vd->vdev_children == 0 && nspares == 0 && nl2cache == 0)
+               return (spa_vdev_exit(spa, vd, txg, EINVAL));
+
+       if (vd->vdev_children != 0 &&
+           (error = vdev_create(vd, txg, B_FALSE)) != 0)
+               return (spa_vdev_exit(spa, vd, txg, error));
+
+       /*
+        * We must validate the spares and l2cache devices after checking the
+        * children.  Otherwise, vdev_inuse() will blindly overwrite the spare.
+        */
+       if ((error = spa_validate_aux(spa, nvroot, txg, VDEV_ALLOC_ADD)) != 0)
+               return (spa_vdev_exit(spa, vd, txg, error));
+
+       /*
+        * Transfer each new top-level vdev from vd to rvd.
+        */
+       for (c = 0; c < vd->vdev_children; c++) {
+
+               /*
+                * Set the vdev id to the first hole, if one exists.
+                */
+               for (id = 0; id < rvd->vdev_children; id++) {
+                       if (rvd->vdev_child[id]->vdev_ishole) {
+                               vdev_free(rvd->vdev_child[id]);
+                               break;
+                       }
+               }
+               tvd = vd->vdev_child[c];
+               vdev_remove_child(vd, tvd);
+               tvd->vdev_id = id;
+               vdev_add_child(rvd, tvd);
+               vdev_config_dirty(tvd);
+       }
+
+       if (nspares != 0) {
+               spa_set_aux_vdevs(&spa->spa_spares, spares, nspares,
+                   ZPOOL_CONFIG_SPARES);
+               spa_load_spares(spa);
+               spa->spa_spares.sav_sync = B_TRUE;
+       }
+
+       if (nl2cache != 0) {
+               spa_set_aux_vdevs(&spa->spa_l2cache, l2cache, nl2cache,
+                   ZPOOL_CONFIG_L2CACHE);
+               spa_load_l2cache(spa);
+               spa->spa_l2cache.sav_sync = B_TRUE;
+       }
+
+       /*
+        * We have to be careful when adding new vdevs to an existing pool.
+        * If other threads start allocating from these vdevs before we
+        * sync the config cache, and we lose power, then upon reboot we may
+        * fail to open the pool because there are DVAs that the config cache
+        * can't translate.  Therefore, we first add the vdevs without
+        * initializing metaslabs; sync the config cache (via spa_vdev_exit());
+        * and then let spa_config_update() initialize the new metaslabs.
+        *
+        * spa_load() checks for added-but-not-initialized vdevs, so that
+        * if we lose power at any point in this sequence, the remaining
+        * steps will be completed the next time we load the pool.
+        */
+       (void) spa_vdev_exit(spa, vd, txg, 0);
+
+       mutex_enter(&spa_namespace_lock);
+       spa_config_update(spa, SPA_CONFIG_UPDATE_POOL);
+       mutex_exit(&spa_namespace_lock);
+
+       return (0);
+}
+
+/*
+ * Attach a device to a mirror.  The arguments are the path to any device
+ * in the mirror, and the nvroot for the new device.  If the path specifies
+ * a device that is not mirrored, we automatically insert the mirror vdev.
+ *
+ * If 'replacing' is specified, the new device is intended to replace the
+ * existing device; in this case the two devices are made into their own
+ * mirror using the 'replacing' vdev, which is functionally identical to
+ * the mirror vdev (it actually reuses all the same ops) but has a few
+ * extra rules: you can't attach to it after it's been created, and upon
+ * completion of resilvering, the first disk (the one being replaced)
+ * is automatically detached.
+ */
+int
+spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
+{
+       uint64_t txg, dtl_max_txg;
+       vdev_t *oldvd, *newvd, *newrootvd, *pvd, *tvd;
+       vdev_ops_t *pvops;
+       char *oldvdpath, *newvdpath;
+       int newvd_isspare;
+       int error;
+       ASSERTV(vdev_t *rvd = spa->spa_root_vdev);
+
+       ASSERT(spa_writeable(spa));
+
+       txg = spa_vdev_enter(spa);
+
+       oldvd = spa_lookup_by_guid(spa, guid, B_FALSE);
+
+       if (oldvd == NULL)
+               return (spa_vdev_exit(spa, NULL, txg, ENODEV));
+
+       if (!oldvd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_exit(spa, NULL, txg, ENOTSUP));
+
+       pvd = oldvd->vdev_parent;
+
+       if ((error = spa_config_parse(spa, &newrootvd, nvroot, NULL, 0,
+           VDEV_ALLOC_ATTACH)) != 0)
+               return (spa_vdev_exit(spa, NULL, txg, EINVAL));
+
+       if (newrootvd->vdev_children != 1)
+               return (spa_vdev_exit(spa, newrootvd, txg, EINVAL));
+
+       newvd = newrootvd->vdev_child[0];
+
+       if (!newvd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_exit(spa, newrootvd, txg, EINVAL));
+
+       if ((error = vdev_create(newrootvd, txg, replacing)) != 0)
+               return (spa_vdev_exit(spa, newrootvd, txg, error));
+
+       /*
+        * Spares can't replace logs
+        */
+       if (oldvd->vdev_top->vdev_islog && newvd->vdev_isspare)
+               return (spa_vdev_exit(spa, newrootvd, txg, ENOTSUP));
+
+       if (!replacing) {
+               /*
+                * For attach, the only allowable parent is a mirror or the root
+                * vdev.
+                */
+               if (pvd->vdev_ops != &vdev_mirror_ops &&
+                   pvd->vdev_ops != &vdev_root_ops)
+                       return (spa_vdev_exit(spa, newrootvd, txg, ENOTSUP));
+
+               pvops = &vdev_mirror_ops;
+       } else {
+               /*
+                * Active hot spares can only be replaced by inactive hot
+                * spares.
+                */
+               if (pvd->vdev_ops == &vdev_spare_ops &&
+                   oldvd->vdev_isspare &&
+                   !spa_has_spare(spa, newvd->vdev_guid))
+                       return (spa_vdev_exit(spa, newrootvd, txg, ENOTSUP));
+
+               /*
+                * If the source is a hot spare, and the parent isn't already a
+                * spare, then we want to create a new hot spare.  Otherwise, we
+                * want to create a replacing vdev.  The user is not allowed to
+                * attach to a spared vdev child unless the 'isspare' state is
+                * the same (spare replaces spare, non-spare replaces
+                * non-spare).
+                */
+               if (pvd->vdev_ops == &vdev_replacing_ops &&
+                   spa_version(spa) < SPA_VERSION_MULTI_REPLACE) {
+                       return (spa_vdev_exit(spa, newrootvd, txg, ENOTSUP));
+               } else if (pvd->vdev_ops == &vdev_spare_ops &&
+                   newvd->vdev_isspare != oldvd->vdev_isspare) {
+                       return (spa_vdev_exit(spa, newrootvd, txg, ENOTSUP));
+               }
+
+               if (newvd->vdev_isspare)
+                       pvops = &vdev_spare_ops;
+               else
+                       pvops = &vdev_replacing_ops;
+       }
+
+       /*
+        * Make sure the new device is big enough.
+        */
+       if (newvd->vdev_asize < vdev_get_min_asize(oldvd))
+               return (spa_vdev_exit(spa, newrootvd, txg, EOVERFLOW));
+
+       /*
+        * The new device cannot have a higher alignment requirement
+        * than the top-level vdev.
+        */
+       if (newvd->vdev_ashift > oldvd->vdev_top->vdev_ashift)
+               return (spa_vdev_exit(spa, newrootvd, txg, EDOM));
+
+       /*
+        * If this is an in-place replacement, update oldvd's path and devid
+        * to make it distinguishable from newvd, and unopenable from now on.
+        */
+       if (strcmp(oldvd->vdev_path, newvd->vdev_path) == 0) {
+               spa_strfree(oldvd->vdev_path);
+               oldvd->vdev_path = kmem_alloc(strlen(newvd->vdev_path) + 5,
+                   KM_SLEEP);
+               (void) sprintf(oldvd->vdev_path, "%s/%s",
+                   newvd->vdev_path, "old");
+               if (oldvd->vdev_devid != NULL) {
+                       spa_strfree(oldvd->vdev_devid);
+                       oldvd->vdev_devid = NULL;
+               }
+       }
+
+       /* mark the device being resilvered */
+       newvd->vdev_resilver_txg = txg;
+
+       /*
+        * If the parent is not a mirror, or if we're replacing, insert the new
+        * mirror/replacing/spare vdev above oldvd.
+        */
+       if (pvd->vdev_ops != pvops)
+               pvd = vdev_add_parent(oldvd, pvops);
+
+       ASSERT(pvd->vdev_top->vdev_parent == rvd);
+       ASSERT(pvd->vdev_ops == pvops);
+       ASSERT(oldvd->vdev_parent == pvd);
+
+       /*
+        * Extract the new device from its root and add it to pvd.
+        */
+       vdev_remove_child(newrootvd, newvd);
+       newvd->vdev_id = pvd->vdev_children;
+       newvd->vdev_crtxg = oldvd->vdev_crtxg;
+       vdev_add_child(pvd, newvd);
+
+       tvd = newvd->vdev_top;
+       ASSERT(pvd->vdev_top == tvd);
+       ASSERT(tvd->vdev_parent == rvd);
+
+       vdev_config_dirty(tvd);
+
+       /*
+        * Set newvd's DTL to [TXG_INITIAL, dtl_max_txg) so that we account
+        * for any dmu_sync-ed blocks.  It will propagate upward when
+        * spa_vdev_exit() calls vdev_dtl_reassess().
+        */
+       dtl_max_txg = txg + TXG_CONCURRENT_STATES;
+
+       vdev_dtl_dirty(newvd, DTL_MISSING, TXG_INITIAL,
+           dtl_max_txg - TXG_INITIAL);
+
+       if (newvd->vdev_isspare) {
+               spa_spare_activate(newvd);
+               spa_event_notify(spa, newvd, FM_EREPORT_ZFS_DEVICE_SPARE);
+       }
+
+       oldvdpath = spa_strdup(oldvd->vdev_path);
+       newvdpath = spa_strdup(newvd->vdev_path);
+       newvd_isspare = newvd->vdev_isspare;
+
+       /*
+        * Mark newvd's DTL dirty in this txg.
+        */
+       vdev_dirty(tvd, VDD_DTL, newvd, txg);
+
+       /*
+        * Schedule the resilver to restart in the future. We do this to
+        * ensure that dmu_sync-ed blocks have been stitched into the
+        * respective datasets.
+        */
+       dsl_resilver_restart(spa->spa_dsl_pool, dtl_max_txg);
+
+       /*
+        * Commit the config
+        */
+       (void) spa_vdev_exit(spa, newrootvd, dtl_max_txg, 0);
+
+       spa_history_log_internal(spa, "vdev attach", NULL,
+           "%s vdev=%s %s vdev=%s",
+           replacing && newvd_isspare ? "spare in" :
+           replacing ? "replace" : "attach", newvdpath,
+           replacing ? "for" : "to", oldvdpath);
+
+       spa_strfree(oldvdpath);
+       spa_strfree(newvdpath);
+
+       if (spa->spa_bootfs)
+               spa_event_notify(spa, newvd, FM_EREPORT_ZFS_BOOTFS_VDEV_ATTACH);
+
+       return (0);
+}
+
+/*
+ * Detach a device from a mirror or replacing vdev.
+ *
+ * If 'replace_done' is specified, only detach if the parent
+ * is a replacing vdev.
+ */
+int
+spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done)
+{
+       uint64_t txg;
+       int error;
+       vdev_t *vd, *pvd, *cvd, *tvd;
+       boolean_t unspare = B_FALSE;
+       uint64_t unspare_guid = 0;
+       char *vdpath;
+       int c, t;
+       ASSERTV(vdev_t *rvd = spa->spa_root_vdev);
+       ASSERT(spa_writeable(spa));
+
+       txg = spa_vdev_enter(spa);
+
+       vd = spa_lookup_by_guid(spa, guid, B_FALSE);
+
+       if (vd == NULL)
+               return (spa_vdev_exit(spa, NULL, txg, ENODEV));
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_exit(spa, NULL, txg, ENOTSUP));
+
+       pvd = vd->vdev_parent;
+
+       /*
+        * If the parent/child relationship is not as expected, don't do it.
+        * Consider M(A,R(B,C)) -- that is, a mirror of A with a replacing
+        * vdev that's replacing B with C.  The user's intent in replacing
+        * is to go from M(A,B) to M(A,C).  If the user decides to cancel
+        * the replace by detaching C, the expected behavior is to end up
+        * M(A,B).  But suppose that right after deciding to detach C,
+        * the replacement of B completes.  We would have M(A,C), and then
+        * ask to detach C, which would leave us with just A -- not what
+        * the user wanted.  To prevent this, we make sure that the
+        * parent/child relationship hasn't changed -- in this example,
+        * that C's parent is still the replacing vdev R.
+        */
+       if (pvd->vdev_guid != pguid && pguid != 0)
+               return (spa_vdev_exit(spa, NULL, txg, EBUSY));
+
+       /*
+        * Only 'replacing' or 'spare' vdevs can be replaced.
+        */
+       if (replace_done && pvd->vdev_ops != &vdev_replacing_ops &&
+           pvd->vdev_ops != &vdev_spare_ops)
+               return (spa_vdev_exit(spa, NULL, txg, ENOTSUP));
+
+       ASSERT(pvd->vdev_ops != &vdev_spare_ops ||
+           spa_version(spa) >= SPA_VERSION_SPARES);
+
+       /*
+        * Only mirror, replacing, and spare vdevs support detach.
+        */
+       if (pvd->vdev_ops != &vdev_replacing_ops &&
+           pvd->vdev_ops != &vdev_mirror_ops &&
+           pvd->vdev_ops != &vdev_spare_ops)
+               return (spa_vdev_exit(spa, NULL, txg, ENOTSUP));
+
+       /*
+        * If this device has the only valid copy of some data,
+        * we cannot safely detach it.
+        */
+       if (vdev_dtl_required(vd))
+               return (spa_vdev_exit(spa, NULL, txg, EBUSY));
+
+       ASSERT(pvd->vdev_children >= 2);
+
+       /*
+        * If we are detaching the second disk from a replacing vdev, then
+        * check to see if we changed the original vdev's path to have "/old"
+        * at the end in spa_vdev_attach().  If so, undo that change now.
+        */
+       if (pvd->vdev_ops == &vdev_replacing_ops && vd->vdev_id > 0 &&
+           vd->vdev_path != NULL) {
+               size_t len = strlen(vd->vdev_path);
+
+               for (c = 0; c < pvd->vdev_children; c++) {
+                       cvd = pvd->vdev_child[c];
+
+                       if (cvd == vd || cvd->vdev_path == NULL)
+                               continue;
+
+                       if (strncmp(cvd->vdev_path, vd->vdev_path, len) == 0 &&
+                           strcmp(cvd->vdev_path + len, "/old") == 0) {
+                               spa_strfree(cvd->vdev_path);
+                               cvd->vdev_path = spa_strdup(vd->vdev_path);
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If we are detaching the original disk from a spare, then it implies
+        * that the spare should become a real disk, and be removed from the
+        * active spare list for the pool.
+        */
+       if (pvd->vdev_ops == &vdev_spare_ops &&
+           vd->vdev_id == 0 &&
+           pvd->vdev_child[pvd->vdev_children - 1]->vdev_isspare)
+               unspare = B_TRUE;
+
+       /*
+        * Erase the disk labels so the disk can be used for other things.
+        * This must be done after all other error cases are handled,
+        * but before we disembowel vd (so we can still do I/O to it).
+        * But if we can't do it, don't treat the error as fatal --
+        * it may be that the unwritability of the disk is the reason
+        * it's being detached!
+        */
+       error = vdev_label_init(vd, 0, VDEV_LABEL_REMOVE);
+
+       /*
+        * Remove vd from its parent and compact the parent's children.
+        */
+       vdev_remove_child(pvd, vd);
+       vdev_compact_children(pvd);
+
+       /*
+        * Remember one of the remaining children so we can get tvd below.
+        */
+       cvd = pvd->vdev_child[pvd->vdev_children - 1];
+
+       /*
+        * If we need to remove the remaining child from the list of hot spares,
+        * do it now, marking the vdev as no longer a spare in the process.
+        * We must do this before vdev_remove_parent(), because that can
+        * change the GUID if it creates a new toplevel GUID.  For a similar
+        * reason, we must remove the spare now, in the same txg as the detach;
+        * otherwise someone could attach a new sibling, change the GUID, and
+        * the subsequent attempt to spa_vdev_remove(unspare_guid) would fail.
+        */
+       if (unspare) {
+               ASSERT(cvd->vdev_isspare);
+               spa_spare_remove(cvd);
+               unspare_guid = cvd->vdev_guid;
+               (void) spa_vdev_remove(spa, unspare_guid, B_TRUE);
+               cvd->vdev_unspare = B_TRUE;
+       }
+
+       /*
+        * If the parent mirror/replacing vdev only has one child,
+        * the parent is no longer needed.  Remove it from the tree.
+        */
+       if (pvd->vdev_children == 1) {
+               if (pvd->vdev_ops == &vdev_spare_ops)
+                       cvd->vdev_unspare = B_FALSE;
+               vdev_remove_parent(cvd);
+       }
+
+
+       /*
+        * We don't set tvd until now because the parent we just removed
+        * may have been the previous top-level vdev.
+        */
+       tvd = cvd->vdev_top;
+       ASSERT(tvd->vdev_parent == rvd);
+
+       /*
+        * Reevaluate the parent vdev state.
+        */
+       vdev_propagate_state(cvd);
+
+       /*
+        * If the 'autoexpand' property is set on the pool then automatically
+        * try to expand the size of the pool. For example if the device we
+        * just detached was smaller than the others, it may be possible to
+        * add metaslabs (i.e. grow the pool). We need to reopen the vdev
+        * first so that we can obtain the updated sizes of the leaf vdevs.
+        */
+       if (spa->spa_autoexpand) {
+               vdev_reopen(tvd);
+               vdev_expand(tvd, txg);
+       }
+
+       vdev_config_dirty(tvd);
+
+       /*
+        * Mark vd's DTL as dirty in this txg.  vdev_dtl_sync() will see that
+        * vd->vdev_detached is set and free vd's DTL object in syncing context.
+        * 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);
+       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);
+
+       /* hang on to the spa before we release the lock */
+       spa_open_ref(spa, FTAG);
+
+       error = spa_vdev_exit(spa, vd, txg, 0);
+
+       spa_history_log_internal(spa, "detach", NULL,
+           "vdev=%s", vdpath);
+       spa_strfree(vdpath);
+
+       /*
+        * If this was the removal of the original device in a hot spare vdev,
+        * then we want to go through and remove the device from the hot spare
+        * list of every other pool.
+        */
+       if (unspare) {
+               spa_t *altspa = NULL;
+
+               mutex_enter(&spa_namespace_lock);
+               while ((altspa = spa_next(altspa)) != NULL) {
+                       if (altspa->spa_state != POOL_STATE_ACTIVE ||
+                           altspa == spa)
+                               continue;
+
+                       spa_open_ref(altspa, FTAG);
+                       mutex_exit(&spa_namespace_lock);
+                       (void) spa_vdev_remove(altspa, unspare_guid, B_TRUE);
+                       mutex_enter(&spa_namespace_lock);
+                       spa_close(altspa, FTAG);
+               }
+               mutex_exit(&spa_namespace_lock);
+
+               /* search the rest of the vdevs for spares to remove */
+               spa_vdev_resilver_done(spa);
+       }
+
+       /* all done with the spa; OK to release */
+       mutex_enter(&spa_namespace_lock);
+       spa_close(spa, FTAG);
+       mutex_exit(&spa_namespace_lock);
+
+       return (error);
+}
+
+/*
+ * Split a set of devices from their mirrors, and create a new pool from them.
+ */
+int
+spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
+    nvlist_t *props, boolean_t exp)
+{
+       int error = 0;
+       uint64_t txg, *glist;
+       spa_t *newspa;
+       uint_t c, children, lastlog;
+       nvlist_t **child, *nvl, *tmp;
+       dmu_tx_t *tx;
+       char *altroot = NULL;
+       vdev_t *rvd, **vml = NULL;                      /* vdev modify list */
+       boolean_t activate_slog;
+
+       ASSERT(spa_writeable(spa));
+
+       txg = spa_vdev_enter(spa);
+
+       /* clear the log and flush everything up to now */
+       activate_slog = spa_passivate_log(spa);
+       (void) spa_vdev_config_exit(spa, NULL, txg, 0, FTAG);
+       error = spa_offline_log(spa);
+       txg = spa_vdev_config_enter(spa);
+
+       if (activate_slog)
+               spa_activate_log(spa);
+
+       if (error != 0)
+               return (spa_vdev_exit(spa, NULL, txg, error));
+
+       /* check new spa name before going any further */
+       if (spa_lookup(newname) != NULL)
+               return (spa_vdev_exit(spa, NULL, txg, EEXIST));
+
+       /*
+        * scan through all the children to ensure they're all mirrors
+        */
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvl) != 0 ||
+           nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) != 0)
+               return (spa_vdev_exit(spa, NULL, txg, EINVAL));
+
+       /* first, check to ensure we've got the right child count */
+       rvd = spa->spa_root_vdev;
+       lastlog = 0;
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *vd = rvd->vdev_child[c];
+
+               /* don't count the holes & logs as children */
+               if (vd->vdev_islog || vd->vdev_ishole) {
+                       if (lastlog == 0)
+                               lastlog = c;
+                       continue;
+               }
+
+               lastlog = 0;
+       }
+       if (children != (lastlog != 0 ? lastlog : rvd->vdev_children))
+               return (spa_vdev_exit(spa, NULL, txg, EINVAL));
+
+       /* next, ensure no spare or cache devices are part of the split */
+       if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_SPARES, &tmp) == 0 ||
+           nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_L2CACHE, &tmp) == 0)
+               return (spa_vdev_exit(spa, NULL, txg, EINVAL));
+
+       vml = kmem_zalloc(children * sizeof (vdev_t *), KM_SLEEP);
+       glist = kmem_zalloc(children * sizeof (uint64_t), KM_SLEEP);
+
+       /* then, loop over each vdev and validate it */
+       for (c = 0; c < children; c++) {
+               uint64_t is_hole = 0;
+
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
+                   &is_hole);
+
+               if (is_hole != 0) {
+                       if (spa->spa_root_vdev->vdev_child[c]->vdev_ishole ||
+                           spa->spa_root_vdev->vdev_child[c]->vdev_islog) {
+                               continue;
+                       } else {
+                               error = SET_ERROR(EINVAL);
+                               break;
+                       }
+               }
+
+               /* which disk is going to be split? */
+               if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_GUID,
+                   &glist[c]) != 0) {
+                       error = SET_ERROR(EINVAL);
+                       break;
+               }
+
+               /* look it up in the spa */
+               vml[c] = spa_lookup_by_guid(spa, glist[c], B_FALSE);
+               if (vml[c] == NULL) {
+                       error = SET_ERROR(ENODEV);
+                       break;
+               }
+
+               /* make sure there's nothing stopping the split */
+               if (vml[c]->vdev_parent->vdev_ops != &vdev_mirror_ops ||
+                   vml[c]->vdev_islog ||
+                   vml[c]->vdev_ishole ||
+                   vml[c]->vdev_isspare ||
+                   vml[c]->vdev_isl2cache ||
+                   !vdev_writeable(vml[c]) ||
+                   vml[c]->vdev_children != 0 ||
+                   vml[c]->vdev_state != VDEV_STATE_HEALTHY ||
+                   c != spa->spa_root_vdev->vdev_child[c]->vdev_id) {
+                       error = SET_ERROR(EINVAL);
+                       break;
+               }
+
+               if (vdev_dtl_required(vml[c])) {
+                       error = SET_ERROR(EBUSY);
+                       break;
+               }
+
+               /* we need certain info from the top level */
+               VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_METASLAB_ARRAY,
+                   vml[c]->vdev_top->vdev_ms_array) == 0);
+               VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_METASLAB_SHIFT,
+                   vml[c]->vdev_top->vdev_ms_shift) == 0);
+               VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_ASIZE,
+                   vml[c]->vdev_top->vdev_asize) == 0);
+               VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_ASHIFT,
+                   vml[c]->vdev_top->vdev_ashift) == 0);
+       }
+
+       if (error != 0) {
+               kmem_free(vml, children * sizeof (vdev_t *));
+               kmem_free(glist, children * sizeof (uint64_t));
+               return (spa_vdev_exit(spa, NULL, txg, error));
+       }
+
+       /* stop writers from using the disks */
+       for (c = 0; c < children; c++) {
+               if (vml[c] != NULL)
+                       vml[c]->vdev_offline = B_TRUE;
+       }
+       vdev_reopen(spa->spa_root_vdev);
+
+       /*
+        * Temporarily record the splitting vdevs in the spa config.  This
+        * will disappear once the config is regenerated.
+        */
+       VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+       VERIFY(nvlist_add_uint64_array(nvl, ZPOOL_CONFIG_SPLIT_LIST,
+           glist, children) == 0);
+       kmem_free(glist, children * sizeof (uint64_t));
+
+       mutex_enter(&spa->spa_props_lock);
+       VERIFY(nvlist_add_nvlist(spa->spa_config, ZPOOL_CONFIG_SPLIT,
+           nvl) == 0);
+       mutex_exit(&spa->spa_props_lock);
+       spa->spa_config_splitting = nvl;
+       vdev_config_dirty(spa->spa_root_vdev);
+
+       /* configure and create the new pool */
+       VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, newname) == 0);
+       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+           exp ? POOL_STATE_EXPORTED : POOL_STATE_ACTIVE) == 0);
+       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
+           spa_version(spa)) == 0);
+       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG,
+           spa->spa_config_txg) == 0);
+       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+           spa_generate_guid(NULL)) == 0);
+       (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_config_txg = spa->spa_config_txg;
+       spa_set_log_state(newspa, SPA_LOG_CLEAR);
+
+       /* release the spa config lock, retaining the namespace lock */
+       spa_vdev_config_exit(spa, NULL, txg, 0, FTAG);
+
+       if (zio_injection_enabled)
+               zio_handle_panic_injection(spa, FTAG, 1);
+
+       spa_activate(newspa, spa_mode_global);
+       spa_async_suspend(newspa);
+
+       /* create the new pool from the disks of the original pool */
+       error = spa_load(newspa, SPA_LOAD_IMPORT, SPA_IMPORT_ASSEMBLE, B_TRUE);
+       if (error)
+               goto out;
+
+       /* if that worked, generate a real config for the new pool */
+       if (newspa->spa_root_vdev != NULL) {
+               VERIFY(nvlist_alloc(&newspa->spa_config_splitting,
+                   NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               VERIFY(nvlist_add_uint64(newspa->spa_config_splitting,
+                   ZPOOL_CONFIG_SPLIT_GUID, spa_guid(spa)) == 0);
+               spa_config_set(newspa, spa_config_generate(newspa, NULL, -1ULL,
+                   B_TRUE));
+       }
+
+       /* set the props */
+       if (props != NULL) {
+               spa_configfile_set(newspa, props, B_FALSE);
+               error = spa_prop_set(newspa, props);
+               if (error)
+                       goto out;
+       }
+
+       /* flush everything */
+       txg = spa_vdev_config_enter(newspa);
+       vdev_config_dirty(newspa->spa_root_vdev);
+       (void) spa_vdev_config_exit(newspa, NULL, txg, 0, FTAG);
+
+       if (zio_injection_enabled)
+               zio_handle_panic_injection(spa, FTAG, 2);
+
+       spa_async_resume(newspa);
+
+       /* finally, update the original pool's config */
+       txg = spa_vdev_config_enter(spa);
+       tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error != 0)
+               dmu_tx_abort(tx);
+       for (c = 0; c < children; c++) {
+               if (vml[c] != NULL) {
+                       vdev_split(vml[c]);
+                       if (error == 0)
+                               spa_history_log_internal(spa, "detach", tx,
+                                   "vdev=%s", vml[c]->vdev_path);
+                       vdev_free(vml[c]);
+               }
+       }
+       vdev_config_dirty(spa->spa_root_vdev);
+       spa->spa_config_splitting = NULL;
+       nvlist_free(nvl);
+       if (error == 0)
+               dmu_tx_commit(tx);
+       (void) spa_vdev_exit(spa, NULL, txg, 0);
+
+       if (zio_injection_enabled)
+               zio_handle_panic_injection(spa, FTAG, 3);
+
+       /* split is complete; log a history record */
+       spa_history_log_internal(newspa, "split", NULL,
+           "from pool %s", spa_name(spa));
+
+       kmem_free(vml, children * sizeof (vdev_t *));
+
+       /* if we're not going to mount the filesystems in userland, export */
+       if (exp)
+               error = spa_export_common(newname, POOL_STATE_EXPORTED, NULL,
+                   B_FALSE, B_FALSE);
+
+       return (error);
+
+out:
+       spa_unload(newspa);
+       spa_deactivate(newspa);
+       spa_remove(newspa);
+
+       txg = spa_vdev_config_enter(spa);
+
+       /* re-online all offlined disks */
+       for (c = 0; c < children; c++) {
+               if (vml[c] != NULL)
+                       vml[c]->vdev_offline = B_FALSE;
+       }
+       vdev_reopen(spa->spa_root_vdev);
+
+       nvlist_free(spa->spa_config_splitting);
+       spa->spa_config_splitting = NULL;
+       (void) spa_vdev_exit(spa, NULL, txg, error);
+
+       kmem_free(vml, children * sizeof (vdev_t *));
+       return (error);
+}
+
+static nvlist_t *
+spa_nvlist_lookup_by_guid(nvlist_t **nvpp, int count, uint64_t target_guid)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               uint64_t guid;
+
+               VERIFY(nvlist_lookup_uint64(nvpp[i], ZPOOL_CONFIG_GUID,
+                   &guid) == 0);
+
+               if (guid == target_guid)
+                       return (nvpp[i]);
+       }
+
+       return (NULL);
+}
+
+static void
+spa_vdev_remove_aux(nvlist_t *config, char *name, nvlist_t **dev, int count,
+       nvlist_t *dev_to_remove)
+{
+       nvlist_t **newdev = NULL;
+       int i, j;
+
+       if (count > 1)
+               newdev = kmem_alloc((count - 1) * sizeof (void *), KM_SLEEP);
+
+       for (i = 0, j = 0; i < count; i++) {
+               if (dev[i] == dev_to_remove)
+                       continue;
+               VERIFY(nvlist_dup(dev[i], &newdev[j++], KM_SLEEP) == 0);
+       }
+
+       VERIFY(nvlist_remove(config, name, DATA_TYPE_NVLIST_ARRAY) == 0);
+       VERIFY(nvlist_add_nvlist_array(config, name, newdev, count - 1) == 0);
+
+       for (i = 0; i < count - 1; i++)
+               nvlist_free(newdev[i]);
+
+       if (count > 1)
+               kmem_free(newdev, (count - 1) * sizeof (void *));
+}
+
+/*
+ * Evacuate the device.
+ */
+static int
+spa_vdev_remove_evacuate(spa_t *spa, vdev_t *vd)
+{
+       uint64_t txg;
+       int error = 0;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == 0);
+       ASSERT(vd == vd->vdev_top);
+
+       /*
+        * Evacuate the device.  We don't hold the config lock as writer
+        * since we need to do I/O but we do keep the
+        * spa_namespace_lock held.  Once this completes the device
+        * should no longer have any blocks allocated on it.
+        */
+       if (vd->vdev_islog) {
+               if (vd->vdev_stat.vs_alloc != 0)
+                       error = spa_offline_log(spa);
+       } else {
+               error = SET_ERROR(ENOTSUP);
+       }
+
+       if (error)
+               return (error);
+
+       /*
+        * The evacuation succeeded.  Remove any remaining MOS metadata
+        * associated with this vdev, and wait for these changes to sync.
+        */
+       ASSERT0(vd->vdev_stat.vs_alloc);
+       txg = spa_vdev_config_enter(spa);
+       vd->vdev_removing = B_TRUE;
+       vdev_dirty_leaves(vd, VDD_DTL, txg);
+       vdev_config_dirty(vd);
+       spa_vdev_config_exit(spa, NULL, txg, 0, FTAG);
+
+       return (0);
+}
+
+/*
+ * Complete the removal by cleaning up the namespace.
+ */
+static void
+spa_vdev_remove_from_namespace(spa_t *spa, vdev_t *vd)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       uint64_t id = vd->vdev_id;
+       boolean_t last_vdev = (id == (rvd->vdev_children - 1));
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+       ASSERT(vd == vd->vdev_top);
+
+       /*
+        * Only remove any devices which are empty.
+        */
+       if (vd->vdev_stat.vs_alloc != 0)
+               return;
+
+       (void) vdev_label_init(vd, 0, VDEV_LABEL_REMOVE);
+
+       if (list_link_active(&vd->vdev_state_dirty_node))
+               vdev_state_clean(vd);
+       if (list_link_active(&vd->vdev_config_dirty_node))
+               vdev_config_clean(vd);
+
+       vdev_free(vd);
+
+       if (last_vdev) {
+               vdev_compact_children(rvd);
+       } else {
+               vd = vdev_alloc_common(spa, id, 0, &vdev_hole_ops);
+               vdev_add_child(rvd, vd);
+       }
+       vdev_config_dirty(rvd);
+
+       /*
+        * Reassess the health of our root vdev.
+        */
+       vdev_reopen(rvd);
+}
+
+/*
+ * Remove a device from the pool -
+ *
+ * Removing a device from the vdev namespace requires several steps
+ * and can take a significant amount of time.  As a result we use
+ * the spa_vdev_config_[enter/exit] functions which allow us to
+ * grab and release the spa_config_lock while still holding the namespace
+ * lock.  During each step the configuration is synced out.
+ *
+ * Currently, this supports removing only hot spares, slogs, and level 2 ARC
+ * devices.
+ */
+int
+spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
+{
+       vdev_t *vd;
+       metaslab_group_t *mg;
+       nvlist_t **spares, **l2cache, *nv;
+       uint64_t txg = 0;
+       uint_t nspares, nl2cache;
+       int error = 0;
+       boolean_t locked = MUTEX_HELD(&spa_namespace_lock);
+
+       ASSERT(spa_writeable(spa));
+
+       if (!locked)
+               txg = spa_vdev_enter(spa);
+
+       vd = spa_lookup_by_guid(spa, guid, B_FALSE);
+
+       if (spa->spa_spares.sav_vdevs != NULL &&
+           nvlist_lookup_nvlist_array(spa->spa_spares.sav_config,
+           ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0 &&
+           (nv = spa_nvlist_lookup_by_guid(spares, nspares, guid)) != NULL) {
+               /*
+                * Only remove the hot spare if it's not currently in use
+                * in this pool.
+                */
+               if (vd == NULL || unspare) {
+                       spa_vdev_remove_aux(spa->spa_spares.sav_config,
+                           ZPOOL_CONFIG_SPARES, spares, nspares, nv);
+                       spa_load_spares(spa);
+                       spa->spa_spares.sav_sync = B_TRUE;
+               } else {
+                       error = SET_ERROR(EBUSY);
+               }
+       } else if (spa->spa_l2cache.sav_vdevs != NULL &&
+           nvlist_lookup_nvlist_array(spa->spa_l2cache.sav_config,
+           ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0 &&
+           (nv = spa_nvlist_lookup_by_guid(l2cache, nl2cache, guid)) != NULL) {
+               /*
+                * Cache devices can always be removed.
+                */
+               spa_vdev_remove_aux(spa->spa_l2cache.sav_config,
+                   ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache, nv);
+               spa_load_l2cache(spa);
+               spa->spa_l2cache.sav_sync = B_TRUE;
+       } else if (vd != NULL && vd->vdev_islog) {
+               ASSERT(!locked);
+               ASSERT(vd == vd->vdev_top);
+
+               mg = vd->vdev_mg;
+
+               /*
+                * Stop allocating from this vdev.
+                */
+               metaslab_group_passivate(mg);
+
+               /*
+                * Wait for the youngest allocations and frees to sync,
+                * and then wait for the deferral of those frees to finish.
+                */
+               spa_vdev_config_exit(spa, NULL,
+                   txg + TXG_CONCURRENT_STATES + TXG_DEFER_SIZE, 0, FTAG);
+
+               /*
+                * Attempt to evacuate the vdev.
+                */
+               error = spa_vdev_remove_evacuate(spa, vd);
+
+               txg = spa_vdev_config_enter(spa);
+
+               /*
+                * If we couldn't evacuate the vdev, unwind.
+                */
+               if (error) {
+                       metaslab_group_activate(mg);
+                       return (spa_vdev_exit(spa, NULL, txg, error));
+               }
+
+               /*
+                * Clean up the vdev namespace.
+                */
+               spa_vdev_remove_from_namespace(spa, vd);
+
+       } else if (vd != NULL) {
+               /*
+                * Normal vdevs cannot be removed (yet).
+                */
+               error = SET_ERROR(ENOTSUP);
+       } else {
+               /*
+                * There is no vdev of any kind with the specified guid.
+                */
+               error = SET_ERROR(ENOENT);
+       }
+
+       if (!locked)
+               return (spa_vdev_exit(spa, NULL, txg, error));
+
+       return (error);
+}
+
+/*
+ * Find any device that's done replacing, or a vdev marked 'unspare' that's
+ * currently spared, so we can detach it.
+ */
+static vdev_t *
+spa_vdev_resilver_done_hunt(vdev_t *vd)
+{
+       vdev_t *newvd, *oldvd;
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               oldvd = spa_vdev_resilver_done_hunt(vd->vdev_child[c]);
+               if (oldvd != NULL)
+                       return (oldvd);
+       }
+
+       /*
+        * Check for a completed replacement.  We always consider the first
+        * vdev in the list to be the oldest vdev, and the last one to be
+        * the newest (see spa_vdev_attach() for how that works).  In
+        * the case where the newest vdev is faulted, we will not automatically
+        * remove it after a resilver completes.  This is OK as it will require
+        * user intervention to determine which disk the admin wishes to keep.
+        */
+       if (vd->vdev_ops == &vdev_replacing_ops) {
+               ASSERT(vd->vdev_children > 1);
+
+               newvd = vd->vdev_child[vd->vdev_children - 1];
+               oldvd = vd->vdev_child[0];
+
+               if (vdev_dtl_empty(newvd, DTL_MISSING) &&
+                   vdev_dtl_empty(newvd, DTL_OUTAGE) &&
+                   !vdev_dtl_required(oldvd))
+                       return (oldvd);
+       }
+
+       /*
+        * Check for a completed resilver with the 'unspare' flag set.
+        */
+       if (vd->vdev_ops == &vdev_spare_ops) {
+               vdev_t *first = vd->vdev_child[0];
+               vdev_t *last = vd->vdev_child[vd->vdev_children - 1];
+
+               if (last->vdev_unspare) {
+                       oldvd = first;
+                       newvd = last;
+               } else if (first->vdev_unspare) {
+                       oldvd = last;
+                       newvd = first;
+               } else {
+                       oldvd = NULL;
+               }
+
+               if (oldvd != NULL &&
+                   vdev_dtl_empty(newvd, DTL_MISSING) &&
+                   vdev_dtl_empty(newvd, DTL_OUTAGE) &&
+                   !vdev_dtl_required(oldvd))
+                       return (oldvd);
+
+               /*
+                * If there are more than two spares attached to a disk,
+                * and those spares are not required, then we want to
+                * attempt to free them up now so that they can be used
+                * by other pools.  Once we're back down to a single
+                * disk+spare, we stop removing them.
+                */
+               if (vd->vdev_children > 2) {
+                       newvd = vd->vdev_child[1];
+
+                       if (newvd->vdev_isspare && last->vdev_isspare &&
+                           vdev_dtl_empty(last, DTL_MISSING) &&
+                           vdev_dtl_empty(last, DTL_OUTAGE) &&
+                           !vdev_dtl_required(newvd))
+                               return (newvd);
+               }
+       }
+
+       return (NULL);
+}
+
+static void
+spa_vdev_resilver_done(spa_t *spa)
+{
+       vdev_t *vd, *pvd, *ppvd;
+       uint64_t guid, sguid, pguid, ppguid;
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+       while ((vd = spa_vdev_resilver_done_hunt(spa->spa_root_vdev)) != NULL) {
+               pvd = vd->vdev_parent;
+               ppvd = pvd->vdev_parent;
+               guid = vd->vdev_guid;
+               pguid = pvd->vdev_guid;
+               ppguid = ppvd->vdev_guid;
+               sguid = 0;
+               /*
+                * If we have just finished replacing a hot spared device, then
+                * we need to detach the parent's first child (the original hot
+                * spare) as well.
+                */
+               if (ppvd->vdev_ops == &vdev_spare_ops && pvd->vdev_id == 0 &&
+                   ppvd->vdev_children == 2) {
+                       ASSERT(pvd->vdev_ops == &vdev_replacing_ops);
+                       sguid = ppvd->vdev_child[1]->vdev_guid;
+               }
+               ASSERT(vd->vdev_resilver_txg == 0 || !vdev_dtl_required(vd));
+
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               if (spa_vdev_detach(spa, guid, pguid, B_TRUE) != 0)
+                       return;
+               if (sguid && spa_vdev_detach(spa, sguid, ppguid, B_TRUE) != 0)
+                       return;
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       }
+
+       spa_config_exit(spa, SCL_ALL, FTAG);
+}
+
+/*
+ * Update the stored path or FRU for this vdev.
+ */
+int
+spa_vdev_set_common(spa_t *spa, uint64_t guid, const char *value,
+    boolean_t ispath)
+{
+       vdev_t *vd;
+       boolean_t sync = B_FALSE;
+
+       ASSERT(spa_writeable(spa));
+
+       spa_vdev_state_enter(spa, SCL_ALL);
+
+       if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
+               return (spa_vdev_state_exit(spa, NULL, ENOENT));
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
+
+       if (ispath) {
+               if (strcmp(value, vd->vdev_path) != 0) {
+                       spa_strfree(vd->vdev_path);
+                       vd->vdev_path = spa_strdup(value);
+                       sync = B_TRUE;
+               }
+       } else {
+               if (vd->vdev_fru == NULL) {
+                       vd->vdev_fru = spa_strdup(value);
+                       sync = B_TRUE;
+               } else if (strcmp(value, vd->vdev_fru) != 0) {
+                       spa_strfree(vd->vdev_fru);
+                       vd->vdev_fru = spa_strdup(value);
+                       sync = B_TRUE;
+               }
+       }
+
+       return (spa_vdev_state_exit(spa, sync ? vd : NULL, 0));
+}
+
+int
+spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath)
+{
+       return (spa_vdev_set_common(spa, guid, newpath, B_TRUE));
+}
+
+int
+spa_vdev_setfru(spa_t *spa, uint64_t guid, const char *newfru)
+{
+       return (spa_vdev_set_common(spa, guid, newfru, B_FALSE));
+}
+
+/*
+ * ==========================================================================
+ * SPA Scanning
+ * ==========================================================================
+ */
+
+int
+spa_scan_stop(spa_t *spa)
+{
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == 0);
+       if (dsl_scan_resilvering(spa->spa_dsl_pool))
+               return (SET_ERROR(EBUSY));
+       return (dsl_scan_cancel(spa->spa_dsl_pool));
+}
+
+int
+spa_scan(spa_t *spa, pool_scan_func_t func)
+{
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == 0);
+
+       if (func >= POOL_SCAN_FUNCS || func == POOL_SCAN_NONE)
+               return (SET_ERROR(ENOTSUP));
+
+       /*
+        * If a resilver was requested, but there is no DTL on a
+        * writeable leaf device, we have nothing to do.
+        */
+       if (func == POOL_SCAN_RESILVER &&
+           !vdev_resilver_needed(spa->spa_root_vdev, NULL, NULL)) {
+               spa_async_request(spa, SPA_ASYNC_RESILVER_DONE);
+               return (0);
+       }
+
+       return (dsl_scan(spa->spa_dsl_pool, func));
+}
+
+/*
+ * ==========================================================================
+ * SPA async task processing
+ * ==========================================================================
+ */
+
+static void
+spa_async_remove(spa_t *spa, vdev_t *vd)
+{
+       int c;
+
+       if (vd->vdev_remove_wanted) {
+               vd->vdev_remove_wanted = B_FALSE;
+               vd->vdev_delayed_close = B_FALSE;
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_REMOVED, VDEV_AUX_NONE);
+
+               /*
+                * We want to clear the stats, but we don't want to do a full
+                * vdev_clear() as that will cause us to throw away
+                * degraded/faulted state as well as attempt to reopen the
+                * device, all of which is a waste.
+                */
+               vd->vdev_stat.vs_read_errors = 0;
+               vd->vdev_stat.vs_write_errors = 0;
+               vd->vdev_stat.vs_checksum_errors = 0;
+
+               vdev_state_dirty(vd->vdev_top);
+       }
+
+       for (c = 0; c < vd->vdev_children; c++)
+               spa_async_remove(spa, vd->vdev_child[c]);
+}
+
+static void
+spa_async_probe(spa_t *spa, vdev_t *vd)
+{
+       int c;
+
+       if (vd->vdev_probe_wanted) {
+               vd->vdev_probe_wanted = B_FALSE;
+               vdev_reopen(vd);        /* vdev_open() does the actual probe */
+       }
+
+       for (c = 0; c < vd->vdev_children; c++)
+               spa_async_probe(spa, vd->vdev_child[c]);
+}
+
+static void
+spa_async_autoexpand(spa_t *spa, vdev_t *vd)
+{
+       int c;
+
+       if (!spa->spa_autoexpand)
+               return;
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               vdev_t *cvd = vd->vdev_child[c];
+               spa_async_autoexpand(spa, cvd);
+       }
+
+       if (!vd->vdev_ops->vdev_op_leaf || vd->vdev_physpath == NULL)
+               return;
+
+       spa_event_notify(vd->vdev_spa, vd, FM_EREPORT_ZFS_DEVICE_AUTOEXPAND);
+}
+
+static void
+spa_async_thread(spa_t *spa)
+{
+       int tasks, i;
+
+       ASSERT(spa->spa_sync_on);
+
+       mutex_enter(&spa->spa_async_lock);
+       tasks = spa->spa_async_tasks;
+       spa->spa_async_tasks = 0;
+       mutex_exit(&spa->spa_async_lock);
+
+       /*
+        * See if the config needs to be updated.
+        */
+       if (tasks & SPA_ASYNC_CONFIG_UPDATE) {
+               uint64_t old_space, new_space;
+
+               mutex_enter(&spa_namespace_lock);
+               old_space = metaslab_class_get_space(spa_normal_class(spa));
+               spa_config_update(spa, SPA_CONFIG_UPDATE_POOL);
+               new_space = metaslab_class_get_space(spa_normal_class(spa));
+               mutex_exit(&spa_namespace_lock);
+
+               /*
+                * If the pool grew as a result of the config update,
+                * then log an internal history event.
+                */
+               if (new_space != old_space) {
+                       spa_history_log_internal(spa, "vdev online", NULL,
+                           "pool '%s' size: %llu(+%llu)",
+                           spa_name(spa), new_space, new_space - old_space);
+               }
+       }
+
+       /*
+        * See if any devices need to be marked REMOVED.
+        */
+       if (tasks & SPA_ASYNC_REMOVE) {
+               spa_vdev_state_enter(spa, SCL_NONE);
+               spa_async_remove(spa, spa->spa_root_vdev);
+               for (i = 0; i < spa->spa_l2cache.sav_count; i++)
+                       spa_async_remove(spa, spa->spa_l2cache.sav_vdevs[i]);
+               for (i = 0; i < spa->spa_spares.sav_count; i++)
+                       spa_async_remove(spa, spa->spa_spares.sav_vdevs[i]);
+               (void) spa_vdev_state_exit(spa, NULL, 0);
+       }
+
+       if ((tasks & SPA_ASYNC_AUTOEXPAND) && !spa_suspended(spa)) {
+               spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+               spa_async_autoexpand(spa, spa->spa_root_vdev);
+               spa_config_exit(spa, SCL_CONFIG, FTAG);
+       }
+
+       /*
+        * See if any devices need to be probed.
+        */
+       if (tasks & SPA_ASYNC_PROBE) {
+               spa_vdev_state_enter(spa, SCL_NONE);
+               spa_async_probe(spa, spa->spa_root_vdev);
+               (void) spa_vdev_state_exit(spa, NULL, 0);
+       }
+
+       /*
+        * If any devices are done replacing, detach them.
+        */
+       if (tasks & SPA_ASYNC_RESILVER_DONE)
+               spa_vdev_resilver_done(spa);
+
+       /*
+        * Kick off a resilver.
+        */
+       if (tasks & SPA_ASYNC_RESILVER)
+               dsl_resilver_restart(spa->spa_dsl_pool, 0);
+
+       /*
+        * Let the world know that we're done.
+        */
+       mutex_enter(&spa->spa_async_lock);
+       spa->spa_async_thread = NULL;
+       cv_broadcast(&spa->spa_async_cv);
+       mutex_exit(&spa->spa_async_lock);
+       thread_exit();
+}
+
+void
+spa_async_suspend(spa_t *spa)
+{
+       mutex_enter(&spa->spa_async_lock);
+       spa->spa_async_suspended++;
+       while (spa->spa_async_thread != NULL)
+               cv_wait(&spa->spa_async_cv, &spa->spa_async_lock);
+       mutex_exit(&spa->spa_async_lock);
+}
+
+void
+spa_async_resume(spa_t *spa)
+{
+       mutex_enter(&spa->spa_async_lock);
+       ASSERT(spa->spa_async_suspended != 0);
+       spa->spa_async_suspended--;
+       mutex_exit(&spa->spa_async_lock);
+}
+
+static void
+spa_async_dispatch(spa_t *spa)
+{
+       mutex_enter(&spa->spa_async_lock);
+       if (spa->spa_async_tasks && !spa->spa_async_suspended &&
+           spa->spa_async_thread == NULL &&
+           rootdir != NULL && !vn_is_readonly(rootdir))
+               spa->spa_async_thread = thread_create(NULL, 0,
+                   spa_async_thread, spa, 0, &p0, TS_RUN, maxclsyspri);
+       mutex_exit(&spa->spa_async_lock);
+}
+
+void
+spa_async_request(spa_t *spa, int task)
+{
+       zfs_dbgmsg("spa=%s async request task=%u", spa->spa_name, task);
+       mutex_enter(&spa->spa_async_lock);
+       spa->spa_async_tasks |= task;
+       mutex_exit(&spa->spa_async_lock);
+}
+
+/*
+ * ==========================================================================
+ * SPA syncing routines
+ * ==========================================================================
+ */
+
+static int
+bpobj_enqueue_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       bpobj_t *bpo = arg;
+       bpobj_enqueue(bpo, bp, tx);
+       return (0);
+}
+
+static int
+spa_free_sync_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       zio_t *zio = arg;
+
+       zio_nowait(zio_free_sync(zio, zio->io_spa, dmu_tx_get_txg(tx), bp,
+           zio->io_flags));
+       return (0);
+}
+
+/*
+ * Note: this simple function is not inlined to make it easier to dtrace the
+ * amount of time spent syncing frees.
+ */
+static void
+spa_sync_frees(spa_t *spa, bplist_t *bpl, dmu_tx_t *tx)
+{
+       zio_t *zio = zio_root(spa, NULL, NULL, 0);
+       bplist_iterate(bpl, spa_free_sync_cb, zio, tx);
+       VERIFY(zio_wait(zio) == 0);
+}
+
+/*
+ * Note: this simple function is not inlined to make it easier to dtrace the
+ * amount of time spent syncing deferred frees.
+ */
+static void
+spa_sync_deferred_frees(spa_t *spa, dmu_tx_t *tx)
+{
+       zio_t *zio = zio_root(spa, NULL, NULL, 0);
+       VERIFY3U(bpobj_iterate(&spa->spa_deferred_bpobj,
+           spa_free_sync_cb, zio, tx), ==, 0);
+       VERIFY0(zio_wait(zio));
+}
+
+static void
+spa_sync_nvlist(spa_t *spa, uint64_t obj, nvlist_t *nv, dmu_tx_t *tx)
+{
+       char *packed = NULL;
+       size_t bufsize;
+       size_t nvsize = 0;
+       dmu_buf_t *db;
+
+       VERIFY(nvlist_size(nv, &nvsize, NV_ENCODE_XDR) == 0);
+
+       /*
+        * Write full (SPA_CONFIG_BLOCKSIZE) blocks of configuration
+        * information.  This avoids the dmu_buf_will_dirty() path and
+        * saves us a pre-read to get data we don't actually care about.
+        */
+       bufsize = P2ROUNDUP((uint64_t)nvsize, SPA_CONFIG_BLOCKSIZE);
+       packed = vmem_alloc(bufsize, KM_SLEEP);
+
+       VERIFY(nvlist_pack(nv, &packed, &nvsize, NV_ENCODE_XDR,
+           KM_SLEEP) == 0);
+       bzero(packed + nvsize, bufsize - nvsize);
+
+       dmu_write(spa->spa_meta_objset, obj, 0, bufsize, packed, tx);
+
+       vmem_free(packed, bufsize);
+
+       VERIFY(0 == dmu_bonus_hold(spa->spa_meta_objset, obj, FTAG, &db));
+       dmu_buf_will_dirty(db, tx);
+       *(uint64_t *)db->db_data = nvsize;
+       dmu_buf_rele(db, FTAG);
+}
+
+static void
+spa_sync_aux_dev(spa_t *spa, spa_aux_vdev_t *sav, dmu_tx_t *tx,
+    const char *config, const char *entry)
+{
+       nvlist_t *nvroot;
+       nvlist_t **list;
+       int i;
+
+       if (!sav->sav_sync)
+               return;
+
+       /*
+        * Update the MOS nvlist describing the list of available devices.
+        * spa_validate_aux() will have already made sure this nvlist is
+        * valid and the vdevs are labeled appropriately.
+        */
+       if (sav->sav_object == 0) {
+               sav->sav_object = dmu_object_alloc(spa->spa_meta_objset,
+                   DMU_OT_PACKED_NVLIST, 1 << 14, DMU_OT_PACKED_NVLIST_SIZE,
+                   sizeof (uint64_t), tx);
+               VERIFY(zap_update(spa->spa_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT, entry, sizeof (uint64_t), 1,
+                   &sav->sav_object, tx) == 0);
+       }
+
+       VERIFY(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+       if (sav->sav_count == 0) {
+               VERIFY(nvlist_add_nvlist_array(nvroot, config, NULL, 0) == 0);
+       } else {
+               list = kmem_alloc(sav->sav_count*sizeof (void *), KM_SLEEP);
+               for (i = 0; i < sav->sav_count; i++)
+                       list[i] = vdev_config_generate(spa, sav->sav_vdevs[i],
+                           B_FALSE, VDEV_CONFIG_L2CACHE);
+               VERIFY(nvlist_add_nvlist_array(nvroot, config, list,
+                   sav->sav_count) == 0);
+               for (i = 0; i < sav->sav_count; i++)
+                       nvlist_free(list[i]);
+               kmem_free(list, sav->sav_count * sizeof (void *));
+       }
+
+       spa_sync_nvlist(spa, sav->sav_object, nvroot, tx);
+       nvlist_free(nvroot);
+
+       sav->sav_sync = B_FALSE;
+}
+
+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))
+               return;
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+
+       config = spa_config_generate(spa, spa->spa_root_vdev,
+           dmu_tx_get_txg(tx), B_FALSE);
+
+       /*
+        * If we're upgrading the spa version then make sure that
+        * the config object gets updated with the correct version.
+        */
+       if (spa->spa_ubsync.ub_version < spa->spa_uberblock.ub_version)
+               fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
+                   spa->spa_uberblock.ub_version);
+
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       if (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);
+}
+
+static void
+spa_sync_version(void *arg, dmu_tx_t *tx)
+{
+       uint64_t *versionp = arg;
+       uint64_t version = *versionp;
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+
+       /*
+        * Setting the version is special cased when first creating the pool.
+        */
+       ASSERT(tx->tx_txg != TXG_INITIAL);
+
+       ASSERT(SPA_VERSION_IS_SUPPORTED(version));
+       ASSERT(version >= spa_version(spa));
+
+       spa->spa_uberblock.ub_version = version;
+       vdev_config_dirty(spa->spa_root_vdev);
+       spa_history_log_internal(spa, "set", tx, "version=%lld", version);
+}
+
+/*
+ * Set zpool properties.
+ */
+static void
+spa_sync_props(void *arg, dmu_tx_t *tx)
+{
+       nvlist_t *nvp = arg;
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       objset_t *mos = spa->spa_meta_objset;
+       nvpair_t *elem = NULL;
+
+       mutex_enter(&spa->spa_props_lock);
+
+       while ((elem = nvlist_next_nvpair(nvp, elem))) {
+               uint64_t intval;
+               char *strval, *fname;
+               zpool_prop_t prop;
+               const char *propname;
+               zprop_type_t proptype;
+               spa_feature_t fid;
+
+               prop = zpool_name_to_prop(nvpair_name(elem));
+               switch ((int)prop) {
+               case ZPROP_INVAL:
+                       /*
+                        * We checked this earlier in spa_prop_validate().
+                        */
+                       ASSERT(zpool_prop_feature(nvpair_name(elem)));
+
+                       fname = strchr(nvpair_name(elem), '@') + 1;
+                       VERIFY0(zfeature_lookup_name(fname, &fid));
+
+                       spa_feature_enable(spa, fid, tx);
+                       spa_history_log_internal(spa, "set", tx,
+                           "%s=enabled", nvpair_name(elem));
+                       break;
+
+               case ZPOOL_PROP_VERSION:
+                       intval = fnvpair_value_uint64(elem);
+                       /*
+                        * The version is synced seperatly before other
+                        * properties and should be correct by now.
+                        */
+                       ASSERT3U(spa_version(spa), >=, intval);
+                       break;
+
+               case ZPOOL_PROP_ALTROOT:
+                       /*
+                        * 'altroot' is a non-persistent property. It should
+                        * have been set temporarily at creation or import time.
+                        */
+                       ASSERT(spa->spa_root != NULL);
+                       break;
+
+               case ZPOOL_PROP_READONLY:
+               case ZPOOL_PROP_CACHEFILE:
+                       /*
+                        * 'readonly' and 'cachefile' are also non-persisitent
+                        * properties.
+                        */
+                       break;
+               case ZPOOL_PROP_COMMENT:
+                       strval = fnvpair_value_string(elem);
+                       if (spa->spa_comment != NULL)
+                               spa_strfree(spa->spa_comment);
+                       spa->spa_comment = spa_strdup(strval);
+                       /*
+                        * We need to dirty the configuration on all the vdevs
+                        * so that their labels get updated.  It's unnecessary
+                        * to do this for pool creation since the vdev's
+                        * configuratoin has already been dirtied.
+                        */
+                       if (tx->tx_txg != TXG_INITIAL)
+                               vdev_config_dirty(spa->spa_root_vdev);
+                       spa_history_log_internal(spa, "set", tx,
+                           "%s=%s", nvpair_name(elem), strval);
+                       break;
+               default:
+                       /*
+                        * Set pool property values in the poolprops mos object.
+                        */
+                       if (spa->spa_pool_props_object == 0) {
+                               spa->spa_pool_props_object =
+                                   zap_create_link(mos, DMU_OT_POOL_PROPS,
+                                   DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_PROPS,
+                                   tx);
+                       }
+
+                       /* normalize the property name */
+                       propname = zpool_prop_to_name(prop);
+                       proptype = zpool_prop_get_type(prop);
+
+                       if (nvpair_type(elem) == DATA_TYPE_STRING) {
+                               ASSERT(proptype == PROP_TYPE_STRING);
+                               strval = fnvpair_value_string(elem);
+                               VERIFY0(zap_update(mos,
+                                   spa->spa_pool_props_object, propname,
+                                   1, strlen(strval) + 1, strval, tx));
+                               spa_history_log_internal(spa, "set", tx,
+                                   "%s=%s", nvpair_name(elem), strval);
+                       } else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
+                               intval = fnvpair_value_uint64(elem);
+
+                               if (proptype == PROP_TYPE_INDEX) {
+                                       const char *unused;
+                                       VERIFY0(zpool_prop_index_to_string(
+                                           prop, intval, &unused));
+                               }
+                               VERIFY0(zap_update(mos,
+                                   spa->spa_pool_props_object, propname,
+                                   8, 1, &intval, tx));
+                               spa_history_log_internal(spa, "set", tx,
+                                   "%s=%lld", nvpair_name(elem), intval);
+                       } else {
+                               ASSERT(0); /* not allowed */
+                       }
+
+                       switch (prop) {
+                       case ZPOOL_PROP_DELEGATION:
+                               spa->spa_delegation = intval;
+                               break;
+                       case ZPOOL_PROP_BOOTFS:
+                               spa->spa_bootfs = intval;
+                               break;
+                       case ZPOOL_PROP_FAILUREMODE:
+                               spa->spa_failmode = intval;
+                               break;
+                       case ZPOOL_PROP_AUTOEXPAND:
+                               spa->spa_autoexpand = intval;
+                               if (tx->tx_txg != TXG_INITIAL)
+                                       spa_async_request(spa,
+                                           SPA_ASYNC_AUTOEXPAND);
+                               break;
+                       case ZPOOL_PROP_DEDUPDITTO:
+                               spa->spa_dedup_ditto = intval;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+       }
+
+       mutex_exit(&spa->spa_props_lock);
+}
+
+/*
+ * Perform one-time upgrade on-disk changes.  spa_version() does not
+ * reflect the new version this txg, so there must be no changes this
+ * txg to anything that the upgrade code depends on after it executes.
+ * Therefore this must be called after dsl_pool_sync() does the sync
+ * tasks.
+ */
+static void
+spa_sync_upgrades(spa_t *spa, dmu_tx_t *tx)
+{
+       dsl_pool_t *dp = spa->spa_dsl_pool;
+
+       ASSERT(spa->spa_sync_pass == 1);
+
+       rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
+
+       if (spa->spa_ubsync.ub_version < SPA_VERSION_ORIGIN &&
+           spa->spa_uberblock.ub_version >= SPA_VERSION_ORIGIN) {
+               dsl_pool_create_origin(dp, tx);
+
+               /* Keeping the origin open increases spa_minref */
+               spa->spa_minref += 3;
+       }
+
+       if (spa->spa_ubsync.ub_version < SPA_VERSION_NEXT_CLONES &&
+           spa->spa_uberblock.ub_version >= SPA_VERSION_NEXT_CLONES) {
+               dsl_pool_upgrade_clones(dp, tx);
+       }
+
+       if (spa->spa_ubsync.ub_version < SPA_VERSION_DIR_CLONES &&
+           spa->spa_uberblock.ub_version >= SPA_VERSION_DIR_CLONES) {
+               dsl_pool_upgrade_dir_clones(dp, tx);
+
+               /* Keeping the freedir open increases spa_minref */
+               spa->spa_minref += 3;
+       }
+
+       if (spa->spa_ubsync.ub_version < SPA_VERSION_FEATURES &&
+           spa->spa_uberblock.ub_version >= SPA_VERSION_FEATURES) {
+               spa_feature_create_zap_objects(spa, tx);
+       }
+
+       /*
+        * LZ4_COMPRESS feature's behaviour was changed to activate_on_enable
+        * when possibility to use lz4 compression for metadata was added
+        * Old pools that have this feature enabled must be upgraded to have
+        * this feature active
+        */
+       if (spa->spa_uberblock.ub_version >= SPA_VERSION_FEATURES) {
+               boolean_t lz4_en = spa_feature_is_enabled(spa,
+                   SPA_FEATURE_LZ4_COMPRESS);
+               boolean_t lz4_ac = spa_feature_is_active(spa,
+                   SPA_FEATURE_LZ4_COMPRESS);
+
+               if (lz4_en && !lz4_ac)
+                       spa_feature_incr(spa, SPA_FEATURE_LZ4_COMPRESS, tx);
+       }
+       rrw_exit(&dp->dp_config_rwlock, FTAG);
+}
+
+/*
+ * Sync the specified transaction group.  New blocks may be dirtied as
+ * part of the process, so we iterate until it converges.
+ */
+void
+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];
+       vdev_t *rvd = spa->spa_root_vdev;
+       vdev_t *vd;
+       dmu_tx_t *tx;
+       int error;
+       int c;
+
+       VERIFY(spa_writeable(spa));
+
+       /*
+        * Lock out configuration changes.
+        */
+       spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+
+       spa->spa_syncing_txg = txg;
+       spa->spa_sync_pass = 0;
+
+       /*
+        * If there are any pending vdev state changes, convert them
+        * into config changes that go out with this transaction group.
+        */
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+       while (list_head(&spa->spa_state_dirty_list) != NULL) {
+               /*
+                * We need the write lock here because, for aux vdevs,
+                * calling vdev_config_dirty() modifies sav_config.
+                * This is ugly and will become unnecessary when we
+                * eliminate the aux vdev wart by integrating all vdevs
+                * into the root vdev tree.
+                */
+               spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG);
+               spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_WRITER);
+               while ((vd = list_head(&spa->spa_state_dirty_list)) != NULL) {
+                       vdev_state_clean(vd);
+                       vdev_config_dirty(vd);
+               }
+               spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG);
+               spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER);
+       }
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       tx = dmu_tx_create_assigned(dp, txg);
+
+       spa->spa_sync_starttime = gethrtime();
+       taskq_cancel_id(system_taskq, spa->spa_deadman_tqid);
+       spa->spa_deadman_tqid = taskq_dispatch_delay(system_taskq,
+           spa_deadman, spa, TQ_SLEEP, ddi_get_lbolt() +
+           NSEC_TO_TICK(spa->spa_deadman_synctime));
+
+       /*
+        * If we are upgrading to SPA_VERSION_RAIDZ_DEFLATE this txg,
+        * set spa_deflate if we have no raid-z vdevs.
+        */
+       if (spa->spa_ubsync.ub_version < SPA_VERSION_RAIDZ_DEFLATE &&
+           spa->spa_uberblock.ub_version >= SPA_VERSION_RAIDZ_DEFLATE) {
+               int i;
+
+               for (i = 0; i < rvd->vdev_children; i++) {
+                       vd = rvd->vdev_child[i];
+                       if (vd->vdev_deflate_ratio != SPA_MINBLOCKSIZE)
+                               break;
+               }
+               if (i == rvd->vdev_children) {
+                       spa->spa_deflate = TRUE;
+                       VERIFY(0 == zap_add(spa->spa_meta_objset,
+                           DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_DEFLATE,
+                           sizeof (uint64_t), 1, &spa->spa_deflate, tx));
+               }
+       }
+
+       /*
+        * Iterate to convergence.
+        */
+       do {
+               int pass = ++spa->spa_sync_pass;
+
+               spa_sync_config_object(spa, tx);
+               spa_sync_aux_dev(spa, &spa->spa_spares, tx,
+                   ZPOOL_CONFIG_SPARES, DMU_POOL_SPARES);
+               spa_sync_aux_dev(spa, &spa->spa_l2cache, tx,
+                   ZPOOL_CONFIG_L2CACHE, DMU_POOL_L2CACHE);
+               spa_errlog_sync(spa, txg);
+               dsl_pool_sync(dp, txg);
+
+               if (pass < zfs_sync_pass_deferred_free) {
+                       spa_sync_frees(spa, free_bpl, tx);
+               } else {
+                       /*
+                        * We can not defer frees in pass 1, because
+                        * we sync the deferred frees later in pass 1.
+                        */
+                       ASSERT3U(pass, >, 1);
+                       bplist_iterate(free_bpl, bpobj_enqueue_cb,
+                           &spa->spa_deferred_bpobj, tx);
+               }
+
+               ddt_sync(spa, txg);
+               dsl_scan_sync(dp, tx);
+
+               while ((vd = txg_list_remove(&spa->spa_vdev_txg_list, txg)))
+                       vdev_sync(vd, txg);
+
+               if (pass == 1) {
+                       spa_sync_upgrades(spa, tx);
+                       ASSERT3U(txg, >=,
+                           spa->spa_uberblock.ub_rootbp.blk_birth);
+                       /*
+                        * Note: We need to check if the MOS is dirty
+                        * because we could have marked the MOS dirty
+                        * without updating the uberblock (e.g. if we
+                        * have sync tasks but no dirty user data).  We
+                        * need to check the uberblock's rootbp because
+                        * it is updated if we have synced out dirty
+                        * data (though in this case the MOS will most
+                        * likely also be dirty due to second order
+                        * effects, we don't want to rely on that here).
+                        */
+                       if (spa->spa_uberblock.ub_rootbp.blk_birth < txg &&
+                           !dmu_objset_is_dirty(mos, txg)) {
+                               /*
+                                * Nothing changed on the first pass,
+                                * therefore this TXG is a no-op.  Avoid
+                                * syncing deferred frees, so that we
+                                * can keep this TXG as a no-op.
+                                */
+                               ASSERT(txg_list_empty(&dp->dp_dirty_datasets,
+                                   txg));
+                               ASSERT(txg_list_empty(&dp->dp_dirty_dirs, txg));
+                               ASSERT(txg_list_empty(&dp->dp_sync_tasks, txg));
+                               break;
+                       }
+                       spa_sync_deferred_frees(spa, tx);
+               }
+
+       } while (dmu_objset_is_dirty(mos, txg));
+
+       /*
+        * Rewrite the vdev configuration (which includes the uberblock)
+        * to commit the transaction group.
+        *
+        * If there are no dirty vdevs, we sync the uberblock to a few
+        * random top-level vdevs that are known to be visible in the
+        * config cache (see spa_vdev_add() for a complete description).
+        * If there *are* dirty vdevs, sync the uberblock to all vdevs.
+        */
+       for (;;) {
+               /*
+                * We hold SCL_STATE to prevent vdev open/close/etc.
+                * while we're attempting to write the vdev labels.
+                */
+               spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+
+               if (list_is_empty(&spa->spa_config_dirty_list)) {
+                       vdev_t *svd[SPA_DVAS_PER_BP];
+                       int svdcount = 0;
+                       int children = rvd->vdev_children;
+                       int c0 = spa_get_random(children);
+
+                       for (c = 0; c < children; c++) {
+                               vd = rvd->vdev_child[(c0 + c) % children];
+                               if (vd->vdev_ms_array == 0 || vd->vdev_islog)
+                                       continue;
+                               svd[svdcount++] = vd;
+                               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);
+               } 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);
+               }
+
+               if (error == 0)
+                       spa->spa_last_synced_guid = rvd->vdev_guid;
+
+               spa_config_exit(spa, SCL_STATE, FTAG);
+
+               if (error == 0)
+                       break;
+               zio_suspend(spa, NULL);
+               zio_resume_wait(spa);
+       }
+       dmu_tx_commit(tx);
+
+       taskq_cancel_id(system_taskq, spa->spa_deadman_tqid);
+       spa->spa_deadman_tqid = 0;
+
+       /*
+        * Clear the dirty config list.
+        */
+       while ((vd = list_head(&spa->spa_config_dirty_list)) != NULL)
+               vdev_config_clean(vd);
+
+       /*
+        * Now that the new config has synced transactionally,
+        * let it become visible to the config cache.
+        */
+       if (spa->spa_config_syncing != NULL) {
+               spa_config_set(spa, spa->spa_config_syncing);
+               spa->spa_config_txg = txg;
+               spa->spa_config_syncing = NULL;
+       }
+
+       spa->spa_ubsync = spa->spa_uberblock;
+
+       dsl_pool_sync_done(dp, txg);
+
+       /*
+        * Update usable space statistics.
+        */
+       while ((vd = txg_list_remove(&spa->spa_vdev_txg_list, TXG_CLEAN(txg))))
+               vdev_sync_done(vd, txg);
+
+       spa_update_dspace(spa);
+
+       /*
+        * It had better be the case that we didn't dirty anything
+        * since vdev_config_sync().
+        */
+       ASSERT(txg_list_empty(&dp->dp_dirty_datasets, txg));
+       ASSERT(txg_list_empty(&dp->dp_dirty_dirs, txg));
+       ASSERT(txg_list_empty(&spa->spa_vdev_txg_list, txg));
+
+       spa->spa_sync_pass = 0;
+
+       spa_config_exit(spa, SCL_CONFIG, FTAG);
+
+       spa_handle_ignored_writes(spa);
+
+       /*
+        * If any async tasks have been requested, kick them off.
+        */
+       spa_async_dispatch(spa);
+}
+
+/*
+ * Sync all pools.  We don't want to hold the namespace lock across these
+ * operations, so we take a reference on the spa_t and drop the lock during the
+ * sync.
+ */
+void
+spa_sync_allpools(void)
+{
+       spa_t *spa = NULL;
+       mutex_enter(&spa_namespace_lock);
+       while ((spa = spa_next(spa)) != NULL) {
+               if (spa_state(spa) != POOL_STATE_ACTIVE ||
+                   !spa_writeable(spa) || spa_suspended(spa))
+                       continue;
+               spa_open_ref(spa, FTAG);
+               mutex_exit(&spa_namespace_lock);
+               txg_wait_synced(spa_get_dsl(spa), 0);
+               mutex_enter(&spa_namespace_lock);
+               spa_close(spa, FTAG);
+       }
+       mutex_exit(&spa_namespace_lock);
+}
+
+/*
+ * ==========================================================================
+ * Miscellaneous routines
+ * ==========================================================================
+ */
+
+/*
+ * Remove all pools in the system.
+ */
+void
+spa_evict_all(void)
+{
+       spa_t *spa;
+
+       /*
+        * Remove all cached state.  All pools should be closed now,
+        * so every spa in the AVL tree should be unreferenced.
+        */
+       mutex_enter(&spa_namespace_lock);
+       while ((spa = spa_next(NULL)) != NULL) {
+               /*
+                * Stop async tasks.  The async thread may need to detach
+                * a device that's been replaced, which requires grabbing
+                * spa_namespace_lock, so we must drop it here.
+                */
+               spa_open_ref(spa, FTAG);
+               mutex_exit(&spa_namespace_lock);
+               spa_async_suspend(spa);
+               mutex_enter(&spa_namespace_lock);
+               spa_close(spa, FTAG);
+
+               if (spa->spa_state != POOL_STATE_UNINITIALIZED) {
+                       spa_unload(spa);
+                       spa_deactivate(spa);
+               }
+               spa_remove(spa);
+       }
+       mutex_exit(&spa_namespace_lock);
+}
+
+vdev_t *
+spa_lookup_by_guid(spa_t *spa, uint64_t guid, boolean_t aux)
+{
+       vdev_t *vd;
+       int i;
+
+       if ((vd = vdev_lookup_by_guid(spa->spa_root_vdev, guid)) != NULL)
+               return (vd);
+
+       if (aux) {
+               for (i = 0; i < spa->spa_l2cache.sav_count; i++) {
+                       vd = spa->spa_l2cache.sav_vdevs[i];
+                       if (vd->vdev_guid == guid)
+                               return (vd);
+               }
+
+               for (i = 0; i < spa->spa_spares.sav_count; i++) {
+                       vd = spa->spa_spares.sav_vdevs[i];
+                       if (vd->vdev_guid == guid)
+                               return (vd);
+               }
+       }
+
+       return (NULL);
+}
+
+void
+spa_upgrade(spa_t *spa, uint64_t version)
+{
+       ASSERT(spa_writeable(spa));
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+       /*
+        * This should only be called for a non-faulted pool, and since a
+        * future version would result in an unopenable pool, this shouldn't be
+        * possible.
+        */
+       ASSERT(SPA_VERSION_IS_SUPPORTED(spa->spa_uberblock.ub_version));
+       ASSERT3U(version, >=, spa->spa_uberblock.ub_version);
+
+       spa->spa_uberblock.ub_version = version;
+       vdev_config_dirty(spa->spa_root_vdev);
+
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       txg_wait_synced(spa_get_dsl(spa), 0);
+}
+
+boolean_t
+spa_has_spare(spa_t *spa, uint64_t guid)
+{
+       int i;
+       uint64_t spareguid;
+       spa_aux_vdev_t *sav = &spa->spa_spares;
+
+       for (i = 0; i < sav->sav_count; i++)
+               if (sav->sav_vdevs[i]->vdev_guid == guid)
+                       return (B_TRUE);
+
+       for (i = 0; i < sav->sav_npending; i++) {
+               if (nvlist_lookup_uint64(sav->sav_pending[i], ZPOOL_CONFIG_GUID,
+                   &spareguid) == 0 && spareguid == guid)
+                       return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Check if a pool has an active shared spare device.
+ * Note: reference count of an active spare is 2, as a spare and as a replace
+ */
+static boolean_t
+spa_has_active_shared_spare(spa_t *spa)
+{
+       int i, refcnt;
+       uint64_t pool;
+       spa_aux_vdev_t *sav = &spa->spa_spares;
+
+       for (i = 0; i < sav->sav_count; i++) {
+               if (spa_spare_exists(sav->sav_vdevs[i]->vdev_guid, &pool,
+                   &refcnt) && pool != 0ULL && pool == spa_guid(spa) &&
+                   refcnt > 2)
+                       return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Post a FM_EREPORT_ZFS_* event from sys/fm/fs/zfs.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.
+ */
+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
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+/* state manipulation functions */
+EXPORT_SYMBOL(spa_open);
+EXPORT_SYMBOL(spa_open_rewind);
+EXPORT_SYMBOL(spa_get_stats);
+EXPORT_SYMBOL(spa_create);
+EXPORT_SYMBOL(spa_import);
+EXPORT_SYMBOL(spa_tryimport);
+EXPORT_SYMBOL(spa_destroy);
+EXPORT_SYMBOL(spa_export);
+EXPORT_SYMBOL(spa_reset);
+EXPORT_SYMBOL(spa_async_request);
+EXPORT_SYMBOL(spa_async_suspend);
+EXPORT_SYMBOL(spa_async_resume);
+EXPORT_SYMBOL(spa_inject_addref);
+EXPORT_SYMBOL(spa_inject_delref);
+EXPORT_SYMBOL(spa_scan_stat_init);
+EXPORT_SYMBOL(spa_scan_get_stats);
+
+/* device maniion */
+EXPORT_SYMBOL(spa_vdev_add);
+EXPORT_SYMBOL(spa_vdev_attach);
+EXPORT_SYMBOL(spa_vdev_detach);
+EXPORT_SYMBOL(spa_vdev_remove);
+EXPORT_SYMBOL(spa_vdev_setpath);
+EXPORT_SYMBOL(spa_vdev_setfru);
+EXPORT_SYMBOL(spa_vdev_split_mirror);
+
+/* spare statech is global across all pools) */
+EXPORT_SYMBOL(spa_spare_add);
+EXPORT_SYMBOL(spa_spare_remove);
+EXPORT_SYMBOL(spa_spare_exists);
+EXPORT_SYMBOL(spa_spare_activate);
+
+/* L2ARC statech is global across all pools) */
+EXPORT_SYMBOL(spa_l2cache_add);
+EXPORT_SYMBOL(spa_l2cache_remove);
+EXPORT_SYMBOL(spa_l2cache_exists);
+EXPORT_SYMBOL(spa_l2cache_activate);
+EXPORT_SYMBOL(spa_l2cache_drop);
+
+/* scanning */
+EXPORT_SYMBOL(spa_scan);
+EXPORT_SYMBOL(spa_scan_stop);
+
+/* spa syncing */
+EXPORT_SYMBOL(spa_sync); /* only for DMU use */
+EXPORT_SYMBOL(spa_sync_allpools);
+
+/* properties */
+EXPORT_SYMBOL(spa_prop_set);
+EXPORT_SYMBOL(spa_prop_get);
+EXPORT_SYMBOL(spa_prop_clear_bootfs);
+
+/* asynchronous event notification */
+EXPORT_SYMBOL(spa_event_notify);
+#endif
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(spa_load_verify_maxinflight, int, 0644);
+MODULE_PARM_DESC(spa_load_verify_maxinflight,
+       "Max concurrent traversal I/Os while verifying pool during import -X");
+
+module_param(spa_load_verify_metadata, int, 0644);
+MODULE_PARM_DESC(spa_load_verify_metadata,
+       "Set to traverse metadata on pool import");
+
+module_param(spa_load_verify_data, int, 0644);
+MODULE_PARM_DESC(spa_load_verify_data,
+       "Set to traverse data on pool import");
+
+module_param(zio_taskq_batch_pct, uint, 0444);
+MODULE_PARM_DESC(zio_taskq_batch_pct,
+       "Percentage of CPUs to run an IO worker thread");
+
+#endif
diff --git a/zfs/module/zfs/spa_boot.c b/zfs/module/zfs/spa_boot.c
new file mode 100644 (file)
index 0000000..be79542
--- /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 (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifdef _KERNEL
+
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/sunddi.h>
+
+char *
+spa_get_bootprop(char *propname)
+{
+       char *value;
+
+       if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
+           DDI_PROP_DONTPASS, propname, &value) != DDI_SUCCESS)
+               return (NULL);
+       return (value);
+}
+
+void
+spa_free_bootprop(char *value)
+{
+       ddi_prop_free(value);
+}
+
+#endif /* _KERNEL */
diff --git a/zfs/module/zfs/spa_config.c b/zfs/module/zfs/spa_config.c
new file mode 100644 (file)
index 0000000..19432e0
--- /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) 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.
+ */
+
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/nvpair.h>
+#include <sys/uio.h>
+#include <sys/fs/zfs.h>
+#include <sys/vdev_impl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/systeminfo.h>
+#include <sys/sunddi.h>
+#include <sys/zfeature.h>
+#ifdef _KERNEL
+#include <sys/kobj.h>
+#include <sys/zone.h>
+#endif
+
+/*
+ * Pool configuration repository.
+ *
+ * Pool configuration is stored as a packed nvlist on the filesystem.  By
+ * default, all pools are stored in /etc/zfs/zpool.cache and loaded on boot
+ * (when the ZFS module is loaded).  Pools can also have the 'cachefile'
+ * property set that allows them to be stored in an alternate location until
+ * the control of external software.
+ *
+ * For each cache file, we have a single nvlist which holds all the
+ * configuration information.  When the module loads, we read this information
+ * from /etc/zfs/zpool.cache and populate the SPA namespace.  This namespace is
+ * maintained independently in spa.c.  Whenever the namespace is modified, or
+ * the configuration of a pool is changed, we call spa_config_sync(), which
+ * walks through all the active pools and writes the configuration to disk.
+ */
+
+static uint64_t spa_config_generation = 1;
+
+/*
+ * This can be overridden in userland to preserve an alternate namespace for
+ * userland pools when doing testing.
+ */
+char *spa_config_path = ZPOOL_CACHE;
+int zfs_autoimport_disable = 1;
+
+/*
+ * Called when the module is first loaded, this routine loads the configuration
+ * file into the SPA namespace.  It does not actually open or load the pools; it
+ * only populates the namespace.
+ */
+void
+spa_config_load(void)
+{
+       void *buf = NULL;
+       nvlist_t *nvlist, *child;
+       nvpair_t *nvpair;
+       char *pathname;
+       struct _buf *file;
+       uint64_t fsize;
+
+#ifdef _KERNEL
+       if (zfs_autoimport_disable)
+               return;
+#endif
+
+       /*
+        * Open the configuration file.
+        */
+       pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+       (void) snprintf(pathname, MAXPATHLEN, "%s%s",
+           (rootdir != NULL) ? "./" : "", spa_config_path);
+
+       file = kobj_open_file(pathname);
+
+       kmem_free(pathname, MAXPATHLEN);
+
+       if (file == (struct _buf *)-1)
+               return;
+
+       if (kobj_get_filesize(file, &fsize) != 0)
+               goto out;
+
+       buf = kmem_alloc(fsize, KM_SLEEP);
+
+       /*
+        * Read the nvlist from the file.
+        */
+       if (kobj_read_file(file, buf, fsize, 0) < 0)
+               goto out;
+
+       /*
+        * Unpack the nvlist.
+        */
+       if (nvlist_unpack(buf, fsize, &nvlist, KM_SLEEP) != 0)
+               goto out;
+
+       /*
+        * Iterate over all elements in the nvlist, creating a new spa_t for
+        * each one with the specified configuration.
+        */
+       mutex_enter(&spa_namespace_lock);
+       nvpair = NULL;
+       while ((nvpair = nvlist_next_nvpair(nvlist, nvpair)) != NULL) {
+               if (nvpair_type(nvpair) != DATA_TYPE_NVLIST)
+                       continue;
+
+               VERIFY(nvpair_value_nvlist(nvpair, &child) == 0);
+
+               if (spa_lookup(nvpair_name(nvpair)) != NULL)
+                       continue;
+               (void) spa_add(nvpair_name(nvpair), child, NULL);
+       }
+       mutex_exit(&spa_namespace_lock);
+
+       nvlist_free(nvlist);
+
+out:
+       if (buf != NULL)
+               kmem_free(buf, fsize);
+
+       kobj_close_file(file);
+}
+
+static void
+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;
+
+       /*
+        * If the nvlist is empty (NULL), then remove the old cachefile.
+        */
+       if (nvl == NULL) {
+               (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
+               return;
+       }
+
+       /*
+        * Pack the configuration into a buffer.
+        */
+       VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);
+
+       buf = vmem_alloc(buflen, KM_SLEEP);
+       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
+        * in performing a rename from within the kernel the file is truncated
+        * 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,
+                   UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL);
+               if (error == 0)
+                       error = VOP_FSYNC(vp, FSYNC, kcred, NULL);
+
+               (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
+
+               if (error)
+                       (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
+       }
+#else
+       /*
+        * Write the configuration to disk.  We need to do the traditional
+        * 'write to temporary file, sync, move over original' to make sure we
+        * always have a consistent view of the data.
+        */
+       (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);
+               }
+               (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
+       }
+
+       (void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
+#endif
+
+       vmem_free(buf, buflen);
+       kmem_free(temp, MAXPATHLEN);
+}
+
+/*
+ * Synchronize pool configuration to disk.  This must be called with the
+ * namespace lock held. Synchronizing the pool cache is typically done after
+ * the configuration has been synced to the MOS. This exposes a window where
+ * the MOS config will have been updated but the cache file has not. If
+ * the system were to crash at that instant then the cached config may not
+ * contain the correct information to open the pool and an explicity import
+ * would be required.
+ */
+void
+spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
+{
+       spa_config_dirent_t *dp, *tdp;
+       nvlist_t *nvl;
+       char *pool_name;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       if (rootdir == NULL || !(spa_mode_global & FWRITE))
+               return;
+
+       /*
+        * Iterate over all cachefiles for the pool, past or present.  When the
+        * cachefile is changed, the new one is pushed onto this list, allowing
+        * us to update previous cachefiles that no longer contain this pool.
+        */
+       for (dp = list_head(&target->spa_config_list); dp != NULL;
+           dp = list_next(&target->spa_config_list, dp)) {
+               spa_t *spa = NULL;
+               if (dp->scd_path == NULL)
+                       continue;
+
+               /*
+                * Iterate over all pools, adding any matching pools to 'nvl'.
+                */
+               nvl = NULL;
+               while ((spa = spa_next(spa)) != NULL) {
+                       /*
+                        * Skip over our own pool if we're about to remove
+                        * ourselves from the spa namespace or any pool that
+                        * is readonly. Since we cannot guarantee that a
+                        * readonly pool would successfully import upon reboot,
+                        * we don't allow them to be written to the cache file.
+                        */
+                       if ((spa == target && removing) ||
+                           !spa_writeable(spa))
+                               continue;
+
+                       mutex_enter(&spa->spa_props_lock);
+                       tdp = list_head(&spa->spa_config_list);
+                       if (spa->spa_config == NULL ||
+                           tdp->scd_path == NULL ||
+                           strcmp(tdp->scd_path, dp->scd_path) != 0) {
+                               mutex_exit(&spa->spa_props_lock);
+                               continue;
+                       }
+
+                       if (nvl == NULL)
+                               VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME,
+                                   KM_SLEEP) == 0);
+
+                       if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
+                               VERIFY0(nvlist_lookup_string(spa->spa_config,
+                                       ZPOOL_CONFIG_POOL_NAME, &pool_name));
+                       } else
+                               pool_name = spa_name(spa);
+
+                       VERIFY(nvlist_add_nvlist(nvl, pool_name,
+                           spa->spa_config) == 0);
+                       mutex_exit(&spa->spa_props_lock);
+               }
+
+               spa_config_write(dp, nvl);
+               nvlist_free(nvl);
+       }
+
+       /*
+        * Remove any config entries older than the current one.
+        */
+       dp = list_head(&target->spa_config_list);
+       while ((tdp = list_next(&target->spa_config_list, dp)) != NULL) {
+               list_remove(&target->spa_config_list, tdp);
+               if (tdp->scd_path != NULL)
+                       spa_strfree(tdp->scd_path);
+               kmem_free(tdp, sizeof (spa_config_dirent_t));
+       }
+
+       spa_config_generation++;
+
+       if (postsysevent)
+               spa_event_notify(target, NULL, FM_EREPORT_ZFS_CONFIG_SYNC);
+}
+
+/*
+ * Sigh.  Inside a local zone, we don't have access to /etc/zfs/zpool.cache,
+ * and we don't want to allow the local zone to see all the pools anyway.
+ * So we have to invent the ZFS_IOC_CONFIG ioctl to grab the configuration
+ * information for all pool visible within the zone.
+ */
+nvlist_t *
+spa_all_configs(uint64_t *generation)
+{
+       nvlist_t *pools;
+       spa_t *spa = NULL;
+
+       if (*generation == spa_config_generation)
+               return (NULL);
+
+       VERIFY(nvlist_alloc(&pools, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       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);
+                       mutex_exit(&spa->spa_props_lock);
+               }
+       }
+       *generation = spa_config_generation;
+       mutex_exit(&spa_namespace_lock);
+
+       return (pools);
+}
+
+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);
+       spa->spa_config = config;
+       mutex_exit(&spa->spa_props_lock);
+}
+
+/*
+ * Generate the pool's configuration based on the current in-core state.
+ *
+ * We infer whether to generate a complete config or just one top-level config
+ * based on whether vd is the root vdev.
+ */
+nvlist_t *
+spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
+{
+       nvlist_t *config, *nvroot;
+       vdev_t *rvd = spa->spa_root_vdev;
+       unsigned long hostid = 0;
+       boolean_t locked = B_FALSE;
+       uint64_t split_guid;
+       char *pool_name;
+
+       if (vd == NULL) {
+               vd = rvd;
+               locked = B_TRUE;
+               spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER);
+       }
+
+       ASSERT(spa_config_held(spa, SCL_CONFIG | SCL_STATE, RW_READER) ==
+           (SCL_CONFIG | SCL_STATE));
+
+       /*
+        * If txg is -1, report the current value of spa->spa_config_txg.
+        */
+       if (txg == -1ULL)
+               txg = spa->spa_config_txg;
+
+       /*
+        * Originally, users had to handle spa namespace collisions by either
+        * exporting the already imported pool or by specifying a new name for
+        * the pool with a conflicting name. In the case of root pools from
+        * virtual guests, neither approach to collision resolution is
+        * reasonable. This is addressed by extending the new name syntax with
+        * an option to specify that the new name is temporary. When specified,
+        * ZFS_IMPORT_TEMP_NAME will be set in spa->spa_import_flags to tell us
+        * to use the previous name, which we do below.
+        */
+       if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
+               VERIFY0(nvlist_lookup_string(spa->spa_config,
+                       ZPOOL_CONFIG_POOL_NAME, &pool_name));
+       } 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);
+
+
+#ifdef _KERNEL
+       hostid = zone_get_hostid(NULL);
+#else  /* _KERNEL */
+       /*
+        * We're emulating the system's hostid in userland, so we can't use
+        * zone_get_hostid().
+        */
+       (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 (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);
+               if (vd->vdev_isspare)
+                       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_SPARE,
+                           1ULL) == 0);
+               if (vd->vdev_islog)
+                       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_LOG,
+                           1ULL) == 0);
+               vd = vd->vdev_top;              /* label contains top config */
+       } else {
+               /*
+                * Only add the (potentially large) split information
+                * 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);
+       }
+
+       /*
+        * Add the top-level config.  We even add this on pools which
+        * don't support holes in the namespace.
+        */
+       vdev_top_config_generate(spa, config);
+
+       /*
+        * If we're splitting, record the original pool's guid.
+        */
+       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);
+       }
+
+       nvroot = vdev_config_generate(spa, vd, getstats, 0);
+       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
+       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);
+
+       if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
+               ddt_histogram_t *ddh;
+               ddt_stat_t *dds;
+               ddt_object_t *ddo;
+
+               ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
+               ddt_get_dedup_histogram(spa, ddh);
+               VERIFY(nvlist_add_uint64_array(config,
+                   ZPOOL_CONFIG_DDT_HISTOGRAM,
+                   (uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t)) == 0);
+               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,
+                   ZPOOL_CONFIG_DDT_OBJ_STATS,
+                   (uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t)) == 0);
+               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,
+                   ZPOOL_CONFIG_DDT_STATS,
+                   (uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t)) == 0);
+               kmem_free(dds, sizeof (ddt_stat_t));
+       }
+
+       if (locked)
+               spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG);
+
+       return (config);
+}
+
+/*
+ * Update all disk labels, generate a fresh config based on the current
+ * in-core state, and sync the global config cache (do not sync the config
+ * cache if this is a booting rootpool).
+ */
+void
+spa_config_update(spa_t *spa, int what)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       uint64_t txg;
+       int c;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       txg = spa_last_synced_txg(spa) + 1;
+       if (what == SPA_CONFIG_UPDATE_POOL) {
+               vdev_config_dirty(rvd);
+       } else {
+               /*
+                * If we have top-level vdevs that were added but have
+                * not yet been prepared for allocation, do that now.
+                * (It's safe now because the config cache is up to date,
+                * so it will be able to translate the new DVAs.)
+                * See comments in spa_vdev_add() for full details.
+                */
+               for (c = 0; c < rvd->vdev_children; c++) {
+                       vdev_t *tvd = rvd->vdev_child[c];
+                       if (tvd->vdev_ms_array == 0)
+                               vdev_metaslab_set_size(tvd);
+                       vdev_expand(tvd, txg);
+               }
+       }
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       /*
+        * Wait for the mosconfig to be regenerated and synced.
+        */
+       txg_wait_synced(spa->spa_dsl_pool, txg);
+
+       /*
+        * Update the global config cache to reflect the new mosconfig.
+        */
+       if (!spa->spa_is_root)
+               spa_config_sync(spa, B_FALSE, what != SPA_CONFIG_UPDATE_POOL);
+
+       if (what == SPA_CONFIG_UPDATE_POOL)
+               spa_config_update(spa, SPA_CONFIG_UPDATE_VDEVS);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(spa_config_sync);
+EXPORT_SYMBOL(spa_config_load);
+EXPORT_SYMBOL(spa_all_configs);
+EXPORT_SYMBOL(spa_config_set);
+EXPORT_SYMBOL(spa_config_generate);
+EXPORT_SYMBOL(spa_config_update);
+
+module_param(spa_config_path, charp, 0444);
+MODULE_PARM_DESC(spa_config_path, "SPA config file (/etc/zfs/zpool.cache)");
+
+module_param(zfs_autoimport_disable, int, 0644);
+MODULE_PARM_DESC(zfs_autoimport_disable, "Disable pool import at module load");
+
+#endif
diff --git a/zfs/module/zfs/spa_errlog.c b/zfs/module/zfs/spa_errlog.c
new file mode 100644 (file)
index 0000000..925e2af
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * Routines to manage the on-disk persistent error log.
+ *
+ * Each pool stores a log of all logical data errors seen during normal
+ * operation.  This is actually the union of two distinct logs: the last log,
+ * and the current log.  All errors seen are logged to the current log.  When a
+ * scrub completes, the current log becomes the last log, the last log is thrown
+ * out, and the current log is reinitialized.  This way, if an error is somehow
+ * corrected, a new scrub will show that that it no longer exists, and will be
+ * deleted from the log when the scrub completes.
+ *
+ * The log is stored using a ZAP object whose key is a string form of the
+ * zbookmark_phys tuple (objset, object, level, blkid), and whose contents is an
+ * optional 'objset:object' human-readable string describing the data.  When an
+ * error is first logged, this string will be empty, indicating that no name is
+ * known.  This prevents us from having to issue a potentially large amount of
+ * I/O to discover the object name during an error path.  Instead, we do the
+ * calculation when the data is requested, storing the result so future queries
+ * will be faster.
+ *
+ * This log is then shipped into an nvlist where the key is the dataset name and
+ * the value is the object name.  Userland is then responsible for uniquifying
+ * this list and displaying it to the user.
+ */
+
+#include <sys/dmu_tx.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/zap.h>
+#include <sys/zio.h>
+
+
+/*
+ * Convert a bookmark to a string.
+ */
+static void
+bookmark_to_name(zbookmark_phys_t *zb, char *buf, size_t len)
+{
+       (void) snprintf(buf, len, "%llx:%llx:%llx:%llx",
+           (u_longlong_t)zb->zb_objset, (u_longlong_t)zb->zb_object,
+           (u_longlong_t)zb->zb_level, (u_longlong_t)zb->zb_blkid);
+}
+
+/*
+ * Convert a string to a bookmark
+ */
+#ifdef _KERNEL
+static void
+name_to_bookmark(char *buf, zbookmark_phys_t *zb)
+{
+       zb->zb_objset = strtonum(buf, &buf);
+       ASSERT(*buf == ':');
+       zb->zb_object = strtonum(buf + 1, &buf);
+       ASSERT(*buf == ':');
+       zb->zb_level = (int)strtonum(buf + 1, &buf);
+       ASSERT(*buf == ':');
+       zb->zb_blkid = strtonum(buf + 1, &buf);
+       ASSERT(*buf == '\0');
+}
+#endif
+
+/*
+ * Log an uncorrectable error to the persistent error log.  We add it to the
+ * spa's list of pending errors.  The changes are actually synced out to disk
+ * during spa_errlog_sync().
+ */
+void
+spa_log_error(spa_t *spa, zio_t *zio)
+{
+       zbookmark_phys_t *zb = &zio->io_logical->io_bookmark;
+       spa_error_entry_t search;
+       spa_error_entry_t *new;
+       avl_tree_t *tree;
+       avl_index_t where;
+
+       /*
+        * If we are trying to import a pool, ignore any errors, as we won't be
+        * writing to the pool any time soon.
+        */
+       if (spa_load_state(spa) == SPA_LOAD_TRYIMPORT)
+               return;
+
+       mutex_enter(&spa->spa_errlist_lock);
+
+       /*
+        * If we have had a request to rotate the log, log it to the next list
+        * instead of the current one.
+        */
+       if (spa->spa_scrub_active || spa->spa_scrub_finished)
+               tree = &spa->spa_errlist_scrub;
+       else
+               tree = &spa->spa_errlist_last;
+
+       search.se_bookmark = *zb;
+       if (avl_find(tree, &search, &where) != NULL) {
+               mutex_exit(&spa->spa_errlist_lock);
+               return;
+       }
+
+       new = kmem_zalloc(sizeof (spa_error_entry_t), KM_SLEEP);
+       new->se_bookmark = *zb;
+       avl_insert(tree, new, where);
+
+       mutex_exit(&spa->spa_errlist_lock);
+}
+
+/*
+ * Return the number of errors currently in the error log.  This is actually the
+ * sum of both the last log and the current log, since we don't know the union
+ * of these logs until we reach userland.
+ */
+uint64_t
+spa_get_errlog_size(spa_t *spa)
+{
+       uint64_t total = 0, count;
+
+       mutex_enter(&spa->spa_errlog_lock);
+       if (spa->spa_errlog_scrub != 0 &&
+           zap_count(spa->spa_meta_objset, spa->spa_errlog_scrub,
+           &count) == 0)
+               total += count;
+
+       if (spa->spa_errlog_last != 0 && !spa->spa_scrub_finished &&
+           zap_count(spa->spa_meta_objset, spa->spa_errlog_last,
+           &count) == 0)
+               total += count;
+       mutex_exit(&spa->spa_errlog_lock);
+
+       mutex_enter(&spa->spa_errlist_lock);
+       total += avl_numnodes(&spa->spa_errlist_last);
+       total += avl_numnodes(&spa->spa_errlist_scrub);
+       mutex_exit(&spa->spa_errlist_lock);
+
+       return (total);
+}
+
+#ifdef _KERNEL
+static int
+process_error_log(spa_t *spa, uint64_t obj, void *addr, size_t *count)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       zbookmark_phys_t zb;
+
+       if (obj == 0)
+               return (0);
+
+       for (zap_cursor_init(&zc, spa->spa_meta_objset, obj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+
+               if (*count == 0) {
+                       zap_cursor_fini(&zc);
+                       return (SET_ERROR(ENOMEM));
+               }
+
+               name_to_bookmark(za.za_name, &zb);
+
+               if (copyout(&zb, (char *)addr +
+                   (*count - 1) * sizeof (zbookmark_phys_t),
+                   sizeof (zbookmark_phys_t)) != 0) {
+                       zap_cursor_fini(&zc);
+                       return (SET_ERROR(EFAULT));
+               }
+
+               *count -= 1;
+       }
+
+       zap_cursor_fini(&zc);
+
+       return (0);
+}
+
+static int
+process_error_list(avl_tree_t *list, void *addr, size_t *count)
+{
+       spa_error_entry_t *se;
+
+       for (se = avl_first(list); se != NULL; se = AVL_NEXT(list, se)) {
+
+               if (*count == 0)
+                       return (SET_ERROR(ENOMEM));
+
+               if (copyout(&se->se_bookmark, (char *)addr +
+                   (*count - 1) * sizeof (zbookmark_phys_t),
+                   sizeof (zbookmark_phys_t)) != 0)
+                       return (SET_ERROR(EFAULT));
+
+               *count -= 1;
+       }
+
+       return (0);
+}
+#endif
+
+/*
+ * Copy all known errors to userland as an array of bookmarks.  This is
+ * actually a union of the on-disk last log and current log, as well as any
+ * pending error requests.
+ *
+ * Because the act of reading the on-disk log could cause errors to be
+ * generated, we have two separate locks: one for the error log and one for the
+ * in-core error lists.  We only need the error list lock to log and error, so
+ * we grab the error log lock while we read the on-disk logs, and only pick up
+ * the error list lock when we are finished.
+ */
+int
+spa_get_errlog(spa_t *spa, void *uaddr, size_t *count)
+{
+       int ret = 0;
+
+#ifdef _KERNEL
+       mutex_enter(&spa->spa_errlog_lock);
+
+       ret = process_error_log(spa, spa->spa_errlog_scrub, uaddr, count);
+
+       if (!ret && !spa->spa_scrub_finished)
+               ret = process_error_log(spa, spa->spa_errlog_last, uaddr,
+                   count);
+
+       mutex_enter(&spa->spa_errlist_lock);
+       if (!ret)
+               ret = process_error_list(&spa->spa_errlist_scrub, uaddr,
+                   count);
+       if (!ret)
+               ret = process_error_list(&spa->spa_errlist_last, uaddr,
+                   count);
+       mutex_exit(&spa->spa_errlist_lock);
+
+       mutex_exit(&spa->spa_errlog_lock);
+#endif
+
+       return (ret);
+}
+
+/*
+ * Called when a scrub completes.  This simply set a bit which tells which AVL
+ * tree to add new errors.  spa_errlog_sync() is responsible for actually
+ * syncing the changes to the underlying objects.
+ */
+void
+spa_errlog_rotate(spa_t *spa)
+{
+       mutex_enter(&spa->spa_errlist_lock);
+       spa->spa_scrub_finished = B_TRUE;
+       mutex_exit(&spa->spa_errlist_lock);
+}
+
+/*
+ * Discard any pending errors from the spa_t.  Called when unloading a faulted
+ * pool, as the errors encountered during the open cannot be synced to disk.
+ */
+void
+spa_errlog_drain(spa_t *spa)
+{
+       spa_error_entry_t *se;
+       void *cookie;
+
+       mutex_enter(&spa->spa_errlist_lock);
+
+       cookie = NULL;
+       while ((se = avl_destroy_nodes(&spa->spa_errlist_last,
+           &cookie)) != NULL)
+               kmem_free(se, sizeof (spa_error_entry_t));
+       cookie = NULL;
+       while ((se = avl_destroy_nodes(&spa->spa_errlist_scrub,
+           &cookie)) != NULL)
+               kmem_free(se, sizeof (spa_error_entry_t));
+
+       mutex_exit(&spa->spa_errlist_lock);
+}
+
+/*
+ * Process a list of errors into the current on-disk log.
+ */
+static void
+sync_error_list(spa_t *spa, avl_tree_t *t, uint64_t *obj, dmu_tx_t *tx)
+{
+       spa_error_entry_t *se;
+       char buf[64];
+       void *cookie;
+
+       if (avl_numnodes(t) != 0) {
+               /* create log if necessary */
+               if (*obj == 0)
+                       *obj = zap_create(spa->spa_meta_objset,
+                           DMU_OT_ERROR_LOG, DMU_OT_NONE,
+                           0, tx);
+
+               /* add errors to the current log */
+               for (se = avl_first(t); se != NULL; se = AVL_NEXT(t, se)) {
+                       char *name = se->se_name ? se->se_name : "";
+
+                       bookmark_to_name(&se->se_bookmark, buf, sizeof (buf));
+
+                       (void) zap_update(spa->spa_meta_objset,
+                           *obj, buf, 1, strlen(name) + 1, name, tx);
+               }
+
+               /* purge the error list */
+               cookie = NULL;
+               while ((se = avl_destroy_nodes(t, &cookie)) != NULL)
+                       kmem_free(se, sizeof (spa_error_entry_t));
+       }
+}
+
+/*
+ * Sync the error log out to disk.  This is a little tricky because the act of
+ * writing the error log requires the spa_errlist_lock.  So, we need to lock the
+ * error lists, take a copy of the lists, and then reinitialize them.  Then, we
+ * drop the error list lock and take the error log lock, at which point we
+ * do the errlog processing.  Then, if we encounter an I/O error during this
+ * process, we can successfully add the error to the list.  Note that this will
+ * result in the perpetual recycling of errors, but it is an unlikely situation
+ * and not a performance critical operation.
+ */
+void
+spa_errlog_sync(spa_t *spa, uint64_t txg)
+{
+       dmu_tx_t *tx;
+       avl_tree_t scrub, last;
+       int scrub_finished;
+
+       mutex_enter(&spa->spa_errlist_lock);
+
+       /*
+        * Bail out early under normal circumstances.
+        */
+       if (avl_numnodes(&spa->spa_errlist_scrub) == 0 &&
+           avl_numnodes(&spa->spa_errlist_last) == 0 &&
+           !spa->spa_scrub_finished) {
+               mutex_exit(&spa->spa_errlist_lock);
+               return;
+       }
+
+       spa_get_errlists(spa, &last, &scrub);
+       scrub_finished = spa->spa_scrub_finished;
+       spa->spa_scrub_finished = B_FALSE;
+
+       mutex_exit(&spa->spa_errlist_lock);
+       mutex_enter(&spa->spa_errlog_lock);
+
+       tx = dmu_tx_create_assigned(spa->spa_dsl_pool, txg);
+
+       /*
+        * Sync out the current list of errors.
+        */
+       sync_error_list(spa, &last, &spa->spa_errlog_last, tx);
+
+       /*
+        * Rotate the log if necessary.
+        */
+       if (scrub_finished) {
+               if (spa->spa_errlog_last != 0)
+                       VERIFY(dmu_object_free(spa->spa_meta_objset,
+                           spa->spa_errlog_last, tx) == 0);
+               spa->spa_errlog_last = spa->spa_errlog_scrub;
+               spa->spa_errlog_scrub = 0;
+
+               sync_error_list(spa, &scrub, &spa->spa_errlog_last, tx);
+       }
+
+       /*
+        * Sync out any pending scrub errors.
+        */
+       sync_error_list(spa, &scrub, &spa->spa_errlog_scrub, tx);
+
+       /*
+        * Update the MOS to reflect the new values.
+        */
+       (void) zap_update(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_ERRLOG_LAST, sizeof (uint64_t), 1,
+           &spa->spa_errlog_last, tx);
+       (void) zap_update(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_ERRLOG_SCRUB, sizeof (uint64_t), 1,
+           &spa->spa_errlog_scrub, tx);
+
+       dmu_tx_commit(tx);
+
+       mutex_exit(&spa->spa_errlog_lock);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+/* error handling */
+EXPORT_SYMBOL(spa_log_error);
+EXPORT_SYMBOL(spa_get_errlog_size);
+EXPORT_SYMBOL(spa_get_errlog);
+EXPORT_SYMBOL(spa_errlog_rotate);
+EXPORT_SYMBOL(spa_errlog_drain);
+EXPORT_SYMBOL(spa_errlog_sync);
+EXPORT_SYMBOL(spa_get_errlists);
+#endif
diff --git a/zfs/module/zfs/spa_history.c b/zfs/module/zfs/spa_history.c
new file mode 100644 (file)
index 0000000..01aa464
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/zap.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dmu_tx.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/cmn_err.h>
+#include <sys/sunddi.h>
+#include <sys/cred.h>
+#include "zfs_comutil.h"
+#ifdef _KERNEL
+#include <sys/zone.h>
+#endif
+
+/*
+ * Routines to manage the on-disk history log.
+ *
+ * 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
+ * "packed record length" is the packed length of the "record nvlist" stored
+ * as a little endian uint64_t.
+ *
+ * The log is implemented as a ring buffer, though the original creation
+ * of the pool ('zpool create') is never overwritten.
+ *
+ * The history log is tracked as object 'spa_t::spa_history'.  The bonus buffer
+ * of 'spa_history' stores the offsets for logging/retrieving history as
+ * 'spa_history_phys_t'.  'sh_pool_create_len' is the ending offset in bytes of
+ * where the 'zpool create' record is stored.  This allows us to never
+ * overwrite the original creation of the pool.  'sh_phys_max_off' is the
+ * physical ending offset in bytes of the log.  This tells you the length of
+ * the buffer. 'sh_eof' is the logical EOF (in bytes).  Whenever a record
+ * is added, 'sh_eof' is incremented by the the size of the record.
+ * 'sh_eof' is never decremented.  'sh_bof' is the logical BOF (in bytes).
+ * This is where the consumer should start reading from after reading in
+ * the 'zpool create' portion of the log.
+ *
+ * 'sh_records_lost' keeps track of how many records have been overwritten
+ * and permanently lost.
+ */
+
+/* convert a logical offset to physical */
+static uint64_t
+spa_history_log_to_phys(uint64_t log_off, spa_history_phys_t *shpp)
+{
+       uint64_t phys_len;
+
+       phys_len = shpp->sh_phys_max_off - shpp->sh_pool_create_len;
+       return ((log_off - shpp->sh_pool_create_len) % phys_len
+           + shpp->sh_pool_create_len);
+}
+
+void
+spa_history_create_obj(spa_t *spa, dmu_tx_t *tx)
+{
+       dmu_buf_t *dbp;
+       spa_history_phys_t *shpp;
+       objset_t *mos = spa->spa_meta_objset;
+
+       ASSERT(spa->spa_history == 0);
+       spa->spa_history = dmu_object_alloc(mos, DMU_OT_SPA_HISTORY,
+           SPA_OLD_MAXBLOCKSIZE, DMU_OT_SPA_HISTORY_OFFSETS,
+           sizeof (spa_history_phys_t), tx);
+
+       VERIFY(zap_add(mos, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_HISTORY, sizeof (uint64_t), 1,
+           &spa->spa_history, tx) == 0);
+
+       VERIFY(0 == dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp));
+       ASSERT(dbp->db_size >= sizeof (spa_history_phys_t));
+
+       shpp = dbp->db_data;
+       dmu_buf_will_dirty(dbp, tx);
+
+       /*
+        * Figure out maximum size of history log.  We set it at
+        * 0.1% of pool size, with a max of 1G and min of 128KB.
+        */
+       shpp->sh_phys_max_off =
+           metaslab_class_get_dspace(spa_normal_class(spa)) / 1000;
+       shpp->sh_phys_max_off = MIN(shpp->sh_phys_max_off, 1<<30);
+       shpp->sh_phys_max_off = MAX(shpp->sh_phys_max_off, 128<<10);
+
+       dmu_buf_rele(dbp, FTAG);
+}
+
+/*
+ * Change 'sh_bof' to the beginning of the next record.
+ */
+static int
+spa_history_advance_bof(spa_t *spa, spa_history_phys_t *shpp)
+{
+       objset_t *mos = spa->spa_meta_objset;
+       uint64_t firstread, reclen, phys_bof;
+       char buf[sizeof (reclen)];
+       int err;
+
+       phys_bof = spa_history_log_to_phys(shpp->sh_bof, shpp);
+       firstread = MIN(sizeof (reclen), shpp->sh_phys_max_off - phys_bof);
+
+       if ((err = dmu_read(mos, spa->spa_history, phys_bof, firstread,
+           buf, DMU_READ_PREFETCH)) != 0)
+               return (err);
+       if (firstread != sizeof (reclen)) {
+               if ((err = dmu_read(mos, spa->spa_history,
+                   shpp->sh_pool_create_len, sizeof (reclen) - firstread,
+                   buf + firstread, DMU_READ_PREFETCH)) != 0)
+                       return (err);
+       }
+
+       reclen = LE_64(*((uint64_t *)buf));
+       shpp->sh_bof += reclen + sizeof (reclen);
+       shpp->sh_records_lost++;
+       return (0);
+}
+
+static int
+spa_history_write(spa_t *spa, void *buf, uint64_t len, spa_history_phys_t *shpp,
+    dmu_tx_t *tx)
+{
+       uint64_t firstwrite, phys_eof;
+       objset_t *mos = spa->spa_meta_objset;
+       int err;
+
+       ASSERT(MUTEX_HELD(&spa->spa_history_lock));
+
+       /* see if we need to reset logical BOF */
+       while (shpp->sh_phys_max_off - shpp->sh_pool_create_len -
+           (shpp->sh_eof - shpp->sh_bof) <= len) {
+               if ((err = spa_history_advance_bof(spa, shpp)) != 0) {
+                       return (err);
+               }
+       }
+
+       phys_eof = spa_history_log_to_phys(shpp->sh_eof, shpp);
+       firstwrite = MIN(len, shpp->sh_phys_max_off - phys_eof);
+       shpp->sh_eof += len;
+       dmu_write(mos, spa->spa_history, phys_eof, firstwrite, buf, tx);
+
+       len -= firstwrite;
+       if (len > 0) {
+               /* write out the rest at the beginning of physical file */
+               dmu_write(mos, spa->spa_history, shpp->sh_pool_create_len,
+                   len, (char *)buf + firstwrite, tx);
+       }
+
+       return (0);
+}
+
+static char *
+spa_history_zone(void)
+{
+#ifdef _KERNEL
+#ifdef HAVE_SPL
+       return ("linux");
+#else
+       return (curproc->p_zone->zone_name);
+#endif
+#else
+       return (NULL);
+#endif
+}
+
+/*
+ * Write out a history event.
+ */
+/*ARGSUSED*/
+static void
+spa_history_log_sync(void *arg, dmu_tx_t *tx)
+{
+       nvlist_t        *nvl = arg;
+       spa_t           *spa = dmu_tx_pool(tx)->dp_spa;
+       objset_t        *mos = spa->spa_meta_objset;
+       dmu_buf_t       *dbp;
+       spa_history_phys_t *shpp;
+       size_t          reclen;
+       uint64_t        le_len;
+       char            *record_packed = NULL;
+       int             ret;
+
+       /*
+        * If we have an older pool that doesn't have a command
+        * history object, create it now.
+        */
+       mutex_enter(&spa->spa_history_lock);
+       if (!spa->spa_history)
+               spa_history_create_obj(spa, tx);
+       mutex_exit(&spa->spa_history_lock);
+
+       /*
+        * Get the offset of where we need to write via the bonus buffer.
+        * Update the offset when the write completes.
+        */
+       VERIFY0(dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp));
+       shpp = dbp->db_data;
+
+       dmu_buf_will_dirty(dbp, tx);
+
+#ifdef ZFS_DEBUG
+       {
+               dmu_object_info_t doi;
+               dmu_object_info_from_db(dbp, &doi);
+               ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS);
+       }
+#endif
+
+       fnvlist_add_uint64(nvl, ZPOOL_HIST_TIME, gethrestime_sec());
+       fnvlist_add_string(nvl, ZPOOL_HIST_HOST, utsname()->nodename);
+
+       if (nvlist_exists(nvl, ZPOOL_HIST_CMD)) {
+               zfs_dbgmsg("command: %s",
+                   fnvlist_lookup_string(nvl, ZPOOL_HIST_CMD));
+       } else if (nvlist_exists(nvl, ZPOOL_HIST_INT_NAME)) {
+               if (nvlist_exists(nvl, ZPOOL_HIST_DSNAME)) {
+                       zfs_dbgmsg("txg %lld %s %s (id %llu) %s",
+                           fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG),
+                           fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
+                           fnvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME),
+                           fnvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID),
+                           fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
+               } else {
+                       zfs_dbgmsg("txg %lld %s %s",
+                           fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG),
+                           fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
+                           fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
+               }
+       } else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) {
+               zfs_dbgmsg("ioctl %s",
+                   fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL));
+       }
+
+       VERIFY3U(nvlist_pack(nvl, &record_packed, &reclen, NV_ENCODE_NATIVE,
+           KM_SLEEP), ==, 0);
+
+       mutex_enter(&spa->spa_history_lock);
+
+       /* write out the packed length as little endian */
+       le_len = LE_64((uint64_t)reclen);
+       ret = spa_history_write(spa, &le_len, sizeof (le_len), shpp, tx);
+       if (!ret)
+               ret = spa_history_write(spa, record_packed, reclen, shpp, tx);
+
+       /* The first command is the create, which we keep forever */
+       if (ret == 0 && shpp->sh_pool_create_len == 0 &&
+           nvlist_exists(nvl, ZPOOL_HIST_CMD)) {
+               shpp->sh_pool_create_len = shpp->sh_bof = shpp->sh_eof;
+       }
+
+       mutex_exit(&spa->spa_history_lock);
+       fnvlist_pack_free(record_packed, reclen);
+       dmu_buf_rele(dbp, FTAG);
+       fnvlist_free(nvl);
+}
+
+/*
+ * Write out a history event.
+ */
+int
+spa_history_log(spa_t *spa, const char *msg)
+{
+       int err;
+       nvlist_t *nvl = fnvlist_alloc();
+
+       fnvlist_add_string(nvl, ZPOOL_HIST_CMD, msg);
+       err = spa_history_log_nvl(spa, nvl);
+       fnvlist_free(nvl);
+       return (err);
+}
+
+int
+spa_history_log_nvl(spa_t *spa, nvlist_t *nvl)
+{
+       int err = 0;
+       dmu_tx_t *tx;
+       nvlist_t *nvarg;
+
+       if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY || !spa_writeable(spa))
+               return (SET_ERROR(EINVAL));
+
+       tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err) {
+               dmu_tx_abort(tx);
+               return (err);
+       }
+
+       VERIFY0(nvlist_dup(nvl, &nvarg, KM_SLEEP));
+       if (spa_history_zone() != NULL) {
+               fnvlist_add_string(nvarg, ZPOOL_HIST_ZONE,
+                   spa_history_zone());
+       }
+       fnvlist_add_uint64(nvarg, ZPOOL_HIST_WHO, crgetruid(CRED()));
+
+       /* Kick this off asynchronously; errors are ignored. */
+       dsl_sync_task_nowait(spa_get_dsl(spa), spa_history_log_sync,
+           nvarg, 0, ZFS_SPACE_CHECK_NONE, tx);
+       dmu_tx_commit(tx);
+
+       /* spa_history_log_sync will free nvl */
+       return (err);
+
+}
+
+/*
+ * Read out the command history.
+ */
+int
+spa_history_get(spa_t *spa, uint64_t *offp, uint64_t *len, char *buf)
+{
+       objset_t *mos = spa->spa_meta_objset;
+       dmu_buf_t *dbp;
+       uint64_t read_len, phys_read_off, phys_eof;
+       uint64_t leftover = 0;
+       spa_history_phys_t *shpp;
+       int err;
+
+       /*
+        * If the command history doesn't exist (older pool),
+        * that's ok, just return ENOENT.
+        */
+       if (!spa->spa_history)
+               return (SET_ERROR(ENOENT));
+
+       /*
+        * The history is logged asynchronously, so when they request
+        * the first chunk of history, make sure everything has been
+        * synced to disk so that we get it.
+        */
+       if (*offp == 0 && spa_writeable(spa))
+               txg_wait_synced(spa_get_dsl(spa), 0);
+
+       if ((err = dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp)) != 0)
+               return (err);
+       shpp = dbp->db_data;
+
+#ifdef ZFS_DEBUG
+       {
+               dmu_object_info_t doi;
+               dmu_object_info_from_db(dbp, &doi);
+               ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS);
+       }
+#endif
+
+       mutex_enter(&spa->spa_history_lock);
+       phys_eof = spa_history_log_to_phys(shpp->sh_eof, shpp);
+
+       if (*offp < shpp->sh_pool_create_len) {
+               /* read in just the zpool create history */
+               phys_read_off = *offp;
+               read_len = MIN(*len, shpp->sh_pool_create_len -
+                   phys_read_off);
+       } else {
+               /*
+                * Need to reset passed in offset to BOF if the passed in
+                * offset has since been overwritten.
+                */
+               *offp = MAX(*offp, shpp->sh_bof);
+               phys_read_off = spa_history_log_to_phys(*offp, shpp);
+
+               /*
+                * Read up to the minimum of what the user passed down or
+                * the EOF (physical or logical).  If we hit physical EOF,
+                * use 'leftover' to read from the physical BOF.
+                */
+               if (phys_read_off <= phys_eof) {
+                       read_len = MIN(*len, phys_eof - phys_read_off);
+               } else {
+                       read_len = MIN(*len,
+                           shpp->sh_phys_max_off - phys_read_off);
+                       if (phys_read_off + *len > shpp->sh_phys_max_off) {
+                               leftover = MIN(*len - read_len,
+                                   phys_eof - shpp->sh_pool_create_len);
+                       }
+               }
+       }
+
+       /* offset for consumer to use next */
+       *offp += read_len + leftover;
+
+       /* tell the consumer how much you actually read */
+       *len = read_len + leftover;
+
+       if (read_len == 0) {
+               mutex_exit(&spa->spa_history_lock);
+               dmu_buf_rele(dbp, FTAG);
+               return (0);
+       }
+
+       err = dmu_read(mos, spa->spa_history, phys_read_off, read_len, buf,
+           DMU_READ_PREFETCH);
+       if (leftover && err == 0) {
+               err = dmu_read(mos, spa->spa_history, shpp->sh_pool_create_len,
+                   leftover, buf + read_len, DMU_READ_PREFETCH);
+       }
+       mutex_exit(&spa->spa_history_lock);
+
+       dmu_buf_rele(dbp, FTAG);
+       return (err);
+}
+
+/*
+ * The nvlist will be consumed by this call.
+ */
+static void
+log_internal(nvlist_t *nvl, const char *operation, spa_t *spa,
+    dmu_tx_t *tx, const char *fmt, va_list adx)
+{
+       char *msg;
+
+       /*
+        * If this is part of creating a pool, not everything is
+        * initialized yet, so don't bother logging the internal events.
+        * Likewise if the pool is not writeable.
+        */
+       if (tx->tx_txg == TXG_INITIAL || !spa_writeable(spa)) {
+               fnvlist_free(nvl);
+               return;
+       }
+
+       msg = kmem_vasprintf(fmt, adx);
+       fnvlist_add_string(nvl, ZPOOL_HIST_INT_STR, msg);
+       strfree(msg);
+
+       fnvlist_add_string(nvl, ZPOOL_HIST_INT_NAME, operation);
+       fnvlist_add_uint64(nvl, ZPOOL_HIST_TXG, tx->tx_txg);
+
+       if (dmu_tx_is_syncing(tx)) {
+               spa_history_log_sync(nvl, tx);
+       } else {
+               dsl_sync_task_nowait(spa_get_dsl(spa),
+                   spa_history_log_sync, nvl, 0, ZFS_SPACE_CHECK_NONE, tx);
+       }
+       /* spa_history_log_sync() will free nvl */
+}
+
+void
+spa_history_log_internal(spa_t *spa, const char *operation,
+    dmu_tx_t *tx, const char *fmt, ...)
+{
+       dmu_tx_t *htx = tx;
+       va_list adx;
+
+       /* create a tx if we didn't get one */
+       if (tx == NULL) {
+               htx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
+               if (dmu_tx_assign(htx, TXG_WAIT) != 0) {
+                       dmu_tx_abort(htx);
+                       return;
+               }
+       }
+
+       va_start(adx, fmt);
+       log_internal(fnvlist_alloc(), operation, spa, htx, fmt, adx);
+       va_end(adx);
+
+       /* if we didn't get a tx from the caller, commit the one we made */
+       if (tx == NULL)
+               dmu_tx_commit(htx);
+}
+
+void
+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];
+       nvlist_t *nvl = fnvlist_alloc();
+
+       ASSERT(tx != NULL);
+
+       dsl_dataset_name(ds, namebuf);
+       fnvlist_add_string(nvl, ZPOOL_HIST_DSNAME, namebuf);
+       fnvlist_add_uint64(nvl, ZPOOL_HIST_DSID, ds->ds_object);
+
+       va_start(adx, fmt);
+       log_internal(nvl, operation, dsl_dataset_get_spa(ds), tx, fmt, adx);
+       va_end(adx);
+}
+
+void
+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];
+       nvlist_t *nvl = fnvlist_alloc();
+
+       ASSERT(tx != NULL);
+
+       dsl_dir_name(dd, namebuf);
+       fnvlist_add_string(nvl, ZPOOL_HIST_DSNAME, namebuf);
+       fnvlist_add_uint64(nvl, ZPOOL_HIST_DSID,
+           dsl_dir_phys(dd)->dd_head_dataset_obj);
+
+       va_start(adx, fmt);
+       log_internal(nvl, operation, dd->dd_pool->dp_spa, tx, fmt, adx);
+       va_end(adx);
+}
+
+void
+spa_history_log_version(spa_t *spa, const char *operation)
+{
+       utsname_t *u = utsname();
+
+       spa_history_log_internal(spa, operation, NULL,
+           "pool version %llu; software version %llu/%d; uts %s %s %s %s",
+           (u_longlong_t)spa_version(spa), SPA_VERSION, ZPL_VERSION,
+           u->nodename, u->release, u->version, u->machine);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(spa_history_create_obj);
+EXPORT_SYMBOL(spa_history_get);
+EXPORT_SYMBOL(spa_history_log);
+EXPORT_SYMBOL(spa_history_log_internal);
+EXPORT_SYMBOL(spa_history_log_version);
+#endif
diff --git a/zfs/module/zfs/spa_misc.c b/zfs/module/zfs/spa_misc.c
new file mode 100644 (file)
index 0000000..409dce1
--- /dev/null
@@ -0,0 +1,2100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa_impl.h>
+#include <sys/zio.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/zap.h>
+#include <sys/zil.h>
+#include <sys/vdev_impl.h>
+#include <sys/vdev_file.h>
+#include <sys/metaslab.h>
+#include <sys/uberblock_impl.h>
+#include <sys/txg.h>
+#include <sys/avl.h>
+#include <sys/unique.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/fm/util.h>
+#include <sys/dsl_scan.h>
+#include <sys/fs/zfs.h>
+#include <sys/metaslab_impl.h>
+#include <sys/arc.h>
+#include <sys/ddt.h>
+#include <sys/kstat.h>
+#include "zfs_prop.h"
+#include "zfeature_common.h"
+
+/*
+ * SPA locking
+ *
+ * There are four basic locks for managing spa_t structures:
+ *
+ * spa_namespace_lock (global mutex)
+ *
+ *     This lock must be acquired to do any of the following:
+ *
+ *             - Lookup a spa_t by name
+ *             - Add or remove a spa_t from the namespace
+ *             - Increase spa_refcount from non-zero
+ *             - Check if spa_refcount is zero
+ *             - Rename a spa_t
+ *             - add/remove/attach/detach devices
+ *             - Held for the duration of create/destroy/import/export
+ *
+ *     It does not need to handle recursion.  A create or destroy may
+ *     reference objects (files or zvols) in other pools, but by
+ *     definition they must have an existing reference, and will never need
+ *     to lookup a spa_t by name.
+ *
+ * spa_refcount (per-spa refcount_t protected by mutex)
+ *
+ *     This reference count keep track of any active users of the spa_t.  The
+ *     spa_t cannot be destroyed or freed while this is non-zero.  Internally,
+ *     the refcount is never really 'zero' - opening a pool implicitly keeps
+ *     some references in the DMU.  Internally we check against spa_minref, but
+ *     present the image of a zero/non-zero value to consumers.
+ *
+ * spa_config_lock[] (per-spa array of rwlocks)
+ *
+ *     This protects the spa_t from config changes, and must be held in
+ *     the following circumstances:
+ *
+ *             - RW_READER to perform I/O to the spa
+ *             - RW_WRITER to change the vdev config
+ *
+ * The locking order is fairly straightforward:
+ *
+ *             spa_namespace_lock      ->      spa_refcount
+ *
+ *     The namespace lock must be acquired to increase the refcount from 0
+ *     or to check if it is zero.
+ *
+ *             spa_refcount            ->      spa_config_lock[]
+ *
+ *     There must be at least one valid reference on the spa_t to acquire
+ *     the config lock.
+ *
+ *             spa_namespace_lock      ->      spa_config_lock[]
+ *
+ *     The namespace lock must always be taken before the config lock.
+ *
+ *
+ * The spa_namespace_lock can be acquired directly and is globally visible.
+ *
+ * The namespace is manipulated using the following functions, all of which
+ * require the spa_namespace_lock to be held.
+ *
+ *     spa_lookup()            Lookup a spa_t by name.
+ *
+ *     spa_add()               Create a new spa_t in the namespace.
+ *
+ *     spa_remove()            Remove a spa_t from the namespace.  This also
+ *                             frees up any memory associated with the spa_t.
+ *
+ *     spa_next()              Returns the next spa_t in the system, or the
+ *                             first if NULL is passed.
+ *
+ *     spa_evict_all()         Shutdown and remove all spa_t structures in
+ *                             the system.
+ *
+ *     spa_guid_exists()       Determine whether a pool/device guid exists.
+ *
+ * The spa_refcount is manipulated using the following functions:
+ *
+ *     spa_open_ref()          Adds a reference to the given spa_t.  Must be
+ *                             called with spa_namespace_lock held if the
+ *                             refcount is currently zero.
+ *
+ *     spa_close()             Remove a reference from the spa_t.  This will
+ *                             not free the spa_t or remove it from the
+ *                             namespace.  No locking is required.
+ *
+ *     spa_refcount_zero()     Returns true if the refcount is currently
+ *                             zero.  Must be called with spa_namespace_lock
+ *                             held.
+ *
+ * The spa_config_lock[] is an array of rwlocks, ordered as follows:
+ * SCL_CONFIG > SCL_STATE > SCL_ALLOC > SCL_ZIO > SCL_FREE > SCL_VDEV.
+ * spa_config_lock[] is manipulated with spa_config_{enter,exit,held}().
+ *
+ * To read the configuration, it suffices to hold one of these locks as reader.
+ * To modify the configuration, you must hold all locks as writer.  To modify
+ * vdev state without altering the vdev tree's topology (e.g. online/offline),
+ * you must hold SCL_STATE and SCL_ZIO as writer.
+ *
+ * We use these distinct config locks to avoid recursive lock entry.
+ * For example, spa_sync() (which holds SCL_CONFIG as reader) induces
+ * block allocations (SCL_ALLOC), which may require reading space maps
+ * from disk (dmu_read() -> zio_read() -> SCL_ZIO).
+ *
+ * The spa config locks cannot be normal rwlocks because we need the
+ * ability to hand off ownership.  For example, SCL_ZIO is acquired
+ * by the issuing thread and later released by an interrupt thread.
+ * They do, however, obey the usual write-wanted semantics to prevent
+ * writer (i.e. system administrator) starvation.
+ *
+ * The lock acquisition rules are as follows:
+ *
+ * SCL_CONFIG
+ *     Protects changes to the vdev tree topology, such as vdev
+ *     add/remove/attach/detach.  Protects the dirty config list
+ *     (spa_config_dirty_list) and the set of spares and l2arc devices.
+ *
+ * SCL_STATE
+ *     Protects changes to pool state and vdev state, such as vdev
+ *     online/offline/fault/degrade/clear.  Protects the dirty state list
+ *     (spa_state_dirty_list) and global pool state (spa_state).
+ *
+ * SCL_ALLOC
+ *     Protects changes to metaslab groups and classes.
+ *     Held as reader by metaslab_alloc() and metaslab_claim().
+ *
+ * SCL_ZIO
+ *     Held by bp-level zios (those which have no io_vd upon entry)
+ *     to prevent changes to the vdev tree.  The bp-level zio implicitly
+ *     protects all of its vdev child zios, which do not hold SCL_ZIO.
+ *
+ * SCL_FREE
+ *     Protects changes to metaslab groups and classes.
+ *     Held as reader by metaslab_free().  SCL_FREE is distinct from
+ *     SCL_ALLOC, and lower than SCL_ZIO, so that we can safely free
+ *     blocks in zio_done() while another i/o that holds either
+ *     SCL_ALLOC or SCL_ZIO is waiting for this i/o to complete.
+ *
+ * SCL_VDEV
+ *     Held as reader to prevent changes to the vdev tree during trivial
+ *     inquiries such as bp_get_dsize().  SCL_VDEV is distinct from the
+ *     other locks, and lower than all of them, to ensure that it's safe
+ *     to acquire regardless of caller context.
+ *
+ * In addition, the following rules apply:
+ *
+ * (a) spa_props_lock protects pool properties, spa_config and spa_config_list.
+ *     The lock ordering is SCL_CONFIG > spa_props_lock.
+ *
+ * (b) I/O operations on leaf vdevs.  For any zio operation that takes
+ *     an explicit vdev_t argument -- such as zio_ioctl(), zio_read_phys(),
+ *     or zio_write_phys() -- the caller must ensure that the config cannot
+ *     cannot change in the interim, and that the vdev cannot be reopened.
+ *     SCL_STATE as reader suffices for both.
+ *
+ * The vdev configuration is protected by spa_vdev_enter() / spa_vdev_exit().
+ *
+ *     spa_vdev_enter()        Acquire the namespace lock and the config lock
+ *                             for writing.
+ *
+ *     spa_vdev_exit()         Release the config lock, wait for all I/O
+ *                             to complete, sync the updated configs to the
+ *                             cache, and release the namespace lock.
+ *
+ * vdev state is protected by spa_vdev_state_enter() / spa_vdev_state_exit().
+ * Like spa_vdev_enter/exit, these are convenience wrappers -- the actual
+ * locking is, always, based on spa_namespace_lock and spa_config_lock[].
+ *
+ * spa_rename() is also implemented within this file since it requires
+ * manipulation of the namespace.
+ */
+
+static avl_tree_t spa_namespace_avl;
+kmutex_t spa_namespace_lock;
+static kcondvar_t spa_namespace_cv;
+int spa_max_replication_override = SPA_DVAS_PER_BP;
+
+static kmutex_t spa_spare_lock;
+static avl_tree_t spa_spare_avl;
+static kmutex_t spa_l2cache_lock;
+static avl_tree_t spa_l2cache_avl;
+
+kmem_cache_t *spa_buffer_pool;
+int spa_mode_global;
+
+#ifdef ZFS_DEBUG
+/* Everything except dprintf and spa is on by default in debug builds */
+int zfs_flags = ~(ZFS_DEBUG_DPRINTF | ZFS_DEBUG_SPA);
+#else
+int zfs_flags = 0;
+#endif
+
+/*
+ * zfs_recover can be set to nonzero to attempt to recover from
+ * otherwise-fatal errors, typically caused by on-disk corruption.  When
+ * set, calls to zfs_panic_recover() will turn into warning messages.
+ * This should only be used as a last resort, as it typically results
+ * in leaked space, or worse.
+ */
+int zfs_recover = B_FALSE;
+
+/*
+ * 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.
+ */
+int zfs_free_leak_on_eio = B_FALSE;
+
+/*
+ * 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 system panic.
+ */
+unsigned long zfs_deadman_synctime_ms = 1000000ULL;
+
+/*
+ * By default the deadman is enabled.
+ */
+int zfs_deadman_enabled = 1;
+
+/*
+ * The worst case is single-sector max-parity RAID-Z blocks, in which
+ * case the space requirement is exactly (VDEV_RAIDZ_MAXPARITY + 1)
+ * times the size; so just assume that.  Add to this the fact that
+ * we can have up to 3 DVAs per bp, and one more factor of 2 because
+ * the block may be dittoed with up to 3 DVAs by ddt_sync().  All together,
+ * the worst case is:
+ *     (VDEV_RAIDZ_MAXPARITY + 1) * SPA_DVAS_PER_BP * 2 == 24
+ */
+int spa_asize_inflation = 24;
+
+/*
+ * 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.
+ *
+ * Certain operations (e.g. file removal, most administrative actions) can
+ * use half the slop space.  They will only return ENOSPC if less than half
+ * the slop space is free.  Typically, once the pool has less than the slop
+ * space free, the user will use these operations to free up space in the pool.
+ * These are the operations that call dsl_pool_adjustedsize() with the netfree
+ * argument set to TRUE.
+ *
+ * A very restricted set of operations are always permitted, regardless of
+ * the amount of free space.  These are the operations that call
+ * dsl_sync_task(ZFS_SPACE_CHECK_NONE), e.g. "zfs destroy".  If these
+ * operations result in a net increase in the amount of space used,
+ * it is possible to run the pool completely out of space, causing it to
+ * be permanently read-only.
+ *
+ * See also the comments in zfs_space_check_t.
+ */
+int spa_slop_shift = 5;
+
+/*
+ * ==========================================================================
+ * SPA config locking
+ * ==========================================================================
+ */
+static void
+spa_config_lock_init(spa_t *spa)
+{
+       int i;
+
+       for (i = 0; i < SCL_LOCKS; i++) {
+               spa_config_lock_t *scl = &spa->spa_config_lock[i];
+               mutex_init(&scl->scl_lock, NULL, MUTEX_DEFAULT, NULL);
+               cv_init(&scl->scl_cv, NULL, CV_DEFAULT, NULL);
+               refcount_create_untracked(&scl->scl_count);
+               scl->scl_writer = NULL;
+               scl->scl_write_wanted = 0;
+       }
+}
+
+static void
+spa_config_lock_destroy(spa_t *spa)
+{
+       int i;
+
+       for (i = 0; i < SCL_LOCKS; i++) {
+               spa_config_lock_t *scl = &spa->spa_config_lock[i];
+               mutex_destroy(&scl->scl_lock);
+               cv_destroy(&scl->scl_cv);
+               refcount_destroy(&scl->scl_count);
+               ASSERT(scl->scl_writer == NULL);
+               ASSERT(scl->scl_write_wanted == 0);
+       }
+}
+
+int
+spa_config_tryenter(spa_t *spa, int locks, void *tag, krw_t rw)
+{
+       int i;
+
+       for (i = 0; i < SCL_LOCKS; i++) {
+               spa_config_lock_t *scl = &spa->spa_config_lock[i];
+               if (!(locks & (1 << i)))
+                       continue;
+               mutex_enter(&scl->scl_lock);
+               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);
+                               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);
+                               return (0);
+                       }
+                       scl->scl_writer = curthread;
+               }
+               (void) refcount_add(&scl->scl_count, tag);
+               mutex_exit(&scl->scl_lock);
+       }
+       return (1);
+}
+
+void
+spa_config_enter(spa_t *spa, int locks, void *tag, krw_t rw)
+{
+       int wlocks_held = 0;
+       int i;
+
+       ASSERT3U(SCL_LOCKS, <, sizeof (wlocks_held) * NBBY);
+
+       for (i = 0; i < SCL_LOCKS; i++) {
+               spa_config_lock_t *scl = &spa->spa_config_lock[i];
+               if (scl->scl_writer == curthread)
+                       wlocks_held |= (1 << i);
+               if (!(locks & (1 << i)))
+                       continue;
+               mutex_enter(&scl->scl_lock);
+               if (rw == RW_READER) {
+                       while (scl->scl_writer || scl->scl_write_wanted) {
+                               cv_wait(&scl->scl_cv, &scl->scl_lock);
+                       }
+               } else {
+                       ASSERT(scl->scl_writer != curthread);
+                       while (!refcount_is_zero(&scl->scl_count)) {
+                               scl->scl_write_wanted++;
+                               cv_wait(&scl->scl_cv, &scl->scl_lock);
+                               scl->scl_write_wanted--;
+                       }
+                       scl->scl_writer = curthread;
+               }
+               (void) refcount_add(&scl->scl_count, tag);
+               mutex_exit(&scl->scl_lock);
+       }
+       ASSERT(wlocks_held <= locks);
+}
+
+void
+spa_config_exit(spa_t *spa, int locks, void *tag)
+{
+       int i;
+
+       for (i = SCL_LOCKS - 1; i >= 0; i--) {
+               spa_config_lock_t *scl = &spa->spa_config_lock[i];
+               if (!(locks & (1 << i)))
+                       continue;
+               mutex_enter(&scl->scl_lock);
+               ASSERT(!refcount_is_zero(&scl->scl_count));
+               if (refcount_remove(&scl->scl_count, tag) == 0) {
+                       ASSERT(scl->scl_writer == NULL ||
+                           scl->scl_writer == curthread);
+                       scl->scl_writer = NULL; /* OK in either case */
+                       cv_broadcast(&scl->scl_cv);
+               }
+               mutex_exit(&scl->scl_lock);
+       }
+}
+
+int
+spa_config_held(spa_t *spa, int locks, krw_t rw)
+{
+       int i, locks_held = 0;
+
+       for (i = 0; i < SCL_LOCKS; i++) {
+               spa_config_lock_t *scl = &spa->spa_config_lock[i];
+               if (!(locks & (1 << i)))
+                       continue;
+               if ((rw == RW_READER && !refcount_is_zero(&scl->scl_count)) ||
+                   (rw == RW_WRITER && scl->scl_writer == curthread))
+                       locks_held |= 1 << i;
+       }
+
+       return (locks_held);
+}
+
+/*
+ * ==========================================================================
+ * SPA namespace functions
+ * ==========================================================================
+ */
+
+/*
+ * Lookup the named spa_t in the AVL tree.  The spa_namespace_lock must be held.
+ * Returns NULL if no matching spa_t is found.
+ */
+spa_t *
+spa_lookup(const char *name)
+{
+       static spa_t search;    /* spa_t is large; don't allocate on stack */
+       spa_t *spa;
+       avl_index_t where;
+       char *cp;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       (void) strlcpy(search.spa_name, name, sizeof (search.spa_name));
+
+       /*
+        * If it's a full dataset name, figure out the pool name and
+        * just use that.
+        */
+       cp = strpbrk(search.spa_name, "/@#");
+       if (cp != NULL)
+               *cp = '\0';
+
+       spa = avl_find(&spa_namespace_avl, &search, &where);
+
+       return (spa);
+}
+
+/*
+ * Fires when spa_sync has not completed within zfs_deadman_synctime_ms.
+ * If the zfs_deadman_enabled flag is set then it inspects all vdev queues
+ * looking for potentially hung I/Os.
+ */
+void
+spa_deadman(void *arg)
+{
+       spa_t *spa = arg;
+
+       zfs_dbgmsg("slow spa_sync: started %llu seconds ago, calls %llu",
+           (gethrtime() - spa->spa_sync_starttime) / NANOSEC,
+           ++spa->spa_deadman_calls);
+       if (zfs_deadman_enabled)
+               vdev_deadman(spa->spa_root_vdev);
+
+       spa->spa_deadman_tqid = taskq_dispatch_delay(system_taskq,
+           spa_deadman, spa, KM_SLEEP, ddi_get_lbolt() +
+           NSEC_TO_TICK(spa->spa_deadman_synctime));
+}
+
+/*
+ * Create an uninitialized spa_t with the given name.  Requires
+ * spa_namespace_lock.  The caller must ensure that the spa_t doesn't already
+ * exist by calling spa_lookup() first.
+ */
+spa_t *
+spa_add(const char *name, nvlist_t *config, const char *altroot)
+{
+       spa_t *spa;
+       spa_config_dirent_t *dp;
+       int t;
+       int i;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       spa = kmem_zalloc(sizeof (spa_t), KM_SLEEP);
+
+       mutex_init(&spa->spa_async_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa->spa_errlist_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa->spa_errlog_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa->spa_evicting_os_lock, NULL, MUTEX_DEFAULT, NULL);
+       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_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);
+
+       cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&spa->spa_proc_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&spa->spa_scrub_io_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&spa->spa_suspend_cv, NULL, CV_DEFAULT, NULL);
+
+       for (t = 0; t < TXG_SIZE; t++)
+               bplist_create(&spa->spa_free_bplist[t]);
+
+       (void) strlcpy(spa->spa_name, name, sizeof (spa->spa_name));
+       spa->spa_state = POOL_STATE_UNINITIALIZED;
+       spa->spa_freeze_txg = UINT64_MAX;
+       spa->spa_final_txg = UINT64_MAX;
+       spa->spa_load_max_txg = UINT64_MAX;
+       spa->spa_proc = &p0;
+       spa->spa_proc_state = SPA_PROC_NONE;
+
+       spa->spa_deadman_synctime = MSEC2NSEC(zfs_deadman_synctime_ms);
+
+       refcount_create(&spa->spa_refcount);
+       spa_config_lock_init(spa);
+       spa_stats_init(spa);
+
+       avl_add(&spa_namespace_avl, spa);
+
+       /*
+        * Set the alternate root, if there is one.
+        */
+       if (altroot)
+               spa->spa_root = spa_strdup(altroot);
+
+       /*
+        * Every pool starts with the default cachefile
+        */
+       list_create(&spa->spa_config_list, sizeof (spa_config_dirent_t),
+           offsetof(spa_config_dirent_t, scd_link));
+
+       dp = kmem_zalloc(sizeof (spa_config_dirent_t), KM_SLEEP);
+       dp->scd_path = altroot ? NULL : spa_strdup(spa_config_path);
+       list_insert_head(&spa->spa_config_list, dp);
+
+       VERIFY(nvlist_alloc(&spa->spa_load_info, NV_UNIQUE_NAME,
+           KM_SLEEP) == 0);
+
+       if (config != NULL) {
+               nvlist_t *features;
+
+               if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
+                   &features) == 0) {
+                       VERIFY(nvlist_dup(features, &spa->spa_label_features,
+                           0) == 0);
+               }
+
+               VERIFY(nvlist_dup(config, &spa->spa_config, 0) == 0);
+       }
+
+       if (spa->spa_label_features == NULL) {
+               VERIFY(nvlist_alloc(&spa->spa_label_features, NV_UNIQUE_NAME,
+                   KM_SLEEP) == 0);
+       }
+
+       spa->spa_debug = ((zfs_flags & ZFS_DEBUG_SPA) != 0);
+
+       spa->spa_min_ashift = INT_MAX;
+       spa->spa_max_ashift = 0;
+
+       /*
+        * As a pool is being created, treat all features as disabled by
+        * setting SPA_FEATURE_DISABLED for all entries in the feature
+        * refcount cache.
+        */
+       for (i = 0; i < SPA_FEATURES; i++) {
+               spa->spa_feat_refcount_cache[i] = SPA_FEATURE_DISABLED;
+       }
+
+       return (spa);
+}
+
+/*
+ * Removes a spa_t from the namespace, freeing up any memory used.  Requires
+ * spa_namespace_lock.  This is called only after the spa_t has been closed and
+ * deactivated.
+ */
+void
+spa_remove(spa_t *spa)
+{
+       spa_config_dirent_t *dp;
+       int t;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+       ASSERT(spa->spa_state == POOL_STATE_UNINITIALIZED);
+       ASSERT3U(refcount_count(&spa->spa_refcount), ==, 0);
+
+       nvlist_free(spa->spa_config_splitting);
+
+       avl_remove(&spa_namespace_avl, spa);
+       cv_broadcast(&spa_namespace_cv);
+
+       if (spa->spa_root)
+               spa_strfree(spa->spa_root);
+
+       while ((dp = list_head(&spa->spa_config_list)) != NULL) {
+               list_remove(&spa->spa_config_list, dp);
+               if (dp->scd_path != NULL)
+                       spa_strfree(dp->scd_path);
+               kmem_free(dp, sizeof (spa_config_dirent_t));
+       }
+
+       list_destroy(&spa->spa_config_list);
+
+       nvlist_free(spa->spa_label_features);
+       nvlist_free(spa->spa_load_info);
+       nvlist_free(spa->spa_feat_stats);
+       spa_config_set(spa, NULL);
+
+       refcount_destroy(&spa->spa_refcount);
+
+       spa_stats_destroy(spa);
+       spa_config_lock_destroy(spa);
+
+       for (t = 0; t < TXG_SIZE; t++)
+               bplist_destroy(&spa->spa_free_bplist[t]);
+
+       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_async_lock);
+       mutex_destroy(&spa->spa_errlist_lock);
+       mutex_destroy(&spa->spa_errlog_lock);
+       mutex_destroy(&spa->spa_evicting_os_lock);
+       mutex_destroy(&spa->spa_history_lock);
+       mutex_destroy(&spa->spa_proc_lock);
+       mutex_destroy(&spa->spa_props_lock);
+       mutex_destroy(&spa->spa_scrub_lock);
+       mutex_destroy(&spa->spa_suspend_lock);
+       mutex_destroy(&spa->spa_vdev_top_lock);
+       mutex_destroy(&spa->spa_feat_stats_lock);
+
+       kmem_free(spa, sizeof (spa_t));
+}
+
+/*
+ * Given a pool, return the next pool in the namespace, or NULL if there is
+ * none.  If 'prev' is NULL, return the first pool.
+ */
+spa_t *
+spa_next(spa_t *prev)
+{
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       if (prev)
+               return (AVL_NEXT(&spa_namespace_avl, prev));
+       else
+               return (avl_first(&spa_namespace_avl));
+}
+
+/*
+ * ==========================================================================
+ * SPA refcount functions
+ * ==========================================================================
+ */
+
+/*
+ * Add a reference to the given spa_t.  Must have at least one reference, or
+ * have the namespace lock held.
+ */
+void
+spa_open_ref(spa_t *spa, void *tag)
+{
+       ASSERT(refcount_count(&spa->spa_refcount) >= spa->spa_minref ||
+           MUTEX_HELD(&spa_namespace_lock));
+       (void) refcount_add(&spa->spa_refcount, tag);
+}
+
+/*
+ * Remove a reference to the given spa_t.  Must have at least one reference, or
+ * have the namespace lock held.
+ */
+void
+spa_close(spa_t *spa, void *tag)
+{
+       ASSERT(refcount_count(&spa->spa_refcount) > spa->spa_minref ||
+           MUTEX_HELD(&spa_namespace_lock));
+       (void) refcount_remove(&spa->spa_refcount, tag);
+}
+
+/*
+ * Remove a reference to the given spa_t held by a dsl dir that is
+ * being asynchronously released.  Async releases occur from a taskq
+ * performing eviction of dsl datasets and dirs.  The namespace lock
+ * isn't held and the hold by the object being evicted may contribute to
+ * spa_minref (e.g. dataset or directory released during pool export),
+ * so the asserts in spa_close() do not apply.
+ */
+void
+spa_async_close(spa_t *spa, void *tag)
+{
+       (void) refcount_remove(&spa->spa_refcount, tag);
+}
+
+/*
+ * Check to see if the spa refcount is zero.  Must be called with
+ * spa_namespace_lock held.  We really compare against spa_minref, which is the
+ * number of references acquired when opening a pool
+ */
+boolean_t
+spa_refcount_zero(spa_t *spa)
+{
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       return (refcount_count(&spa->spa_refcount) == spa->spa_minref);
+}
+
+/*
+ * ==========================================================================
+ * SPA spare and l2cache tracking
+ * ==========================================================================
+ */
+
+/*
+ * Hot spares and cache devices are tracked using the same code below,
+ * for 'auxiliary' devices.
+ */
+
+typedef struct spa_aux {
+       uint64_t        aux_guid;
+       uint64_t        aux_pool;
+       avl_node_t      aux_avl;
+       int             aux_count;
+} spa_aux_t;
+
+static int
+spa_aux_compare(const void *a, const void *b)
+{
+       const spa_aux_t *sa = a;
+       const spa_aux_t *sb = b;
+
+       if (sa->aux_guid < sb->aux_guid)
+               return (-1);
+       else if (sa->aux_guid > sb->aux_guid)
+               return (1);
+       else
+               return (0);
+}
+
+void
+spa_aux_add(vdev_t *vd, avl_tree_t *avl)
+{
+       avl_index_t where;
+       spa_aux_t search;
+       spa_aux_t *aux;
+
+       search.aux_guid = vd->vdev_guid;
+       if ((aux = avl_find(avl, &search, &where)) != NULL) {
+               aux->aux_count++;
+       } else {
+               aux = kmem_zalloc(sizeof (spa_aux_t), KM_SLEEP);
+               aux->aux_guid = vd->vdev_guid;
+               aux->aux_count = 1;
+               avl_insert(avl, aux, where);
+       }
+}
+
+void
+spa_aux_remove(vdev_t *vd, avl_tree_t *avl)
+{
+       spa_aux_t search;
+       spa_aux_t *aux;
+       avl_index_t where;
+
+       search.aux_guid = vd->vdev_guid;
+       aux = avl_find(avl, &search, &where);
+
+       ASSERT(aux != NULL);
+
+       if (--aux->aux_count == 0) {
+               avl_remove(avl, aux);
+               kmem_free(aux, sizeof (spa_aux_t));
+       } else if (aux->aux_pool == spa_guid(vd->vdev_spa)) {
+               aux->aux_pool = 0ULL;
+       }
+}
+
+boolean_t
+spa_aux_exists(uint64_t guid, uint64_t *pool, int *refcnt, avl_tree_t *avl)
+{
+       spa_aux_t search, *found;
+
+       search.aux_guid = guid;
+       found = avl_find(avl, &search, NULL);
+
+       if (pool) {
+               if (found)
+                       *pool = found->aux_pool;
+               else
+                       *pool = 0ULL;
+       }
+
+       if (refcnt) {
+               if (found)
+                       *refcnt = found->aux_count;
+               else
+                       *refcnt = 0;
+       }
+
+       return (found != NULL);
+}
+
+void
+spa_aux_activate(vdev_t *vd, avl_tree_t *avl)
+{
+       spa_aux_t search, *found;
+       avl_index_t where;
+
+       search.aux_guid = vd->vdev_guid;
+       found = avl_find(avl, &search, &where);
+       ASSERT(found != NULL);
+       ASSERT(found->aux_pool == 0ULL);
+
+       found->aux_pool = spa_guid(vd->vdev_spa);
+}
+
+/*
+ * Spares are tracked globally due to the following constraints:
+ *
+ *     - A spare may be part of multiple pools.
+ *     - A spare may be added to a pool even if it's actively in use within
+ *       another pool.
+ *     - A spare in use in any pool can only be the source of a replacement if
+ *       the target is a spare in the same pool.
+ *
+ * We keep track of all spares on the system through the use of a reference
+ * counted AVL tree.  When a vdev is added as a spare, or used as a replacement
+ * spare, then we bump the reference count in the AVL tree.  In addition, we set
+ * the 'vdev_isspare' member to indicate that the device is a spare (active or
+ * inactive).  When a spare is made active (used to replace a device in the
+ * pool), we also keep track of which pool its been made a part of.
+ *
+ * The 'spa_spare_lock' protects the AVL tree.  These functions are normally
+ * called under the spa_namespace lock as part of vdev reconfiguration.  The
+ * separate spare lock exists for the status query path, which does not need to
+ * be completely consistent with respect to other vdev configuration changes.
+ */
+
+static int
+spa_spare_compare(const void *a, const void *b)
+{
+       return (spa_aux_compare(a, b));
+}
+
+void
+spa_spare_add(vdev_t *vd)
+{
+       mutex_enter(&spa_spare_lock);
+       ASSERT(!vd->vdev_isspare);
+       spa_aux_add(vd, &spa_spare_avl);
+       vd->vdev_isspare = B_TRUE;
+       mutex_exit(&spa_spare_lock);
+}
+
+void
+spa_spare_remove(vdev_t *vd)
+{
+       mutex_enter(&spa_spare_lock);
+       ASSERT(vd->vdev_isspare);
+       spa_aux_remove(vd, &spa_spare_avl);
+       vd->vdev_isspare = B_FALSE;
+       mutex_exit(&spa_spare_lock);
+}
+
+boolean_t
+spa_spare_exists(uint64_t guid, uint64_t *pool, int *refcnt)
+{
+       boolean_t found;
+
+       mutex_enter(&spa_spare_lock);
+       found = spa_aux_exists(guid, pool, refcnt, &spa_spare_avl);
+       mutex_exit(&spa_spare_lock);
+
+       return (found);
+}
+
+void
+spa_spare_activate(vdev_t *vd)
+{
+       mutex_enter(&spa_spare_lock);
+       ASSERT(vd->vdev_isspare);
+       spa_aux_activate(vd, &spa_spare_avl);
+       mutex_exit(&spa_spare_lock);
+}
+
+/*
+ * Level 2 ARC devices are tracked globally for the same reasons as spares.
+ * Cache devices currently only support one pool per cache device, and so
+ * for these devices the aux reference count is currently unused beyond 1.
+ */
+
+static int
+spa_l2cache_compare(const void *a, const void *b)
+{
+       return (spa_aux_compare(a, b));
+}
+
+void
+spa_l2cache_add(vdev_t *vd)
+{
+       mutex_enter(&spa_l2cache_lock);
+       ASSERT(!vd->vdev_isl2cache);
+       spa_aux_add(vd, &spa_l2cache_avl);
+       vd->vdev_isl2cache = B_TRUE;
+       mutex_exit(&spa_l2cache_lock);
+}
+
+void
+spa_l2cache_remove(vdev_t *vd)
+{
+       mutex_enter(&spa_l2cache_lock);
+       ASSERT(vd->vdev_isl2cache);
+       spa_aux_remove(vd, &spa_l2cache_avl);
+       vd->vdev_isl2cache = B_FALSE;
+       mutex_exit(&spa_l2cache_lock);
+}
+
+boolean_t
+spa_l2cache_exists(uint64_t guid, uint64_t *pool)
+{
+       boolean_t found;
+
+       mutex_enter(&spa_l2cache_lock);
+       found = spa_aux_exists(guid, pool, NULL, &spa_l2cache_avl);
+       mutex_exit(&spa_l2cache_lock);
+
+       return (found);
+}
+
+void
+spa_l2cache_activate(vdev_t *vd)
+{
+       mutex_enter(&spa_l2cache_lock);
+       ASSERT(vd->vdev_isl2cache);
+       spa_aux_activate(vd, &spa_l2cache_avl);
+       mutex_exit(&spa_l2cache_lock);
+}
+
+/*
+ * ==========================================================================
+ * SPA vdev locking
+ * ==========================================================================
+ */
+
+/*
+ * Lock the given spa_t for the purpose of adding or removing a vdev.
+ * Grabs the global spa_namespace_lock plus the spa config lock for writing.
+ * It returns the next transaction group for the spa_t.
+ */
+uint64_t
+spa_vdev_enter(spa_t *spa)
+{
+       mutex_enter(&spa->spa_vdev_top_lock);
+       mutex_enter(&spa_namespace_lock);
+       return (spa_vdev_config_enter(spa));
+}
+
+/*
+ * Internal implementation for spa_vdev_enter().  Used when a vdev
+ * operation requires multiple syncs (i.e. removing a device) while
+ * keeping the spa_namespace_lock held.
+ */
+uint64_t
+spa_vdev_config_enter(spa_t *spa)
+{
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       spa_config_enter(spa, SCL_ALL, spa, RW_WRITER);
+
+       return (spa_last_synced_txg(spa) + 1);
+}
+
+/*
+ * Used in combination with spa_vdev_config_enter() to allow the syncing
+ * of multiple transactions without releasing the spa_namespace_lock.
+ */
+void
+spa_vdev_config_exit(spa_t *spa, vdev_t *vd, uint64_t txg, int error, char *tag)
+{
+       int config_changed = B_FALSE;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+       ASSERT(txg > spa_last_synced_txg(spa));
+
+       spa->spa_pending_vdev = NULL;
+
+       /*
+        * Reassess the DTLs.
+        */
+       vdev_dtl_reassess(spa->spa_root_vdev, 0, 0, B_FALSE);
+
+       if (error == 0 && !list_is_empty(&spa->spa_config_dirty_list)) {
+               config_changed = B_TRUE;
+               spa->spa_config_generation++;
+       }
+
+       /*
+        * Verify the metaslab classes.
+        */
+       ASSERT(metaslab_class_validate(spa_normal_class(spa)) == 0);
+       ASSERT(metaslab_class_validate(spa_log_class(spa)) == 0);
+
+       spa_config_exit(spa, SCL_ALL, spa);
+
+       /*
+        * Panic the system if the specified tag requires it.  This
+        * is useful for ensuring that configurations are updated
+        * transactionally.
+        */
+       if (zio_injection_enabled)
+               zio_handle_panic_injection(spa, tag, 0);
+
+       /*
+        * Note: this txg_wait_synced() is important because it ensures
+        * that there won't be more than one config change per txg.
+        * This allows us to use the txg as the generation number.
+        */
+       if (error == 0)
+               txg_wait_synced(spa->spa_dsl_pool, txg);
+
+       if (vd != NULL) {
+               ASSERT(!vd->vdev_detached || vd->vdev_dtl_sm == NULL);
+               spa_config_enter(spa, SCL_ALL, spa, RW_WRITER);
+               vdev_free(vd);
+               spa_config_exit(spa, SCL_ALL, spa);
+       }
+
+       /*
+        * If the config changed, update the config cache.
+        */
+       if (config_changed)
+               spa_config_sync(spa, B_FALSE, B_TRUE);
+}
+
+/*
+ * Unlock the spa_t after adding or removing a vdev.  Besides undoing the
+ * locking of spa_vdev_enter(), we also want make sure the transactions have
+ * synced to disk, and then update the global configuration cache with the new
+ * information.
+ */
+int
+spa_vdev_exit(spa_t *spa, vdev_t *vd, uint64_t txg, int error)
+{
+       spa_vdev_config_exit(spa, vd, txg, error, FTAG);
+       mutex_exit(&spa_namespace_lock);
+       mutex_exit(&spa->spa_vdev_top_lock);
+
+       return (error);
+}
+
+/*
+ * Lock the given spa_t for the purpose of changing vdev state.
+ */
+void
+spa_vdev_state_enter(spa_t *spa, int oplocks)
+{
+       int locks = SCL_STATE_ALL | oplocks;
+
+       /*
+        * Root pools may need to read of the underlying devfs filesystem
+        * when opening up a vdev.  Unfortunately if we're holding the
+        * SCL_ZIO lock it will result in a deadlock when we try to issue
+        * the read from the root filesystem.  Instead we "prefetch"
+        * the associated vnodes that we need prior to opening the
+        * underlying devices and cache them so that we can prevent
+        * any I/O when we are doing the actual open.
+        */
+       if (spa_is_root(spa)) {
+               int low = locks & ~(SCL_ZIO - 1);
+               int high = locks & ~low;
+
+               spa_config_enter(spa, high, spa, RW_WRITER);
+               vdev_hold(spa->spa_root_vdev);
+               spa_config_enter(spa, low, spa, RW_WRITER);
+       } else {
+               spa_config_enter(spa, locks, spa, RW_WRITER);
+       }
+       spa->spa_vdev_locks = locks;
+}
+
+int
+spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error)
+{
+       boolean_t config_changed = B_FALSE;
+
+       if (vd != NULL || error == 0)
+               vdev_dtl_reassess(vd ? vd->vdev_top : spa->spa_root_vdev,
+                   0, 0, B_FALSE);
+
+       if (vd != NULL) {
+               vdev_state_dirty(vd->vdev_top);
+               config_changed = B_TRUE;
+               spa->spa_config_generation++;
+       }
+
+       if (spa_is_root(spa))
+               vdev_rele(spa->spa_root_vdev);
+
+       ASSERT3U(spa->spa_vdev_locks, >=, SCL_STATE_ALL);
+       spa_config_exit(spa, spa->spa_vdev_locks, spa);
+
+       /*
+        * If anything changed, wait for it to sync.  This ensures that,
+        * from the system administrator's perspective, zpool(1M) commands
+        * are synchronous.  This is important for things like zpool offline:
+        * when the command completes, you expect no further I/O from ZFS.
+        */
+       if (vd != NULL)
+               txg_wait_synced(spa->spa_dsl_pool, 0);
+
+       /*
+        * If the config changed, update the config cache.
+        */
+       if (config_changed) {
+               mutex_enter(&spa_namespace_lock);
+               spa_config_sync(spa, B_FALSE, B_TRUE);
+               mutex_exit(&spa_namespace_lock);
+       }
+
+       return (error);
+}
+
+/*
+ * ==========================================================================
+ * Miscellaneous functions
+ * ==========================================================================
+ */
+
+void
+spa_activate_mos_feature(spa_t *spa, const char *feature, dmu_tx_t *tx)
+{
+       if (!nvlist_exists(spa->spa_label_features, feature)) {
+               fnvlist_add_boolean(spa->spa_label_features, feature);
+               /*
+                * When we are creating the pool (tx_txg==TXG_INITIAL), we can't
+                * dirty the vdev config because lock SCL_CONFIG is not held.
+                * Thankfully, in this case we don't need to dirty the config
+                * because it will be written out anyway when we finish
+                * creating the pool.
+                */
+               if (tx->tx_txg != TXG_INITIAL)
+                       vdev_config_dirty(spa->spa_root_vdev);
+       }
+}
+
+void
+spa_deactivate_mos_feature(spa_t *spa, const char *feature)
+{
+       if (nvlist_remove_all(spa->spa_label_features, feature) == 0)
+               vdev_config_dirty(spa->spa_root_vdev);
+}
+
+/*
+ * Rename a spa_t.
+ */
+int
+spa_rename(const char *name, const char *newname)
+{
+       spa_t *spa;
+       int err;
+
+       /*
+        * Lookup the spa_t and grab the config lock for writing.  We need to
+        * actually open the pool so that we can sync out the necessary labels.
+        * It's OK to call spa_open() with the namespace lock held because we
+        * allow recursive calls for other reasons.
+        */
+       mutex_enter(&spa_namespace_lock);
+       if ((err = spa_open(name, &spa, FTAG)) != 0) {
+               mutex_exit(&spa_namespace_lock);
+               return (err);
+       }
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+
+       avl_remove(&spa_namespace_avl, spa);
+       (void) strlcpy(spa->spa_name, newname, sizeof (spa->spa_name));
+       avl_add(&spa_namespace_avl, spa);
+
+       /*
+        * Sync all labels to disk with the new names by marking the root vdev
+        * dirty and waiting for it to sync.  It will pick up the new pool name
+        * during the sync.
+        */
+       vdev_config_dirty(spa->spa_root_vdev);
+
+       spa_config_exit(spa, SCL_ALL, FTAG);
+
+       txg_wait_synced(spa->spa_dsl_pool, 0);
+
+       /*
+        * Sync the updated config cache.
+        */
+       spa_config_sync(spa, B_FALSE, B_TRUE);
+
+       spa_close(spa, FTAG);
+
+       mutex_exit(&spa_namespace_lock);
+
+       return (0);
+}
+
+/*
+ * Return the spa_t associated with given pool_guid, if it exists.  If
+ * device_guid is non-zero, determine whether the pool exists *and* contains
+ * a device with the specified device_guid.
+ */
+spa_t *
+spa_by_guid(uint64_t pool_guid, uint64_t device_guid)
+{
+       spa_t *spa;
+       avl_tree_t *t = &spa_namespace_avl;
+
+       ASSERT(MUTEX_HELD(&spa_namespace_lock));
+
+       for (spa = avl_first(t); spa != NULL; spa = AVL_NEXT(t, spa)) {
+               if (spa->spa_state == POOL_STATE_UNINITIALIZED)
+                       continue;
+               if (spa->spa_root_vdev == NULL)
+                       continue;
+               if (spa_guid(spa) == pool_guid) {
+                       if (device_guid == 0)
+                               break;
+
+                       if (vdev_lookup_by_guid(spa->spa_root_vdev,
+                           device_guid) != NULL)
+                               break;
+
+                       /*
+                        * Check any devices we may be in the process of adding.
+                        */
+                       if (spa->spa_pending_vdev) {
+                               if (vdev_lookup_by_guid(spa->spa_pending_vdev,
+                                   device_guid) != NULL)
+                                       break;
+                       }
+               }
+       }
+
+       return (spa);
+}
+
+/*
+ * Determine whether a pool with the given pool_guid exists.
+ */
+boolean_t
+spa_guid_exists(uint64_t pool_guid, uint64_t device_guid)
+{
+       return (spa_by_guid(pool_guid, device_guid) != NULL);
+}
+
+char *
+spa_strdup(const char *s)
+{
+       size_t len;
+       char *new;
+
+       len = strlen(s);
+       new = kmem_alloc(len + 1, KM_SLEEP);
+       bcopy(s, new, len);
+       new[len] = '\0';
+
+       return (new);
+}
+
+void
+spa_strfree(char *s)
+{
+       kmem_free(s, strlen(s) + 1);
+}
+
+uint64_t
+spa_get_random(uint64_t range)
+{
+       uint64_t r;
+
+       ASSERT(range != 0);
+
+       (void) random_get_pseudo_bytes((void *)&r, sizeof (uint64_t));
+
+       return (r % range);
+}
+
+uint64_t
+spa_generate_guid(spa_t *spa)
+{
+       uint64_t guid = spa_get_random(-1ULL);
+
+       if (spa != NULL) {
+               while (guid == 0 || spa_guid_exists(spa_guid(spa), guid))
+                       guid = spa_get_random(-1ULL);
+       } else {
+               while (guid == 0 || spa_guid_exists(guid, 0))
+                       guid = spa_get_random(-1ULL);
+       }
+
+       return (guid);
+}
+
+void
+snprintf_blkptr(char *buf, size_t buflen, const blkptr_t *bp)
+{
+       char type[256];
+       char *checksum = NULL;
+       char *compress = NULL;
+
+       if (bp != NULL) {
+               if (BP_GET_TYPE(bp) & DMU_OT_NEWTYPE) {
+                       dmu_object_byteswap_t bswap =
+                           DMU_OT_BYTESWAP(BP_GET_TYPE(bp));
+                       (void) snprintf(type, sizeof (type), "bswap %s %s",
+                           DMU_OT_IS_METADATA(BP_GET_TYPE(bp)) ?
+                           "metadata" : "data",
+                           dmu_ot_byteswap[bswap].ob_name);
+               } else {
+                       (void) strlcpy(type, dmu_ot[BP_GET_TYPE(bp)].ot_name,
+                           sizeof (type));
+               }
+               if (!BP_IS_EMBEDDED(bp)) {
+                       checksum =
+                           zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_name;
+               }
+               compress = zio_compress_table[BP_GET_COMPRESS(bp)].ci_name;
+       }
+
+       SNPRINTF_BLKPTR(snprintf, ' ', buf, buflen, bp, type, checksum,
+           compress);
+}
+
+void
+spa_freeze(spa_t *spa)
+{
+       uint64_t freeze_txg = 0;
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       if (spa->spa_freeze_txg == UINT64_MAX) {
+               freeze_txg = spa_last_synced_txg(spa) + TXG_SIZE;
+               spa->spa_freeze_txg = freeze_txg;
+       }
+       spa_config_exit(spa, SCL_ALL, FTAG);
+       if (freeze_txg != 0)
+               txg_wait_synced(spa_get_dsl(spa), freeze_txg);
+}
+
+void
+zfs_panic_recover(const char *fmt, ...)
+{
+       va_list adx;
+
+       va_start(adx, fmt);
+       vcmn_err(zfs_recover ? CE_WARN : CE_PANIC, fmt, adx);
+       va_end(adx);
+}
+
+/*
+ * This is a stripped-down version of strtoull, suitable only for converting
+ * lowercase hexadecimal numbers that don't overflow.
+ */
+uint64_t
+strtonum(const char *str, char **nptr)
+{
+       uint64_t val = 0;
+       char c;
+       int digit;
+
+       while ((c = *str) != '\0') {
+               if (c >= '0' && c <= '9')
+                       digit = c - '0';
+               else if (c >= 'a' && c <= 'f')
+                       digit = 10 + c - 'a';
+               else
+                       break;
+
+               val *= 16;
+               val += digit;
+
+               str++;
+       }
+
+       if (nptr)
+               *nptr = (char *)str;
+
+       return (val);
+}
+
+/*
+ * ==========================================================================
+ * Accessor functions
+ * ==========================================================================
+ */
+
+boolean_t
+spa_shutting_down(spa_t *spa)
+{
+       return (spa->spa_async_suspended);
+}
+
+dsl_pool_t *
+spa_get_dsl(spa_t *spa)
+{
+       return (spa->spa_dsl_pool);
+}
+
+boolean_t
+spa_is_initializing(spa_t *spa)
+{
+       return (spa->spa_is_initializing);
+}
+
+blkptr_t *
+spa_get_rootblkptr(spa_t *spa)
+{
+       return (&spa->spa_ubsync.ub_rootbp);
+}
+
+void
+spa_set_rootblkptr(spa_t *spa, const blkptr_t *bp)
+{
+       spa->spa_uberblock.ub_rootbp = *bp;
+}
+
+void
+spa_altroot(spa_t *spa, char *buf, size_t buflen)
+{
+       if (spa->spa_root == NULL)
+               buf[0] = '\0';
+       else
+               (void) strncpy(buf, spa->spa_root, buflen);
+}
+
+int
+spa_sync_pass(spa_t *spa)
+{
+       return (spa->spa_sync_pass);
+}
+
+char *
+spa_name(spa_t *spa)
+{
+       return (spa->spa_name);
+}
+
+uint64_t
+spa_guid(spa_t *spa)
+{
+       dsl_pool_t *dp = spa_get_dsl(spa);
+       uint64_t guid;
+
+       /*
+        * If we fail to parse the config during spa_load(), we can go through
+        * the error path (which posts an ereport) and end up here with no root
+        * vdev.  We stash the original pool guid in 'spa_config_guid' to handle
+        * this case.
+        */
+       if (spa->spa_root_vdev == NULL)
+               return (spa->spa_config_guid);
+
+       guid = spa->spa_last_synced_guid != 0 ?
+           spa->spa_last_synced_guid : spa->spa_root_vdev->vdev_guid;
+
+       /*
+        * Return the most recently synced out guid unless we're
+        * in syncing context.
+        */
+       if (dp && dsl_pool_sync_context(dp))
+               return (spa->spa_root_vdev->vdev_guid);
+       else
+               return (guid);
+}
+
+uint64_t
+spa_load_guid(spa_t *spa)
+{
+       /*
+        * This is a GUID that exists solely as a reference for the
+        * purposes of the arc.  It is generated at load time, and
+        * is never written to persistent storage.
+        */
+       return (spa->spa_load_guid);
+}
+
+uint64_t
+spa_last_synced_txg(spa_t *spa)
+{
+       return (spa->spa_ubsync.ub_txg);
+}
+
+uint64_t
+spa_first_txg(spa_t *spa)
+{
+       return (spa->spa_first_txg);
+}
+
+uint64_t
+spa_syncing_txg(spa_t *spa)
+{
+       return (spa->spa_syncing_txg);
+}
+
+pool_state_t
+spa_state(spa_t *spa)
+{
+       return (spa->spa_state);
+}
+
+spa_load_state_t
+spa_load_state(spa_t *spa)
+{
+       return (spa->spa_load_state);
+}
+
+uint64_t
+spa_freeze_txg(spa_t *spa)
+{
+       return (spa->spa_freeze_txg);
+}
+
+/* ARGSUSED */
+uint64_t
+spa_get_asize(spa_t *spa, uint64_t lsize)
+{
+       return (lsize * spa_asize_inflation);
+}
+
+/*
+ * Return the amount of slop space in bytes.  It is 1/32 of the pool (3.2%),
+ * or at least 32MB.
+ *
+ * See the comment above spa_slop_shift for details.
+ */
+uint64_t
+spa_get_slop_space(spa_t *spa) {
+       uint64_t space = spa_get_dspace(spa);
+       return (MAX(space >> spa_slop_shift, SPA_MINDEVSIZE >> 1));
+}
+
+uint64_t
+spa_get_dspace(spa_t *spa)
+{
+       return (spa->spa_dspace);
+}
+
+void
+spa_update_dspace(spa_t *spa)
+{
+       spa->spa_dspace = metaslab_class_get_dspace(spa_normal_class(spa)) +
+           ddt_get_dedup_dspace(spa);
+}
+
+/*
+ * Return the failure mode that has been set to this pool. The default
+ * behavior will be to block all I/Os when a complete failure occurs.
+ */
+uint8_t
+spa_get_failmode(spa_t *spa)
+{
+       return (spa->spa_failmode);
+}
+
+boolean_t
+spa_suspended(spa_t *spa)
+{
+       return (spa->spa_suspended);
+}
+
+uint64_t
+spa_version(spa_t *spa)
+{
+       return (spa->spa_ubsync.ub_version);
+}
+
+boolean_t
+spa_deflate(spa_t *spa)
+{
+       return (spa->spa_deflate);
+}
+
+metaslab_class_t *
+spa_normal_class(spa_t *spa)
+{
+       return (spa->spa_normal_class);
+}
+
+metaslab_class_t *
+spa_log_class(spa_t *spa)
+{
+       return (spa->spa_log_class);
+}
+
+void
+spa_evicting_os_register(spa_t *spa, objset_t *os)
+{
+       mutex_enter(&spa->spa_evicting_os_lock);
+       list_insert_head(&spa->spa_evicting_os_list, os);
+       mutex_exit(&spa->spa_evicting_os_lock);
+}
+
+void
+spa_evicting_os_deregister(spa_t *spa, objset_t *os)
+{
+       mutex_enter(&spa->spa_evicting_os_lock);
+       list_remove(&spa->spa_evicting_os_list, os);
+       cv_broadcast(&spa->spa_evicting_os_cv);
+       mutex_exit(&spa->spa_evicting_os_lock);
+}
+
+void
+spa_evicting_os_wait(spa_t *spa)
+{
+       mutex_enter(&spa->spa_evicting_os_lock);
+       while (!list_is_empty(&spa->spa_evicting_os_list))
+               cv_wait(&spa->spa_evicting_os_cv, &spa->spa_evicting_os_lock);
+       mutex_exit(&spa->spa_evicting_os_lock);
+
+       dmu_buf_user_evict_wait();
+}
+
+int
+spa_max_replication(spa_t *spa)
+{
+       /*
+        * As of SPA_VERSION == SPA_VERSION_DITTO_BLOCKS, we are able to
+        * handle BPs with more than one DVA allocated.  Set our max
+        * replication level accordingly.
+        */
+       if (spa_version(spa) < SPA_VERSION_DITTO_BLOCKS)
+               return (1);
+       return (MIN(SPA_DVAS_PER_BP, spa_max_replication_override));
+}
+
+int
+spa_prev_software_version(spa_t *spa)
+{
+       return (spa->spa_prev_software_version);
+}
+
+uint64_t
+spa_deadman_synctime(spa_t *spa)
+{
+       return (spa->spa_deadman_synctime);
+}
+
+uint64_t
+dva_get_dsize_sync(spa_t *spa, const dva_t *dva)
+{
+       uint64_t asize = DVA_GET_ASIZE(dva);
+       uint64_t dsize = asize;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+
+       if (asize != 0 && spa->spa_deflate) {
+               vdev_t *vd = vdev_lookup_top(spa, DVA_GET_VDEV(dva));
+               if (vd != NULL)
+                       dsize = (asize >> SPA_MINBLOCKSHIFT) *
+                           vd->vdev_deflate_ratio;
+       }
+
+       return (dsize);
+}
+
+uint64_t
+bp_get_dsize_sync(spa_t *spa, const blkptr_t *bp)
+{
+       uint64_t dsize = 0;
+       int d;
+
+       for (d = 0; d < BP_GET_NDVAS(bp); d++)
+               dsize += dva_get_dsize_sync(spa, &bp->blk_dva[d]);
+
+       return (dsize);
+}
+
+uint64_t
+bp_get_dsize(spa_t *spa, const blkptr_t *bp)
+{
+       uint64_t dsize = 0;
+       int d;
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       for (d = 0; d < BP_GET_NDVAS(bp); d++)
+               dsize += dva_get_dsize_sync(spa, &bp->blk_dva[d]);
+
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+
+       return (dsize);
+}
+
+/*
+ * ==========================================================================
+ * Initialization and Termination
+ * ==========================================================================
+ */
+
+static int
+spa_name_compare(const void *a1, const void *a2)
+{
+       const spa_t *s1 = a1;
+       const spa_t *s2 = a2;
+       int s;
+
+       s = strcmp(s1->spa_name, s2->spa_name);
+       if (s > 0)
+               return (1);
+       if (s < 0)
+               return (-1);
+       return (0);
+}
+
+void
+spa_boot_init(void)
+{
+       spa_config_load();
+}
+
+void
+spa_init(int mode)
+{
+       mutex_init(&spa_namespace_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa_spare_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa_l2cache_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&spa_namespace_cv, NULL, CV_DEFAULT, NULL);
+
+       avl_create(&spa_namespace_avl, spa_name_compare, sizeof (spa_t),
+           offsetof(spa_t, spa_avl));
+
+       avl_create(&spa_spare_avl, spa_spare_compare, sizeof (spa_aux_t),
+           offsetof(spa_aux_t, aux_avl));
+
+       avl_create(&spa_l2cache_avl, spa_l2cache_compare, sizeof (spa_aux_t),
+           offsetof(spa_aux_t, aux_avl));
+
+       spa_mode_global = mode;
+
+#ifndef _KERNEL
+       if (spa_mode_global != FREAD && dprintf_find_string("watch")) {
+               struct sigaction sa;
+
+               sa.sa_flags = SA_SIGINFO;
+               sigemptyset(&sa.sa_mask);
+               sa.sa_sigaction = arc_buf_sigsegv;
+
+               if (sigaction(SIGSEGV, &sa, NULL) == -1) {
+                       perror("could not enable watchpoints: "
+                           "sigaction(SIGSEGV, ...) = ");
+               } else {
+                       arc_watch = B_TRUE;
+               }
+       }
+#endif
+
+       fm_init();
+       refcount_init();
+       unique_init();
+       range_tree_init();
+       ddt_init();
+       zio_init();
+       dmu_init();
+       zil_init();
+       vdev_cache_stat_init();
+       zfs_prop_init();
+       zpool_prop_init();
+       zpool_feature_init();
+       spa_config_load();
+       l2arc_start();
+}
+
+void
+spa_fini(void)
+{
+       l2arc_stop();
+
+       spa_evict_all();
+
+       vdev_cache_stat_fini();
+       zil_fini();
+       dmu_fini();
+       zio_fini();
+       ddt_fini();
+       range_tree_fini();
+       unique_fini();
+       refcount_fini();
+       fm_fini();
+
+       avl_destroy(&spa_namespace_avl);
+       avl_destroy(&spa_spare_avl);
+       avl_destroy(&spa_l2cache_avl);
+
+       cv_destroy(&spa_namespace_cv);
+       mutex_destroy(&spa_namespace_lock);
+       mutex_destroy(&spa_spare_lock);
+       mutex_destroy(&spa_l2cache_lock);
+}
+
+/*
+ * Return whether this pool has slogs. No locking needed.
+ * It's not a problem if the wrong answer is returned as it's only for
+ * performance and not correctness
+ */
+boolean_t
+spa_has_slogs(spa_t *spa)
+{
+       return (spa->spa_log_class->mc_rotor != NULL);
+}
+
+spa_log_state_t
+spa_get_log_state(spa_t *spa)
+{
+       return (spa->spa_log_state);
+}
+
+void
+spa_set_log_state(spa_t *spa, spa_log_state_t state)
+{
+       spa->spa_log_state = state;
+}
+
+boolean_t
+spa_is_root(spa_t *spa)
+{
+       return (spa->spa_is_root);
+}
+
+boolean_t
+spa_writeable(spa_t *spa)
+{
+       return (!!(spa->spa_mode & FWRITE));
+}
+
+/*
+ * Returns true if there is a pending sync task in any of the current
+ * syncing txg, the current quiescing txg, or the current open txg.
+ */
+boolean_t
+spa_has_pending_synctask(spa_t *spa)
+{
+       return (!txg_all_lists_empty(&spa->spa_dsl_pool->dp_sync_tasks));
+}
+
+int
+spa_mode(spa_t *spa)
+{
+       return (spa->spa_mode);
+}
+
+uint64_t
+spa_bootfs(spa_t *spa)
+{
+       return (spa->spa_bootfs);
+}
+
+uint64_t
+spa_delegation(spa_t *spa)
+{
+       return (spa->spa_delegation);
+}
+
+objset_t *
+spa_meta_objset(spa_t *spa)
+{
+       return (spa->spa_meta_objset);
+}
+
+enum zio_checksum
+spa_dedup_checksum(spa_t *spa)
+{
+       return (spa->spa_dedup_checksum);
+}
+
+/*
+ * Reset pool scan stat per scan pass (or reboot).
+ */
+void
+spa_scan_stat_init(spa_t *spa)
+{
+       /* data not stored on disk */
+       spa->spa_scan_pass_start = gethrestime_sec();
+       spa->spa_scan_pass_exam = 0;
+       vdev_scan_stat_init(spa->spa_root_vdev);
+}
+
+/*
+ * Get scan stats for zpool status reports
+ */
+int
+spa_scan_get_stats(spa_t *spa, pool_scan_stat_t *ps)
+{
+       dsl_scan_t *scn = spa->spa_dsl_pool ? spa->spa_dsl_pool->dp_scan : NULL;
+
+       if (scn == NULL || scn->scn_phys.scn_func == POOL_SCAN_NONE)
+               return (SET_ERROR(ENOENT));
+       bzero(ps, sizeof (pool_scan_stat_t));
+
+       /* data stored on disk */
+       ps->pss_func = scn->scn_phys.scn_func;
+       ps->pss_start_time = scn->scn_phys.scn_start_time;
+       ps->pss_end_time = scn->scn_phys.scn_end_time;
+       ps->pss_to_examine = scn->scn_phys.scn_to_examine;
+       ps->pss_examined = scn->scn_phys.scn_examined;
+       ps->pss_to_process = scn->scn_phys.scn_to_process;
+       ps->pss_processed = scn->scn_phys.scn_processed;
+       ps->pss_errors = scn->scn_phys.scn_errors;
+       ps->pss_state = scn->scn_phys.scn_state;
+
+       /* data not stored on disk */
+       ps->pss_pass_start = spa->spa_scan_pass_start;
+       ps->pss_pass_exam = spa->spa_scan_pass_exam;
+
+       return (0);
+}
+
+boolean_t
+spa_debug_enabled(spa_t *spa)
+{
+       return (spa->spa_debug);
+}
+
+int
+spa_maxblocksize(spa_t *spa)
+{
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_BLOCKS))
+               return (SPA_MAXBLOCKSIZE);
+       else
+               return (SPA_OLD_MAXBLOCKSIZE);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+/* Namespace manipulation */
+EXPORT_SYMBOL(spa_lookup);
+EXPORT_SYMBOL(spa_add);
+EXPORT_SYMBOL(spa_remove);
+EXPORT_SYMBOL(spa_next);
+
+/* Refcount functions */
+EXPORT_SYMBOL(spa_open_ref);
+EXPORT_SYMBOL(spa_close);
+EXPORT_SYMBOL(spa_refcount_zero);
+
+/* Pool configuration lock */
+EXPORT_SYMBOL(spa_config_tryenter);
+EXPORT_SYMBOL(spa_config_enter);
+EXPORT_SYMBOL(spa_config_exit);
+EXPORT_SYMBOL(spa_config_held);
+
+/* Pool vdev add/remove lock */
+EXPORT_SYMBOL(spa_vdev_enter);
+EXPORT_SYMBOL(spa_vdev_exit);
+
+/* Pool vdev state change lock */
+EXPORT_SYMBOL(spa_vdev_state_enter);
+EXPORT_SYMBOL(spa_vdev_state_exit);
+
+/* Accessor functions */
+EXPORT_SYMBOL(spa_shutting_down);
+EXPORT_SYMBOL(spa_get_dsl);
+EXPORT_SYMBOL(spa_get_rootblkptr);
+EXPORT_SYMBOL(spa_set_rootblkptr);
+EXPORT_SYMBOL(spa_altroot);
+EXPORT_SYMBOL(spa_sync_pass);
+EXPORT_SYMBOL(spa_name);
+EXPORT_SYMBOL(spa_guid);
+EXPORT_SYMBOL(spa_last_synced_txg);
+EXPORT_SYMBOL(spa_first_txg);
+EXPORT_SYMBOL(spa_syncing_txg);
+EXPORT_SYMBOL(spa_version);
+EXPORT_SYMBOL(spa_state);
+EXPORT_SYMBOL(spa_load_state);
+EXPORT_SYMBOL(spa_freeze_txg);
+EXPORT_SYMBOL(spa_get_asize);
+EXPORT_SYMBOL(spa_get_dspace);
+EXPORT_SYMBOL(spa_update_dspace);
+EXPORT_SYMBOL(spa_deflate);
+EXPORT_SYMBOL(spa_normal_class);
+EXPORT_SYMBOL(spa_log_class);
+EXPORT_SYMBOL(spa_max_replication);
+EXPORT_SYMBOL(spa_prev_software_version);
+EXPORT_SYMBOL(spa_get_failmode);
+EXPORT_SYMBOL(spa_suspended);
+EXPORT_SYMBOL(spa_bootfs);
+EXPORT_SYMBOL(spa_delegation);
+EXPORT_SYMBOL(spa_meta_objset);
+EXPORT_SYMBOL(spa_maxblocksize);
+
+/* Miscellaneous support routines */
+EXPORT_SYMBOL(spa_rename);
+EXPORT_SYMBOL(spa_guid_exists);
+EXPORT_SYMBOL(spa_strdup);
+EXPORT_SYMBOL(spa_strfree);
+EXPORT_SYMBOL(spa_get_random);
+EXPORT_SYMBOL(spa_generate_guid);
+EXPORT_SYMBOL(snprintf_blkptr);
+EXPORT_SYMBOL(spa_freeze);
+EXPORT_SYMBOL(spa_upgrade);
+EXPORT_SYMBOL(spa_evict_all);
+EXPORT_SYMBOL(spa_lookup_by_guid);
+EXPORT_SYMBOL(spa_has_spare);
+EXPORT_SYMBOL(dva_get_dsize_sync);
+EXPORT_SYMBOL(bp_get_dsize_sync);
+EXPORT_SYMBOL(bp_get_dsize);
+EXPORT_SYMBOL(spa_has_slogs);
+EXPORT_SYMBOL(spa_is_root);
+EXPORT_SYMBOL(spa_writeable);
+EXPORT_SYMBOL(spa_mode);
+
+EXPORT_SYMBOL(spa_namespace_lock);
+
+module_param(zfs_flags, uint, 0644);
+MODULE_PARM_DESC(zfs_flags, "Set additional debugging flags");
+
+module_param(zfs_recover, int, 0644);
+MODULE_PARM_DESC(zfs_recover, "Set to attempt to recover from fatal errors");
+
+module_param(zfs_free_leak_on_eio, int, 0644);
+MODULE_PARM_DESC(zfs_free_leak_on_eio,
+       "Set to ignore IO errors during free and permanently leak the space");
+
+module_param(zfs_deadman_synctime_ms, ulong, 0644);
+MODULE_PARM_DESC(zfs_deadman_synctime_ms, "Expiration time in milliseconds");
+
+module_param(zfs_deadman_enabled, int, 0644);
+MODULE_PARM_DESC(zfs_deadman_enabled, "Enable deadman timer");
+
+module_param(spa_asize_inflation, int, 0644);
+MODULE_PARM_DESC(spa_asize_inflation,
+       "SPA size estimate multiplication factor");
+
+module_param(spa_slop_shift, int, 0644);
+MODULE_PARM_DESC(spa_slop_shift, "Reserved free space in pool");
+#endif
diff --git a/zfs/module/zfs/spa_stats.c b/zfs/module/zfs/spa_stats.c
new file mode 100644 (file)
index 0000000..2b8559b
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this 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/zfs_context.h>
+#include <sys/spa_impl.h>
+
+/*
+ * Keeps stats on last N reads per spa_t, disabled by default.
+ */
+int zfs_read_history = 0;
+
+/*
+ * Include cache hits in history, disabled by default.
+ */
+int zfs_read_history_hits = 0;
+
+/*
+ * Keeps stats on the last N txgs, disabled by default.
+ */
+int zfs_txg_history = 0;
+
+/*
+ * ==========================================================================
+ * SPA Read History Routines
+ * ==========================================================================
+ */
+
+/*
+ * Read statistics - Information exported regarding each arc_read call
+ */
+typedef struct spa_read_history {
+       uint64_t        uid;            /* unique identifier */
+       hrtime_t        start;          /* time read completed */
+       uint64_t        objset;         /* read from this objset */
+       uint64_t        object;         /* read of this object number */
+       uint64_t        level;          /* block's indirection level */
+       uint64_t        blkid;          /* read of this block id */
+       char            origin[24];     /* read originated from here */
+       uint32_t        aflags;         /* ARC flags (cached, prefetch, etc.) */
+       pid_t           pid;            /* PID of task doing read */
+       char            comm[16];       /* process name of task doing read */
+       list_node_t     srh_link;
+} spa_read_history_t;
+
+static int
+spa_read_history_headers(char *buf, size_t size)
+{
+       (void) snprintf(buf, size, "%-8s %-16s %-8s %-8s %-8s %-8s %-8s "
+           "%-24s %-8s %-16s\n", "UID", "start", "objset", "object",
+           "level", "blkid", "aflags", "origin", "pid", "process");
+
+       return (0);
+}
+
+static int
+spa_read_history_data(char *buf, size_t size, void *data)
+{
+       spa_read_history_t *srh = (spa_read_history_t *)data;
+
+       (void) snprintf(buf, size, "%-8llu %-16llu 0x%-6llx "
+           "%-8lli %-8lli %-8lli 0x%-6x %-24s %-8i %-16s\n",
+           (u_longlong_t)srh->uid, srh->start,
+           (longlong_t)srh->objset, (longlong_t)srh->object,
+           (longlong_t)srh->level, (longlong_t)srh->blkid,
+           srh->aflags, srh->origin, srh->pid, srh->comm);
+
+       return (0);
+}
+
+/*
+ * Calculate the address for the next spa_stats_history_t entry.  The
+ * ssh->lock will be held until ksp->ks_ndata entries are processed.
+ */
+static void *
+spa_read_history_addr(kstat_t *ksp, loff_t n)
+{
+       spa_t *spa = ksp->ks_private;
+       spa_stats_history_t *ssh = &spa->spa_stats.read_history;
+
+       ASSERT(MUTEX_HELD(&ssh->lock));
+
+       if (n == 0)
+               ssh->private = list_tail(&ssh->list);
+       else if (ssh->private)
+               ssh->private = list_prev(&ssh->list, ssh->private);
+
+       return (ssh->private);
+}
+
+/*
+ * When the kstat is written discard all spa_read_history_t entires.  The
+ * ssh->lock will be held until ksp->ks_ndata entries are processed.
+ */
+static int
+spa_read_history_update(kstat_t *ksp, int rw)
+{
+       spa_t *spa = ksp->ks_private;
+       spa_stats_history_t *ssh = &spa->spa_stats.read_history;
+
+       if (rw == KSTAT_WRITE) {
+               spa_read_history_t *srh;
+
+               while ((srh = list_remove_head(&ssh->list))) {
+                       ssh->size--;
+                       kmem_free(srh, sizeof (spa_read_history_t));
+               }
+
+               ASSERT3U(ssh->size, ==, 0);
+       }
+
+       ksp->ks_ndata = ssh->size;
+       ksp->ks_data_size = ssh->size * sizeof (spa_read_history_t);
+
+       return (0);
+}
+
+static void
+spa_read_history_init(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.read_history;
+       char name[KSTAT_STRLEN];
+       kstat_t *ksp;
+
+       mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&ssh->list, sizeof (spa_read_history_t),
+           offsetof(spa_read_history_t, srh_link));
+
+       ssh->count = 0;
+       ssh->size = 0;
+       ssh->private = NULL;
+
+       (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
+
+       ksp = kstat_create(name, 0, "reads", "misc",
+           KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+       ssh->kstat = ksp;
+
+       if (ksp) {
+               ksp->ks_lock = &ssh->lock;
+               ksp->ks_data = NULL;
+               ksp->ks_private = spa;
+               ksp->ks_update = spa_read_history_update;
+               kstat_set_raw_ops(ksp, spa_read_history_headers,
+                   spa_read_history_data, spa_read_history_addr);
+               kstat_install(ksp);
+       }
+}
+
+static void
+spa_read_history_destroy(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.read_history;
+       spa_read_history_t *srh;
+       kstat_t *ksp;
+
+       ksp = ssh->kstat;
+       if (ksp)
+               kstat_delete(ksp);
+
+       mutex_enter(&ssh->lock);
+       while ((srh = list_remove_head(&ssh->list))) {
+               ssh->size--;
+               kmem_free(srh, sizeof (spa_read_history_t));
+       }
+
+       ASSERT3U(ssh->size, ==, 0);
+       list_destroy(&ssh->list);
+       mutex_exit(&ssh->lock);
+
+       mutex_destroy(&ssh->lock);
+}
+
+void
+spa_read_history_add(spa_t *spa, const zbookmark_phys_t *zb, uint32_t aflags)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.read_history;
+       spa_read_history_t *srh, *rm;
+
+       ASSERT3P(spa, !=, NULL);
+       ASSERT3P(zb,  !=, NULL);
+
+       if (zfs_read_history == 0 && ssh->size == 0)
+               return;
+
+       if (zfs_read_history_hits == 0 && (aflags & ARC_FLAG_CACHED))
+               return;
+
+       srh = kmem_zalloc(sizeof (spa_read_history_t), KM_SLEEP);
+       strlcpy(srh->comm, getcomm(), sizeof (srh->comm));
+       srh->start  = gethrtime();
+       srh->objset = zb->zb_objset;
+       srh->object = zb->zb_object;
+       srh->level  = zb->zb_level;
+       srh->blkid  = zb->zb_blkid;
+       srh->aflags = aflags;
+       srh->pid    = getpid();
+
+       mutex_enter(&ssh->lock);
+
+       srh->uid = ssh->count++;
+       list_insert_head(&ssh->list, srh);
+       ssh->size++;
+
+       while (ssh->size > zfs_read_history) {
+               ssh->size--;
+               rm = list_remove_tail(&ssh->list);
+               kmem_free(rm, sizeof (spa_read_history_t));
+       }
+
+       mutex_exit(&ssh->lock);
+}
+
+/*
+ * ==========================================================================
+ * SPA TXG History Routines
+ * ==========================================================================
+ */
+
+/*
+ * Txg statistics - Information exported regarding each txg sync
+ */
+
+typedef struct spa_txg_history {
+       uint64_t        txg;            /* txg id */
+       txg_state_t     state;          /* active txg state */
+       uint64_t        nread;          /* number of bytes read */
+       uint64_t        nwritten;       /* number of bytes written */
+       uint64_t        reads;          /* number of read operations */
+       uint64_t        writes;         /* number of write operations */
+       uint64_t        ndirty;         /* number of dirty bytes */
+       hrtime_t        times[TXG_STATE_COMMITTED]; /* completion times */
+       list_node_t     sth_link;
+} spa_txg_history_t;
+
+static int
+spa_txg_history_headers(char *buf, size_t size)
+{
+       (void) snprintf(buf, size, "%-8s %-16s %-5s %-12s %-12s %-12s "
+           "%-8s %-8s %-12s %-12s %-12s %-12s\n", "txg", "birth", "state",
+           "ndirty", "nread", "nwritten", "reads", "writes",
+           "otime", "qtime", "wtime", "stime");
+
+       return (0);
+}
+
+static int
+spa_txg_history_data(char *buf, size_t size, void *data)
+{
+       spa_txg_history_t *sth = (spa_txg_history_t *)data;
+       uint64_t open = 0, quiesce = 0, wait = 0, sync = 0;
+       char state;
+
+       switch (sth->state) {
+               case TXG_STATE_BIRTH:           state = 'B';    break;
+               case TXG_STATE_OPEN:            state = 'O';    break;
+               case TXG_STATE_QUIESCED:        state = 'Q';    break;
+               case TXG_STATE_WAIT_FOR_SYNC:   state = 'W';    break;
+               case TXG_STATE_SYNCED:          state = 'S';    break;
+               case TXG_STATE_COMMITTED:       state = 'C';    break;
+               default:                        state = '?';    break;
+       }
+
+       if (sth->times[TXG_STATE_OPEN])
+               open = sth->times[TXG_STATE_OPEN] -
+                   sth->times[TXG_STATE_BIRTH];
+
+       if (sth->times[TXG_STATE_QUIESCED])
+               quiesce = sth->times[TXG_STATE_QUIESCED] -
+                   sth->times[TXG_STATE_OPEN];
+
+       if (sth->times[TXG_STATE_WAIT_FOR_SYNC])
+               wait = sth->times[TXG_STATE_WAIT_FOR_SYNC] -
+                   sth->times[TXG_STATE_QUIESCED];
+
+       if (sth->times[TXG_STATE_SYNCED])
+               sync = sth->times[TXG_STATE_SYNCED] -
+                   sth->times[TXG_STATE_WAIT_FOR_SYNC];
+
+       (void) snprintf(buf, size, "%-8llu %-16llu %-5c %-12llu "
+           "%-12llu %-12llu %-8llu %-8llu %-12llu %-12llu %-12llu %-12llu\n",
+           (longlong_t)sth->txg, sth->times[TXG_STATE_BIRTH], state,
+           (u_longlong_t)sth->ndirty,
+           (u_longlong_t)sth->nread, (u_longlong_t)sth->nwritten,
+           (u_longlong_t)sth->reads, (u_longlong_t)sth->writes,
+           (u_longlong_t)open, (u_longlong_t)quiesce, (u_longlong_t)wait,
+           (u_longlong_t)sync);
+
+       return (0);
+}
+
+/*
+ * Calculate the address for the next spa_stats_history_t entry.  The
+ * ssh->lock will be held until ksp->ks_ndata entries are processed.
+ */
+static void *
+spa_txg_history_addr(kstat_t *ksp, loff_t n)
+{
+       spa_t *spa = ksp->ks_private;
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+
+       ASSERT(MUTEX_HELD(&ssh->lock));
+
+       if (n == 0)
+               ssh->private = list_tail(&ssh->list);
+       else if (ssh->private)
+               ssh->private = list_prev(&ssh->list, ssh->private);
+
+       return (ssh->private);
+}
+
+/*
+ * When the kstat is written discard all spa_txg_history_t entires.  The
+ * ssh->lock will be held until ksp->ks_ndata entries are processed.
+ */
+static int
+spa_txg_history_update(kstat_t *ksp, int rw)
+{
+       spa_t *spa = ksp->ks_private;
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+
+       ASSERT(MUTEX_HELD(&ssh->lock));
+
+       if (rw == KSTAT_WRITE) {
+               spa_txg_history_t *sth;
+
+               while ((sth = list_remove_head(&ssh->list))) {
+                       ssh->size--;
+                       kmem_free(sth, sizeof (spa_txg_history_t));
+               }
+
+               ASSERT3U(ssh->size, ==, 0);
+       }
+
+       ksp->ks_ndata = ssh->size;
+       ksp->ks_data_size = ssh->size * sizeof (spa_txg_history_t);
+
+       return (0);
+}
+
+static void
+spa_txg_history_init(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+       char name[KSTAT_STRLEN];
+       kstat_t *ksp;
+
+       mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&ssh->list, sizeof (spa_txg_history_t),
+           offsetof(spa_txg_history_t, sth_link));
+
+       ssh->count = 0;
+       ssh->size = 0;
+       ssh->private = NULL;
+
+       (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
+
+       ksp = kstat_create(name, 0, "txgs", "misc",
+           KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+       ssh->kstat = ksp;
+
+       if (ksp) {
+               ksp->ks_lock = &ssh->lock;
+               ksp->ks_data = NULL;
+               ksp->ks_private = spa;
+               ksp->ks_update = spa_txg_history_update;
+               kstat_set_raw_ops(ksp, spa_txg_history_headers,
+                   spa_txg_history_data, spa_txg_history_addr);
+               kstat_install(ksp);
+       }
+}
+
+static void
+spa_txg_history_destroy(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+       spa_txg_history_t *sth;
+       kstat_t *ksp;
+
+       ksp = ssh->kstat;
+       if (ksp)
+               kstat_delete(ksp);
+
+       mutex_enter(&ssh->lock);
+       while ((sth = list_remove_head(&ssh->list))) {
+               ssh->size--;
+               kmem_free(sth, sizeof (spa_txg_history_t));
+       }
+
+       ASSERT3U(ssh->size, ==, 0);
+       list_destroy(&ssh->list);
+       mutex_exit(&ssh->lock);
+
+       mutex_destroy(&ssh->lock);
+}
+
+/*
+ * Add a new txg to historical record.
+ */
+void
+spa_txg_history_add(spa_t *spa, uint64_t txg, hrtime_t birth_time)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+       spa_txg_history_t *sth, *rm;
+
+       if (zfs_txg_history == 0 && ssh->size == 0)
+               return;
+
+       sth = kmem_zalloc(sizeof (spa_txg_history_t), KM_SLEEP);
+       sth->txg = txg;
+       sth->state = TXG_STATE_OPEN;
+       sth->times[TXG_STATE_BIRTH] = birth_time;
+
+       mutex_enter(&ssh->lock);
+
+       list_insert_head(&ssh->list, sth);
+       ssh->size++;
+
+       while (ssh->size > zfs_txg_history) {
+               ssh->size--;
+               rm = list_remove_tail(&ssh->list);
+               kmem_free(rm, sizeof (spa_txg_history_t));
+       }
+
+       mutex_exit(&ssh->lock);
+}
+
+/*
+ * Set txg state completion time and increment current state.
+ */
+int
+spa_txg_history_set(spa_t *spa, uint64_t txg, txg_state_t completed_state,
+    hrtime_t completed_time)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+       spa_txg_history_t *sth;
+       int error = ENOENT;
+
+       if (zfs_txg_history == 0)
+               return (0);
+
+       mutex_enter(&ssh->lock);
+       for (sth = list_head(&ssh->list); sth != NULL;
+           sth = list_next(&ssh->list, sth)) {
+               if (sth->txg == txg) {
+                       sth->times[completed_state] = completed_time;
+                       sth->state++;
+                       error = 0;
+                       break;
+               }
+       }
+       mutex_exit(&ssh->lock);
+
+       return (error);
+}
+
+/*
+ * Set txg IO stats.
+ */
+int
+spa_txg_history_set_io(spa_t *spa, uint64_t txg, uint64_t nread,
+    uint64_t nwritten, uint64_t reads, uint64_t writes, uint64_t ndirty)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.txg_history;
+       spa_txg_history_t *sth;
+       int error = ENOENT;
+
+       if (zfs_txg_history == 0)
+               return (0);
+
+       mutex_enter(&ssh->lock);
+       for (sth = list_head(&ssh->list); sth != NULL;
+           sth = list_next(&ssh->list, sth)) {
+               if (sth->txg == txg) {
+                       sth->nread = nread;
+                       sth->nwritten = nwritten;
+                       sth->reads = reads;
+                       sth->writes = writes;
+                       sth->ndirty = ndirty;
+                       error = 0;
+                       break;
+               }
+       }
+       mutex_exit(&ssh->lock);
+
+       return (error);
+}
+
+/*
+ * ==========================================================================
+ * SPA TX Assign Histogram Routines
+ * ==========================================================================
+ */
+
+/*
+ * Tx statistics - Information exported regarding dmu_tx_assign time.
+ */
+
+/*
+ * When the kstat is written zero all buckets.  When the kstat is read
+ * count the number of trailing buckets set to zero and update ks_ndata
+ * such that they are not output.
+ */
+static int
+spa_tx_assign_update(kstat_t *ksp, int rw)
+{
+       spa_t *spa = ksp->ks_private;
+       spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+       int i;
+
+       if (rw == KSTAT_WRITE) {
+               for (i = 0; i < ssh->count; i++)
+                       ((kstat_named_t *)ssh->private)[i].value.ui64 = 0;
+       }
+
+       for (i = ssh->count; i > 0; i--)
+               if (((kstat_named_t *)ssh->private)[i-1].value.ui64 != 0)
+                       break;
+
+       ksp->ks_ndata = i;
+       ksp->ks_data_size = i * sizeof (kstat_named_t);
+
+       return (0);
+}
+
+static void
+spa_tx_assign_init(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+       char name[KSTAT_STRLEN];
+       kstat_named_t *ks;
+       kstat_t *ksp;
+       int i;
+
+       mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
+
+       ssh->count = 42; /* power of two buckets for 1ns to 2,199s */
+       ssh->size = ssh->count * sizeof (kstat_named_t);
+       ssh->private = kmem_alloc(ssh->size, KM_SLEEP);
+
+       (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
+
+       for (i = 0; i < ssh->count; i++) {
+               ks = &((kstat_named_t *)ssh->private)[i];
+               ks->data_type = KSTAT_DATA_UINT64;
+               ks->value.ui64 = 0;
+               (void) snprintf(ks->name, KSTAT_STRLEN, "%llu ns",
+                   (u_longlong_t)1 << i);
+       }
+
+       ksp = kstat_create(name, 0, "dmu_tx_assign", "misc",
+           KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
+       ssh->kstat = ksp;
+
+       if (ksp) {
+               ksp->ks_lock = &ssh->lock;
+               ksp->ks_data = ssh->private;
+               ksp->ks_ndata = ssh->count;
+               ksp->ks_data_size = ssh->size;
+               ksp->ks_private = spa;
+               ksp->ks_update = spa_tx_assign_update;
+               kstat_install(ksp);
+       }
+}
+
+static void
+spa_tx_assign_destroy(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
+       kstat_t *ksp;
+
+       ksp = ssh->kstat;
+       if (ksp)
+               kstat_delete(ksp);
+
+       kmem_free(ssh->private, ssh->size);
+       mutex_destroy(&ssh->lock);
+}
+
+void
+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))
+               idx++;
+
+       atomic_inc_64(&((kstat_named_t *)ssh->private)[idx].value.ui64);
+}
+
+/*
+ * ==========================================================================
+ * SPA IO History Routines
+ * ==========================================================================
+ */
+static int
+spa_io_history_update(kstat_t *ksp, int rw)
+{
+       if (rw == KSTAT_WRITE)
+               memset(ksp->ks_data, 0, ksp->ks_data_size);
+
+       return (0);
+}
+
+static void
+spa_io_history_init(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+       char name[KSTAT_STRLEN];
+       kstat_t *ksp;
+
+       mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
+
+       (void) snprintf(name, KSTAT_STRLEN, "zfs/%s", spa_name(spa));
+
+       ksp = kstat_create(name, 0, "io", "disk", KSTAT_TYPE_IO, 1, 0);
+       ssh->kstat = ksp;
+
+       if (ksp) {
+               ksp->ks_lock = &ssh->lock;
+               ksp->ks_private = spa;
+               ksp->ks_update = spa_io_history_update;
+               kstat_install(ksp);
+       }
+}
+
+static void
+spa_io_history_destroy(spa_t *spa)
+{
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       if (ssh->kstat)
+               kstat_delete(ssh->kstat);
+
+       mutex_destroy(&ssh->lock);
+}
+
+void
+spa_stats_init(spa_t *spa)
+{
+       spa_read_history_init(spa);
+       spa_txg_history_init(spa);
+       spa_tx_assign_init(spa);
+       spa_io_history_init(spa);
+}
+
+void
+spa_stats_destroy(spa_t *spa)
+{
+       spa_tx_assign_destroy(spa);
+       spa_txg_history_destroy(spa);
+       spa_read_history_destroy(spa);
+       spa_io_history_destroy(spa);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_read_history, int, 0644);
+MODULE_PARM_DESC(zfs_read_history, "Historic statistics for the last N reads");
+
+module_param(zfs_read_history_hits, int, 0644);
+MODULE_PARM_DESC(zfs_read_history_hits, "Include cache hits in read history");
+
+module_param(zfs_txg_history, int, 0644);
+MODULE_PARM_DESC(zfs_txg_history, "Historic statistics for the last N txgs");
+#endif
diff --git a/zfs/module/zfs/space_map.c b/zfs/module/zfs/space_map.c
new file mode 100644 (file)
index 0000000..b3aa469
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/dnode.h>
+#include <sys/dsl_pool.h>
+#include <sys/zio.h>
+#include <sys/space_map.h>
+#include <sys/refcount.h>
+#include <sys/zfeature.h>
+
+/*
+ * The data for a given space map can be kept on blocks of any size.
+ * Larger blocks entail fewer i/o operations, but they also cause the
+ * DMU to keep more data in-core, and also to waste more i/o bandwidth
+ * when only a few blocks have changed since the last transaction group.
+ */
+int space_map_blksz = (1 << 12);
+
+/*
+ * Load the space map disk into the specified range tree. Segments of maptype
+ * are added to the range tree, other segment types are removed.
+ *
+ * Note: space_map_load() will drop sm_lock across dmu_read() calls.
+ * The caller must be OK with this.
+ */
+int
+space_map_load(space_map_t *sm, range_tree_t *rt, maptype_t maptype)
+{
+       uint64_t *entry, *entry_map, *entry_map_end;
+       uint64_t bufsize, size, offset, end, space;
+       int error = 0;
+
+       ASSERT(MUTEX_HELD(sm->sm_lock));
+
+       end = space_map_length(sm);
+       space = space_map_allocated(sm);
+
+       VERIFY0(range_tree_space(rt));
+
+       if (maptype == SM_FREE) {
+               range_tree_add(rt, sm->sm_start, sm->sm_size);
+               space = sm->sm_size - space;
+       }
+
+       bufsize = MAX(sm->sm_blksz, SPA_MINBLOCKSIZE);
+       entry_map = zio_buf_alloc(bufsize);
+
+       mutex_exit(sm->sm_lock);
+       if (end > bufsize) {
+               dmu_prefetch(sm->sm_os, space_map_object(sm), bufsize,
+                   end - bufsize);
+       }
+       mutex_enter(sm->sm_lock);
+
+       for (offset = 0; offset < end; offset += bufsize) {
+               size = MIN(end - offset, bufsize);
+               VERIFY(P2PHASE(size, sizeof (uint64_t)) == 0);
+               VERIFY(size != 0);
+               ASSERT3U(sm->sm_blksz, !=, 0);
+
+               dprintf("object=%llu  offset=%llx  size=%llx\n",
+                   space_map_object(sm), offset, size);
+
+               mutex_exit(sm->sm_lock);
+               error = dmu_read(sm->sm_os, space_map_object(sm), offset, size,
+                   entry_map, DMU_READ_PREFETCH);
+               mutex_enter(sm->sm_lock);
+               if (error != 0)
+                       break;
+
+               entry_map_end = entry_map + (size / sizeof (uint64_t));
+               for (entry = entry_map; entry < entry_map_end; entry++) {
+                       uint64_t e = *entry;
+                       uint64_t offset, size;
+
+                       if (SM_DEBUG_DECODE(e))         /* Skip debug entries */
+                               continue;
+
+                       offset = (SM_OFFSET_DECODE(e) << sm->sm_shift) +
+                           sm->sm_start;
+                       size = SM_RUN_DECODE(e) << sm->sm_shift;
+
+                       VERIFY0(P2PHASE(offset, 1ULL << sm->sm_shift));
+                       VERIFY0(P2PHASE(size, 1ULL << sm->sm_shift));
+                       VERIFY3U(offset, >=, sm->sm_start);
+                       VERIFY3U(offset + size, <=, sm->sm_start + sm->sm_size);
+                       if (SM_TYPE_DECODE(e) == maptype) {
+                               VERIFY3U(range_tree_space(rt) + size, <=,
+                                   sm->sm_size);
+                               range_tree_add(rt, offset, size);
+                       } else {
+                               range_tree_remove(rt, offset, size);
+                       }
+               }
+       }
+
+       if (error == 0)
+               VERIFY3U(range_tree_space(rt), ==, space);
+       else
+               range_tree_vacate(rt, NULL, NULL);
+
+       zio_buf_free(entry_map, bufsize);
+       return (error);
+}
+
+void
+space_map_histogram_clear(space_map_t *sm)
+{
+       if (sm->sm_dbuf->db_size != sizeof (space_map_phys_t))
+               return;
+
+       bzero(sm->sm_phys->smp_histogram, sizeof (sm->sm_phys->smp_histogram));
+}
+
+boolean_t
+space_map_histogram_verify(space_map_t *sm, range_tree_t *rt)
+{
+       int i;
+
+       /*
+        * Verify that the in-core range tree does not have any
+        * ranges smaller than our sm_shift size.
+        */
+       for (i = 0; i < sm->sm_shift; i++) {
+               if (rt->rt_histogram[i] != 0)
+                       return (B_FALSE);
+       }
+       return (B_TRUE);
+}
+
+void
+space_map_histogram_add(space_map_t *sm, range_tree_t *rt, dmu_tx_t *tx)
+{
+       int idx = 0;
+       int i;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       ASSERT(dmu_tx_is_syncing(tx));
+       VERIFY3U(space_map_object(sm), !=, 0);
+
+       if (sm->sm_dbuf->db_size != sizeof (space_map_phys_t))
+               return;
+
+       dmu_buf_will_dirty(sm->sm_dbuf, tx);
+
+       ASSERT(space_map_histogram_verify(sm, rt));
+
+       /*
+        * Transfer the content of the range tree histogram to the space
+        * map histogram. The space map histogram contains 32 buckets ranging
+        * between 2^sm_shift to 2^(32+sm_shift-1). The range tree,
+        * however, can represent ranges from 2^0 to 2^63. Since the space
+        * map only cares about allocatable blocks (minimum of sm_shift) we
+        * can safely ignore all ranges in the range tree smaller than sm_shift.
+        */
+       for (i = sm->sm_shift; i < RANGE_TREE_HISTOGRAM_SIZE; i++) {
+
+               /*
+                * Since the largest histogram bucket in the space map is
+                * 2^(32+sm_shift-1), we need to normalize the values in
+                * the range tree for any bucket larger than that size. For
+                * example given an sm_shift of 9, ranges larger than 2^40
+                * would get normalized as if they were 1TB ranges. Assume
+                * the range tree had a count of 5 in the 2^44 (16TB) bucket,
+                * the calculation below would normalize this to 5 * 2^4 (16).
+                */
+               ASSERT3U(i, >=, idx + sm->sm_shift);
+               sm->sm_phys->smp_histogram[idx] +=
+                   rt->rt_histogram[i] << (i - idx - sm->sm_shift);
+
+               /*
+                * Increment the space map's index as long as we haven't
+                * reached the maximum bucket size. Accumulate all ranges
+                * larger than the max bucket size into the last bucket.
+                */
+               if (idx < SPACE_MAP_HISTOGRAM_SIZE - 1) {
+                       ASSERT3U(idx + sm->sm_shift, ==, i);
+                       idx++;
+                       ASSERT3U(idx, <, SPACE_MAP_HISTOGRAM_SIZE);
+               }
+       }
+}
+
+uint64_t
+space_map_entries(space_map_t *sm, range_tree_t *rt)
+{
+       avl_tree_t *t = &rt->rt_root;
+       range_seg_t *rs;
+       uint64_t size, entries;
+
+       /*
+        * All space_maps always have a debug entry so account for it here.
+        */
+       entries = 1;
+
+       /*
+        * Traverse the range tree and calculate the number of space map
+        * entries that would be required to write out the range tree.
+        */
+       for (rs = avl_first(t); rs != NULL; rs = AVL_NEXT(t, rs)) {
+               size = (rs->rs_end - rs->rs_start) >> sm->sm_shift;
+               entries += howmany(size, SM_RUN_MAX);
+       }
+       return (entries);
+}
+
+/*
+ * Note: space_map_write() will drop sm_lock across dmu_write() calls.
+ */
+void
+space_map_write(space_map_t *sm, range_tree_t *rt, maptype_t maptype,
+    dmu_tx_t *tx)
+{
+       objset_t *os = sm->sm_os;
+       spa_t *spa = dmu_objset_spa(os);
+       avl_tree_t *t = &rt->rt_root;
+       range_seg_t *rs;
+       uint64_t size, total, rt_space, nodes;
+       uint64_t *entry, *entry_map, *entry_map_end;
+       uint64_t expected_entries, actual_entries = 1;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+       ASSERT(dsl_pool_sync_context(dmu_objset_pool(os)));
+       VERIFY3U(space_map_object(sm), !=, 0);
+       dmu_buf_will_dirty(sm->sm_dbuf, tx);
+
+       /*
+        * This field is no longer necessary since the in-core space map
+        * now contains the object number but is maintained for backwards
+        * compatibility.
+        */
+       sm->sm_phys->smp_object = sm->sm_object;
+
+       if (range_tree_space(rt) == 0) {
+               VERIFY3U(sm->sm_object, ==, sm->sm_phys->smp_object);
+               return;
+       }
+
+       if (maptype == SM_ALLOC)
+               sm->sm_phys->smp_alloc += range_tree_space(rt);
+       else
+               sm->sm_phys->smp_alloc -= range_tree_space(rt);
+
+       expected_entries = space_map_entries(sm, rt);
+
+       entry_map = zio_buf_alloc(sm->sm_blksz);
+       entry_map_end = entry_map + (sm->sm_blksz / sizeof (uint64_t));
+       entry = entry_map;
+
+       *entry++ = SM_DEBUG_ENCODE(1) |
+           SM_DEBUG_ACTION_ENCODE(maptype) |
+           SM_DEBUG_SYNCPASS_ENCODE(spa_sync_pass(spa)) |
+           SM_DEBUG_TXG_ENCODE(dmu_tx_get_txg(tx));
+
+       total = 0;
+       nodes = avl_numnodes(&rt->rt_root);
+       rt_space = range_tree_space(rt);
+       for (rs = avl_first(t); rs != NULL; rs = AVL_NEXT(t, rs)) {
+               uint64_t start;
+
+               size = (rs->rs_end - rs->rs_start) >> sm->sm_shift;
+               start = (rs->rs_start - sm->sm_start) >> sm->sm_shift;
+
+               total += size << sm->sm_shift;
+
+               while (size != 0) {
+                       uint64_t run_len;
+
+                       run_len = MIN(size, SM_RUN_MAX);
+
+                       if (entry == entry_map_end) {
+                               mutex_exit(rt->rt_lock);
+                               dmu_write(os, space_map_object(sm),
+                                   sm->sm_phys->smp_objsize, sm->sm_blksz,
+                                   entry_map, tx);
+                               mutex_enter(rt->rt_lock);
+                               sm->sm_phys->smp_objsize += sm->sm_blksz;
+                               entry = entry_map;
+                       }
+
+                       *entry++ = SM_OFFSET_ENCODE(start) |
+                           SM_TYPE_ENCODE(maptype) |
+                           SM_RUN_ENCODE(run_len);
+
+                       start += run_len;
+                       size -= run_len;
+                       actual_entries++;
+               }
+       }
+
+       if (entry != entry_map) {
+               size = (entry - entry_map) * sizeof (uint64_t);
+               mutex_exit(rt->rt_lock);
+               dmu_write(os, space_map_object(sm), sm->sm_phys->smp_objsize,
+                   size, entry_map, tx);
+               mutex_enter(rt->rt_lock);
+               sm->sm_phys->smp_objsize += size;
+       }
+       ASSERT3U(expected_entries, ==, actual_entries);
+
+       /*
+        * Ensure that the space_map's accounting wasn't changed
+        * while we were in the middle of writing it out.
+        */
+       VERIFY3U(nodes, ==, avl_numnodes(&rt->rt_root));
+       VERIFY3U(range_tree_space(rt), ==, rt_space);
+       VERIFY3U(range_tree_space(rt), ==, total);
+
+       zio_buf_free(entry_map, sm->sm_blksz);
+}
+
+static int
+space_map_open_impl(space_map_t *sm)
+{
+       int error;
+       u_longlong_t blocks;
+
+       error = dmu_bonus_hold(sm->sm_os, sm->sm_object, sm, &sm->sm_dbuf);
+       if (error)
+               return (error);
+
+       dmu_object_size_from_db(sm->sm_dbuf, &sm->sm_blksz, &blocks);
+       sm->sm_phys = sm->sm_dbuf->db_data;
+       return (0);
+}
+
+int
+space_map_open(space_map_t **smp, objset_t *os, uint64_t object,
+    uint64_t start, uint64_t size, uint8_t shift, kmutex_t *lp)
+{
+       space_map_t *sm;
+       int error;
+
+       ASSERT(*smp == NULL);
+       ASSERT(os != NULL);
+       ASSERT(object != 0);
+
+       sm = kmem_alloc(sizeof (space_map_t), KM_SLEEP);
+
+       sm->sm_start = start;
+       sm->sm_size = size;
+       sm->sm_shift = shift;
+       sm->sm_lock = lp;
+       sm->sm_os = os;
+       sm->sm_object = object;
+       sm->sm_length = 0;
+       sm->sm_alloc = 0;
+       sm->sm_blksz = 0;
+       sm->sm_dbuf = NULL;
+       sm->sm_phys = NULL;
+
+       error = space_map_open_impl(sm);
+       if (error != 0) {
+               space_map_close(sm);
+               return (error);
+       }
+
+       *smp = sm;
+
+       return (0);
+}
+
+void
+space_map_close(space_map_t *sm)
+{
+       if (sm == NULL)
+               return;
+
+       if (sm->sm_dbuf != NULL)
+               dmu_buf_rele(sm->sm_dbuf, sm);
+       sm->sm_dbuf = NULL;
+       sm->sm_phys = NULL;
+
+       kmem_free(sm, sizeof (*sm));
+}
+
+void
+space_map_truncate(space_map_t *sm, dmu_tx_t *tx)
+{
+       objset_t *os = sm->sm_os;
+       spa_t *spa = dmu_objset_spa(os);
+       dmu_object_info_t doi;
+
+       ASSERT(dsl_pool_sync_context(dmu_objset_pool(os)));
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       dmu_object_info_from_db(sm->sm_dbuf, &doi);
+
+       /*
+        * If the space map has the wrong bonus size (because
+        * SPA_FEATURE_SPACEMAP_HISTOGRAM has recently been enabled), or
+        * the wrong block size (because space_map_blksz has changed),
+        * free and re-allocate its object with the updated sizes.
+        *
+        * Otherwise, just truncate the current object.
+        */
+       if ((spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM) &&
+           doi.doi_bonus_size != sizeof (space_map_phys_t)) ||
+           doi.doi_data_block_size != space_map_blksz) {
+               zfs_dbgmsg("txg %llu, spa %s, reallocating: "
+                   "old bonus %llu, old blocksz %u", dmu_tx_get_txg(tx),
+                   spa_name(spa), doi.doi_bonus_size, doi.doi_data_block_size);
+
+               space_map_free(sm, tx);
+               dmu_buf_rele(sm->sm_dbuf, sm);
+
+               sm->sm_object = space_map_alloc(sm->sm_os, tx);
+               VERIFY0(space_map_open_impl(sm));
+       } else {
+               VERIFY0(dmu_free_range(os, space_map_object(sm), 0, -1ULL, tx));
+
+               /*
+                * If the spacemap is reallocated, its histogram
+                * will be reset.  Do the same in the common case so that
+                * bugs related to the uncommon case do not go unnoticed.
+                */
+               bzero(sm->sm_phys->smp_histogram,
+                   sizeof (sm->sm_phys->smp_histogram));
+       }
+
+       dmu_buf_will_dirty(sm->sm_dbuf, tx);
+       sm->sm_phys->smp_objsize = 0;
+       sm->sm_phys->smp_alloc = 0;
+}
+
+/*
+ * Update the in-core space_map allocation and length values.
+ */
+void
+space_map_update(space_map_t *sm)
+{
+       if (sm == NULL)
+               return;
+
+       ASSERT(MUTEX_HELD(sm->sm_lock));
+
+       sm->sm_alloc = sm->sm_phys->smp_alloc;
+       sm->sm_length = sm->sm_phys->smp_objsize;
+}
+
+uint64_t
+space_map_alloc(objset_t *os, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_objset_spa(os);
+       uint64_t object;
+       int bonuslen;
+
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
+               spa_feature_incr(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM, tx);
+               bonuslen = sizeof (space_map_phys_t);
+               ASSERT3U(bonuslen, <=, dmu_bonus_max());
+       } else {
+               bonuslen = SPACE_MAP_SIZE_V0;
+       }
+
+       object = dmu_object_alloc(os,
+           DMU_OT_SPACE_MAP, space_map_blksz,
+           DMU_OT_SPACE_MAP_HEADER, bonuslen, tx);
+
+       return (object);
+}
+
+void
+space_map_free(space_map_t *sm, dmu_tx_t *tx)
+{
+       spa_t *spa;
+
+       if (sm == NULL)
+               return;
+
+       spa = dmu_objset_spa(sm->sm_os);
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
+               dmu_object_info_t doi;
+
+               dmu_object_info_from_db(sm->sm_dbuf, &doi);
+               if (doi.doi_bonus_size != SPACE_MAP_SIZE_V0) {
+                       VERIFY(spa_feature_is_active(spa,
+                           SPA_FEATURE_SPACEMAP_HISTOGRAM));
+                       spa_feature_decr(spa,
+                           SPA_FEATURE_SPACEMAP_HISTOGRAM, tx);
+               }
+       }
+
+       VERIFY3U(dmu_object_free(sm->sm_os, space_map_object(sm), tx), ==, 0);
+       sm->sm_object = 0;
+}
+
+uint64_t
+space_map_object(space_map_t *sm)
+{
+       return (sm != NULL ? sm->sm_object : 0);
+}
+
+/*
+ * Returns the already synced, on-disk allocated space.
+ */
+uint64_t
+space_map_allocated(space_map_t *sm)
+{
+       return (sm != NULL ? sm->sm_alloc : 0);
+}
+
+/*
+ * Returns the already synced, on-disk length;
+ */
+uint64_t
+space_map_length(space_map_t *sm)
+{
+       return (sm != NULL ? sm->sm_length : 0);
+}
+
+/*
+ * Returns the allocated space that is currently syncing.
+ */
+int64_t
+space_map_alloc_delta(space_map_t *sm)
+{
+       if (sm == NULL)
+               return (0);
+       ASSERT(sm->sm_dbuf != NULL);
+       return (sm->sm_phys->smp_alloc - space_map_allocated(sm));
+}
diff --git a/zfs/module/zfs/space_reftree.c b/zfs/module/zfs/space_reftree.c
new file mode 100644 (file)
index 0000000..a508092
--- /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.
+ */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/range_tree.h>
+#include <sys/space_reftree.h>
+
+/*
+ * Space reference trees.
+ *
+ * A range tree is a collection of integers.  Every integer is either
+ * in the tree, or it's not.  A space reference tree generalizes
+ * the idea: it allows its members to have arbitrary reference counts,
+ * as opposed to the implicit reference count of 0 or 1 in a range tree.
+ * This representation comes in handy when computing the union or
+ * intersection of multiple space maps.  For example, the union of
+ * N range trees is the subset of the reference tree with refcnt >= 1.
+ * The intersection of N range trees is the subset with refcnt >= N.
+ *
+ * [It's very much like a Fourier transform.  Unions and intersections
+ * are hard to perform in the 'range tree domain', so we convert the trees
+ * into the 'reference count domain', where it's trivial, then invert.]
+ *
+ * vdev_dtl_reassess() uses computations of this form to determine
+ * DTL_MISSING and DTL_OUTAGE for interior vdevs -- e.g. a RAID-Z vdev
+ * has an outage wherever refcnt >= vdev_nparity + 1, and a mirror vdev
+ * has an outage wherever refcnt >= vdev_children.
+ */
+static int
+space_reftree_compare(const void *x1, const void *x2)
+{
+       const space_ref_t *sr1 = x1;
+       const space_ref_t *sr2 = x2;
+
+       if (sr1->sr_offset < sr2->sr_offset)
+               return (-1);
+       if (sr1->sr_offset > sr2->sr_offset)
+               return (1);
+
+       if (sr1 < sr2)
+               return (-1);
+       if (sr1 > sr2)
+               return (1);
+
+       return (0);
+}
+
+void
+space_reftree_create(avl_tree_t *t)
+{
+       avl_create(t, space_reftree_compare,
+           sizeof (space_ref_t), offsetof(space_ref_t, sr_node));
+}
+
+void
+space_reftree_destroy(avl_tree_t *t)
+{
+       space_ref_t *sr;
+       void *cookie = NULL;
+
+       while ((sr = avl_destroy_nodes(t, &cookie)) != NULL)
+               kmem_free(sr, sizeof (*sr));
+
+       avl_destroy(t);
+}
+
+static void
+space_reftree_add_node(avl_tree_t *t, uint64_t offset, int64_t refcnt)
+{
+       space_ref_t *sr;
+
+       sr = kmem_alloc(sizeof (*sr), KM_SLEEP);
+       sr->sr_offset = offset;
+       sr->sr_refcnt = refcnt;
+
+       avl_add(t, sr);
+}
+
+void
+space_reftree_add_seg(avl_tree_t *t, uint64_t start, uint64_t end,
+       int64_t refcnt)
+{
+       space_reftree_add_node(t, start, refcnt);
+       space_reftree_add_node(t, end, -refcnt);
+}
+
+/*
+ * Convert (or add) a range tree into a reference tree.
+ */
+void
+space_reftree_add_map(avl_tree_t *t, range_tree_t *rt, int64_t refcnt)
+{
+       range_seg_t *rs;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+
+       for (rs = avl_first(&rt->rt_root); rs; rs = AVL_NEXT(&rt->rt_root, rs))
+               space_reftree_add_seg(t, rs->rs_start, rs->rs_end, refcnt);
+}
+
+/*
+ * Convert a reference tree into a range tree.  The range tree will contain
+ * all members of the reference tree for which refcnt >= minref.
+ */
+void
+space_reftree_generate_map(avl_tree_t *t, range_tree_t *rt, int64_t minref)
+{
+       uint64_t start = -1ULL;
+       int64_t refcnt = 0;
+       space_ref_t *sr;
+
+       ASSERT(MUTEX_HELD(rt->rt_lock));
+
+       range_tree_vacate(rt, NULL, NULL);
+
+       for (sr = avl_first(t); sr != NULL; sr = AVL_NEXT(t, sr)) {
+               refcnt += sr->sr_refcnt;
+               if (refcnt >= minref) {
+                       if (start == -1ULL) {
+                               start = sr->sr_offset;
+                       }
+               } else {
+                       if (start != -1ULL) {
+                               uint64_t end = sr->sr_offset;
+                               ASSERT(start <= end);
+                               if (end > start)
+                                       range_tree_add(rt, start, end - start);
+                               start = -1ULL;
+                       }
+               }
+       }
+       ASSERT(refcnt == 0);
+       ASSERT(start == -1ULL);
+}
diff --git a/zfs/module/zfs/trace.c b/zfs/module/zfs/trace.c
new file mode 100644 (file)
index 0000000..0c9990e
--- /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 (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Each Linux tracepoints subsystem must define CREATE_TRACE_POINTS in one
+ * (and only one) C file, so this dummy file exists for that purpose.
+ */
+
+#include <sys/multilist.h>
+#include <sys/arc_impl.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/dbuf.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dmu_tx.h>
+#include <sys/dnode.h>
+#include <sys/multilist.h>
+#include <sys/zfs_znode.h>
+#include <sys/zil_impl.h>
+#include <sys/zrlock.h>
+
+#define        CREATE_TRACE_POINTS
+#include <sys/trace.h>
+#include <sys/trace_acl.h>
+#include <sys/trace_arc.h>
+#include <sys/trace_dbuf.h>
+#include <sys/trace_dmu.h>
+#include <sys/trace_dnode.h>
+#include <sys/trace_multilist.h>
+#include <sys/trace_txg.h>
+#include <sys/trace_zil.h>
+#include <sys/trace_zrlock.h>
diff --git a/zfs/module/zfs/txg.c b/zfs/module/zfs/txg.c
new file mode 100644 (file)
index 0000000..1d5ee97
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Portions Copyright 2011 Martin Matuska
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/txg_impl.h>
+#include <sys/dmu_impl.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_scan.h>
+#include <sys/callb.h>
+#include <sys/trace_txg.h>
+
+/*
+ * ZFS Transaction Groups
+ * ----------------------
+ *
+ * ZFS transaction groups are, as the name implies, groups of transactions
+ * that act on persistent state. ZFS asserts consistency at the granularity of
+ * these transaction groups. Each successive transaction group (txg) is
+ * assigned a 64-bit consecutive identifier. There are three active
+ * transaction group states: open, quiescing, or syncing. At any given time,
+ * there may be an active txg associated with each state; each active txg may
+ * either be processing, or blocked waiting to enter the next state. There may
+ * be up to three active txgs, and there is always a txg in the open state
+ * (though it may be blocked waiting to enter the quiescing state). In broad
+ * strokes, transactions -- operations that change in-memory structures -- are
+ * accepted into the txg in the open state, and are completed while the txg is
+ * in the open or quiescing states. The accumulated changes are written to
+ * disk in the syncing state.
+ *
+ * Open
+ *
+ * When a new txg becomes active, it first enters the open state. New
+ * transactions -- updates to in-memory structures -- are assigned to the
+ * currently open txg. There is always a txg in the open state so that ZFS can
+ * accept new changes (though the txg may refuse new changes if it has hit
+ * some limit). ZFS advances the open txg to the next state for a variety of
+ * reasons such as it hitting a time or size threshold, or the execution of an
+ * administrative action that must be completed in the syncing state.
+ *
+ * Quiescing
+ *
+ * After a txg exits the open state, it enters the quiescing state. The
+ * quiescing state is intended to provide a buffer between accepting new
+ * transactions in the open state and writing them out to stable storage in
+ * the syncing state. While quiescing, transactions can continue their
+ * operation without delaying either of the other states. Typically, a txg is
+ * in the quiescing state very briefly since the operations are bounded by
+ * software latencies rather than, say, slower I/O latencies. After all
+ * transactions complete, the txg is ready to enter the next state.
+ *
+ * Syncing
+ *
+ * In the syncing state, the in-memory state built up during the open and (to
+ * a lesser degree) the quiescing states is written to stable storage. The
+ * process of writing out modified data can, in turn modify more data. For
+ * example when we write new blocks, we need to allocate space for them; those
+ * allocations modify metadata (space maps)... which themselves must be
+ * written to stable storage. During the sync state, ZFS iterates, writing out
+ * data until it converges and all in-memory changes have been written out.
+ * The first such pass is the largest as it encompasses all the modified user
+ * data (as opposed to filesystem metadata). Subsequent passes typically have
+ * far less data to write as they consist exclusively of filesystem metadata.
+ *
+ * To ensure convergence, after a certain number of passes ZFS begins
+ * overwriting locations on stable storage that had been allocated earlier in
+ * the syncing state (and subsequently freed). ZFS usually allocates new
+ * blocks to optimize for large, continuous, writes. For the syncing state to
+ * converge however it must complete a pass where no new blocks are allocated
+ * since each allocation requires a modification of persistent metadata.
+ * Further, to hasten convergence, after a prescribed number of passes, ZFS
+ * also defers frees, and stops compressing.
+ *
+ * In addition to writing out user data, we must also execute synctasks during
+ * the syncing context. A synctask is the mechanism by which some
+ * administrative activities work such as creating and destroying snapshots or
+ * datasets. Note that when a synctask is initiated it enters the open txg,
+ * and ZFS then pushes that txg as quickly as possible to completion of the
+ * syncing state in order to reduce the latency of the administrative
+ * activity. To complete the syncing state, ZFS writes out a new uberblock,
+ * the root of the tree of blocks that comprise all state stored on the ZFS
+ * pool. Finally, if there is a quiesced txg waiting, we signal that it can
+ * now transition to the syncing state.
+ */
+
+static void txg_sync_thread(dsl_pool_t *dp);
+static void txg_quiesce_thread(dsl_pool_t *dp);
+
+int zfs_txg_timeout = 5;       /* max seconds worth of delta per txg */
+
+/*
+ * Prepare the txg subsystem.
+ */
+void
+txg_init(dsl_pool_t *dp, uint64_t txg)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       int c;
+       bzero(tx, sizeof (tx_state_t));
+
+       tx->tx_cpu = vmem_zalloc(max_ncpus * sizeof (tx_cpu_t), KM_SLEEP);
+
+       for (c = 0; c < max_ncpus; c++) {
+               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,
+                   NULL);
+               for (i = 0; i < TXG_SIZE; i++) {
+                       cv_init(&tx->tx_cpu[c].tc_cv[i], NULL, CV_DEFAULT,
+                           NULL);
+                       list_create(&tx->tx_cpu[c].tc_callbacks[i],
+                           sizeof (dmu_tx_callback_t),
+                           offsetof(dmu_tx_callback_t, dcb_node));
+               }
+       }
+
+       mutex_init(&tx->tx_sync_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       cv_init(&tx->tx_sync_more_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&tx->tx_sync_done_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&tx->tx_quiesce_more_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&tx->tx_quiesce_done_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&tx->tx_exit_cv, NULL, CV_DEFAULT, NULL);
+
+       tx->tx_open_txg = txg;
+}
+
+/*
+ * Close down the txg subsystem.
+ */
+void
+txg_fini(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       int c;
+
+       ASSERT(tx->tx_threads == 0);
+
+       mutex_destroy(&tx->tx_sync_lock);
+
+       cv_destroy(&tx->tx_sync_more_cv);
+       cv_destroy(&tx->tx_sync_done_cv);
+       cv_destroy(&tx->tx_quiesce_more_cv);
+       cv_destroy(&tx->tx_quiesce_done_cv);
+       cv_destroy(&tx->tx_exit_cv);
+
+       for (c = 0; c < max_ncpus; c++) {
+               int i;
+
+               mutex_destroy(&tx->tx_cpu[c].tc_open_lock);
+               mutex_destroy(&tx->tx_cpu[c].tc_lock);
+               for (i = 0; i < TXG_SIZE; i++) {
+                       cv_destroy(&tx->tx_cpu[c].tc_cv[i]);
+                       list_destroy(&tx->tx_cpu[c].tc_callbacks[i]);
+               }
+       }
+
+       if (tx->tx_commit_cb_taskq != NULL)
+               taskq_destroy(tx->tx_commit_cb_taskq);
+
+       vmem_free(tx->tx_cpu, max_ncpus * sizeof (tx_cpu_t));
+
+       bzero(tx, sizeof (tx_state_t));
+}
+
+/*
+ * Start syncing transaction groups.
+ */
+void
+txg_sync_start(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       mutex_enter(&tx->tx_sync_lock);
+
+       dprintf("pool %p\n", dp);
+
+       ASSERT(tx->tx_threads == 0);
+
+       tx->tx_threads = 2;
+
+       tx->tx_quiesce_thread = thread_create(NULL, 0, txg_quiesce_thread,
+           dp, 0, &p0, TS_RUN, defclsyspri);
+
+       /*
+        * The sync thread can need a larger-than-default stack size on
+        * 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,
+           dp, 0, &p0, TS_RUN, defclsyspri);
+
+       mutex_exit(&tx->tx_sync_lock);
+}
+
+static void
+txg_thread_enter(tx_state_t *tx, callb_cpr_t *cpr)
+{
+       CALLB_CPR_INIT(cpr, &tx->tx_sync_lock, callb_generic_cpr, FTAG);
+       mutex_enter(&tx->tx_sync_lock);
+}
+
+static void
+txg_thread_exit(tx_state_t *tx, callb_cpr_t *cpr, kthread_t **tpp)
+{
+       ASSERT(*tpp != NULL);
+       *tpp = NULL;
+       tx->tx_threads--;
+       cv_broadcast(&tx->tx_exit_cv);
+       CALLB_CPR_EXIT(cpr);            /* drops &tx->tx_sync_lock */
+       thread_exit();
+}
+
+static void
+txg_thread_wait(tx_state_t *tx, callb_cpr_t *cpr, kcondvar_t *cv, clock_t time)
+{
+       CALLB_CPR_SAFE_BEGIN(cpr);
+
+       if (time)
+               (void) cv_timedwait_sig(cv, &tx->tx_sync_lock,
+                   ddi_get_lbolt() + time);
+       else
+               cv_wait_sig(cv, &tx->tx_sync_lock);
+
+       CALLB_CPR_SAFE_END(cpr, &tx->tx_sync_lock);
+}
+
+/*
+ * Stop syncing transaction groups.
+ */
+void
+txg_sync_stop(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       dprintf("pool %p\n", dp);
+       /*
+        * Finish off any work in progress.
+        */
+       ASSERT(tx->tx_threads == 2);
+
+       /*
+        * We need to ensure that we've vacated the deferred space_maps.
+        */
+       txg_wait_synced(dp, tx->tx_open_txg + TXG_DEFER_SIZE);
+
+       /*
+        * Wake all sync threads and wait for them to die.
+        */
+       mutex_enter(&tx->tx_sync_lock);
+
+       ASSERT(tx->tx_threads == 2);
+
+       tx->tx_exiting = 1;
+
+       cv_broadcast(&tx->tx_quiesce_more_cv);
+       cv_broadcast(&tx->tx_quiesce_done_cv);
+       cv_broadcast(&tx->tx_sync_more_cv);
+
+       while (tx->tx_threads != 0)
+               cv_wait(&tx->tx_exit_cv, &tx->tx_sync_lock);
+
+       tx->tx_exiting = 0;
+
+       mutex_exit(&tx->tx_sync_lock);
+}
+
+uint64_t
+txg_hold_open(dsl_pool_t *dp, txg_handle_t *th)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       tx_cpu_t *tc;
+       uint64_t txg;
+
+       /*
+        * It appears the processor id is simply used as a "random"
+        * number to index into the array, and there isn't any other
+        * significance to the chosen tx_cpu. Because.. Why not use
+        * the current cpu to index into the array?
+        */
+       kpreempt_disable();
+       tc = &tx->tx_cpu[CPU_SEQID];
+       kpreempt_enable();
+
+       mutex_enter(&tc->tc_open_lock);
+       txg = tx->tx_open_txg;
+
+       mutex_enter(&tc->tc_lock);
+       tc->tc_count[txg & TXG_MASK]++;
+       mutex_exit(&tc->tc_lock);
+
+       th->th_cpu = tc;
+       th->th_txg = txg;
+
+       return (txg);
+}
+
+void
+txg_rele_to_quiesce(txg_handle_t *th)
+{
+       tx_cpu_t *tc = th->th_cpu;
+
+       ASSERT(!MUTEX_HELD(&tc->tc_lock));
+       mutex_exit(&tc->tc_open_lock);
+}
+
+void
+txg_register_callbacks(txg_handle_t *th, list_t *tx_callbacks)
+{
+       tx_cpu_t *tc = th->th_cpu;
+       int g = th->th_txg & TXG_MASK;
+
+       mutex_enter(&tc->tc_lock);
+       list_move_tail(&tc->tc_callbacks[g], tx_callbacks);
+       mutex_exit(&tc->tc_lock);
+}
+
+void
+txg_rele_to_sync(txg_handle_t *th)
+{
+       tx_cpu_t *tc = th->th_cpu;
+       int g = th->th_txg & TXG_MASK;
+
+       mutex_enter(&tc->tc_lock);
+       ASSERT(tc->tc_count[g] != 0);
+       if (--tc->tc_count[g] == 0)
+               cv_broadcast(&tc->tc_cv[g]);
+       mutex_exit(&tc->tc_lock);
+
+       th->th_cpu = NULL;      /* defensive */
+}
+
+/*
+ * Blocks until all transactions in the group are committed.
+ *
+ * On return, the transaction group has reached a stable state in which it can
+ * then be passed off to the syncing context.
+ */
+static void
+txg_quiesce(dsl_pool_t *dp, uint64_t txg)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       int g = txg & TXG_MASK;
+       int c;
+
+       /*
+        * Grab all tc_open_locks so nobody else can get into this txg.
+        */
+       for (c = 0; c < max_ncpus; c++)
+               mutex_enter(&tx->tx_cpu[c].tc_open_lock);
+
+       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);
+
+       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);
+
+       /*
+        * Now that we've incremented tx_open_txg, we can let threads
+        * enter the next transaction group.
+        */
+       for (c = 0; c < max_ncpus; c++)
+               mutex_exit(&tx->tx_cpu[c].tc_open_lock);
+
+       /*
+        * Quiesce the transaction group by waiting for everyone to txg_exit().
+        */
+       for (c = 0; c < max_ncpus; c++) {
+               tx_cpu_t *tc = &tx->tx_cpu[c];
+               mutex_enter(&tc->tc_lock);
+               while (tc->tc_count[g] != 0)
+                       cv_wait(&tc->tc_cv[g], &tc->tc_lock);
+               mutex_exit(&tc->tc_lock);
+       }
+
+       spa_txg_history_set(dp->dp_spa, txg, TXG_STATE_QUIESCED, gethrtime());
+}
+
+static void
+txg_do_callbacks(list_t *cb_list)
+{
+       dmu_tx_do_callbacks(cb_list, 0);
+
+       list_destroy(cb_list);
+
+       kmem_free(cb_list, sizeof (list_t));
+}
+
+/*
+ * Dispatch the commit callbacks registered on this txg to worker threads.
+ *
+ * If no callbacks are registered for a given TXG, nothing happens.
+ * This function creates a taskq for the associated pool, if needed.
+ */
+static void
+txg_dispatch_callbacks(dsl_pool_t *dp, uint64_t txg)
+{
+       int c;
+       tx_state_t *tx = &dp->dp_tx;
+       list_t *cb_list;
+
+       for (c = 0; c < max_ncpus; c++) {
+               tx_cpu_t *tc = &tx->tx_cpu[c];
+               /*
+                * No need to lock tx_cpu_t at this point, since this can
+                * only be called once a txg has been synced.
+                */
+
+               int g = txg & TXG_MASK;
+
+               if (list_is_empty(&tc->tc_callbacks[g]))
+                       continue;
+
+               if (tx->tx_commit_cb_taskq == NULL) {
+                       /*
+                        * Commit callback taskq hasn't been created yet.
+                        */
+                       tx->tx_commit_cb_taskq = taskq_create("tx_commit_cb",
+                           max_ncpus, defclsyspri, max_ncpus, max_ncpus * 2,
+                           TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
+               }
+
+               cb_list = kmem_alloc(sizeof (list_t), KM_SLEEP);
+               list_create(cb_list, sizeof (dmu_tx_callback_t),
+                   offsetof(dmu_tx_callback_t, dcb_node));
+
+               list_move_tail(cb_list, &tc->tc_callbacks[g]);
+
+               (void) taskq_dispatch(tx->tx_commit_cb_taskq, (task_func_t *)
+                   txg_do_callbacks, cb_list, TQ_SLEEP);
+       }
+}
+
+/*
+ * Wait for pending commit callbacks of already-synced transactions to finish
+ * processing.
+ * Calling this function from within a commit callback will deadlock.
+ */
+void
+txg_wait_callbacks(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       if (tx->tx_commit_cb_taskq != NULL)
+               taskq_wait_outstanding(tx->tx_commit_cb_taskq, 0);
+}
+
+static void
+txg_sync_thread(dsl_pool_t *dp)
+{
+       spa_t *spa = dp->dp_spa;
+       tx_state_t *tx = &dp->dp_tx;
+       callb_cpr_t cpr;
+       vdev_stat_t *vs1, *vs2;
+       clock_t start, delta;
+
+       (void) spl_fstrans_mark();
+       txg_thread_enter(tx, &cpr);
+
+       vs1 = kmem_alloc(sizeof (vdev_stat_t), KM_SLEEP);
+       vs2 = kmem_alloc(sizeof (vdev_stat_t), KM_SLEEP);
+
+       start = delta = 0;
+       for (;;) {
+               clock_t timer, timeout;
+               uint64_t txg;
+               uint64_t ndirty;
+
+               timeout = zfs_txg_timeout * hz;
+
+               /*
+                * We sync when we're scanning, there's someone waiting
+                * on us, or the quiesce thread has handed off a txg to
+                * us, or we have reached our timeout.
+                */
+               timer = (delta >= timeout ? 0 : timeout - delta);
+               while (!dsl_scan_active(dp->dp_scan) &&
+                   !tx->tx_exiting && timer > 0 &&
+                   tx->tx_synced_txg >= tx->tx_sync_txg_waiting &&
+                   tx->tx_quiesced_txg == 0 &&
+                   dp->dp_dirty_total < zfs_dirty_data_sync) {
+                       dprintf("waiting; tx_synced=%llu waiting=%llu dp=%p\n",
+                           tx->tx_synced_txg, tx->tx_sync_txg_waiting, dp);
+                       txg_thread_wait(tx, &cpr, &tx->tx_sync_more_cv, timer);
+                       delta = ddi_get_lbolt() - start;
+                       timer = (delta > timeout ? 0 : timeout - delta);
+               }
+
+               /*
+                * Wait until the quiesce thread hands off a txg to us,
+                * prompting it to do so if necessary.
+                */
+               while (!tx->tx_exiting && tx->tx_quiesced_txg == 0) {
+                       if (tx->tx_quiesce_txg_waiting < tx->tx_open_txg+1)
+                               tx->tx_quiesce_txg_waiting = tx->tx_open_txg+1;
+                       cv_broadcast(&tx->tx_quiesce_more_cv);
+                       txg_thread_wait(tx, &cpr, &tx->tx_quiesce_done_cv, 0);
+               }
+
+               if (tx->tx_exiting) {
+                       kmem_free(vs2, sizeof (vdev_stat_t));
+                       kmem_free(vs1, sizeof (vdev_stat_t));
+                       txg_thread_exit(tx, &cpr, &tx->tx_sync_thread);
+               }
+
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_READER);
+               vdev_get_stats(spa->spa_root_vdev, vs1);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+
+               /*
+                * Consume the quiesced txg which has been handed off to
+                * us.  This may cause the quiescing thread to now be
+                * able to quiesce another txg, so we must signal it.
+                */
+               txg = tx->tx_quiesced_txg;
+               tx->tx_quiesced_txg = 0;
+               tx->tx_syncing_txg = txg;
+               DTRACE_PROBE2(txg__syncing, dsl_pool_t *, dp, uint64_t, txg);
+               cv_broadcast(&tx->tx_quiesce_more_cv);
+
+               dprintf("txg=%llu quiesce_txg=%llu sync_txg=%llu\n",
+                   txg, tx->tx_quiesce_txg_waiting, tx->tx_sync_txg_waiting);
+               mutex_exit(&tx->tx_sync_lock);
+
+               spa_txg_history_set(spa, txg, TXG_STATE_WAIT_FOR_SYNC,
+                   gethrtime());
+               ndirty = dp->dp_dirty_pertxg[txg & TXG_MASK];
+
+               start = ddi_get_lbolt();
+               spa_sync(spa, txg);
+               delta = ddi_get_lbolt() - start;
+
+               mutex_enter(&tx->tx_sync_lock);
+               tx->tx_synced_txg = txg;
+               tx->tx_syncing_txg = 0;
+               DTRACE_PROBE2(txg__synced, dsl_pool_t *, dp, uint64_t, txg);
+               cv_broadcast(&tx->tx_sync_done_cv);
+
+               /*
+                * Dispatch commit callbacks to worker threads.
+                */
+               txg_dispatch_callbacks(dp, txg);
+
+               spa_config_enter(spa, SCL_ALL, FTAG, RW_READER);
+               vdev_get_stats(spa->spa_root_vdev, vs2);
+               spa_config_exit(spa, SCL_ALL, FTAG);
+               spa_txg_history_set_io(spa, txg,
+                   vs2->vs_bytes[ZIO_TYPE_READ]-vs1->vs_bytes[ZIO_TYPE_READ],
+                   vs2->vs_bytes[ZIO_TYPE_WRITE]-vs1->vs_bytes[ZIO_TYPE_WRITE],
+                   vs2->vs_ops[ZIO_TYPE_READ]-vs1->vs_ops[ZIO_TYPE_READ],
+                   vs2->vs_ops[ZIO_TYPE_WRITE]-vs1->vs_ops[ZIO_TYPE_WRITE],
+                   ndirty);
+               spa_txg_history_set(spa, txg, TXG_STATE_SYNCED, gethrtime());
+       }
+}
+
+static void
+txg_quiesce_thread(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       callb_cpr_t cpr;
+
+       txg_thread_enter(tx, &cpr);
+
+       for (;;) {
+               uint64_t txg;
+
+               /*
+                * We quiesce when there's someone waiting on us.
+                * However, we can only have one txg in "quiescing" or
+                * "quiesced, waiting to sync" state.  So we wait until
+                * the "quiesced, waiting to sync" txg has been consumed
+                * by the sync thread.
+                */
+               while (!tx->tx_exiting &&
+                   (tx->tx_open_txg >= tx->tx_quiesce_txg_waiting ||
+                   tx->tx_quiesced_txg != 0))
+                       txg_thread_wait(tx, &cpr, &tx->tx_quiesce_more_cv, 0);
+
+               if (tx->tx_exiting)
+                       txg_thread_exit(tx, &cpr, &tx->tx_quiesce_thread);
+
+               txg = tx->tx_open_txg;
+               dprintf("txg=%llu quiesce_txg=%llu sync_txg=%llu\n",
+                   txg, tx->tx_quiesce_txg_waiting,
+                   tx->tx_sync_txg_waiting);
+               mutex_exit(&tx->tx_sync_lock);
+               txg_quiesce(dp, txg);
+               mutex_enter(&tx->tx_sync_lock);
+
+               /*
+                * Hand this txg off to the sync thread.
+                */
+               dprintf("quiesce done, handing off txg %llu\n", txg);
+               tx->tx_quiesced_txg = txg;
+               DTRACE_PROBE2(txg__quiesced, dsl_pool_t *, dp, uint64_t, txg);
+               cv_broadcast(&tx->tx_sync_more_cv);
+               cv_broadcast(&tx->tx_quiesce_done_cv);
+       }
+}
+
+/*
+ * Delay this thread by delay nanoseconds if we are still in the open
+ * transaction group and there is already a waiting txg quiesing or quiesced.
+ * Abort the delay if this txg stalls or enters the quiesing state.
+ */
+void
+txg_delay(dsl_pool_t *dp, uint64_t txg, hrtime_t delay, hrtime_t resolution)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       hrtime_t start = gethrtime();
+
+       /* don't delay if this txg could transition to quiescing immediately */
+       if (tx->tx_open_txg > txg ||
+           tx->tx_syncing_txg == txg-1 || tx->tx_synced_txg == txg-1)
+               return;
+
+       mutex_enter(&tx->tx_sync_lock);
+       if (tx->tx_open_txg > txg || tx->tx_synced_txg == txg-1) {
+               mutex_exit(&tx->tx_sync_lock);
+               return;
+       }
+
+       while (gethrtime() - start < delay &&
+           tx->tx_syncing_txg < txg-1 && !txg_stalled(dp)) {
+               (void) cv_timedwait_hires(&tx->tx_quiesce_more_cv,
+                   &tx->tx_sync_lock, delay, resolution, 0);
+       }
+
+       DMU_TX_STAT_BUMP(dmu_tx_delay);
+
+       mutex_exit(&tx->tx_sync_lock);
+}
+
+void
+txg_wait_synced(dsl_pool_t *dp, uint64_t txg)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       ASSERT(!dsl_pool_config_held(dp));
+
+       mutex_enter(&tx->tx_sync_lock);
+       ASSERT(tx->tx_threads == 2);
+       if (txg == 0)
+               txg = tx->tx_open_txg + TXG_DEFER_SIZE;
+       if (tx->tx_sync_txg_waiting < txg)
+               tx->tx_sync_txg_waiting = txg;
+       dprintf("txg=%llu quiesce_txg=%llu sync_txg=%llu\n",
+           txg, tx->tx_quiesce_txg_waiting, tx->tx_sync_txg_waiting);
+       while (tx->tx_synced_txg < txg) {
+               dprintf("broadcasting sync more "
+                   "tx_synced=%llu waiting=%llu dp=%p\n",
+                   tx->tx_synced_txg, tx->tx_sync_txg_waiting, dp);
+               cv_broadcast(&tx->tx_sync_more_cv);
+               cv_wait(&tx->tx_sync_done_cv, &tx->tx_sync_lock);
+       }
+       mutex_exit(&tx->tx_sync_lock);
+}
+
+void
+txg_wait_open(dsl_pool_t *dp, uint64_t txg)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       ASSERT(!dsl_pool_config_held(dp));
+
+       mutex_enter(&tx->tx_sync_lock);
+       ASSERT(tx->tx_threads == 2);
+       if (txg == 0)
+               txg = tx->tx_open_txg + 1;
+       if (tx->tx_quiesce_txg_waiting < txg)
+               tx->tx_quiesce_txg_waiting = txg;
+       dprintf("txg=%llu quiesce_txg=%llu sync_txg=%llu\n",
+           txg, tx->tx_quiesce_txg_waiting, tx->tx_sync_txg_waiting);
+       while (tx->tx_open_txg < txg) {
+               cv_broadcast(&tx->tx_quiesce_more_cv);
+               cv_wait(&tx->tx_quiesce_done_cv, &tx->tx_sync_lock);
+       }
+       mutex_exit(&tx->tx_sync_lock);
+}
+
+/*
+ * If there isn't a txg syncing or in the pipeline, push another txg through
+ * the pipeline by queiscing the open txg.
+ */
+void
+txg_kick(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       ASSERT(!dsl_pool_config_held(dp));
+
+       mutex_enter(&tx->tx_sync_lock);
+       if (tx->tx_syncing_txg == 0 &&
+           tx->tx_quiesce_txg_waiting <= tx->tx_open_txg &&
+           tx->tx_sync_txg_waiting <= tx->tx_synced_txg &&
+           tx->tx_quiesced_txg <= tx->tx_synced_txg) {
+               tx->tx_quiesce_txg_waiting = tx->tx_open_txg + 1;
+               cv_broadcast(&tx->tx_quiesce_more_cv);
+       }
+       mutex_exit(&tx->tx_sync_lock);
+}
+
+boolean_t
+txg_stalled(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+       return (tx->tx_quiesce_txg_waiting > tx->tx_open_txg);
+}
+
+boolean_t
+txg_sync_waiting(dsl_pool_t *dp)
+{
+       tx_state_t *tx = &dp->dp_tx;
+
+       return (tx->tx_syncing_txg <= tx->tx_sync_txg_waiting ||
+           tx->tx_quiesced_txg != 0);
+}
+
+/*
+ * Per-txg object lists.
+ */
+void
+txg_list_create(txg_list_t *tl, size_t offset)
+{
+       int t;
+
+       mutex_init(&tl->tl_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       tl->tl_offset = offset;
+
+       for (t = 0; t < TXG_SIZE; t++)
+               tl->tl_head[t] = NULL;
+}
+
+void
+txg_list_destroy(txg_list_t *tl)
+{
+       int t;
+
+       for (t = 0; t < TXG_SIZE; t++)
+               ASSERT(txg_list_empty(tl, t));
+
+       mutex_destroy(&tl->tl_lock);
+}
+
+boolean_t
+txg_list_empty(txg_list_t *tl, uint64_t txg)
+{
+       return (tl->tl_head[txg & TXG_MASK] == NULL);
+}
+
+/*
+ * Returns true if all txg lists are empty.
+ *
+ * Warning: this is inherently racy (an item could be added immediately
+ * after this function returns). We don't bother with the lock because
+ * it wouldn't change the semantics.
+ */
+boolean_t
+txg_all_lists_empty(txg_list_t *tl)
+{
+       int i;
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               if (!txg_list_empty(tl, i)) {
+                       return (B_FALSE);
+               }
+       }
+       return (B_TRUE);
+}
+
+/*
+ * Add an entry to the list (unless it's already on the list).
+ * Returns B_TRUE if it was actually added.
+ */
+boolean_t
+txg_list_add(txg_list_t *tl, void *p, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn = (txg_node_t *)((char *)p + tl->tl_offset);
+       boolean_t add;
+
+       mutex_enter(&tl->tl_lock);
+       add = (tn->tn_member[t] == 0);
+       if (add) {
+               tn->tn_member[t] = 1;
+               tn->tn_next[t] = tl->tl_head[t];
+               tl->tl_head[t] = tn;
+       }
+       mutex_exit(&tl->tl_lock);
+
+       return (add);
+}
+
+/*
+ * Add an entry to the end of the list, unless it's already on the list.
+ * (walks list to find end)
+ * Returns B_TRUE if it was actually added.
+ */
+boolean_t
+txg_list_add_tail(txg_list_t *tl, void *p, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn = (txg_node_t *)((char *)p + tl->tl_offset);
+       boolean_t add;
+
+       mutex_enter(&tl->tl_lock);
+       add = (tn->tn_member[t] == 0);
+       if (add) {
+               txg_node_t **tp;
+
+               for (tp = &tl->tl_head[t]; *tp != NULL; tp = &(*tp)->tn_next[t])
+                       continue;
+
+               tn->tn_member[t] = 1;
+               tn->tn_next[t] = NULL;
+               *tp = tn;
+       }
+       mutex_exit(&tl->tl_lock);
+
+       return (add);
+}
+
+/*
+ * Remove the head of the list and return it.
+ */
+void *
+txg_list_remove(txg_list_t *tl, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn;
+       void *p = NULL;
+
+       mutex_enter(&tl->tl_lock);
+       if ((tn = tl->tl_head[t]) != NULL) {
+               p = (char *)tn - tl->tl_offset;
+               tl->tl_head[t] = tn->tn_next[t];
+               tn->tn_next[t] = NULL;
+               tn->tn_member[t] = 0;
+       }
+       mutex_exit(&tl->tl_lock);
+
+       return (p);
+}
+
+/*
+ * Remove a specific item from the list and return it.
+ */
+void *
+txg_list_remove_this(txg_list_t *tl, void *p, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn, **tp;
+
+       mutex_enter(&tl->tl_lock);
+
+       for (tp = &tl->tl_head[t]; (tn = *tp) != NULL; tp = &tn->tn_next[t]) {
+               if ((char *)tn - tl->tl_offset == p) {
+                       *tp = tn->tn_next[t];
+                       tn->tn_next[t] = NULL;
+                       tn->tn_member[t] = 0;
+                       mutex_exit(&tl->tl_lock);
+                       return (p);
+               }
+       }
+
+       mutex_exit(&tl->tl_lock);
+
+       return (NULL);
+}
+
+boolean_t
+txg_list_member(txg_list_t *tl, void *p, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn = (txg_node_t *)((char *)p + tl->tl_offset);
+
+       return (tn->tn_member[t] != 0);
+}
+
+/*
+ * Walk a txg list -- only safe if you know it's not changing.
+ */
+void *
+txg_list_head(txg_list_t *tl, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn = tl->tl_head[t];
+
+       return (tn == NULL ? NULL : (char *)tn - tl->tl_offset);
+}
+
+void *
+txg_list_next(txg_list_t *tl, void *p, uint64_t txg)
+{
+       int t = txg & TXG_MASK;
+       txg_node_t *tn = (txg_node_t *)((char *)p + tl->tl_offset);
+
+       tn = tn->tn_next[t];
+
+       return (tn == NULL ? NULL : (char *)tn - tl->tl_offset);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(txg_init);
+EXPORT_SYMBOL(txg_fini);
+EXPORT_SYMBOL(txg_sync_start);
+EXPORT_SYMBOL(txg_sync_stop);
+EXPORT_SYMBOL(txg_hold_open);
+EXPORT_SYMBOL(txg_rele_to_quiesce);
+EXPORT_SYMBOL(txg_rele_to_sync);
+EXPORT_SYMBOL(txg_register_callbacks);
+EXPORT_SYMBOL(txg_delay);
+EXPORT_SYMBOL(txg_wait_synced);
+EXPORT_SYMBOL(txg_wait_open);
+EXPORT_SYMBOL(txg_wait_callbacks);
+EXPORT_SYMBOL(txg_stalled);
+EXPORT_SYMBOL(txg_sync_waiting);
+
+module_param(zfs_txg_timeout, int, 0644);
+MODULE_PARM_DESC(zfs_txg_timeout, "Max seconds worth of delta per txg");
+#endif
diff --git a/zfs/module/zfs/uberblock.c b/zfs/module/zfs/uberblock.c
new file mode 100644 (file)
index 0000000..f8bdecd
--- /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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/uberblock_impl.h>
+#include <sys/vdev_impl.h>
+
+int
+uberblock_verify(uberblock_t *ub)
+{
+       if (ub->ub_magic == BSWAP_64((uint64_t)UBERBLOCK_MAGIC))
+               byteswap_uint64_array(ub, sizeof (uberblock_t));
+
+       if (ub->ub_magic != UBERBLOCK_MAGIC)
+               return (SET_ERROR(EINVAL));
+
+       return (0);
+}
+
+/*
+ * Update the uberblock and return TRUE if anything changed in this
+ * transaction group.
+ */
+boolean_t
+uberblock_update(uberblock_t *ub, vdev_t *rvd, uint64_t txg)
+{
+       ASSERT(ub->ub_txg < txg);
+
+       /*
+        * We explicitly do not set ub_version here, so that older versions
+        * continue to be written with the previous uberblock version.
+        */
+       ub->ub_magic = UBERBLOCK_MAGIC;
+       ub->ub_txg = txg;
+       ub->ub_guid_sum = rvd->vdev_guid_sum;
+       ub->ub_timestamp = gethrestime_sec();
+       ub->ub_software_version = SPA_VERSION;
+
+       return (ub->ub_rootbp.blk_birth == txg);
+}
diff --git a/zfs/module/zfs/unique.c b/zfs/module/zfs/unique.c
new file mode 100644 (file)
index 0000000..8c1d2e2
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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/avl.h>
+#include <sys/unique.h>
+
+static avl_tree_t unique_avl;
+static kmutex_t unique_mtx;
+
+typedef struct unique {
+       avl_node_t un_link;
+       uint64_t un_value;
+} unique_t;
+
+#define        UNIQUE_MASK ((1ULL << UNIQUE_BITS) - 1)
+
+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);
+}
+
+void
+unique_init(void)
+{
+       avl_create(&unique_avl, unique_compare,
+           sizeof (unique_t), offsetof(unique_t, un_link));
+       mutex_init(&unique_mtx, NULL, MUTEX_DEFAULT, NULL);
+}
+
+void
+unique_fini(void)
+{
+       avl_destroy(&unique_avl);
+       mutex_destroy(&unique_mtx);
+}
+
+uint64_t
+unique_create(void)
+{
+       uint64_t value = unique_insert(0);
+       unique_remove(value);
+       return (value);
+}
+
+uint64_t
+unique_insert(uint64_t value)
+{
+       avl_index_t idx;
+       unique_t *un = kmem_alloc(sizeof (unique_t), KM_SLEEP);
+
+       un->un_value = value;
+
+       mutex_enter(&unique_mtx);
+       while (un->un_value == 0 || un->un_value & ~UNIQUE_MASK ||
+           avl_find(&unique_avl, un, &idx)) {
+               mutex_exit(&unique_mtx);
+               (void) random_get_pseudo_bytes((void*)&un->un_value,
+                   sizeof (un->un_value));
+               un->un_value &= UNIQUE_MASK;
+               mutex_enter(&unique_mtx);
+       }
+
+       avl_insert(&unique_avl, un, idx);
+       mutex_exit(&unique_mtx);
+
+       return (un->un_value);
+}
+
+void
+unique_remove(uint64_t value)
+{
+       unique_t un_tofind;
+       unique_t *un;
+
+       un_tofind.un_value = value;
+       mutex_enter(&unique_mtx);
+       un = avl_find(&unique_avl, &un_tofind, NULL);
+       if (un != NULL) {
+               avl_remove(&unique_avl, un);
+               kmem_free(un, sizeof (unique_t));
+       }
+       mutex_exit(&unique_mtx);
+}
diff --git a/zfs/module/zfs/vdev.c b/zfs/module/zfs/vdev.c
new file mode 100644 (file)
index 0000000..7d814a6
--- /dev/null
@@ -0,0 +1,3448 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/fm/fs/zfs.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/dmu_tx.h>
+#include <sys/vdev_impl.h>
+#include <sys/uberblock_impl.h>
+#include <sys/metaslab.h>
+#include <sys/metaslab_impl.h>
+#include <sys/space_map.h>
+#include <sys/space_reftree.h>
+#include <sys/zio.h>
+#include <sys/zap.h>
+#include <sys/fs/zfs.h>
+#include <sys/arc.h>
+#include <sys/zil.h>
+#include <sys/dsl_scan.h>
+#include <sys/zvol.h>
+
+/*
+ * When a vdev is added, it will be divided into approximately (but no
+ * more than) this number of metaslabs.
+ */
+int metaslabs_per_vdev = 200;
+
+/*
+ * Virtual device management.
+ */
+
+static vdev_ops_t *vdev_ops_table[] = {
+       &vdev_root_ops,
+       &vdev_raidz_ops,
+       &vdev_mirror_ops,
+       &vdev_replacing_ops,
+       &vdev_spare_ops,
+       &vdev_disk_ops,
+       &vdev_file_ops,
+       &vdev_missing_ops,
+       &vdev_hole_ops,
+       NULL
+};
+
+/*
+ * Given a vdev type, return the appropriate ops vector.
+ */
+static vdev_ops_t *
+vdev_getops(const char *type)
+{
+       vdev_ops_t *ops, **opspp;
+
+       for (opspp = vdev_ops_table; (ops = *opspp) != NULL; opspp++)
+               if (strcmp(ops->vdev_op_type, type) == 0)
+                       break;
+
+       return (ops);
+}
+
+/*
+ * Default asize function: return the MAX of psize with the asize of
+ * all children.  This is what's used by anything other than RAID-Z.
+ */
+uint64_t
+vdev_default_asize(vdev_t *vd, uint64_t psize)
+{
+       uint64_t asize = P2ROUNDUP(psize, 1ULL << vd->vdev_top->vdev_ashift);
+       uint64_t csize;
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               csize = vdev_psize_to_asize(vd->vdev_child[c], psize);
+               asize = MAX(asize, csize);
+       }
+
+       return (asize);
+}
+
+/*
+ * Get the minimum allocatable size. We define the allocatable size as
+ * the vdev's asize rounded to the nearest metaslab. This allows us to
+ * replace or attach devices which don't have the same physical size but
+ * can still satisfy the same number of allocations.
+ */
+uint64_t
+vdev_get_min_asize(vdev_t *vd)
+{
+       vdev_t *pvd = vd->vdev_parent;
+
+       /*
+        * If our parent is NULL (inactive spare or cache) or is the root,
+        * just return our own asize.
+        */
+       if (pvd == NULL)
+               return (vd->vdev_asize);
+
+       /*
+        * The top-level vdev just returns the allocatable size rounded
+        * to the nearest metaslab.
+        */
+       if (vd == vd->vdev_top)
+               return (P2ALIGN(vd->vdev_asize, 1ULL << vd->vdev_ms_shift));
+
+       /*
+        * The allocatable space for a raidz vdev is N * sizeof(smallest child),
+        * so each child must provide at least 1/Nth of its asize.
+        */
+       if (pvd->vdev_ops == &vdev_raidz_ops)
+               return (pvd->vdev_min_asize / pvd->vdev_children);
+
+       return (pvd->vdev_min_asize);
+}
+
+void
+vdev_set_min_asize(vdev_t *vd)
+{
+       int c;
+       vd->vdev_min_asize = vdev_get_min_asize(vd);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_set_min_asize(vd->vdev_child[c]);
+}
+
+vdev_t *
+vdev_lookup_top(spa_t *spa, uint64_t vdev)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+
+       if (vdev < rvd->vdev_children) {
+               ASSERT(rvd->vdev_child[vdev] != NULL);
+               return (rvd->vdev_child[vdev]);
+       }
+
+       return (NULL);
+}
+
+vdev_t *
+vdev_lookup_by_guid(vdev_t *vd, uint64_t guid)
+{
+       vdev_t *mvd;
+       int c;
+
+       if (vd->vdev_guid == guid)
+               return (vd);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               if ((mvd = vdev_lookup_by_guid(vd->vdev_child[c], guid)) !=
+                   NULL)
+                       return (mvd);
+
+       return (NULL);
+}
+
+static int
+vdev_count_leaves_impl(vdev_t *vd)
+{
+       int n = 0;
+       int c;
+
+       if (vd->vdev_ops->vdev_op_leaf)
+               return (1);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               n += vdev_count_leaves_impl(vd->vdev_child[c]);
+
+       return (n);
+}
+
+int
+vdev_count_leaves(spa_t *spa)
+{
+       return (vdev_count_leaves_impl(spa->spa_root_vdev));
+}
+
+void
+vdev_add_child(vdev_t *pvd, vdev_t *cvd)
+{
+       size_t oldsize, newsize;
+       uint64_t id = cvd->vdev_id;
+       vdev_t **newchild;
+
+       ASSERT(spa_config_held(cvd->vdev_spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+       ASSERT(cvd->vdev_parent == NULL);
+
+       cvd->vdev_parent = pvd;
+
+       if (pvd == NULL)
+               return;
+
+       ASSERT(id >= pvd->vdev_children || pvd->vdev_child[id] == NULL);
+
+       oldsize = pvd->vdev_children * sizeof (vdev_t *);
+       pvd->vdev_children = MAX(pvd->vdev_children, id + 1);
+       newsize = pvd->vdev_children * sizeof (vdev_t *);
+
+       newchild = kmem_alloc(newsize, KM_SLEEP);
+       if (pvd->vdev_child != NULL) {
+               bcopy(pvd->vdev_child, newchild, oldsize);
+               kmem_free(pvd->vdev_child, oldsize);
+       }
+
+       pvd->vdev_child = newchild;
+       pvd->vdev_child[id] = cvd;
+
+       cvd->vdev_top = (pvd->vdev_top ? pvd->vdev_top: cvd);
+       ASSERT(cvd->vdev_top->vdev_parent->vdev_parent == NULL);
+
+       /*
+        * Walk up all ancestors to update guid sum.
+        */
+       for (; pvd != NULL; pvd = pvd->vdev_parent)
+               pvd->vdev_guid_sum += cvd->vdev_guid_sum;
+}
+
+void
+vdev_remove_child(vdev_t *pvd, vdev_t *cvd)
+{
+       int c;
+       uint_t id = cvd->vdev_id;
+
+       ASSERT(cvd->vdev_parent == pvd);
+
+       if (pvd == NULL)
+               return;
+
+       ASSERT(id < pvd->vdev_children);
+       ASSERT(pvd->vdev_child[id] == cvd);
+
+       pvd->vdev_child[id] = NULL;
+       cvd->vdev_parent = NULL;
+
+       for (c = 0; c < pvd->vdev_children; c++)
+               if (pvd->vdev_child[c])
+                       break;
+
+       if (c == pvd->vdev_children) {
+               kmem_free(pvd->vdev_child, c * sizeof (vdev_t *));
+               pvd->vdev_child = NULL;
+               pvd->vdev_children = 0;
+       }
+
+       /*
+        * Walk up all ancestors to update guid sum.
+        */
+       for (; pvd != NULL; pvd = pvd->vdev_parent)
+               pvd->vdev_guid_sum -= cvd->vdev_guid_sum;
+}
+
+/*
+ * Remove any holes in the child array.
+ */
+void
+vdev_compact_children(vdev_t *pvd)
+{
+       vdev_t **newchild, *cvd;
+       int oldc = pvd->vdev_children;
+       int newc;
+       int c;
+
+       ASSERT(spa_config_held(pvd->vdev_spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       for (c = newc = 0; c < oldc; c++)
+               if (pvd->vdev_child[c])
+                       newc++;
+
+       newchild = kmem_zalloc(newc * sizeof (vdev_t *), KM_SLEEP);
+
+       for (c = newc = 0; c < oldc; c++) {
+               if ((cvd = pvd->vdev_child[c]) != NULL) {
+                       newchild[newc] = cvd;
+                       cvd->vdev_id = newc++;
+               }
+       }
+
+       kmem_free(pvd->vdev_child, oldc * sizeof (vdev_t *));
+       pvd->vdev_child = newchild;
+       pvd->vdev_children = newc;
+}
+
+/*
+ * Allocate and minimally initialize a vdev_t.
+ */
+vdev_t *
+vdev_alloc_common(spa_t *spa, uint_t id, uint64_t guid, vdev_ops_t *ops)
+{
+       vdev_t *vd;
+       int t;
+
+       vd = kmem_zalloc(sizeof (vdev_t), KM_SLEEP);
+
+       if (spa->spa_root_vdev == NULL) {
+               ASSERT(ops == &vdev_root_ops);
+               spa->spa_root_vdev = vd;
+               spa->spa_load_guid = spa_generate_guid(NULL);
+       }
+
+       if (guid == 0 && ops != &vdev_hole_ops) {
+               if (spa->spa_root_vdev == vd) {
+                       /*
+                        * The root vdev's guid will also be the pool guid,
+                        * which must be unique among all pools.
+                        */
+                       guid = spa_generate_guid(NULL);
+               } else {
+                       /*
+                        * Any other vdev's guid must be unique within the pool.
+                        */
+                       guid = spa_generate_guid(spa);
+               }
+               ASSERT(!spa_guid_exists(spa_guid(spa), guid));
+       }
+
+       vd->vdev_spa = spa;
+       vd->vdev_id = id;
+       vd->vdev_guid = guid;
+       vd->vdev_guid_sum = guid;
+       vd->vdev_ops = ops;
+       vd->vdev_state = VDEV_STATE_CLOSED;
+       vd->vdev_ishole = (ops == &vdev_hole_ops);
+
+       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_stat_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&vd->vdev_probe_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);
+       }
+       txg_list_create(&vd->vdev_ms_list,
+           offsetof(struct metaslab, ms_txg_node));
+       txg_list_create(&vd->vdev_dtl_list,
+           offsetof(struct vdev, vdev_dtl_node));
+       vd->vdev_stat.vs_timestamp = gethrtime();
+       vdev_queue_init(vd);
+       vdev_cache_init(vd);
+
+       return (vd);
+}
+
+/*
+ * Allocate a new vdev.  The 'alloctype' is used to control whether we are
+ * creating a new vdev or loading an existing one - the behavior is slightly
+ * different for each case.
+ */
+int
+vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
+    int alloctype)
+{
+       vdev_ops_t *ops;
+       char *type;
+       uint64_t guid = 0, islog, nparity;
+       vdev_t *vd;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
+               return (SET_ERROR(EINVAL));
+
+       if ((ops = vdev_getops(type)) == NULL)
+               return (SET_ERROR(EINVAL));
+
+       /*
+        * If this is a load, get the vdev guid from the nvlist.
+        * Otherwise, vdev_alloc_common() will generate one for us.
+        */
+       if (alloctype == VDEV_ALLOC_LOAD) {
+               uint64_t label_id;
+
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, &label_id) ||
+                   label_id != id)
+                       return (SET_ERROR(EINVAL));
+
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0)
+                       return (SET_ERROR(EINVAL));
+       } else if (alloctype == VDEV_ALLOC_SPARE) {
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0)
+                       return (SET_ERROR(EINVAL));
+       } else if (alloctype == VDEV_ALLOC_L2CACHE) {
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0)
+                       return (SET_ERROR(EINVAL));
+       } else if (alloctype == VDEV_ALLOC_ROOTPOOL) {
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0)
+                       return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * The first allocated vdev must be of type 'root'.
+        */
+       if (ops != &vdev_root_ops && spa->spa_root_vdev == NULL)
+               return (SET_ERROR(EINVAL));
+
+       /*
+        * Determine whether we're a log vdev.
+        */
+       islog = 0;
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &islog);
+       if (islog && spa_version(spa) < SPA_VERSION_SLOGS)
+               return (SET_ERROR(ENOTSUP));
+
+       if (ops == &vdev_hole_ops && spa_version(spa) < SPA_VERSION_HOLES)
+               return (SET_ERROR(ENOTSUP));
+
+       /*
+        * Set the nparity property for RAID-Z vdevs.
+        */
+       nparity = -1ULL;
+       if (ops == &vdev_raidz_ops) {
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
+                   &nparity) == 0) {
+                       if (nparity == 0 || nparity > VDEV_RAIDZ_MAXPARITY)
+                               return (SET_ERROR(EINVAL));
+                       /*
+                        * Previous versions could only support 1 or 2 parity
+                        * device.
+                        */
+                       if (nparity > 1 &&
+                           spa_version(spa) < SPA_VERSION_RAIDZ2)
+                               return (SET_ERROR(ENOTSUP));
+                       if (nparity > 2 &&
+                           spa_version(spa) < SPA_VERSION_RAIDZ3)
+                               return (SET_ERROR(ENOTSUP));
+               } else {
+                       /*
+                        * We require the parity to be specified for SPAs that
+                        * support multiple parity levels.
+                        */
+                       if (spa_version(spa) >= SPA_VERSION_RAIDZ2)
+                               return (SET_ERROR(EINVAL));
+                       /*
+                        * Otherwise, we default to 1 parity device for RAID-Z.
+                        */
+                       nparity = 1;
+               }
+       } else {
+               nparity = 0;
+       }
+       ASSERT(nparity != -1ULL);
+
+       vd = vdev_alloc_common(spa, id, guid, ops);
+
+       vd->vdev_islog = islog;
+       vd->vdev_nparity = nparity;
+
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &vd->vdev_path) == 0)
+               vd->vdev_path = spa_strdup(vd->vdev_path);
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &vd->vdev_devid) == 0)
+               vd->vdev_devid = spa_strdup(vd->vdev_devid);
+       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_FRU, &vd->vdev_fru) == 0)
+               vd->vdev_fru = spa_strdup(vd->vdev_fru);
+
+       /*
+        * Set the whole_disk property.  If it's not specified, leave the value
+        * as -1.
+        */
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+           &vd->vdev_wholedisk) != 0)
+               vd->vdev_wholedisk = -1ULL;
+
+       /*
+        * Look for the 'not present' flag.  This will only be set if the device
+        * was not present at the time of import.
+        */
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
+           &vd->vdev_not_present);
+
+       /*
+        * Get the alignment requirement.
+        */
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ASHIFT, &vd->vdev_ashift);
+
+       /*
+        * Retrieve the vdev creation time.
+        */
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_CREATE_TXG,
+           &vd->vdev_crtxg);
+
+       /*
+        * If we're a top-level vdev, try to load the allocation parameters.
+        */
+       if (parent && !parent->vdev_parent &&
+           (alloctype == VDEV_ALLOC_LOAD || alloctype == VDEV_ALLOC_SPLIT)) {
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_METASLAB_ARRAY,
+                   &vd->vdev_ms_array);
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_METASLAB_SHIFT,
+                   &vd->vdev_ms_shift);
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ASIZE,
+                   &vd->vdev_asize);
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVING,
+                   &vd->vdev_removing);
+       }
+
+       if (parent && !parent->vdev_parent && alloctype != VDEV_ALLOC_ATTACH) {
+               ASSERT(alloctype == VDEV_ALLOC_LOAD ||
+                   alloctype == VDEV_ALLOC_ADD ||
+                   alloctype == VDEV_ALLOC_SPLIT ||
+                   alloctype == VDEV_ALLOC_ROOTPOOL);
+               vd->vdev_mg = metaslab_group_create(islog ?
+                   spa_log_class(spa) : spa_normal_class(spa), vd);
+       }
+
+       /*
+        * 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)) {
+               if (alloctype == VDEV_ALLOC_LOAD) {
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_DTL,
+                           &vd->vdev_dtl_object);
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_UNSPARE,
+                           &vd->vdev_unspare);
+               }
+
+               if (alloctype == VDEV_ALLOC_ROOTPOOL) {
+                       uint64_t spare = 0;
+
+                       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE,
+                           &spare) == 0 && spare)
+                               spa_spare_add(vd);
+               }
+
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE,
+                   &vd->vdev_offline);
+
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_RESILVER_TXG,
+                   &vd->vdev_resilver_txg);
+
+               /*
+                * When importing a pool, we want to ignore the persistent fault
+                * state, as the diagnosis made on another system may not be
+                * valid in the current context.  Local vdevs will
+                * remain in the faulted state.
+                */
+               if (spa_load_state(spa) == SPA_LOAD_OPEN) {
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED,
+                           &vd->vdev_faulted);
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_DEGRADED,
+                           &vd->vdev_degraded);
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED,
+                           &vd->vdev_removed);
+
+                       if (vd->vdev_faulted || vd->vdev_degraded) {
+                               char *aux;
+
+                               vd->vdev_label_aux =
+                                   VDEV_AUX_ERR_EXCEEDED;
+                               if (nvlist_lookup_string(nv,
+                                   ZPOOL_CONFIG_AUX_STATE, &aux) == 0 &&
+                                   strcmp(aux, "external") == 0)
+                                       vd->vdev_label_aux = VDEV_AUX_EXTERNAL;
+                       }
+               }
+       }
+
+       /*
+        * Add ourselves to the parent's list of children.
+        */
+       vdev_add_child(parent, vd);
+
+       *vdp = vd;
+
+       return (0);
+}
+
+void
+vdev_free(vdev_t *vd)
+{
+       int c, t;
+       spa_t *spa = vd->vdev_spa;
+
+       /*
+        * vdev_free() implies closing the vdev first.  This is simpler than
+        * trying to ensure complicated semantics for all callers.
+        */
+       vdev_close(vd);
+
+       ASSERT(!list_link_active(&vd->vdev_config_dirty_node));
+       ASSERT(!list_link_active(&vd->vdev_state_dirty_node));
+
+       /*
+        * Free all children.
+        */
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_free(vd->vdev_child[c]);
+
+       ASSERT(vd->vdev_child == NULL);
+       ASSERT(vd->vdev_guid_sum == vd->vdev_guid);
+
+       /*
+        * Discard allocation state.
+        */
+       if (vd->vdev_mg != NULL) {
+               vdev_metaslab_fini(vd);
+               metaslab_group_destroy(vd->vdev_mg);
+       }
+
+       ASSERT0(vd->vdev_stat.vs_space);
+       ASSERT0(vd->vdev_stat.vs_dspace);
+       ASSERT0(vd->vdev_stat.vs_alloc);
+
+       /*
+        * Remove this vdev from its parent's child list.
+        */
+       vdev_remove_child(vd->vdev_parent, vd);
+
+       ASSERT(vd->vdev_parent == NULL);
+
+       /*
+        * Clean up vdev structure.
+        */
+       vdev_queue_fini(vd);
+       vdev_cache_fini(vd);
+
+       if (vd->vdev_path)
+               spa_strfree(vd->vdev_path);
+       if (vd->vdev_devid)
+               spa_strfree(vd->vdev_devid);
+       if (vd->vdev_physpath)
+               spa_strfree(vd->vdev_physpath);
+       if (vd->vdev_fru)
+               spa_strfree(vd->vdev_fru);
+
+       if (vd->vdev_isspare)
+               spa_spare_remove(vd);
+       if (vd->vdev_isl2cache)
+               spa_l2cache_remove(vd);
+
+       txg_list_destroy(&vd->vdev_ms_list);
+       txg_list_destroy(&vd->vdev_dtl_list);
+
+       mutex_enter(&vd->vdev_dtl_lock);
+       space_map_close(vd->vdev_dtl_sm);
+       for (t = 0; t < DTL_TYPES; t++) {
+               range_tree_vacate(vd->vdev_dtl[t], NULL, NULL);
+               range_tree_destroy(vd->vdev_dtl[t]);
+       }
+       mutex_exit(&vd->vdev_dtl_lock);
+
+       mutex_destroy(&vd->vdev_dtl_lock);
+       mutex_destroy(&vd->vdev_stat_lock);
+       mutex_destroy(&vd->vdev_probe_lock);
+
+       if (vd == spa->spa_root_vdev)
+               spa->spa_root_vdev = NULL;
+
+       kmem_free(vd, sizeof (vdev_t));
+}
+
+/*
+ * Transfer top-level vdev state from svd to tvd.
+ */
+static void
+vdev_top_transfer(vdev_t *svd, vdev_t *tvd)
+{
+       spa_t *spa = svd->vdev_spa;
+       metaslab_t *msp;
+       vdev_t *vd;
+       int t;
+
+       ASSERT(tvd == tvd->vdev_top);
+
+       tvd->vdev_ms_array = svd->vdev_ms_array;
+       tvd->vdev_ms_shift = svd->vdev_ms_shift;
+       tvd->vdev_ms_count = svd->vdev_ms_count;
+
+       svd->vdev_ms_array = 0;
+       svd->vdev_ms_shift = 0;
+       svd->vdev_ms_count = 0;
+
+       if (tvd->vdev_mg)
+               ASSERT3P(tvd->vdev_mg, ==, svd->vdev_mg);
+       tvd->vdev_mg = svd->vdev_mg;
+       tvd->vdev_ms = svd->vdev_ms;
+
+       svd->vdev_mg = NULL;
+       svd->vdev_ms = NULL;
+
+       if (tvd->vdev_mg != NULL)
+               tvd->vdev_mg->mg_vd = tvd;
+
+       tvd->vdev_stat.vs_alloc = svd->vdev_stat.vs_alloc;
+       tvd->vdev_stat.vs_space = svd->vdev_stat.vs_space;
+       tvd->vdev_stat.vs_dspace = svd->vdev_stat.vs_dspace;
+
+       svd->vdev_stat.vs_alloc = 0;
+       svd->vdev_stat.vs_space = 0;
+       svd->vdev_stat.vs_dspace = 0;
+
+       for (t = 0; t < TXG_SIZE; t++) {
+               while ((msp = txg_list_remove(&svd->vdev_ms_list, t)) != NULL)
+                       (void) txg_list_add(&tvd->vdev_ms_list, msp, t);
+               while ((vd = txg_list_remove(&svd->vdev_dtl_list, t)) != NULL)
+                       (void) txg_list_add(&tvd->vdev_dtl_list, vd, t);
+               if (txg_list_remove_this(&spa->spa_vdev_txg_list, svd, t))
+                       (void) txg_list_add(&spa->spa_vdev_txg_list, tvd, t);
+       }
+
+       if (list_link_active(&svd->vdev_config_dirty_node)) {
+               vdev_config_clean(svd);
+               vdev_config_dirty(tvd);
+       }
+
+       if (list_link_active(&svd->vdev_state_dirty_node)) {
+               vdev_state_clean(svd);
+               vdev_state_dirty(tvd);
+       }
+
+       tvd->vdev_deflate_ratio = svd->vdev_deflate_ratio;
+       svd->vdev_deflate_ratio = 0;
+
+       tvd->vdev_islog = svd->vdev_islog;
+       svd->vdev_islog = 0;
+}
+
+static void
+vdev_top_update(vdev_t *tvd, vdev_t *vd)
+{
+       int c;
+
+       if (vd == NULL)
+               return;
+
+       vd->vdev_top = tvd;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_top_update(tvd, vd->vdev_child[c]);
+}
+
+/*
+ * Add a mirror/replacing vdev above an existing vdev.
+ */
+vdev_t *
+vdev_add_parent(vdev_t *cvd, vdev_ops_t *ops)
+{
+       spa_t *spa = cvd->vdev_spa;
+       vdev_t *pvd = cvd->vdev_parent;
+       vdev_t *mvd;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       mvd = vdev_alloc_common(spa, cvd->vdev_id, 0, ops);
+
+       mvd->vdev_asize = cvd->vdev_asize;
+       mvd->vdev_min_asize = cvd->vdev_min_asize;
+       mvd->vdev_max_asize = cvd->vdev_max_asize;
+       mvd->vdev_ashift = cvd->vdev_ashift;
+       mvd->vdev_state = cvd->vdev_state;
+       mvd->vdev_crtxg = cvd->vdev_crtxg;
+
+       vdev_remove_child(pvd, cvd);
+       vdev_add_child(pvd, mvd);
+       cvd->vdev_id = mvd->vdev_children;
+       vdev_add_child(mvd, cvd);
+       vdev_top_update(cvd->vdev_top, cvd->vdev_top);
+
+       if (mvd == mvd->vdev_top)
+               vdev_top_transfer(cvd, mvd);
+
+       return (mvd);
+}
+
+/*
+ * Remove a 1-way mirror/replacing vdev from the tree.
+ */
+void
+vdev_remove_parent(vdev_t *cvd)
+{
+       vdev_t *mvd = cvd->vdev_parent;
+       vdev_t *pvd = mvd->vdev_parent;
+
+       ASSERT(spa_config_held(cvd->vdev_spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       ASSERT(mvd->vdev_children == 1);
+       ASSERT(mvd->vdev_ops == &vdev_mirror_ops ||
+           mvd->vdev_ops == &vdev_replacing_ops ||
+           mvd->vdev_ops == &vdev_spare_ops);
+       cvd->vdev_ashift = mvd->vdev_ashift;
+
+       vdev_remove_child(mvd, cvd);
+       vdev_remove_child(pvd, mvd);
+
+       /*
+        * If cvd will replace mvd as a top-level vdev, preserve mvd's guid.
+        * Otherwise, we could have detached an offline device, and when we
+        * go to import the pool we'll think we have two top-level vdevs,
+        * instead of a different version of the same top-level vdev.
+        */
+       if (mvd->vdev_top == mvd) {
+               uint64_t guid_delta = mvd->vdev_guid - cvd->vdev_guid;
+               cvd->vdev_orig_guid = cvd->vdev_guid;
+               cvd->vdev_guid += guid_delta;
+               cvd->vdev_guid_sum += guid_delta;
+
+               /*
+                * If pool not set for autoexpand, we need to also preserve
+                * mvd's asize to prevent automatic expansion of cvd.
+                * Otherwise if we are adjusting the mirror by attaching and
+                * detaching children of non-uniform sizes, the mirror could
+                * autoexpand, unexpectedly requiring larger devices to
+                * re-establish the mirror.
+                */
+               if (!cvd->vdev_spa->spa_autoexpand)
+                       cvd->vdev_asize = mvd->vdev_asize;
+       }
+       cvd->vdev_id = mvd->vdev_id;
+       vdev_add_child(pvd, cvd);
+       vdev_top_update(cvd->vdev_top, cvd->vdev_top);
+
+       if (cvd == cvd->vdev_top)
+               vdev_top_transfer(mvd, cvd);
+
+       ASSERT(mvd->vdev_children == 0);
+       vdev_free(mvd);
+}
+
+int
+vdev_metaslab_init(vdev_t *vd, uint64_t txg)
+{
+       spa_t *spa = vd->vdev_spa;
+       objset_t *mos = spa->spa_meta_objset;
+       uint64_t m;
+       uint64_t oldc = vd->vdev_ms_count;
+       uint64_t newc = vd->vdev_asize >> vd->vdev_ms_shift;
+       metaslab_t **mspp;
+       int error;
+
+       ASSERT(txg == 0 || spa_config_held(spa, SCL_ALLOC, RW_WRITER));
+
+       /*
+        * This vdev is not being allocated from yet or is a hole.
+        */
+       if (vd->vdev_ms_shift == 0)
+               return (0);
+
+       ASSERT(!vd->vdev_ishole);
+
+       /*
+        * Compute the raidz-deflation ratio.  Note, we hard-code
+        * in 128k (1 << 17) because it is the "typical" blocksize.
+        * Even though SPA_MAXBLOCKSIZE changed, this algorithm can not change,
+        * otherwise it would inconsistently account for existing bp's.
+        */
+       vd->vdev_deflate_ratio = (1 << 17) /
+           (vdev_psize_to_asize(vd, 1 << 17) >> SPA_MINBLOCKSHIFT);
+
+       ASSERT(oldc <= newc);
+
+       mspp = vmem_zalloc(newc * sizeof (*mspp), KM_SLEEP);
+
+       if (oldc != 0) {
+               bcopy(vd->vdev_ms, mspp, oldc * sizeof (*mspp));
+               vmem_free(vd->vdev_ms, oldc * sizeof (*mspp));
+       }
+
+       vd->vdev_ms = mspp;
+       vd->vdev_ms_count = newc;
+
+       for (m = oldc; m < newc; m++) {
+               uint64_t object = 0;
+
+               if (txg == 0) {
+                       error = dmu_read(mos, vd->vdev_ms_array,
+                           m * sizeof (uint64_t), sizeof (uint64_t), &object,
+                           DMU_READ_PREFETCH);
+                       if (error)
+                               return (error);
+               }
+
+               error = metaslab_init(vd->vdev_mg, m, object, txg,
+                   &(vd->vdev_ms[m]));
+               if (error)
+                       return (error);
+       }
+
+       if (txg == 0)
+               spa_config_enter(spa, SCL_ALLOC, FTAG, RW_WRITER);
+
+       /*
+        * If the vdev is being removed we don't activate
+        * the metaslabs since we want to ensure that no new
+        * allocations are performed on this device.
+        */
+       if (oldc == 0 && !vd->vdev_removing)
+               metaslab_group_activate(vd->vdev_mg);
+
+       if (txg == 0)
+               spa_config_exit(spa, SCL_ALLOC, FTAG);
+
+       return (0);
+}
+
+void
+vdev_metaslab_fini(vdev_t *vd)
+{
+       uint64_t m;
+       uint64_t count = vd->vdev_ms_count;
+
+       if (vd->vdev_ms != NULL) {
+               metaslab_group_passivate(vd->vdev_mg);
+               for (m = 0; m < count; m++) {
+                       metaslab_t *msp = vd->vdev_ms[m];
+
+                       if (msp != NULL)
+                               metaslab_fini(msp);
+               }
+               vmem_free(vd->vdev_ms, count * sizeof (metaslab_t *));
+               vd->vdev_ms = NULL;
+       }
+
+       ASSERT3U(vd->vdev_pending_fastwrite, ==, 0);
+}
+
+typedef struct vdev_probe_stats {
+       boolean_t       vps_readable;
+       boolean_t       vps_writeable;
+       int             vps_flags;
+} vdev_probe_stats_t;
+
+static void
+vdev_probe_done(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       vdev_t *vd = zio->io_vd;
+       vdev_probe_stats_t *vps = zio->io_private;
+
+       ASSERT(vd->vdev_probe_zio != NULL);
+
+       if (zio->io_type == ZIO_TYPE_READ) {
+               if (zio->io_error == 0)
+                       vps->vps_readable = 1;
+               if (zio->io_error == 0 && spa_writeable(spa)) {
+                       zio_nowait(zio_write_phys(vd->vdev_probe_zio, vd,
+                           zio->io_offset, zio->io_size, zio->io_data,
+                           ZIO_CHECKSUM_OFF, vdev_probe_done, vps,
+                           ZIO_PRIORITY_SYNC_WRITE, vps->vps_flags, B_TRUE));
+               } else {
+                       zio_buf_free(zio->io_data, zio->io_size);
+               }
+       } else if (zio->io_type == ZIO_TYPE_WRITE) {
+               if (zio->io_error == 0)
+                       vps->vps_writeable = 1;
+               zio_buf_free(zio->io_data, zio->io_size);
+       } else if (zio->io_type == ZIO_TYPE_NULL) {
+               zio_t *pio;
+
+               vd->vdev_cant_read |= !vps->vps_readable;
+               vd->vdev_cant_write |= !vps->vps_writeable;
+
+               if (vdev_readable(vd) &&
+                   (vdev_writeable(vd) || !spa_writeable(spa))) {
+                       zio->io_error = 0;
+               } else {
+                       ASSERT(zio->io_error != 0);
+                       zfs_ereport_post(FM_EREPORT_ZFS_PROBE_FAILURE,
+                           spa, vd, NULL, 0, 0);
+                       zio->io_error = SET_ERROR(ENXIO);
+               }
+
+               mutex_enter(&vd->vdev_probe_lock);
+               ASSERT(vd->vdev_probe_zio == zio);
+               vd->vdev_probe_zio = NULL;
+               mutex_exit(&vd->vdev_probe_lock);
+
+               while ((pio = zio_walk_parents(zio)) != NULL)
+                       if (!vdev_accessible(vd, pio))
+                               pio->io_error = SET_ERROR(ENXIO);
+
+               kmem_free(vps, sizeof (*vps));
+       }
+}
+
+/*
+ * Determine whether this device is accessible.
+ *
+ * Read and write to several known locations: the pad regions of each
+ * vdev label but the first, which we leave alone in case it contains
+ * a VTOC.
+ */
+zio_t *
+vdev_probe(vdev_t *vd, zio_t *zio)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_probe_stats_t *vps = NULL;
+       zio_t *pio;
+       int l;
+
+       ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+       /*
+        * Don't probe the probe.
+        */
+       if (zio && (zio->io_flags & ZIO_FLAG_PROBE))
+               return (NULL);
+
+       /*
+        * To prevent 'probe storms' when a device fails, we create
+        * just one probe i/o at a time.  All zios that want to probe
+        * this vdev will become parents of the probe io.
+        */
+       mutex_enter(&vd->vdev_probe_lock);
+
+       if ((pio = vd->vdev_probe_zio) == NULL) {
+               vps = kmem_zalloc(sizeof (*vps), KM_SLEEP);
+
+               vps->vps_flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_PROBE |
+                   ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_AGGREGATE |
+                   ZIO_FLAG_TRYHARD;
+
+               if (spa_config_held(spa, SCL_ZIO, RW_WRITER)) {
+                       /*
+                        * vdev_cant_read and vdev_cant_write can only
+                        * transition from TRUE to FALSE when we have the
+                        * SCL_ZIO lock as writer; otherwise they can only
+                        * transition from FALSE to TRUE.  This ensures that
+                        * any zio looking at these values can assume that
+                        * failures persist for the life of the I/O.  That's
+                        * important because when a device has intermittent
+                        * connectivity problems, we want to ensure that
+                        * they're ascribed to the device (ENXIO) and not
+                        * the zio (EIO).
+                        *
+                        * Since we hold SCL_ZIO as writer here, clear both
+                        * values so the probe can reevaluate from first
+                        * principles.
+                        */
+                       vps->vps_flags |= ZIO_FLAG_CONFIG_WRITER;
+                       vd->vdev_cant_read = B_FALSE;
+                       vd->vdev_cant_write = B_FALSE;
+               }
+
+               vd->vdev_probe_zio = pio = zio_null(NULL, spa, vd,
+                   vdev_probe_done, vps,
+                   vps->vps_flags | ZIO_FLAG_DONT_PROPAGATE);
+
+               /*
+                * We can't change the vdev state in this context, so we
+                * kick off an async task to do it on our behalf.
+                */
+               if (zio != NULL) {
+                       vd->vdev_probe_wanted = B_TRUE;
+                       spa_async_request(spa, SPA_ASYNC_PROBE);
+               }
+       }
+
+       if (zio != NULL)
+               zio_add_child(zio, pio);
+
+       mutex_exit(&vd->vdev_probe_lock);
+
+       if (vps == NULL) {
+               ASSERT(zio != NULL);
+               return (NULL);
+       }
+
+       for (l = 1; l < VDEV_LABELS; l++) {
+               zio_nowait(zio_read_phys(pio, vd,
+                   vdev_label_offset(vd->vdev_psize, l,
+                   offsetof(vdev_label_t, vl_pad2)),
+                   VDEV_PAD_SIZE, zio_buf_alloc(VDEV_PAD_SIZE),
+                   ZIO_CHECKSUM_OFF, vdev_probe_done, vps,
+                   ZIO_PRIORITY_SYNC_READ, vps->vps_flags, B_TRUE));
+       }
+
+       if (zio == NULL)
+               return (pio);
+
+       zio_nowait(pio);
+       return (NULL);
+}
+
+static void
+vdev_open_child(void *arg)
+{
+       vdev_t *vd = 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
+vdev_uses_zvols(vdev_t *vd)
+{
+       int c;
+
+#ifdef _KERNEL
+       if (zvol_is_zvol(vd->vdev_path))
+               return (B_TRUE);
+#endif
+
+       for (c = 0; c < vd->vdev_children; c++)
+               if (vdev_uses_zvols(vd->vdev_child[c]))
+                       return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+void
+vdev_open_children(vdev_t *vd)
+{
+       taskq_t *tq;
+       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++) {
+                       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);
+
+       for (c = 0; c < children; c++)
+               VERIFY(taskq_dispatch(tq, vdev_open_child, vd->vdev_child[c],
+                   TQ_SLEEP) != 0);
+
+       taskq_destroy(tq);
+
+       for (c = 0; c < children; c++)
+               vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot;
+}
+
+/*
+ * Prepare a virtual device for access.
+ */
+int
+vdev_open(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       int error;
+       uint64_t osize = 0;
+       uint64_t max_osize = 0;
+       uint64_t asize, max_asize, psize;
+       uint64_t ashift = 0;
+       int c;
+
+       ASSERT(vd->vdev_open_thread == curthread ||
+           spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+       ASSERT(vd->vdev_state == VDEV_STATE_CLOSED ||
+           vd->vdev_state == VDEV_STATE_CANT_OPEN ||
+           vd->vdev_state == VDEV_STATE_OFFLINE);
+
+       vd->vdev_stat.vs_aux = VDEV_AUX_NONE;
+       vd->vdev_cant_read = B_FALSE;
+       vd->vdev_cant_write = B_FALSE;
+       vd->vdev_min_asize = vdev_get_min_asize(vd);
+
+       /*
+        * If this vdev is not removed, check its fault status.  If it's
+        * faulted, bail out of the open.
+        */
+       if (!vd->vdev_removed && vd->vdev_faulted) {
+               ASSERT(vd->vdev_children == 0);
+               ASSERT(vd->vdev_label_aux == VDEV_AUX_ERR_EXCEEDED ||
+                   vd->vdev_label_aux == VDEV_AUX_EXTERNAL);
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_FAULTED,
+                   vd->vdev_label_aux);
+               return (SET_ERROR(ENXIO));
+       } else if (vd->vdev_offline) {
+               ASSERT(vd->vdev_children == 0);
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_OFFLINE, VDEV_AUX_NONE);
+               return (SET_ERROR(ENXIO));
+       }
+
+       error = vd->vdev_ops->vdev_op_open(vd, &osize, &max_osize, &ashift);
+
+       /*
+        * Reset the vdev_reopening flag so that we actually close
+        * the vdev on error.
+        */
+       vd->vdev_reopening = B_FALSE;
+       if (zio_injection_enabled && error == 0)
+               error = zio_handle_device_injection(vd, NULL, ENXIO);
+
+       if (error) {
+               if (vd->vdev_removed &&
+                   vd->vdev_stat.vs_aux != VDEV_AUX_OPEN_FAILED)
+                       vd->vdev_removed = B_FALSE;
+
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
+                   vd->vdev_stat.vs_aux);
+               return (error);
+       }
+
+       vd->vdev_removed = B_FALSE;
+
+       /*
+        * Recheck the faulted flag now that we have confirmed that
+        * the vdev is accessible.  If we're faulted, bail.
+        */
+       if (vd->vdev_faulted) {
+               ASSERT(vd->vdev_children == 0);
+               ASSERT(vd->vdev_label_aux == VDEV_AUX_ERR_EXCEEDED ||
+                   vd->vdev_label_aux == VDEV_AUX_EXTERNAL);
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_FAULTED,
+                   vd->vdev_label_aux);
+               return (SET_ERROR(ENXIO));
+       }
+
+       if (vd->vdev_degraded) {
+               ASSERT(vd->vdev_children == 0);
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_DEGRADED,
+                   VDEV_AUX_ERR_EXCEEDED);
+       } else {
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_HEALTHY, 0);
+       }
+
+       /*
+        * For hole or missing vdevs we just return success.
+        */
+       if (vd->vdev_ishole || vd->vdev_ops == &vdev_missing_ops)
+               return (0);
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               if (vd->vdev_child[c]->vdev_state != VDEV_STATE_HEALTHY) {
+                       vdev_set_state(vd, B_TRUE, VDEV_STATE_DEGRADED,
+                           VDEV_AUX_NONE);
+                       break;
+               }
+       }
+
+       osize = P2ALIGN(osize, (uint64_t)sizeof (vdev_label_t));
+       max_osize = P2ALIGN(max_osize, (uint64_t)sizeof (vdev_label_t));
+
+       if (vd->vdev_children == 0) {
+               if (osize < SPA_MINDEVSIZE) {
+                       vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_TOO_SMALL);
+                       return (SET_ERROR(EOVERFLOW));
+               }
+               psize = osize;
+               asize = osize - (VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE);
+               max_asize = max_osize - (VDEV_LABEL_START_SIZE +
+                   VDEV_LABEL_END_SIZE);
+       } else {
+               if (vd->vdev_parent != NULL && osize < SPA_MINDEVSIZE -
+                   (VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE)) {
+                       vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_TOO_SMALL);
+                       return (SET_ERROR(EOVERFLOW));
+               }
+               psize = 0;
+               asize = osize;
+               max_asize = max_osize;
+       }
+
+       vd->vdev_psize = psize;
+
+       /*
+        * Make sure the allocatable size hasn't shrunk.
+        */
+       if (asize < vd->vdev_min_asize) {
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_BAD_LABEL);
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (vd->vdev_asize == 0) {
+               /*
+                * This is the first-ever open, so use the computed values.
+                * For compatibility, a different ashift can be requested.
+                */
+               vd->vdev_asize = asize;
+               vd->vdev_max_asize = max_asize;
+               if (vd->vdev_ashift == 0)
+                       vd->vdev_ashift = ashift;
+       } else {
+               /*
+                * Detect if the alignment requirement has increased.
+                * We don't want to make the pool unavailable, just
+                * post an event instead.
+                */
+               if (ashift > vd->vdev_top->vdev_ashift &&
+                   vd->vdev_ops->vdev_op_leaf) {
+                       zfs_ereport_post(FM_EREPORT_ZFS_DEVICE_BAD_ASHIFT,
+                           spa, vd, NULL, 0, 0);
+               }
+
+               vd->vdev_max_asize = max_asize;
+       }
+
+       /*
+        * If all children are healthy and the asize has increased,
+        * then we've experienced dynamic LUN growth.  If automatic
+        * expansion is enabled then use the additional space.
+        */
+       if (vd->vdev_state == VDEV_STATE_HEALTHY && asize > vd->vdev_asize &&
+           (vd->vdev_expanding || spa->spa_autoexpand))
+               vd->vdev_asize = asize;
+
+       vdev_set_min_asize(vd);
+
+       /*
+        * Ensure we can issue some IO before declaring the
+        * vdev open for business.
+        */
+       if (vd->vdev_ops->vdev_op_leaf &&
+           (error = zio_wait(vdev_probe(vd, NULL))) != 0) {
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_FAULTED,
+                   VDEV_AUX_ERR_EXCEEDED);
+               return (error);
+       }
+
+       /*
+        * Track the min and max ashift values for normal data devices.
+        */
+       if (vd->vdev_top == vd && vd->vdev_ashift != 0 &&
+           !vd->vdev_islog && vd->vdev_aux == NULL) {
+               if (vd->vdev_ashift > spa->spa_max_ashift)
+                       spa->spa_max_ashift = vd->vdev_ashift;
+               if (vd->vdev_ashift < spa->spa_min_ashift)
+                       spa->spa_min_ashift = vd->vdev_ashift;
+       }
+
+       /*
+        * If a leaf vdev has a DTL, and seems healthy, then kick off a
+        * resilver.  But don't do this if we are doing a reopen for a scrub,
+        * since this would just restart the scrub we are already doing.
+        */
+       if (vd->vdev_ops->vdev_op_leaf && !spa->spa_scrub_reopen &&
+           vdev_resilver_needed(vd, NULL, NULL))
+               spa_async_request(spa, SPA_ASYNC_RESILVER);
+
+       return (0);
+}
+
+/*
+ * Called once the vdevs are all opened, this routine validates the label
+ * contents.  This needs to be done before vdev_load() so that we don't
+ * inadvertently do repair I/Os to the wrong device.
+ *
+ * If 'strict' is false ignore the spa guid check. This is necessary because
+ * if the machine crashed during a re-guid the new guid might have been written
+ * to all of the vdev labels, but not the cached config. The strict check
+ * will be performed when the pool is opened again using the mos config.
+ *
+ * This function will only return failure if one of the vdevs indicates that it
+ * has since been destroyed or exported.  This is only possible if
+ * /etc/zfs/zpool.cache was readonly at the time.  Otherwise, the vdev state
+ * will be updated but the function will return 0.
+ */
+int
+vdev_validate(vdev_t *vd, boolean_t strict)
+{
+       spa_t *spa = vd->vdev_spa;
+       nvlist_t *label;
+       uint64_t guid = 0, top_guid;
+       uint64_t state;
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               if (vdev_validate(vd->vdev_child[c], strict) != 0)
+                       return (SET_ERROR(EBADF));
+
+       /*
+        * If the device has already failed, or was marked offline, don't do
+        * any further validation.  Otherwise, label I/O will fail and we will
+        * overwrite the previous state.
+        */
+       if (vd->vdev_ops->vdev_op_leaf && vdev_readable(vd)) {
+               uint64_t aux_guid = 0;
+               nvlist_t *nvl;
+               uint64_t txg = spa_last_synced_txg(spa) != 0 ?
+                   spa_last_synced_txg(spa) : -1ULL;
+
+               if ((label = vdev_label_read_config(vd, txg)) == NULL) {
+                       vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_BAD_LABEL);
+                       return (0);
+               }
+
+               /*
+                * Determine if this vdev has been split off into another
+                * pool.  If so, then refuse to open it.
+                */
+               if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_SPLIT_GUID,
+                   &aux_guid) == 0 && aux_guid == spa_guid(spa)) {
+                       vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_SPLIT_POOL);
+                       nvlist_free(label);
+                       return (0);
+               }
+
+               if (strict && (nvlist_lookup_uint64(label,
+                   ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
+                   guid != spa_guid(spa))) {
+                       vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_CORRUPT_DATA);
+                       nvlist_free(label);
+                       return (0);
+               }
+
+               if (nvlist_lookup_nvlist(label, ZPOOL_CONFIG_VDEV_TREE, &nvl)
+                   != 0 || nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_ORIG_GUID,
+                   &aux_guid) != 0)
+                       aux_guid = 0;
+
+               /*
+                * If this vdev just became a top-level vdev because its
+                * sibling was detached, it will have adopted the parent's
+                * vdev guid -- but the label may or may not be on disk yet.
+                * Fortunately, either version of the label will have the
+                * same top guid, so if we're a top-level vdev, we can
+                * safely compare to that instead.
+                *
+                * If we split this vdev off instead, then we also check the
+                * original pool's guid.  We don't want to consider the vdev
+                * corrupt if it is partway through a split operation.
+                */
+               if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID,
+                   &guid) != 0 ||
+                   nvlist_lookup_uint64(label, ZPOOL_CONFIG_TOP_GUID,
+                   &top_guid) != 0 ||
+                   ((vd->vdev_guid != guid && vd->vdev_guid != aux_guid) &&
+                   (vd->vdev_guid != top_guid || vd != vd->vdev_top))) {
+                       vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_CORRUPT_DATA);
+                       nvlist_free(label);
+                       return (0);
+               }
+
+               if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_STATE,
+                   &state) != 0) {
+                       vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_CORRUPT_DATA);
+                       nvlist_free(label);
+                       return (0);
+               }
+
+               nvlist_free(label);
+
+               /*
+                * If this is a verbatim import, no need to check the
+                * state of the pool.
+                */
+               if (!(spa->spa_import_flags & ZFS_IMPORT_VERBATIM) &&
+                   spa_load_state(spa) == SPA_LOAD_OPEN &&
+                   state != POOL_STATE_ACTIVE)
+                       return (SET_ERROR(EBADF));
+
+               /*
+                * If we were able to open and validate a vdev that was
+                * previously marked permanently unavailable, clear that state
+                * now.
+                */
+               if (vd->vdev_not_present)
+                       vd->vdev_not_present = 0;
+       }
+
+       return (0);
+}
+
+/*
+ * Close a virtual device.
+ */
+void
+vdev_close(vdev_t *vd)
+{
+       vdev_t *pvd = vd->vdev_parent;
+       ASSERTV(spa_t *spa = vd->vdev_spa);
+
+       ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+
+       /*
+        * If our parent is reopening, then we are as well, unless we are
+        * going offline.
+        */
+       if (pvd != NULL && pvd->vdev_reopening)
+               vd->vdev_reopening = (pvd->vdev_reopening && !vd->vdev_offline);
+
+       vd->vdev_ops->vdev_op_close(vd);
+
+       vdev_cache_purge(vd);
+
+       /*
+        * We record the previous state before we close it, so that if we are
+        * doing a reopen(), we don't generate FMA ereports if we notice that
+        * it's still faulted.
+        */
+       vd->vdev_prevstate = vd->vdev_state;
+
+       if (vd->vdev_offline)
+               vd->vdev_state = VDEV_STATE_OFFLINE;
+       else
+               vd->vdev_state = VDEV_STATE_CLOSED;
+       vd->vdev_stat.vs_aux = VDEV_AUX_NONE;
+}
+
+void
+vdev_hold(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       int c;
+
+       ASSERT(spa_is_root(spa));
+       if (spa->spa_state == POOL_STATE_UNINITIALIZED)
+               return;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_hold(vd->vdev_child[c]);
+
+       if (vd->vdev_ops->vdev_op_leaf)
+               vd->vdev_ops->vdev_op_hold(vd);
+}
+
+void
+vdev_rele(vdev_t *vd)
+{
+       int c;
+
+       ASSERT(spa_is_root(vd->vdev_spa));
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_rele(vd->vdev_child[c]);
+
+       if (vd->vdev_ops->vdev_op_leaf)
+               vd->vdev_ops->vdev_op_rele(vd);
+}
+
+/*
+ * Reopen all interior vdevs and any unopened leaves.  We don't actually
+ * reopen leaf vdevs which had previously been opened as they might deadlock
+ * on the spa_config_lock.  Instead we only obtain the leaf's physical size.
+ * If the leaf has never been opened then open it, as usual.
+ */
+void
+vdev_reopen(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+
+       ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+
+       /* set the reopening flag unless we're taking the vdev offline */
+       vd->vdev_reopening = !vd->vdev_offline;
+       vdev_close(vd);
+       (void) vdev_open(vd);
+
+       /*
+        * Call vdev_validate() here to make sure we have the same device.
+        * Otherwise, a device with an invalid label could be successfully
+        * opened in response to vdev_reopen().
+        */
+       if (vd->vdev_aux) {
+               (void) vdev_validate_aux(vd);
+               if (vdev_readable(vd) && vdev_writeable(vd) &&
+                   vd->vdev_aux == &spa->spa_l2cache &&
+                   !l2arc_vdev_present(vd))
+                       l2arc_add_vdev(spa, vd);
+       } else {
+               (void) vdev_validate(vd, B_TRUE);
+       }
+
+       /*
+        * Reassess parent vdev's health.
+        */
+       vdev_propagate_state(vd);
+}
+
+int
+vdev_create(vdev_t *vd, uint64_t txg, boolean_t isreplacing)
+{
+       int error;
+
+       /*
+        * Normally, partial opens (e.g. of a mirror) are allowed.
+        * For a create, however, we want to fail the request if
+        * there are any components we can't open.
+        */
+       error = vdev_open(vd);
+
+       if (error || vd->vdev_state != VDEV_STATE_HEALTHY) {
+               vdev_close(vd);
+               return (error ? error : ENXIO);
+       }
+
+       /*
+        * Recursively load DTLs and initialize all labels.
+        */
+       if ((error = vdev_dtl_load(vd)) != 0 ||
+           (error = vdev_label_init(vd, txg, isreplacing ?
+           VDEV_LABEL_REPLACE : VDEV_LABEL_CREATE)) != 0) {
+               vdev_close(vd);
+               return (error);
+       }
+
+       return (0);
+}
+
+void
+vdev_metaslab_set_size(vdev_t *vd)
+{
+       /*
+        * Aim for roughly metaslabs_per_vdev (default 200) metaslabs per vdev.
+        */
+       vd->vdev_ms_shift = highbit64(vd->vdev_asize / metaslabs_per_vdev);
+       vd->vdev_ms_shift = MAX(vd->vdev_ms_shift, SPA_MAXBLOCKSHIFT);
+}
+
+void
+vdev_dirty(vdev_t *vd, int flags, void *arg, uint64_t txg)
+{
+       ASSERT(vd == vd->vdev_top);
+       ASSERT(!vd->vdev_ishole);
+       ASSERT(ISP2(flags));
+       ASSERT(spa_writeable(vd->vdev_spa));
+
+       if (flags & VDD_METASLAB)
+               (void) txg_list_add(&vd->vdev_ms_list, arg, txg);
+
+       if (flags & VDD_DTL)
+               (void) txg_list_add(&vd->vdev_dtl_list, arg, txg);
+
+       (void) txg_list_add(&vd->vdev_spa->spa_vdev_txg_list, vd, txg);
+}
+
+void
+vdev_dirty_leaves(vdev_t *vd, int flags, uint64_t txg)
+{
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_dirty_leaves(vd->vdev_child[c], flags, txg);
+
+       if (vd->vdev_ops->vdev_op_leaf)
+               vdev_dirty(vd->vdev_top, flags, vd, txg);
+}
+
+/*
+ * DTLs.
+ *
+ * A vdev's DTL (dirty time log) is the set of transaction groups for which
+ * the vdev has less than perfect replication.  There are four kinds of DTL:
+ *
+ * DTL_MISSING: txgs for which the vdev has no valid copies of the data
+ *
+ * DTL_PARTIAL: txgs for which data is available, but not fully replicated
+ *
+ * DTL_SCRUB: the txgs that could not be repaired by the last scrub; upon
+ *     scrub completion, DTL_SCRUB replaces DTL_MISSING in the range of
+ *     txgs that was scrubbed.
+ *
+ * DTL_OUTAGE: txgs which cannot currently be read, whether due to
+ *     persistent errors or just some device being offline.
+ *     Unlike the other three, the DTL_OUTAGE map is not generally
+ *     maintained; it's only computed when needed, typically to
+ *     determine whether a device can be detached.
+ *
+ * For leaf vdevs, DTL_MISSING and DTL_PARTIAL are identical: the device
+ * either has the data or it doesn't.
+ *
+ * For interior vdevs such as mirror and RAID-Z the picture is more complex.
+ * A vdev's DTL_PARTIAL is the union of its children's DTL_PARTIALs, because
+ * if any child is less than fully replicated, then so is its parent.
+ * A vdev's DTL_MISSING is a modified union of its children's DTL_MISSINGs,
+ * comprising only those txgs which appear in 'maxfaults' or more children;
+ * those are the txgs we don't have enough replication to read.  For example,
+ * double-parity RAID-Z can tolerate up to two missing devices (maxfaults == 2);
+ * thus, its DTL_MISSING consists of the set of txgs that appear in more than
+ * two child DTL_MISSING maps.
+ *
+ * It should be clear from the above that to compute the DTLs and outage maps
+ * for all vdevs, it suffices to know just the leaf vdevs' DTL_MISSING maps.
+ * Therefore, that is all we keep on disk.  When loading the pool, or after
+ * a configuration change, we generate all other DTLs from first principles.
+ */
+void
+vdev_dtl_dirty(vdev_t *vd, vdev_dtl_type_t t, uint64_t txg, uint64_t size)
+{
+       range_tree_t *rt = vd->vdev_dtl[t];
+
+       ASSERT(t < DTL_TYPES);
+       ASSERT(vd != vd->vdev_spa->spa_root_vdev);
+       ASSERT(spa_writeable(vd->vdev_spa));
+
+       mutex_enter(rt->rt_lock);
+       if (!range_tree_contains(rt, txg, size))
+               range_tree_add(rt, txg, size);
+       mutex_exit(rt->rt_lock);
+}
+
+boolean_t
+vdev_dtl_contains(vdev_t *vd, vdev_dtl_type_t t, uint64_t txg, uint64_t size)
+{
+       range_tree_t *rt = vd->vdev_dtl[t];
+       boolean_t dirty = B_FALSE;
+
+       ASSERT(t < DTL_TYPES);
+       ASSERT(vd != vd->vdev_spa->spa_root_vdev);
+
+       mutex_enter(rt->rt_lock);
+       if (range_tree_space(rt) != 0)
+               dirty = range_tree_contains(rt, txg, size);
+       mutex_exit(rt->rt_lock);
+
+       return (dirty);
+}
+
+boolean_t
+vdev_dtl_empty(vdev_t *vd, vdev_dtl_type_t t)
+{
+       range_tree_t *rt = vd->vdev_dtl[t];
+       boolean_t empty;
+
+       mutex_enter(rt->rt_lock);
+       empty = (range_tree_space(rt) == 0);
+       mutex_exit(rt->rt_lock);
+
+       return (empty);
+}
+
+/*
+ * Returns the lowest txg in the DTL range.
+ */
+static uint64_t
+vdev_dtl_min(vdev_t *vd)
+{
+       range_seg_t *rs;
+
+       ASSERT(MUTEX_HELD(&vd->vdev_dtl_lock));
+       ASSERT3U(range_tree_space(vd->vdev_dtl[DTL_MISSING]), !=, 0);
+       ASSERT0(vd->vdev_children);
+
+       rs = avl_first(&vd->vdev_dtl[DTL_MISSING]->rt_root);
+       return (rs->rs_start - 1);
+}
+
+/*
+ * Returns the highest txg in the DTL.
+ */
+static uint64_t
+vdev_dtl_max(vdev_t *vd)
+{
+       range_seg_t *rs;
+
+       ASSERT(MUTEX_HELD(&vd->vdev_dtl_lock));
+       ASSERT3U(range_tree_space(vd->vdev_dtl[DTL_MISSING]), !=, 0);
+       ASSERT0(vd->vdev_children);
+
+       rs = avl_last(&vd->vdev_dtl[DTL_MISSING]->rt_root);
+       return (rs->rs_end);
+}
+
+/*
+ * Determine if a resilvering vdev should remove any DTL entries from
+ * its range. If the vdev was resilvering for the entire duration of the
+ * scan then it should excise that range from its DTLs. Otherwise, this
+ * vdev is considered partially resilvered and should leave its DTL
+ * entries intact. The comment in vdev_dtl_reassess() describes how we
+ * excise the DTLs.
+ */
+static boolean_t
+vdev_dtl_should_excise(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       dsl_scan_t *scn = spa->spa_dsl_pool->dp_scan;
+
+       ASSERT0(scn->scn_phys.scn_errors);
+       ASSERT0(vd->vdev_children);
+
+       if (vd->vdev_resilver_txg == 0 ||
+           range_tree_space(vd->vdev_dtl[DTL_MISSING]) == 0)
+               return (B_TRUE);
+
+       /*
+        * When a resilver is initiated the scan will assign the scn_max_txg
+        * value to the highest txg value that exists in all DTLs. If this
+        * device's max DTL is not part of this scan (i.e. it is not in
+        * the range (scn_min_txg, scn_max_txg] then it is not eligible
+        * for excision.
+        */
+       if (vdev_dtl_max(vd) <= scn->scn_phys.scn_max_txg) {
+               ASSERT3U(scn->scn_phys.scn_min_txg, <=, vdev_dtl_min(vd));
+               ASSERT3U(scn->scn_phys.scn_min_txg, <, vd->vdev_resilver_txg);
+               ASSERT3U(vd->vdev_resilver_txg, <=, scn->scn_phys.scn_max_txg);
+               return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Reassess DTLs after a config change or scrub completion.
+ */
+void
+vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, int scrub_done)
+{
+       spa_t *spa = vd->vdev_spa;
+       avl_tree_t reftree;
+       int c, t, minref;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_dtl_reassess(vd->vdev_child[c], txg,
+                   scrub_txg, scrub_done);
+
+       if (vd == spa->spa_root_vdev || vd->vdev_ishole || vd->vdev_aux)
+               return;
+
+       if (vd->vdev_ops->vdev_op_leaf) {
+               dsl_scan_t *scn = spa->spa_dsl_pool->dp_scan;
+
+               mutex_enter(&vd->vdev_dtl_lock);
+
+               /*
+                * If we've completed a scan cleanly then determine
+                * if this vdev should remove any DTLs. We only want to
+                * excise regions on vdevs that were available during
+                * the entire duration of this scan.
+                */
+               if (scrub_txg != 0 &&
+                   (spa->spa_scrub_started ||
+                   (scn != NULL && scn->scn_phys.scn_errors == 0)) &&
+                   vdev_dtl_should_excise(vd)) {
+                       /*
+                        * We completed a scrub up to scrub_txg.  If we
+                        * did it without rebooting, then the scrub dtl
+                        * will be valid, so excise the old region and
+                        * fold in the scrub dtl.  Otherwise, leave the
+                        * dtl as-is if there was an error.
+                        *
+                        * There's little trick here: to excise the beginning
+                        * of the DTL_MISSING map, we put it into a reference
+                        * tree and then add a segment with refcnt -1 that
+                        * covers the range [0, scrub_txg).  This means
+                        * that each txg in that range has refcnt -1 or 0.
+                        * We then add DTL_SCRUB with a refcnt of 2, so that
+                        * entries in the range [0, scrub_txg) will have a
+                        * positive refcnt -- either 1 or 2.  We then convert
+                        * the reference tree into the new DTL_MISSING map.
+                        */
+                       space_reftree_create(&reftree);
+                       space_reftree_add_map(&reftree,
+                           vd->vdev_dtl[DTL_MISSING], 1);
+                       space_reftree_add_seg(&reftree, 0, scrub_txg, -1);
+                       space_reftree_add_map(&reftree,
+                           vd->vdev_dtl[DTL_SCRUB], 2);
+                       space_reftree_generate_map(&reftree,
+                           vd->vdev_dtl[DTL_MISSING], 1);
+                       space_reftree_destroy(&reftree);
+               }
+               range_tree_vacate(vd->vdev_dtl[DTL_PARTIAL], NULL, NULL);
+               range_tree_walk(vd->vdev_dtl[DTL_MISSING],
+                   range_tree_add, vd->vdev_dtl[DTL_PARTIAL]);
+               if (scrub_done)
+                       range_tree_vacate(vd->vdev_dtl[DTL_SCRUB], NULL, NULL);
+               range_tree_vacate(vd->vdev_dtl[DTL_OUTAGE], NULL, NULL);
+               if (!vdev_readable(vd))
+                       range_tree_add(vd->vdev_dtl[DTL_OUTAGE], 0, -1ULL);
+               else
+                       range_tree_walk(vd->vdev_dtl[DTL_MISSING],
+                           range_tree_add, vd->vdev_dtl[DTL_OUTAGE]);
+
+               /*
+                * If the vdev was resilvering and no longer has any
+                * DTLs then reset its resilvering flag and dirty
+                * the top level so that we persist the change.
+                */
+               if (vd->vdev_resilver_txg != 0 &&
+                   range_tree_space(vd->vdev_dtl[DTL_MISSING]) == 0 &&
+                   range_tree_space(vd->vdev_dtl[DTL_OUTAGE]) == 0) {
+                       vd->vdev_resilver_txg = 0;
+                       vdev_config_dirty(vd->vdev_top);
+               }
+
+               mutex_exit(&vd->vdev_dtl_lock);
+
+               if (txg != 0)
+                       vdev_dirty(vd->vdev_top, VDD_DTL, vd, txg);
+               return;
+       }
+
+       mutex_enter(&vd->vdev_dtl_lock);
+       for (t = 0; t < DTL_TYPES; t++) {
+               int c;
+
+               /* account for child's outage in parent's missing map */
+               int s = (t == DTL_MISSING) ? DTL_OUTAGE: t;
+               if (t == DTL_SCRUB)
+                       continue;                       /* leaf vdevs only */
+               if (t == DTL_PARTIAL)
+                       minref = 1;                     /* i.e. non-zero */
+               else if (vd->vdev_nparity != 0)
+                       minref = vd->vdev_nparity + 1;  /* RAID-Z */
+               else
+                       minref = vd->vdev_children;     /* any kind of mirror */
+               space_reftree_create(&reftree);
+               for (c = 0; c < vd->vdev_children; c++) {
+                       vdev_t *cvd = vd->vdev_child[c];
+                       mutex_enter(&cvd->vdev_dtl_lock);
+                       space_reftree_add_map(&reftree, cvd->vdev_dtl[s], 1);
+                       mutex_exit(&cvd->vdev_dtl_lock);
+               }
+               space_reftree_generate_map(&reftree, vd->vdev_dtl[t], minref);
+               space_reftree_destroy(&reftree);
+       }
+       mutex_exit(&vd->vdev_dtl_lock);
+}
+
+int
+vdev_dtl_load(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       objset_t *mos = spa->spa_meta_objset;
+       int error = 0;
+       int c;
+
+       if (vd->vdev_ops->vdev_op_leaf && vd->vdev_dtl_object != 0) {
+               ASSERT(!vd->vdev_ishole);
+
+               error = space_map_open(&vd->vdev_dtl_sm, mos,
+                   vd->vdev_dtl_object, 0, -1ULL, 0, &vd->vdev_dtl_lock);
+               if (error)
+                       return (error);
+               ASSERT(vd->vdev_dtl_sm != NULL);
+
+               mutex_enter(&vd->vdev_dtl_lock);
+
+               /*
+                * Now that we've opened the space_map we need to update
+                * the in-core DTL.
+                */
+               space_map_update(vd->vdev_dtl_sm);
+
+               error = space_map_load(vd->vdev_dtl_sm,
+                   vd->vdev_dtl[DTL_MISSING], SM_ALLOC);
+               mutex_exit(&vd->vdev_dtl_lock);
+
+               return (error);
+       }
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               error = vdev_dtl_load(vd->vdev_child[c]);
+               if (error != 0)
+                       break;
+       }
+
+       return (error);
+}
+
+void
+vdev_dtl_sync(vdev_t *vd, uint64_t txg)
+{
+       spa_t *spa = vd->vdev_spa;
+       range_tree_t *rt = vd->vdev_dtl[DTL_MISSING];
+       objset_t *mos = spa->spa_meta_objset;
+       range_tree_t *rtsync;
+       kmutex_t rtlock;
+       dmu_tx_t *tx;
+       uint64_t object = space_map_object(vd->vdev_dtl_sm);
+
+       ASSERT(!vd->vdev_ishole);
+       ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+       tx = dmu_tx_create_assigned(spa->spa_dsl_pool, txg);
+
+       if (vd->vdev_detached || vd->vdev_top->vdev_removing) {
+               mutex_enter(&vd->vdev_dtl_lock);
+               space_map_free(vd->vdev_dtl_sm, tx);
+               space_map_close(vd->vdev_dtl_sm);
+               vd->vdev_dtl_sm = NULL;
+               mutex_exit(&vd->vdev_dtl_lock);
+               dmu_tx_commit(tx);
+               return;
+       }
+
+       if (vd->vdev_dtl_sm == NULL) {
+               uint64_t new_object;
+
+               new_object = space_map_alloc(mos, tx);
+               VERIFY3U(new_object, !=, 0);
+
+               VERIFY0(space_map_open(&vd->vdev_dtl_sm, mos, new_object,
+                   0, -1ULL, 0, &vd->vdev_dtl_lock));
+               ASSERT(vd->vdev_dtl_sm != NULL);
+       }
+
+       mutex_init(&rtlock, NULL, MUTEX_DEFAULT, NULL);
+
+       rtsync = range_tree_create(NULL, NULL, &rtlock);
+
+       mutex_enter(&rtlock);
+
+       mutex_enter(&vd->vdev_dtl_lock);
+       range_tree_walk(rt, range_tree_add, rtsync);
+       mutex_exit(&vd->vdev_dtl_lock);
+
+       space_map_truncate(vd->vdev_dtl_sm, tx);
+       space_map_write(vd->vdev_dtl_sm, rtsync, SM_ALLOC, tx);
+       range_tree_vacate(rtsync, NULL, NULL);
+
+       range_tree_destroy(rtsync);
+
+       mutex_exit(&rtlock);
+       mutex_destroy(&rtlock);
+
+       /*
+        * If the object for the space map has changed then dirty
+        * the top level so that we update the config.
+        */
+       if (object != space_map_object(vd->vdev_dtl_sm)) {
+               zfs_dbgmsg("txg %llu, spa %s, DTL old object %llu, "
+                   "new object %llu", txg, spa_name(spa), object,
+                   space_map_object(vd->vdev_dtl_sm));
+               vdev_config_dirty(vd->vdev_top);
+       }
+
+       dmu_tx_commit(tx);
+
+       mutex_enter(&vd->vdev_dtl_lock);
+       space_map_update(vd->vdev_dtl_sm);
+       mutex_exit(&vd->vdev_dtl_lock);
+}
+
+/*
+ * Determine whether the specified vdev can be offlined/detached/removed
+ * without losing data.
+ */
+boolean_t
+vdev_dtl_required(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *tvd = vd->vdev_top;
+       uint8_t cant_read = vd->vdev_cant_read;
+       boolean_t required;
+
+       ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+
+       if (vd == spa->spa_root_vdev || vd == tvd)
+               return (B_TRUE);
+
+       /*
+        * Temporarily mark the device as unreadable, and then determine
+        * whether this results in any DTL outages in the top-level vdev.
+        * If not, we can safely offline/detach/remove the device.
+        */
+       vd->vdev_cant_read = B_TRUE;
+       vdev_dtl_reassess(tvd, 0, 0, B_FALSE);
+       required = !vdev_dtl_empty(tvd, DTL_OUTAGE);
+       vd->vdev_cant_read = cant_read;
+       vdev_dtl_reassess(tvd, 0, 0, B_FALSE);
+
+       if (!required && zio_injection_enabled)
+               required = !!zio_handle_device_injection(vd, NULL, ECHILD);
+
+       return (required);
+}
+
+/*
+ * Determine if resilver is needed, and if so the txg range.
+ */
+boolean_t
+vdev_resilver_needed(vdev_t *vd, uint64_t *minp, uint64_t *maxp)
+{
+       boolean_t needed = B_FALSE;
+       uint64_t thismin = UINT64_MAX;
+       uint64_t thismax = 0;
+       int c;
+
+       if (vd->vdev_children == 0) {
+               mutex_enter(&vd->vdev_dtl_lock);
+               if (range_tree_space(vd->vdev_dtl[DTL_MISSING]) != 0 &&
+                   vdev_writeable(vd)) {
+
+                       thismin = vdev_dtl_min(vd);
+                       thismax = vdev_dtl_max(vd);
+                       needed = B_TRUE;
+               }
+               mutex_exit(&vd->vdev_dtl_lock);
+       } else {
+               for (c = 0; c < vd->vdev_children; c++) {
+                       vdev_t *cvd = vd->vdev_child[c];
+                       uint64_t cmin, cmax;
+
+                       if (vdev_resilver_needed(cvd, &cmin, &cmax)) {
+                               thismin = MIN(thismin, cmin);
+                               thismax = MAX(thismax, cmax);
+                               needed = B_TRUE;
+                       }
+               }
+       }
+
+       if (needed && minp) {
+               *minp = thismin;
+               *maxp = thismax;
+       }
+       return (needed);
+}
+
+void
+vdev_load(vdev_t *vd)
+{
+       int c;
+
+       /*
+        * Recursively load all children.
+        */
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_load(vd->vdev_child[c]);
+
+       /*
+        * If this is a top-level vdev, initialize its metaslabs.
+        */
+       if (vd == vd->vdev_top && !vd->vdev_ishole &&
+           (vd->vdev_ashift == 0 || vd->vdev_asize == 0 ||
+           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.
+        */
+       if (vd->vdev_ops->vdev_op_leaf && vdev_dtl_load(vd) != 0)
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_CORRUPT_DATA);
+}
+
+/*
+ * The special vdev case is used for hot spares and l2cache devices.  Its
+ * sole purpose it to set the vdev state for the associated vdev.  To do this,
+ * we make sure that we can open the underlying device, then try to read the
+ * label, and make sure that the label is sane and that it hasn't been
+ * repurposed to another pool.
+ */
+int
+vdev_validate_aux(vdev_t *vd)
+{
+       nvlist_t *label;
+       uint64_t guid, version;
+       uint64_t state;
+
+       if (!vdev_readable(vd))
+               return (0);
+
+       if ((label = vdev_label_read_config(vd, -1ULL)) == NULL) {
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_CORRUPT_DATA);
+               return (-1);
+       }
+
+       if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_VERSION, &version) != 0 ||
+           !SPA_VERSION_IS_SUPPORTED(version) ||
+           nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) != 0 ||
+           guid != vd->vdev_guid ||
+           nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_STATE, &state) != 0) {
+               vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_CORRUPT_DATA);
+               nvlist_free(label);
+               return (-1);
+       }
+
+       /*
+        * We don't actually check the pool state here.  If it's in fact in
+        * use by another pool, we update this fact on the fly when requested.
+        */
+       nvlist_free(label);
+       return (0);
+}
+
+void
+vdev_remove(vdev_t *vd, uint64_t txg)
+{
+       spa_t *spa = vd->vdev_spa;
+       objset_t *mos = spa->spa_meta_objset;
+       dmu_tx_t *tx;
+       int m, i;
+
+       tx = dmu_tx_create_assigned(spa_get_dsl(spa), txg);
+
+       if (vd->vdev_ms != NULL) {
+               metaslab_group_t *mg = vd->vdev_mg;
+
+               metaslab_group_histogram_verify(mg);
+               metaslab_class_histogram_verify(mg->mg_class);
+
+               for (m = 0; m < vd->vdev_ms_count; m++) {
+                       metaslab_t *msp = vd->vdev_ms[m];
+
+                       if (msp == NULL || msp->ms_sm == NULL)
+                               continue;
+
+                       mutex_enter(&msp->ms_lock);
+                       /*
+                        * If the metaslab was not loaded when the vdev
+                        * was removed then the histogram accounting may
+                        * not be accurate. Update the histogram information
+                        * here so that we ensure that the metaslab group
+                        * and metaslab class are up-to-date.
+                        */
+                       metaslab_group_histogram_remove(mg, msp);
+
+                       VERIFY0(space_map_allocated(msp->ms_sm));
+                       space_map_free(msp->ms_sm, tx);
+                       space_map_close(msp->ms_sm);
+                       msp->ms_sm = NULL;
+                       mutex_exit(&msp->ms_lock);
+               }
+
+               metaslab_group_histogram_verify(mg);
+               metaslab_class_histogram_verify(mg->mg_class);
+               for (i = 0; i < RANGE_TREE_HISTOGRAM_SIZE; i++)
+                       ASSERT0(mg->mg_histogram[i]);
+
+       }
+
+       if (vd->vdev_ms_array) {
+               (void) dmu_object_free(mos, vd->vdev_ms_array, tx);
+               vd->vdev_ms_array = 0;
+       }
+       dmu_tx_commit(tx);
+}
+
+void
+vdev_sync_done(vdev_t *vd, uint64_t txg)
+{
+       metaslab_t *msp;
+       boolean_t reassess = !txg_list_empty(&vd->vdev_ms_list, TXG_CLEAN(txg));
+
+       ASSERT(!vd->vdev_ishole);
+
+       while ((msp = txg_list_remove(&vd->vdev_ms_list, TXG_CLEAN(txg))))
+               metaslab_sync_done(msp, txg);
+
+       if (reassess)
+               metaslab_sync_reassess(vd->vdev_mg);
+}
+
+void
+vdev_sync(vdev_t *vd, uint64_t txg)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *lvd;
+       metaslab_t *msp;
+       dmu_tx_t *tx;
+
+       ASSERT(!vd->vdev_ishole);
+
+       if (vd->vdev_ms_array == 0 && vd->vdev_ms_shift != 0) {
+               ASSERT(vd == vd->vdev_top);
+               tx = dmu_tx_create_assigned(spa->spa_dsl_pool, txg);
+               vd->vdev_ms_array = dmu_object_alloc(spa->spa_meta_objset,
+                   DMU_OT_OBJECT_ARRAY, 0, DMU_OT_NONE, 0, tx);
+               ASSERT(vd->vdev_ms_array != 0);
+               vdev_config_dirty(vd);
+               dmu_tx_commit(tx);
+       }
+
+       /*
+        * Remove the metadata associated with this vdev once it's empty.
+        */
+       if (vd->vdev_stat.vs_alloc == 0 && vd->vdev_removing)
+               vdev_remove(vd, txg);
+
+       while ((msp = txg_list_remove(&vd->vdev_ms_list, txg)) != NULL) {
+               metaslab_sync(msp, txg);
+               (void) txg_list_add(&vd->vdev_ms_list, msp, TXG_CLEAN(txg));
+       }
+
+       while ((lvd = txg_list_remove(&vd->vdev_dtl_list, txg)) != NULL)
+               vdev_dtl_sync(lvd, txg);
+
+       (void) txg_list_add(&spa->spa_vdev_txg_list, vd, TXG_CLEAN(txg));
+}
+
+uint64_t
+vdev_psize_to_asize(vdev_t *vd, uint64_t psize)
+{
+       return (vd->vdev_ops->vdev_op_asize(vd, psize));
+}
+
+/*
+ * Mark the given vdev faulted.  A faulted vdev behaves as if the device could
+ * not be opened, and no I/O is attempted.
+ */
+int
+vdev_fault(spa_t *spa, uint64_t guid, vdev_aux_t aux)
+{
+       vdev_t *vd, *tvd;
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+
+       if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
+               return (spa_vdev_state_exit(spa, NULL, ENODEV));
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
+
+       tvd = vd->vdev_top;
+
+       /*
+        * We don't directly use the aux state here, but if we do a
+        * vdev_reopen(), we need this value to be present to remember why we
+        * were faulted.
+        */
+       vd->vdev_label_aux = aux;
+
+       /*
+        * Faulted state takes precedence over degraded.
+        */
+       vd->vdev_delayed_close = B_FALSE;
+       vd->vdev_faulted = 1ULL;
+       vd->vdev_degraded = 0ULL;
+       vdev_set_state(vd, B_FALSE, VDEV_STATE_FAULTED, aux);
+
+       /*
+        * If this device has the only valid copy of the data, then
+        * back off and simply mark the vdev as degraded instead.
+        */
+       if (!tvd->vdev_islog && vd->vdev_aux == NULL && vdev_dtl_required(vd)) {
+               vd->vdev_degraded = 1ULL;
+               vd->vdev_faulted = 0ULL;
+
+               /*
+                * If we reopen the device and it's not dead, only then do we
+                * mark it degraded.
+                */
+               vdev_reopen(tvd);
+
+               if (vdev_readable(vd))
+                       vdev_set_state(vd, B_FALSE, VDEV_STATE_DEGRADED, aux);
+       }
+
+       return (spa_vdev_state_exit(spa, vd, 0));
+}
+
+/*
+ * Mark the given vdev degraded.  A degraded vdev is purely an indication to the
+ * user that something is wrong.  The vdev continues to operate as normal as far
+ * as I/O is concerned.
+ */
+int
+vdev_degrade(spa_t *spa, uint64_t guid, vdev_aux_t aux)
+{
+       vdev_t *vd;
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+
+       if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
+               return (spa_vdev_state_exit(spa, NULL, ENODEV));
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
+
+       /*
+        * If the vdev is already faulted, then don't do anything.
+        */
+       if (vd->vdev_faulted || vd->vdev_degraded)
+               return (spa_vdev_state_exit(spa, NULL, 0));
+
+       vd->vdev_degraded = 1ULL;
+       if (!vdev_is_dead(vd))
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_DEGRADED,
+                   aux);
+
+       return (spa_vdev_state_exit(spa, vd, 0));
+}
+
+/*
+ * Online the given vdev.
+ *
+ * If 'ZFS_ONLINE_UNSPARE' is set, it implies two things.  First, any attached
+ * spare device should be detached when the device finishes resilvering.
+ * Second, the online should be treated like a 'test' online case, so no FMA
+ * events are generated if the device fails to open.
+ */
+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;
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+
+       if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
+               return (spa_vdev_state_exit(spa, NULL, ENODEV));
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
+
+       tvd = vd->vdev_top;
+       vd->vdev_offline = B_FALSE;
+       vd->vdev_tmpoffline = B_FALSE;
+       vd->vdev_checkremove = !!(flags & ZFS_ONLINE_CHECKREMOVE);
+       vd->vdev_forcefault = !!(flags & ZFS_ONLINE_FORCEFAULT);
+
+       /* XXX - L2ARC 1.0 does not support expansion */
+       if (!vd->vdev_aux) {
+               for (pvd = vd; pvd != rvd; pvd = pvd->vdev_parent)
+                       pvd->vdev_expanding = !!(flags & ZFS_ONLINE_EXPAND);
+       }
+
+       vdev_reopen(tvd);
+       vd->vdev_checkremove = vd->vdev_forcefault = B_FALSE;
+
+       if (!vd->vdev_aux) {
+               for (pvd = vd; pvd != rvd; pvd = pvd->vdev_parent)
+                       pvd->vdev_expanding = B_FALSE;
+       }
+
+       if (newstate)
+               *newstate = vd->vdev_state;
+       if ((flags & ZFS_ONLINE_UNSPARE) &&
+           !vdev_is_dead(vd) && vd->vdev_parent &&
+           vd->vdev_parent->vdev_ops == &vdev_spare_ops &&
+           vd->vdev_parent->vdev_child[0] == vd)
+               vd->vdev_unspare = B_TRUE;
+
+       if ((flags & ZFS_ONLINE_EXPAND) || spa->spa_autoexpand) {
+
+               /* XXX - L2ARC 1.0 does not support expansion */
+               if (vd->vdev_aux)
+                       return (spa_vdev_state_exit(spa, vd, ENOTSUP));
+               spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
+       }
+       return (spa_vdev_state_exit(spa, vd, 0));
+}
+
+static int
+vdev_offline_locked(spa_t *spa, uint64_t guid, uint64_t flags)
+{
+       vdev_t *vd, *tvd;
+       int error = 0;
+       uint64_t generation;
+       metaslab_group_t *mg;
+
+top:
+       spa_vdev_state_enter(spa, SCL_ALLOC);
+
+       if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
+               return (spa_vdev_state_exit(spa, NULL, ENODEV));
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
+
+       tvd = vd->vdev_top;
+       mg = tvd->vdev_mg;
+       generation = spa->spa_config_generation + 1;
+
+       /*
+        * If the device isn't already offline, try to offline it.
+        */
+       if (!vd->vdev_offline) {
+               /*
+                * If this device has the only valid copy of some data,
+                * don't allow it to be offlined. Log devices are always
+                * expendable.
+                */
+               if (!tvd->vdev_islog && vd->vdev_aux == NULL &&
+                   vdev_dtl_required(vd))
+                       return (spa_vdev_state_exit(spa, NULL, EBUSY));
+
+               /*
+                * If the top-level is a slog and it has had allocations
+                * then proceed.  We check that the vdev's metaslab group
+                * is not NULL since it's possible that we may have just
+                * added this vdev but not yet initialized its metaslabs.
+                */
+               if (tvd->vdev_islog && mg != NULL) {
+                       /*
+                        * Prevent any future allocations.
+                        */
+                       metaslab_group_passivate(mg);
+                       (void) spa_vdev_state_exit(spa, vd, 0);
+
+                       error = spa_offline_log(spa);
+
+                       spa_vdev_state_enter(spa, SCL_ALLOC);
+
+                       /*
+                        * Check to see if the config has changed.
+                        */
+                       if (error || generation != spa->spa_config_generation) {
+                               metaslab_group_activate(mg);
+                               if (error)
+                                       return (spa_vdev_state_exit(spa,
+                                           vd, error));
+                               (void) spa_vdev_state_exit(spa, vd, 0);
+                               goto top;
+                       }
+                       ASSERT0(tvd->vdev_stat.vs_alloc);
+               }
+
+               /*
+                * Offline this device and reopen its top-level vdev.
+                * If the top-level vdev is a log device then just offline
+                * it. Otherwise, if this action results in the top-level
+                * vdev becoming unusable, undo it and fail the request.
+                */
+               vd->vdev_offline = B_TRUE;
+               vdev_reopen(tvd);
+
+               if (!tvd->vdev_islog && vd->vdev_aux == NULL &&
+                   vdev_is_dead(tvd)) {
+                       vd->vdev_offline = B_FALSE;
+                       vdev_reopen(tvd);
+                       return (spa_vdev_state_exit(spa, NULL, EBUSY));
+               }
+
+               /*
+                * Add the device back into the metaslab rotor so that
+                * once we online the device it's open for business.
+                */
+               if (tvd->vdev_islog && mg != NULL)
+                       metaslab_group_activate(mg);
+       }
+
+       vd->vdev_tmpoffline = !!(flags & ZFS_OFFLINE_TEMPORARY);
+
+       return (spa_vdev_state_exit(spa, vd, 0));
+}
+
+int
+vdev_offline(spa_t *spa, uint64_t guid, uint64_t flags)
+{
+       int error;
+
+       mutex_enter(&spa->spa_vdev_top_lock);
+       error = vdev_offline_locked(spa, guid, flags);
+       mutex_exit(&spa->spa_vdev_top_lock);
+
+       return (error);
+}
+
+/*
+ * Clear the error counts associated with this vdev.  Unlike vdev_online() and
+ * vdev_offline(), we assume the spa config is locked.  We also clear all
+ * children.  If 'vd' is NULL, then the user wants to clear all vdevs.
+ */
+void
+vdev_clear(spa_t *spa, vdev_t *vd)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       int c;
+
+       ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+
+       if (vd == NULL)
+               vd = rvd;
+
+       vd->vdev_stat.vs_read_errors = 0;
+       vd->vdev_stat.vs_write_errors = 0;
+       vd->vdev_stat.vs_checksum_errors = 0;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_clear(spa, vd->vdev_child[c]);
+
+       /*
+        * If we're in the FAULTED state or have experienced failed I/O, then
+        * clear the persistent state and attempt to reopen the device.  We
+        * also mark the vdev config dirty, so that the new faulted state is
+        * written out to disk.
+        */
+       if (vd->vdev_faulted || vd->vdev_degraded ||
+           !vdev_readable(vd) || !vdev_writeable(vd)) {
+
+               /*
+                * When reopening in reponse to a clear event, it may be due to
+                * a fmadm repair request.  In this case, if the device is
+                * still broken, we want to still post the ereport again.
+                */
+               vd->vdev_forcefault = B_TRUE;
+
+               vd->vdev_faulted = vd->vdev_degraded = 0ULL;
+               vd->vdev_cant_read = B_FALSE;
+               vd->vdev_cant_write = B_FALSE;
+
+               vdev_reopen(vd == rvd ? rvd : vd->vdev_top);
+
+               vd->vdev_forcefault = B_FALSE;
+
+               if (vd != rvd && vdev_writeable(vd->vdev_top))
+                       vdev_state_dirty(vd->vdev_top);
+
+               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);
+       }
+
+       /*
+        * When clearing a FMA-diagnosed fault, we always want to
+        * unspare the device, as we assume that the original spare was
+        * done in response to the FMA fault.
+        */
+       if (!vdev_is_dead(vd) && vd->vdev_parent != NULL &&
+           vd->vdev_parent->vdev_ops == &vdev_spare_ops &&
+           vd->vdev_parent->vdev_child[0] == vd)
+               vd->vdev_unspare = B_TRUE;
+}
+
+boolean_t
+vdev_is_dead(vdev_t *vd)
+{
+       /*
+        * Holes and missing devices are always considered "dead".
+        * This simplifies the code since we don't have to check for
+        * these types of devices in the various code paths.
+        * Instead we rely on the fact that we skip over dead devices
+        * before issuing I/O to them.
+        */
+       return (vd->vdev_state < VDEV_STATE_DEGRADED || vd->vdev_ishole ||
+           vd->vdev_ops == &vdev_missing_ops);
+}
+
+boolean_t
+vdev_readable(vdev_t *vd)
+{
+       return (!vdev_is_dead(vd) && !vd->vdev_cant_read);
+}
+
+boolean_t
+vdev_writeable(vdev_t *vd)
+{
+       return (!vdev_is_dead(vd) && !vd->vdev_cant_write);
+}
+
+boolean_t
+vdev_allocatable(vdev_t *vd)
+{
+       uint64_t state = vd->vdev_state;
+
+       /*
+        * We currently allow allocations from vdevs which may be in the
+        * process of reopening (i.e. VDEV_STATE_CLOSED). If the device
+        * fails to reopen then we'll catch it later when we're holding
+        * the proper locks.  Note that we have to get the vdev state
+        * in a local variable because although it changes atomically,
+        * we're asking two separate questions about it.
+        */
+       return (!(state < VDEV_STATE_DEGRADED && state != VDEV_STATE_CLOSED) &&
+           !vd->vdev_cant_write && !vd->vdev_ishole);
+}
+
+boolean_t
+vdev_accessible(vdev_t *vd, zio_t *zio)
+{
+       ASSERT(zio->io_vd == vd);
+
+       if (vdev_is_dead(vd) || vd->vdev_remove_wanted)
+               return (B_FALSE);
+
+       if (zio->io_type == ZIO_TYPE_READ)
+               return (!vd->vdev_cant_read);
+
+       if (zio->io_type == ZIO_TYPE_WRITE)
+               return (!vd->vdev_cant_write);
+
+       return (B_TRUE);
+}
+
+/*
+ * Get statistics for the given vdev.
+ */
+void
+vdev_get_stats(vdev_t *vd, vdev_stat_t *vs)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       int c, t;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+
+       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;
+       }
+
+       /*
+        * 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];
+                       vdev_stat_t *cvs = &cvd->vdev_stat;
+
+                       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;
+               }
+       }
+       mutex_exit(&vd->vdev_stat_lock);
+}
+
+void
+vdev_clear_stats(vdev_t *vd)
+{
+       mutex_enter(&vd->vdev_stat_lock);
+       vd->vdev_stat.vs_space = 0;
+       vd->vdev_stat.vs_dspace = 0;
+       vd->vdev_stat.vs_alloc = 0;
+       mutex_exit(&vd->vdev_stat_lock);
+}
+
+void
+vdev_scan_stat_init(vdev_t *vd)
+{
+       vdev_stat_t *vs = &vd->vdev_stat;
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_scan_stat_init(vd->vdev_child[c]);
+
+       mutex_enter(&vd->vdev_stat_lock);
+       vs->vs_scan_processed = 0;
+       mutex_exit(&vd->vdev_stat_lock);
+}
+
+void
+vdev_stat_update(zio_t *zio, uint64_t psize)
+{
+       spa_t *spa = zio->io_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       vdev_t *vd = zio->io_vd ? zio->io_vd : rvd;
+       vdev_t *pvd;
+       uint64_t txg = zio->io_txg;
+       vdev_stat_t *vs = &vd->vdev_stat;
+       zio_type_t type = zio->io_type;
+       int flags = zio->io_flags;
+
+       /*
+        * If this i/o is a gang leader, it didn't do any actual work.
+        */
+       if (zio->io_gang_tree)
+               return;
+
+       if (zio->io_error == 0) {
+               /*
+                * If this is a root i/o, don't count it -- we've already
+                * counted the top-level vdevs, and vdev_get_stats() will
+                * aggregate them when asked.  This reduces contention on
+                * the root vdev_stat_lock and implicitly handles blocks
+                * that compress away to holes, for which there is no i/o.
+                * (Holes never create vdev children, so all the counters
+                * remain zero, which is what we want.)
+                *
+                * Note: this only applies to successful i/o (io_error == 0)
+                * because unlike i/o counts, errors are not additive.
+                * When reading a ditto block, for example, failure of
+                * one top-level vdev does not imply a root-level error.
+                */
+               if (vd == rvd)
+                       return;
+
+               ASSERT(vd == zio->io_vd);
+
+               if (flags & ZIO_FLAG_IO_BYPASS)
+                       return;
+
+               mutex_enter(&vd->vdev_stat_lock);
+
+               if (flags & ZIO_FLAG_IO_REPAIR) {
+                       if (flags & ZIO_FLAG_SCAN_THREAD) {
+                               dsl_scan_phys_t *scn_phys =
+                                   &spa->spa_dsl_pool->dp_scan->scn_phys;
+                               uint64_t *processed = &scn_phys->scn_processed;
+
+                               /* XXX cleanup? */
+                               if (vd->vdev_ops->vdev_op_leaf)
+                                       atomic_add_64(processed, psize);
+                               vs->vs_scan_processed += psize;
+                       }
+
+                       if (flags & ZIO_FLAG_SELF_HEAL)
+                               vs->vs_self_healed += psize;
+               }
+
+               vs->vs_ops[type]++;
+               vs->vs_bytes[type] += psize;
+
+               mutex_exit(&vd->vdev_stat_lock);
+               return;
+       }
+
+       if (flags & ZIO_FLAG_SPECULATIVE)
+               return;
+
+       /*
+        * If this is an I/O error that is going to be retried, then ignore the
+        * error.  Otherwise, the user may interpret B_FAILFAST I/O errors as
+        * hard errors, when in reality they can happen for any number of
+        * innocuous reasons (bus resets, MPxIO link failure, etc).
+        */
+       if (zio->io_error == EIO &&
+           !(zio->io_flags & ZIO_FLAG_IO_RETRY))
+               return;
+
+       /*
+        * Intent logs writes won't propagate their error to the root
+        * I/O so don't mark these types of failures as pool-level
+        * errors.
+        */
+       if (zio->io_vd == NULL && (zio->io_flags & ZIO_FLAG_DONT_PROPAGATE))
+               return;
+
+       mutex_enter(&vd->vdev_stat_lock);
+       if (type == ZIO_TYPE_READ && !vdev_is_dead(vd)) {
+               if (zio->io_error == ECKSUM)
+                       vs->vs_checksum_errors++;
+               else
+                       vs->vs_read_errors++;
+       }
+       if (type == ZIO_TYPE_WRITE && !vdev_is_dead(vd))
+               vs->vs_write_errors++;
+       mutex_exit(&vd->vdev_stat_lock);
+
+       if (type == ZIO_TYPE_WRITE && txg != 0 &&
+           (!(flags & ZIO_FLAG_IO_REPAIR) ||
+           (flags & ZIO_FLAG_SCAN_THREAD) ||
+           spa->spa_claiming)) {
+               /*
+                * This is either a normal write (not a repair), or it's
+                * a repair induced by the scrub thread, or it's a repair
+                * made by zil_claim() during spa_load() in the first txg.
+                * In the normal case, we commit the DTL change in the same
+                * txg as the block was born.  In the scrub-induced repair
+                * case, we know that scrubs run in first-pass syncing context,
+                * so we commit the DTL change in spa_syncing_txg(spa).
+                * In the zil_claim() case, we commit in spa_first_txg(spa).
+                *
+                * We currently do not make DTL entries for failed spontaneous
+                * self-healing writes triggered by normal (non-scrubbing)
+                * reads, because we have no transactional context in which to
+                * do so -- and it's not clear that it'd be desirable anyway.
+                */
+               if (vd->vdev_ops->vdev_op_leaf) {
+                       uint64_t commit_txg = txg;
+                       if (flags & ZIO_FLAG_SCAN_THREAD) {
+                               ASSERT(flags & ZIO_FLAG_IO_REPAIR);
+                               ASSERT(spa_sync_pass(spa) == 1);
+                               vdev_dtl_dirty(vd, DTL_SCRUB, txg, 1);
+                               commit_txg = spa_syncing_txg(spa);
+                       } else if (spa->spa_claiming) {
+                               ASSERT(flags & ZIO_FLAG_IO_REPAIR);
+                               commit_txg = spa_first_txg(spa);
+                       }
+                       ASSERT(commit_txg >= spa_syncing_txg(spa));
+                       if (vdev_dtl_contains(vd, DTL_MISSING, txg, 1))
+                               return;
+                       for (pvd = vd; pvd != rvd; pvd = pvd->vdev_parent)
+                               vdev_dtl_dirty(pvd, DTL_PARTIAL, txg, 1);
+                       vdev_dirty(vd->vdev_top, VDD_DTL, vd, commit_txg);
+               }
+               if (vd != rvd)
+                       vdev_dtl_dirty(vd, DTL_MISSING, txg, 1);
+       }
+}
+
+/*
+ * Update the in-core space usage stats for this vdev, its metaslab class,
+ * and the root vdev.
+ */
+void
+vdev_space_update(vdev_t *vd, int64_t alloc_delta, int64_t defer_delta,
+    int64_t space_delta)
+{
+       int64_t dspace_delta = space_delta;
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       metaslab_group_t *mg = vd->vdev_mg;
+       metaslab_class_t *mc = mg ? mg->mg_class : NULL;
+
+       ASSERT(vd == vd->vdev_top);
+
+       /*
+        * Apply the inverse of the psize-to-asize (ie. RAID-Z) space-expansion
+        * factor.  We must calculate this here and not at the root vdev
+        * because the root vdev's psize-to-asize is simply the max of its
+        * childrens', thus not accurate enough for us.
+        */
+       ASSERT((dspace_delta & (SPA_MINBLOCKSIZE-1)) == 0);
+       ASSERT(vd->vdev_deflate_ratio != 0 || vd->vdev_isl2cache);
+       dspace_delta = (dspace_delta >> SPA_MINBLOCKSHIFT) *
+           vd->vdev_deflate_ratio;
+
+       mutex_enter(&vd->vdev_stat_lock);
+       vd->vdev_stat.vs_alloc += alloc_delta;
+       vd->vdev_stat.vs_space += space_delta;
+       vd->vdev_stat.vs_dspace += dspace_delta;
+       mutex_exit(&vd->vdev_stat_lock);
+
+       if (mc == spa_normal_class(spa)) {
+               mutex_enter(&rvd->vdev_stat_lock);
+               rvd->vdev_stat.vs_alloc += alloc_delta;
+               rvd->vdev_stat.vs_space += space_delta;
+               rvd->vdev_stat.vs_dspace += dspace_delta;
+               mutex_exit(&rvd->vdev_stat_lock);
+       }
+
+       if (mc != NULL) {
+               ASSERT(rvd == vd->vdev_parent);
+               ASSERT(vd->vdev_ms_count != 0);
+
+               metaslab_class_space_update(mc,
+                   alloc_delta, defer_delta, space_delta, dspace_delta);
+       }
+}
+
+/*
+ * Mark a top-level vdev's config as dirty, placing it on the dirty list
+ * so that it will be written out next time the vdev configuration is synced.
+ * If the root vdev is specified (vdev_top == NULL), dirty all top-level vdevs.
+ */
+void
+vdev_config_dirty(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       int c;
+
+       ASSERT(spa_writeable(spa));
+
+       /*
+        * If this is an aux vdev (as with l2cache and spare devices), then we
+        * update the vdev config manually and set the sync flag.
+        */
+       if (vd->vdev_aux != NULL) {
+               spa_aux_vdev_t *sav = vd->vdev_aux;
+               nvlist_t **aux;
+               uint_t naux;
+
+               for (c = 0; c < sav->sav_count; c++) {
+                       if (sav->sav_vdevs[c] == vd)
+                               break;
+               }
+
+               if (c == sav->sav_count) {
+                       /*
+                        * We're being removed.  There's nothing more to do.
+                        */
+                       ASSERT(sav->sav_sync == B_TRUE);
+                       return;
+               }
+
+               sav->sav_sync = B_TRUE;
+
+               if (nvlist_lookup_nvlist_array(sav->sav_config,
+                   ZPOOL_CONFIG_L2CACHE, &aux, &naux) != 0) {
+                       VERIFY(nvlist_lookup_nvlist_array(sav->sav_config,
+                           ZPOOL_CONFIG_SPARES, &aux, &naux) == 0);
+               }
+
+               ASSERT(c < naux);
+
+               /*
+                * Setting the nvlist in the middle if the array is a little
+                * sketchy, but it will work.
+                */
+               nvlist_free(aux[c]);
+               aux[c] = vdev_config_generate(spa, vd, B_TRUE, 0);
+
+               return;
+       }
+
+       /*
+        * The dirty list is protected by the SCL_CONFIG lock.  The caller
+        * must either hold SCL_CONFIG as writer, or must be the sync thread
+        * (which holds SCL_CONFIG as reader).  There's only one sync thread,
+        * so this is sufficient to ensure mutual exclusion.
+        */
+       ASSERT(spa_config_held(spa, SCL_CONFIG, RW_WRITER) ||
+           (dsl_pool_sync_context(spa_get_dsl(spa)) &&
+           spa_config_held(spa, SCL_CONFIG, RW_READER)));
+
+       if (vd == rvd) {
+               for (c = 0; c < rvd->vdev_children; c++)
+                       vdev_config_dirty(rvd->vdev_child[c]);
+       } else {
+               ASSERT(vd == vd->vdev_top);
+
+               if (!list_link_active(&vd->vdev_config_dirty_node) &&
+                   !vd->vdev_ishole)
+                       list_insert_head(&spa->spa_config_dirty_list, vd);
+       }
+}
+
+void
+vdev_config_clean(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+
+       ASSERT(spa_config_held(spa, SCL_CONFIG, RW_WRITER) ||
+           (dsl_pool_sync_context(spa_get_dsl(spa)) &&
+           spa_config_held(spa, SCL_CONFIG, RW_READER)));
+
+       ASSERT(list_link_active(&vd->vdev_config_dirty_node));
+       list_remove(&spa->spa_config_dirty_list, vd);
+}
+
+/*
+ * Mark a top-level vdev's state as dirty, so that the next pass of
+ * spa_sync() can convert this into vdev_config_dirty().  We distinguish
+ * the state changes from larger config changes because they require
+ * much less locking, and are often needed for administrative actions.
+ */
+void
+vdev_state_dirty(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+
+       ASSERT(spa_writeable(spa));
+       ASSERT(vd == vd->vdev_top);
+
+       /*
+        * The state list is protected by the SCL_STATE lock.  The caller
+        * must either hold SCL_STATE as writer, or must be the sync thread
+        * (which holds SCL_STATE as reader).  There's only one sync thread,
+        * so this is sufficient to ensure mutual exclusion.
+        */
+       ASSERT(spa_config_held(spa, SCL_STATE, RW_WRITER) ||
+           (dsl_pool_sync_context(spa_get_dsl(spa)) &&
+           spa_config_held(spa, SCL_STATE, RW_READER)));
+
+       if (!list_link_active(&vd->vdev_state_dirty_node) && !vd->vdev_ishole)
+               list_insert_head(&spa->spa_state_dirty_list, vd);
+}
+
+void
+vdev_state_clean(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+
+       ASSERT(spa_config_held(spa, SCL_STATE, RW_WRITER) ||
+           (dsl_pool_sync_context(spa_get_dsl(spa)) &&
+           spa_config_held(spa, SCL_STATE, RW_READER)));
+
+       ASSERT(list_link_active(&vd->vdev_state_dirty_node));
+       list_remove(&spa->spa_state_dirty_list, vd);
+}
+
+/*
+ * Propagate vdev state up from children to parent.
+ */
+void
+vdev_propagate_state(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       int degraded = 0, faulted = 0;
+       int corrupted = 0;
+       vdev_t *child;
+       int c;
+
+       if (vd->vdev_children > 0) {
+               for (c = 0; c < vd->vdev_children; c++) {
+                       child = vd->vdev_child[c];
+
+                       /*
+                        * Don't factor holes into the decision.
+                        */
+                       if (child->vdev_ishole)
+                               continue;
+
+                       if (!vdev_readable(child) ||
+                           (!vdev_writeable(child) && spa_writeable(spa))) {
+                               /*
+                                * Root special: if there is a top-level log
+                                * device, treat the root vdev as if it were
+                                * degraded.
+                                */
+                               if (child->vdev_islog && vd == rvd)
+                                       degraded++;
+                               else
+                                       faulted++;
+                       } else if (child->vdev_state <= VDEV_STATE_DEGRADED) {
+                               degraded++;
+                       }
+
+                       if (child->vdev_stat.vs_aux == VDEV_AUX_CORRUPT_DATA)
+                               corrupted++;
+               }
+
+               vd->vdev_ops->vdev_op_state_change(vd, faulted, degraded);
+
+               /*
+                * Root special: if there is a top-level vdev that cannot be
+                * opened due to corrupted metadata, then propagate the root
+                * vdev's aux state as 'corrupt' rather than 'insufficient
+                * replicas'.
+                */
+               if (corrupted && vd == rvd &&
+                   rvd->vdev_state == VDEV_STATE_CANT_OPEN)
+                       vdev_set_state(rvd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                           VDEV_AUX_CORRUPT_DATA);
+       }
+
+       if (vd->vdev_parent)
+               vdev_propagate_state(vd->vdev_parent);
+}
+
+/*
+ * Set a vdev's state.  If this is during an open, we don't update the parent
+ * state, because we're in the process of opening children depth-first.
+ * Otherwise, we propagate the change to the parent.
+ *
+ * If this routine places a device in a faulted state, an appropriate ereport is
+ * generated.
+ */
+void
+vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux)
+{
+       uint64_t save_state;
+       spa_t *spa = vd->vdev_spa;
+
+       if (state == vd->vdev_state) {
+               vd->vdev_stat.vs_aux = aux;
+               return;
+       }
+
+       save_state = vd->vdev_state;
+
+       vd->vdev_state = state;
+       vd->vdev_stat.vs_aux = aux;
+
+       /*
+        * If we are setting the vdev state to anything but an open state, then
+        * always close the underlying device unless the device has requested
+        * a delayed close (i.e. we're about to remove or fault the device).
+        * Otherwise, we keep accessible but invalid devices open forever.
+        * We don't call vdev_close() itself, because that implies some extra
+        * checks (offline, etc) that we don't want here.  This is limited to
+        * leaf devices, because otherwise closing the device will affect other
+        * children.
+        */
+       if (!vd->vdev_delayed_close && vdev_is_dead(vd) &&
+           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)) {
+               /*
+                * If the previous state is set to VDEV_STATE_REMOVED, then this
+                * device was previously marked removed and someone attempted to
+                * reopen it.  If this failed due to a nonexistent device, then
+                * keep the device in the REMOVED state.  We also let this be if
+                * it is one of our special test online cases, which is only
+                * attempting to online the device and shouldn't generate an FMA
+                * fault.
+                */
+               vd->vdev_state = VDEV_STATE_REMOVED;
+               vd->vdev_stat.vs_aux = VDEV_AUX_NONE;
+       } else if (state == VDEV_STATE_REMOVED) {
+               vd->vdev_removed = B_TRUE;
+       } else if (state == VDEV_STATE_CANT_OPEN) {
+               /*
+                * If we fail to open a vdev during an import or recovery, we
+                * mark it as "not available", which signifies that it was
+                * never there to begin with.  Failure to open such a device
+                * is not considered an error.
+                */
+               if ((spa_load_state(spa) == SPA_LOAD_IMPORT ||
+                   spa_load_state(spa) == SPA_LOAD_RECOVER) &&
+                   vd->vdev_ops->vdev_op_leaf)
+                       vd->vdev_not_present = 1;
+
+               /*
+                * Post the appropriate ereport.  If the 'prevstate' field is
+                * set to something other than VDEV_STATE_UNKNOWN, it indicates
+                * that this is part of a vdev_reopen().  In this case, we don't
+                * want to post the ereport if the device was already in the
+                * CANT_OPEN state beforehand.
+                *
+                * If the 'checkremove' flag is set, then this is an attempt to
+                * online the device in response to an insertion event.  If we
+                * hit this case, then we have detected an insertion event for a
+                * faulted or offline device that wasn't in the removed state.
+                * In this scenario, we don't post an ereport because we are
+                * about to replace the device, or attempt an online with
+                * vdev_forcefault, which will generate the fault for us.
+                */
+               if ((vd->vdev_prevstate != state || vd->vdev_forcefault) &&
+                   !vd->vdev_not_present && !vd->vdev_checkremove &&
+                   vd != spa->spa_root_vdev) {
+                       const char *class;
+
+                       switch (aux) {
+                       case VDEV_AUX_OPEN_FAILED:
+                               class = FM_EREPORT_ZFS_DEVICE_OPEN_FAILED;
+                               break;
+                       case VDEV_AUX_CORRUPT_DATA:
+                               class = FM_EREPORT_ZFS_DEVICE_CORRUPT_DATA;
+                               break;
+                       case VDEV_AUX_NO_REPLICAS:
+                               class = FM_EREPORT_ZFS_DEVICE_NO_REPLICAS;
+                               break;
+                       case VDEV_AUX_BAD_GUID_SUM:
+                               class = FM_EREPORT_ZFS_DEVICE_BAD_GUID_SUM;
+                               break;
+                       case VDEV_AUX_TOO_SMALL:
+                               class = FM_EREPORT_ZFS_DEVICE_TOO_SMALL;
+                               break;
+                       case VDEV_AUX_BAD_LABEL:
+                               class = FM_EREPORT_ZFS_DEVICE_BAD_LABEL;
+                               break;
+                       default:
+                               class = FM_EREPORT_ZFS_DEVICE_UNKNOWN;
+                       }
+
+                       zfs_ereport_post(class, spa, vd, NULL, save_state, 0);
+               }
+
+               /* Erase any notion of persistent removed state */
+               vd->vdev_removed = B_FALSE;
+       } else {
+               vd->vdev_removed = B_FALSE;
+       }
+
+       if (!isopen && vd->vdev_parent)
+               vdev_propagate_state(vd->vdev_parent);
+}
+
+/*
+ * Check the vdev configuration to ensure that it's capable of supporting
+ * a root pool.
+ */
+boolean_t
+vdev_is_bootable(vdev_t *vd)
+{
+#if defined(__sun__) || defined(__sun)
+       /*
+        * Currently, we do not support RAID-Z or partial configuration.
+        * In addition, only a single top-level vdev is allowed and none of the
+        * leaves can be wholedisks.
+        */
+       int c;
+
+       if (!vd->vdev_ops->vdev_op_leaf) {
+               char *vdev_type = vd->vdev_ops->vdev_op_type;
+
+               if (strcmp(vdev_type, VDEV_TYPE_ROOT) == 0 &&
+                   vd->vdev_children > 1) {
+                       return (B_FALSE);
+               } else if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 ||
+                   strcmp(vdev_type, VDEV_TYPE_MISSING) == 0) {
+                       return (B_FALSE);
+               }
+       } else if (vd->vdev_wholedisk == 1) {
+               return (B_FALSE);
+       }
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               if (!vdev_is_bootable(vd->vdev_child[c]))
+                       return (B_FALSE);
+       }
+#endif /* __sun__ || __sun */
+       return (B_TRUE);
+}
+
+/*
+ * Load the state from the original vdev tree (ovd) which
+ * we've retrieved from the MOS config object. If the original
+ * vdev was offline or faulted then we transfer that state to the
+ * device in the current vdev tree (nvd).
+ */
+void
+vdev_load_log_state(vdev_t *nvd, vdev_t *ovd)
+{
+       int c;
+
+       ASSERT(nvd->vdev_top->vdev_islog);
+       ASSERT(spa_config_held(nvd->vdev_spa,
+           SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+       ASSERT3U(nvd->vdev_guid, ==, ovd->vdev_guid);
+
+       for (c = 0; c < nvd->vdev_children; c++)
+               vdev_load_log_state(nvd->vdev_child[c], ovd->vdev_child[c]);
+
+       if (nvd->vdev_ops->vdev_op_leaf) {
+               /*
+                * Restore the persistent vdev state
+                */
+               nvd->vdev_offline = ovd->vdev_offline;
+               nvd->vdev_faulted = ovd->vdev_faulted;
+               nvd->vdev_degraded = ovd->vdev_degraded;
+               nvd->vdev_removed = ovd->vdev_removed;
+       }
+}
+
+/*
+ * Determine if a log device has valid content.  If the vdev was
+ * removed or faulted in the MOS config then we know that
+ * the content on the log device has already been written to the pool.
+ */
+boolean_t
+vdev_log_state_valid(vdev_t *vd)
+{
+       int c;
+
+       if (vd->vdev_ops->vdev_op_leaf && !vd->vdev_faulted &&
+           !vd->vdev_removed)
+               return (B_TRUE);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               if (vdev_log_state_valid(vd->vdev_child[c]))
+                       return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+/*
+ * Expand a vdev if possible.
+ */
+void
+vdev_expand(vdev_t *vd, uint64_t txg)
+{
+       ASSERT(vd->vdev_top == vd);
+       ASSERT(spa_config_held(vd->vdev_spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       if ((vd->vdev_asize >> vd->vdev_ms_shift) > vd->vdev_ms_count) {
+               VERIFY(vdev_metaslab_init(vd, txg) == 0);
+               vdev_config_dirty(vd);
+       }
+}
+
+/*
+ * Split a vdev.
+ */
+void
+vdev_split(vdev_t *vd)
+{
+       vdev_t *cvd, *pvd = vd->vdev_parent;
+
+       vdev_remove_child(pvd, vd);
+       vdev_compact_children(pvd);
+
+       cvd = pvd->vdev_child[0];
+       if (pvd->vdev_children == 1) {
+               vdev_remove_parent(cvd);
+               cvd->vdev_splitting = B_TRUE;
+       }
+       vdev_propagate_state(cvd);
+}
+
+void
+vdev_deadman(vdev_t *vd)
+{
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               vdev_t *cvd = vd->vdev_child[c];
+
+               vdev_deadman(cvd);
+       }
+
+       if (vd->vdev_ops->vdev_op_leaf) {
+               vdev_queue_t *vq = &vd->vdev_queue;
+
+               mutex_enter(&vq->vq_lock);
+               if (avl_numnodes(&vq->vq_active_tree) > 0) {
+                       spa_t *spa = vd->vdev_spa;
+                       zio_t *fio;
+                       uint64_t delta;
+
+                       /*
+                        * Look at the head of all the pending queues,
+                        * if any I/O has been outstanding for longer than
+                        * the spa_deadman_synctime we log a zevent.
+                        */
+                       fio = avl_first(&vq->vq_active_tree);
+                       delta = gethrtime() - fio->io_timestamp;
+                       if (delta > spa_deadman_synctime(spa)) {
+                               zfs_dbgmsg("SLOW IO: zio timestamp %lluns, "
+                                   "delta %lluns, last io %lluns",
+                                   fio->io_timestamp, delta,
+                                   vq->vq_io_complete_ts);
+                               zfs_ereport_post(FM_EREPORT_ZFS_DELAY,
+                                   spa, vd, fio, 0, 0);
+                       }
+               }
+               mutex_exit(&vq->vq_lock);
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(vdev_fault);
+EXPORT_SYMBOL(vdev_degrade);
+EXPORT_SYMBOL(vdev_online);
+EXPORT_SYMBOL(vdev_offline);
+EXPORT_SYMBOL(vdev_clear);
+
+module_param(metaslabs_per_vdev, int, 0644);
+MODULE_PARM_DESC(metaslabs_per_vdev,
+       "Divide added vdev into approximately (but no more than) this number "
+       "of metaslabs");
+#endif
diff --git a/zfs/module/zfs/vdev_cache.c b/zfs/module/zfs/vdev_cache.c
new file mode 100644 (file)
index 0000000..389fa6f
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/kstat.h>
+
+/*
+ * Virtual device read-ahead caching.
+ *
+ * This file implements a simple LRU read-ahead cache.  When the DMU reads
+ * a given block, it will often want other, nearby blocks soon thereafter.
+ * We take advantage of this by reading a larger disk region and caching
+ * the result.  In the best case, this can turn 128 back-to-back 512-byte
+ * reads into a single 64k read followed by 127 cache hits; this reduces
+ * latency dramatically.  In the worst case, it can turn an isolated 512-byte
+ * read into a 64k read, which doesn't affect latency all that much but is
+ * terribly wasteful of bandwidth.  A more intelligent version of the cache
+ * could keep track of access patterns and not do read-ahead unless it sees
+ * at least two temporally close I/Os to the same region.  Currently, only
+ * metadata I/O is inflated.  A futher enhancement could take advantage of
+ * more semantic information about the I/O.  And it could use something
+ * faster than an AVL tree; that was chosen solely for convenience.
+ *
+ * There are five cache operations: allocate, fill, read, write, evict.
+ *
+ * (1) Allocate.  This reserves a cache entry for the specified region.
+ *     We separate the allocate and fill operations so that multiple threads
+ *     don't generate I/O for the same cache miss.
+ *
+ * (2) Fill.  When the I/O for a cache miss completes, the fill routine
+ *     places the data in the previously allocated cache entry.
+ *
+ * (3) Read.  Read data from the cache.
+ *
+ * (4) Write.  Update cache contents after write completion.
+ *
+ * (5) Evict.  When allocating a new entry, we evict the oldest (LRU) entry
+ *     if the total cache size exceeds zfs_vdev_cache_size.
+ */
+
+/*
+ * These tunables are for performance analysis.
+ */
+/*
+ * All i/os smaller than zfs_vdev_cache_max will be turned into
+ * 1<<zfs_vdev_cache_bshift byte reads by the vdev_cache (aka software
+ * track buffer).  At most zfs_vdev_cache_size bytes will be kept in each
+ * vdev's vdev_cache.
+ *
+ * TODO: Note that with the current ZFS code, it turns out that the
+ * vdev cache is not helpful, and in some cases actually harmful.  It
+ * is better if we disable this.  Once some time has passed, we should
+ * actually remove this to simplify the code.  For now we just disable
+ * it by setting the zfs_vdev_cache_size to zero.  Note that Solaris 11
+ * has made these same changes.
+ */
+int zfs_vdev_cache_max = 1<<14;                        /* 16KB */
+int zfs_vdev_cache_size = 0;
+int zfs_vdev_cache_bshift = 16;
+
+#define        VCBS (1 << zfs_vdev_cache_bshift)       /* 64KB */
+
+kstat_t        *vdc_ksp = NULL;
+
+typedef struct vdc_stats {
+       kstat_named_t vdc_stat_delegations;
+       kstat_named_t vdc_stat_hits;
+       kstat_named_t vdc_stat_misses;
+} vdc_stats_t;
+
+static vdc_stats_t vdc_stats = {
+       { "delegations",        KSTAT_DATA_UINT64 },
+       { "hits",               KSTAT_DATA_UINT64 },
+       { "misses",             KSTAT_DATA_UINT64 }
+};
+
+#define        VDCSTAT_BUMP(stat)      atomic_add_64(&vdc_stats.stat.value.ui64, 1);
+
+static 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);
+}
+
+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;
+
+       if (ddi_time_before(ve1->ve_lastused, ve2->ve_lastused))
+               return (-1);
+       if (ddi_time_after(ve1->ve_lastused, ve2->ve_lastused))
+               return (1);
+
+       /*
+        * Among equally old entries, sort by offset to ensure uniqueness.
+        */
+       return (vdev_cache_offset_compare(a1, a2));
+}
+
+/*
+ * Evict the specified entry from the cache.
+ */
+static void
+vdev_cache_evict(vdev_cache_t *vc, vdev_cache_entry_t *ve)
+{
+       ASSERT(MUTEX_HELD(&vc->vc_lock));
+       ASSERT(ve->ve_fill_io == NULL);
+       ASSERT(ve->ve_data != NULL);
+
+       avl_remove(&vc->vc_lastused_tree, ve);
+       avl_remove(&vc->vc_offset_tree, ve);
+       zio_buf_free(ve->ve_data, VCBS);
+       kmem_free(ve, sizeof (vdev_cache_entry_t));
+}
+
+/*
+ * Allocate an entry in the cache.  At the point we don't have the data,
+ * we're just creating a placeholder so that multiple threads don't all
+ * go off and read the same blocks.
+ */
+static vdev_cache_entry_t *
+vdev_cache_allocate(zio_t *zio)
+{
+       vdev_cache_t *vc = &zio->io_vd->vdev_cache;
+       uint64_t offset = P2ALIGN(zio->io_offset, VCBS);
+       vdev_cache_entry_t *ve;
+
+       ASSERT(MUTEX_HELD(&vc->vc_lock));
+
+       if (zfs_vdev_cache_size == 0)
+               return (NULL);
+
+       /*
+        * If adding a new entry would exceed the cache size,
+        * evict the oldest entry (LRU).
+        */
+       if ((avl_numnodes(&vc->vc_lastused_tree) << zfs_vdev_cache_bshift) >
+           zfs_vdev_cache_size) {
+               ve = avl_first(&vc->vc_lastused_tree);
+               if (ve->ve_fill_io != NULL)
+                       return (NULL);
+               ASSERT(ve->ve_hits != 0);
+               vdev_cache_evict(vc, ve);
+       }
+
+       ve = kmem_zalloc(sizeof (vdev_cache_entry_t), KM_SLEEP);
+       ve->ve_offset = offset;
+       ve->ve_lastused = ddi_get_lbolt();
+       ve->ve_data = zio_buf_alloc(VCBS);
+
+       avl_add(&vc->vc_offset_tree, ve);
+       avl_add(&vc->vc_lastused_tree, ve);
+
+       return (ve);
+}
+
+static void
+vdev_cache_hit(vdev_cache_t *vc, vdev_cache_entry_t *ve, zio_t *zio)
+{
+       uint64_t cache_phase = P2PHASE(zio->io_offset, VCBS);
+
+       ASSERT(MUTEX_HELD(&vc->vc_lock));
+       ASSERT(ve->ve_fill_io == NULL);
+
+       if (ve->ve_lastused != ddi_get_lbolt()) {
+               avl_remove(&vc->vc_lastused_tree, ve);
+               ve->ve_lastused = ddi_get_lbolt();
+               avl_add(&vc->vc_lastused_tree, ve);
+       }
+
+       ve->ve_hits++;
+       bcopy(ve->ve_data + cache_phase, zio->io_data, zio->io_size);
+}
+
+/*
+ * Fill a previously allocated cache entry with data.
+ */
+static void
+vdev_cache_fill(zio_t *fio)
+{
+       vdev_t *vd = fio->io_vd;
+       vdev_cache_t *vc = &vd->vdev_cache;
+       vdev_cache_entry_t *ve = fio->io_private;
+       zio_t *pio;
+
+       ASSERT(fio->io_size == VCBS);
+
+       /*
+        * Add data to the cache.
+        */
+       mutex_enter(&vc->vc_lock);
+
+       ASSERT(ve->ve_fill_io == fio);
+       ASSERT(ve->ve_offset == fio->io_offset);
+       ASSERT(ve->ve_data == fio->io_data);
+
+       ve->ve_fill_io = NULL;
+
+       /*
+        * Even if this cache line was invalidated by a missed write update,
+        * 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)
+               vdev_cache_hit(vc, ve, pio);
+
+       if (fio->io_error || ve->ve_missed_update)
+               vdev_cache_evict(vc, ve);
+
+       mutex_exit(&vc->vc_lock);
+}
+
+/*
+ * Read data from the cache.  Returns B_TRUE cache hit, B_FALSE on miss.
+ */
+boolean_t
+vdev_cache_read(zio_t *zio)
+{
+       vdev_cache_t *vc = &zio->io_vd->vdev_cache;
+       vdev_cache_entry_t *ve, *ve_search;
+       uint64_t cache_offset = P2ALIGN(zio->io_offset, VCBS);
+       zio_t *fio;
+       ASSERTV(uint64_t cache_phase = P2PHASE(zio->io_offset, VCBS));
+
+       ASSERT(zio->io_type == ZIO_TYPE_READ);
+
+       if (zio->io_flags & ZIO_FLAG_DONT_CACHE)
+               return (B_FALSE);
+
+       if (zio->io_size > zfs_vdev_cache_max)
+               return (B_FALSE);
+
+       /*
+        * If the I/O straddles two or more cache blocks, don't cache it.
+        */
+       if (P2BOUNDARY(zio->io_offset, zio->io_size, VCBS))
+               return (B_FALSE);
+
+       ASSERT(cache_phase + zio->io_size <= VCBS);
+
+       mutex_enter(&vc->vc_lock);
+
+       ve_search = kmem_alloc(sizeof (vdev_cache_entry_t), KM_SLEEP);
+       ve_search->ve_offset = cache_offset;
+       ve = avl_find(&vc->vc_offset_tree, ve_search, NULL);
+       kmem_free(ve_search, sizeof (vdev_cache_entry_t));
+
+       if (ve != NULL) {
+               if (ve->ve_missed_update) {
+                       mutex_exit(&vc->vc_lock);
+                       return (B_FALSE);
+               }
+
+               if ((fio = ve->ve_fill_io) != NULL) {
+                       zio_vdev_io_bypass(zio);
+                       zio_add_child(zio, fio);
+                       mutex_exit(&vc->vc_lock);
+                       VDCSTAT_BUMP(vdc_stat_delegations);
+                       return (B_TRUE);
+               }
+
+               vdev_cache_hit(vc, ve, zio);
+               zio_vdev_io_bypass(zio);
+
+               mutex_exit(&vc->vc_lock);
+               VDCSTAT_BUMP(vdc_stat_hits);
+               return (B_TRUE);
+       }
+
+       ve = vdev_cache_allocate(zio);
+
+       if (ve == NULL) {
+               mutex_exit(&vc->vc_lock);
+               return (B_FALSE);
+       }
+
+       fio = zio_vdev_delegated_io(zio->io_vd, cache_offset,
+           ve->ve_data, VCBS, ZIO_TYPE_READ, ZIO_PRIORITY_NOW,
+           ZIO_FLAG_DONT_CACHE, vdev_cache_fill, ve);
+
+       ve->ve_fill_io = fio;
+       zio_vdev_io_bypass(zio);
+       zio_add_child(zio, fio);
+
+       mutex_exit(&vc->vc_lock);
+       zio_nowait(fio);
+       VDCSTAT_BUMP(vdc_stat_misses);
+
+       return (B_TRUE);
+}
+
+/*
+ * Update cache contents upon write completion.
+ */
+void
+vdev_cache_write(zio_t *zio)
+{
+       vdev_cache_t *vc = &zio->io_vd->vdev_cache;
+       vdev_cache_entry_t *ve, ve_search;
+       uint64_t io_start = zio->io_offset;
+       uint64_t io_end = io_start + zio->io_size;
+       uint64_t min_offset = P2ALIGN(io_start, VCBS);
+       uint64_t max_offset = P2ROUNDUP(io_end, VCBS);
+       avl_index_t where;
+
+       ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+
+       mutex_enter(&vc->vc_lock);
+
+       ve_search.ve_offset = min_offset;
+       ve = avl_find(&vc->vc_offset_tree, &ve_search, &where);
+
+       if (ve == NULL)
+               ve = avl_nearest(&vc->vc_offset_tree, where, AVL_AFTER);
+
+       while (ve != NULL && ve->ve_offset < max_offset) {
+               uint64_t start = MAX(ve->ve_offset, io_start);
+               uint64_t end = MIN(ve->ve_offset + VCBS, io_end);
+
+               if (ve->ve_fill_io != NULL) {
+                       ve->ve_missed_update = 1;
+               } else {
+                       bcopy((char *)zio->io_data + start - io_start,
+                           ve->ve_data + start - ve->ve_offset, end - start);
+               }
+               ve = AVL_NEXT(&vc->vc_offset_tree, ve);
+       }
+       mutex_exit(&vc->vc_lock);
+}
+
+void
+vdev_cache_purge(vdev_t *vd)
+{
+       vdev_cache_t *vc = &vd->vdev_cache;
+       vdev_cache_entry_t *ve;
+
+       mutex_enter(&vc->vc_lock);
+       while ((ve = avl_first(&vc->vc_offset_tree)) != NULL)
+               vdev_cache_evict(vc, ve);
+       mutex_exit(&vc->vc_lock);
+}
+
+void
+vdev_cache_init(vdev_t *vd)
+{
+       vdev_cache_t *vc = &vd->vdev_cache;
+
+       mutex_init(&vc->vc_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       avl_create(&vc->vc_offset_tree, vdev_cache_offset_compare,
+           sizeof (vdev_cache_entry_t),
+           offsetof(struct vdev_cache_entry, ve_offset_node));
+
+       avl_create(&vc->vc_lastused_tree, vdev_cache_lastused_compare,
+           sizeof (vdev_cache_entry_t),
+           offsetof(struct vdev_cache_entry, ve_lastused_node));
+}
+
+void
+vdev_cache_fini(vdev_t *vd)
+{
+       vdev_cache_t *vc = &vd->vdev_cache;
+
+       vdev_cache_purge(vd);
+
+       avl_destroy(&vc->vc_offset_tree);
+       avl_destroy(&vc->vc_lastused_tree);
+
+       mutex_destroy(&vc->vc_lock);
+}
+
+void
+vdev_cache_stat_init(void)
+{
+       vdc_ksp = kstat_create("zfs", 0, "vdev_cache_stats", "misc",
+           KSTAT_TYPE_NAMED, sizeof (vdc_stats) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+       if (vdc_ksp != NULL) {
+               vdc_ksp->ks_data = &vdc_stats;
+               kstat_install(vdc_ksp);
+       }
+}
+
+void
+vdev_cache_stat_fini(void)
+{
+       if (vdc_ksp != NULL) {
+               kstat_delete(vdc_ksp);
+               vdc_ksp = NULL;
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_vdev_cache_max, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_cache_max, "Inflate reads small than max");
+
+module_param(zfs_vdev_cache_size, int, 0444);
+MODULE_PARM_DESC(zfs_vdev_cache_size, "Total size of the per-disk cache");
+
+module_param(zfs_vdev_cache_bshift, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_cache_bshift, "Shift size to inflate reads too");
+#endif
diff --git a/zfs/module/zfs/vdev_disk.c b/zfs/module/zfs/vdev_disk.c
new file mode 100644 (file)
index 0000000..5697f68
--- /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) 2008-2010 Lawrence Livermore National Security, LLC.
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/vdev_disk.h>
+#include <sys/vdev_impl.h>
+#include <sys/fs/zfs.h>
+#include <sys/zio.h>
+#include <sys/sunldi.h>
+
+char *zfs_vdev_scheduler = VDEV_SCHEDULER;
+static void *zfs_vdev_holder = VDEV_HOLDER;
+
+/*
+ * Virtual device vector for disks.
+ */
+typedef struct dio_request {
+       zio_t                   *dr_zio;        /* Parent ZIO */
+       atomic_t                dr_ref;         /* References */
+       int                     dr_error;       /* Bio error */
+       int                     dr_bio_count;   /* Count of bio's */
+       struct bio              *dr_bio[0];     /* Attached bio's */
+} dio_request_t;
+
+
+#ifdef HAVE_OPEN_BDEV_EXCLUSIVE
+static fmode_t
+vdev_bdev_mode(int smode)
+{
+       fmode_t mode = 0;
+
+       ASSERT3S(smode & (FREAD | FWRITE), !=, 0);
+
+       if (smode & FREAD)
+               mode |= FMODE_READ;
+
+       if (smode & FWRITE)
+               mode |= FMODE_WRITE;
+
+       return (mode);
+}
+#else
+static int
+vdev_bdev_mode(int smode)
+{
+       int mode = 0;
+
+       ASSERT3S(smode & (FREAD | FWRITE), !=, 0);
+
+       if ((smode & FREAD) && !(smode & FWRITE))
+               mode = MS_RDONLY;
+
+       return (mode);
+}
+#endif /* HAVE_OPEN_BDEV_EXCLUSIVE */
+
+static uint64_t
+bdev_capacity(struct block_device *bdev)
+{
+       struct hd_struct *part = bdev->bd_part;
+
+       /* The partition capacity referenced by the block device */
+       if (part)
+               return (part->nr_sects << 9);
+
+       /* Otherwise assume the full device capacity */
+       return (get_capacity(bdev->bd_disk) << 9);
+}
+
+static void
+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,
+           (u_longlong_t)zio->io_offset, (u_longlong_t)zio->io_size,
+           zio->io_flags, (u_longlong_t)zio->io_delay);
+#endif
+}
+
+/*
+ * Use the Linux 'noop' elevator for zfs managed block devices.  This
+ * strikes the ideal balance by allowing the zfs elevator to do all
+ * request ordering and prioritization.  While allowing the Linux
+ * elevator to do the maximum front/back merging allowed by the
+ * physical device.  This yields the largest possible requests for
+ * the device with the lowest total overhead.
+ */
+static int
+vdev_elevator_switch(vdev_t *v, char *elevator)
+{
+       vdev_disk_t *vd = v->vdev_tsd;
+       struct block_device *bdev = vd->vd_bdev;
+       struct request_queue *q = bdev_get_queue(bdev);
+       char *device = bdev->bd_disk->disk_name;
+       int error;
+
+       /*
+        * Skip devices which are not whole disks (partitions).
+        * Device-mapper devices are excepted since they may be whole
+        * disks despite the vdev_wholedisk flag, in which case we can
+        * and should switch the elevator. If the device-mapper device
+        * does not have an elevator (i.e. dm-raid, dm-crypt, etc.) the
+        * "Skip devices without schedulers" check below will fail.
+        */
+       if (!v->vdev_wholedisk && strncmp(device, "dm-", 3) != 0)
+               return (0);
+
+       /* Skip devices without schedulers (loop, ram, dm, etc) */
+       if (!q->elevator || !blk_queue_stackable(q))
+               return (0);
+
+       /* Leave existing scheduler when set to "none" */
+       if ((strncmp(elevator, "none", 4) == 0) && (strlen(elevator) == 4))
+               return (0);
+
+#ifdef HAVE_ELEVATOR_CHANGE
+       error = elevator_change(q, elevator);
+#else
+       /*
+        * For pre-2.6.36 kernels elevator_change() is not available.
+        * Therefore we fall back to using a usermodehelper to echo the
+        * elevator into sysfs;  This requires /bin/echo and sysfs to be
+        * mounted which may not be true early in the boot process.
+        */
+#define        SET_SCHEDULER_CMD \
+       "exec 0</dev/null " \
+       "     1>/sys/block/%s/queue/scheduler " \
+       "     2>/dev/null; " \
+       "echo %s"
+
+       {
+               char *argv[] = { "/bin/sh", "-c", NULL, NULL };
+               char *envp[] = { NULL };
+
+               argv[2] = kmem_asprintf(SET_SCHEDULER_CMD, device, elevator);
+               error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+               strfree(argv[2]);
+       }
+#endif /* HAVE_ELEVATOR_CHANGE */
+       if (error)
+               printk("ZFS: Unable to set \"%s\" scheduler for %s (%s): %d\n",
+                   elevator, v->vdev_path, device, error);
+
+       return (error);
+}
+
+/*
+ * Expanding a whole disk vdev involves invoking BLKRRPART on the
+ * whole disk device. This poses a problem, because BLKRRPART will
+ * return EBUSY if one of the disk's partitions is open. That's why
+ * we have to do it here, just before opening the data partition.
+ * Unfortunately, BLKRRPART works by dropping all partitions and
+ * recreating them, which means that for a short time window, all
+ * /dev/sdxN device files disappear (until udev recreates them).
+ * This means two things:
+ *  - When we open the data partition just after a BLKRRPART, we
+ *    can't do it using the normal device file path because of the
+ *    obvious race condition with udev. Instead, we use reliable
+ *    kernel APIs to get a handle to the new partition device from
+ *    the whole disk device.
+ *  - Because vdev_disk_open() initially needs to find the device
+ *    using its path, multiple vdev_disk_open() invocations in
+ *    short succession on the same disk with BLKRRPARTs in the
+ *    middle have a high probability of failure (because of the
+ *    race condition with udev). A typical situation where this
+ *    might happen is when the zpool userspace tool does a
+ *    TRYIMPORT immediately followed by an IMPORT. For this
+ *    reason, we only invoke BLKRRPART in the module when strictly
+ *    necessary (zpool online -e case), and rely on userspace to
+ *    do it when possible.
+ */
+static struct block_device *
+vdev_disk_rrpart(const char *path, int mode, vdev_disk_t *vd)
+{
+#if defined(HAVE_3ARG_BLKDEV_GET) && defined(HAVE_GET_GENDISK)
+       struct block_device *bdev, *result = ERR_PTR(-ENXIO);
+       struct gendisk *disk;
+       int error, partno;
+
+       bdev = vdev_bdev_open(path, vdev_bdev_mode(mode), zfs_vdev_holder);
+       if (IS_ERR(bdev))
+               return (bdev);
+
+       disk = get_gendisk(bdev->bd_dev, &partno);
+       vdev_bdev_close(bdev, vdev_bdev_mode(mode));
+
+       if (disk) {
+               bdev = bdget(disk_devt(disk));
+               if (bdev) {
+                       error = blkdev_get(bdev, vdev_bdev_mode(mode), vd);
+                       if (error == 0)
+                               error = ioctl_by_bdev(bdev, BLKRRPART, 0);
+                       vdev_bdev_close(bdev, vdev_bdev_mode(mode));
+               }
+
+               bdev = bdget_disk(disk, partno);
+               if (bdev) {
+                       error = blkdev_get(bdev,
+                           vdev_bdev_mode(mode) | FMODE_EXCL, vd);
+                       if (error == 0)
+                               result = bdev;
+               }
+               put_disk(disk);
+       }
+
+       return (result);
+#else
+       return (ERR_PTR(-EOPNOTSUPP));
+#endif /* defined(HAVE_3ARG_BLKDEV_GET) && defined(HAVE_GET_GENDISK) */
+}
+
+static int
+vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
+    uint64_t *ashift)
+{
+       struct block_device *bdev = ERR_PTR(-ENXIO);
+       vdev_disk_t *vd;
+       int count = 0, mode, block_size;
+
+       /* Must have a pathname and it must be absolute. */
+       if (v->vdev_path == NULL || v->vdev_path[0] != '/') {
+               v->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Reopen the device if it's not currently open. Otherwise,
+        * just update the physical size of the device.
+        */
+       if (v->vdev_tsd != NULL) {
+               ASSERT(v->vdev_reopening);
+               vd = v->vdev_tsd;
+               goto skip_open;
+       }
+
+       vd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP);
+       if (vd == NULL)
+               return (SET_ERROR(ENOMEM));
+
+       /*
+        * Devices are always opened by the path provided at configuration
+        * time.  This means that if the provided path is a udev by-id path
+        * then drives may be recabled without an issue.  If the provided
+        * path is a udev by-path path, then the physical location information
+        * will be preserved.  This can be critical for more complicated
+        * configurations where drives are located in specific physical
+        * locations to maximize the systems tolerence to component failure.
+        * Alternatively, you can provide your own udev rule to flexibly map
+        * the drives as you see fit.  It is not advised that you use the
+        * /dev/[hd]d devices which may be reordered due to probing order.
+        * Devices in the wrong locations will be detected by the higher
+        * level vdev validation.
+        *
+        * The specified paths may be briefly removed and recreated in
+        * response to udev events.  This should be exceptionally unlikely
+        * because the zpool command makes every effort to verify these paths
+        * have already settled prior to reaching this point.  Therefore,
+        * a ENOENT failure at this point is highly likely to be transient
+        * and it is reasonable to sleep and retry before giving up.  In
+        * practice delays have been observed to be on the order of 100ms.
+        */
+       mode = spa_mode(v->vdev_spa);
+       if (v->vdev_wholedisk && v->vdev_expanding)
+               bdev = vdev_disk_rrpart(v->vdev_path, mode, vd);
+
+       while (IS_ERR(bdev) && count < 50) {
+               bdev = vdev_bdev_open(v->vdev_path,
+                   vdev_bdev_mode(mode), zfs_vdev_holder);
+               if (unlikely(PTR_ERR(bdev) == -ENOENT)) {
+                       msleep(10);
+                       count++;
+               } else if (IS_ERR(bdev)) {
+                       break;
+               }
+       }
+
+       if (IS_ERR(bdev)) {
+               dprintf("failed open v->vdev_path=%s, error=%d count=%d\n",
+                   v->vdev_path, -PTR_ERR(bdev), count);
+               kmem_free(vd, sizeof (vdev_disk_t));
+               return (SET_ERROR(-PTR_ERR(bdev)));
+       }
+
+       v->vdev_tsd = vd;
+       vd->vd_bdev = bdev;
+
+skip_open:
+       /*  Determine the physical block size */
+       block_size = vdev_bdev_block_size(vd->vd_bdev);
+
+       /* Clear the nowritecache bit, causes vdev_reopen() to try again. */
+       v->vdev_nowritecache = B_FALSE;
+
+       /* Inform the ZIO pipeline that we are non-rotational */
+       v->vdev_nonrot = blk_queue_nonrot(bdev_get_queue(vd->vd_bdev));
+
+       /* Physical volume size in bytes */
+       *psize = bdev_capacity(vd->vd_bdev);
+
+       /* TODO: report possible expansion size */
+       *max_psize = *psize;
+
+       /* Based on the minimum sector size set the block size */
+       *ashift = highbit64(MAX(block_size, SPA_MINBLOCKSIZE)) - 1;
+
+       /* Try to set the io scheduler elevator algorithm */
+       (void) vdev_elevator_switch(v, zfs_vdev_scheduler);
+
+       return (0);
+}
+
+static void
+vdev_disk_close(vdev_t *v)
+{
+       vdev_disk_t *vd = v->vdev_tsd;
+
+       if (v->vdev_reopening || vd == NULL)
+               return;
+
+       if (vd->vd_bdev != NULL)
+               vdev_bdev_close(vd->vd_bdev,
+                   vdev_bdev_mode(spa_mode(v->vdev_spa)));
+
+       kmem_free(vd, sizeof (vdev_disk_t));
+       v->vdev_tsd = NULL;
+}
+
+static dio_request_t *
+vdev_disk_dio_alloc(int bio_count)
+{
+       dio_request_t *dr;
+       int i;
+
+       dr = kmem_zalloc(sizeof (dio_request_t) +
+           sizeof (struct bio *) * bio_count, KM_SLEEP);
+       if (dr) {
+               atomic_set(&dr->dr_ref, 0);
+               dr->dr_bio_count = bio_count;
+               dr->dr_error = 0;
+
+               for (i = 0; i < dr->dr_bio_count; i++)
+                       dr->dr_bio[i] = NULL;
+       }
+
+       return (dr);
+}
+
+static void
+vdev_disk_dio_free(dio_request_t *dr)
+{
+       int i;
+
+       for (i = 0; i < dr->dr_bio_count; i++)
+               if (dr->dr_bio[i])
+                       bio_put(dr->dr_bio[i]);
+
+       kmem_free(dr, sizeof (dio_request_t) +
+           sizeof (struct bio *) * dr->dr_bio_count);
+}
+
+static void
+vdev_disk_dio_get(dio_request_t *dr)
+{
+       atomic_inc(&dr->dr_ref);
+}
+
+static int
+vdev_disk_dio_put(dio_request_t *dr)
+{
+       int rc = atomic_dec_return(&dr->dr_ref);
+
+       /*
+        * Free the dio_request when the last reference is dropped and
+        * ensure zio_interpret is called only once with the correct zio
+        */
+       if (rc == 0) {
+               zio_t *zio = dr->dr_zio;
+               int error = dr->dr_error;
+
+               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);
+               }
+       }
+
+       return (rc);
+}
+
+BIO_END_IO_PROTO(vdev_disk_physio_completion, bio, error)
+{
+       dio_request_t *dr = bio->bi_private;
+       int rc;
+
+       if (dr->dr_error == 0) {
+#ifdef HAVE_1ARG_BIO_END_IO_T
+               dr->dr_error = -(bio->bi_error);
+#else
+               if (error)
+                       dr->dr_error = -(error);
+               else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+                       dr->dr_error = EIO;
+#endif
+       }
+
+       /* Drop reference aquired by __vdev_disk_physio */
+       rc = vdev_disk_dio_put(dr);
+}
+
+static inline unsigned long
+bio_nr_pages(void *bio_ptr, unsigned int bio_size)
+{
+       return ((((unsigned long)bio_ptr + bio_size + PAGE_SIZE - 1) >>
+           PAGE_SHIFT) - ((unsigned long)bio_ptr >> PAGE_SHIFT));
+}
+
+static unsigned int
+bio_map(struct bio *bio, void *bio_ptr, unsigned int bio_size)
+{
+       unsigned int offset, size, i;
+       struct page *page;
+
+       offset = offset_in_page(bio_ptr);
+       for (i = 0; i < bio->bi_max_vecs; i++) {
+               size = PAGE_SIZE - offset;
+
+               if (bio_size <= 0)
+                       break;
+
+               if (size > bio_size)
+                       size = bio_size;
+
+               if (is_vmalloc_addr(bio_ptr))
+                       page = vmalloc_to_page(bio_ptr);
+               else
+                       page = virt_to_page(bio_ptr);
+
+               /*
+                * Some network related block device uses tcp_sendpage, which
+                * doesn't behave well when using 0-count page, this is a
+                * safety net to catch them.
+                */
+               ASSERT3S(page_count(page), >, 0);
+
+               if (bio_add_page(bio, page, size, offset) != size)
+                       break;
+
+               bio_ptr  += size;
+               bio_size -= size;
+               offset = 0;
+       }
+
+       return (bio_size);
+}
+
+static inline void
+vdev_submit_bio_impl(struct bio *bio)
+{
+#ifdef HAVE_1ARG_SUBMIT_BIO
+       submit_bio(bio);
+#else
+       submit_bio(0, bio);
+#endif
+}
+
+static inline void
+vdev_submit_bio(struct bio *bio)
+{
+#ifdef HAVE_CURRENT_BIO_TAIL
+       struct bio **bio_tail = current->bio_tail;
+       current->bio_tail = NULL;
+       vdev_submit_bio_impl(bio);
+       current->bio_tail = bio_tail;
+#else
+       struct bio_list *bio_list = current->bio_list;
+       current->bio_list = NULL;
+       vdev_submit_bio_impl(bio);
+       current->bio_list = bio_list;
+#endif
+}
+
+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)
+{
+       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);
+
+retry:
+       dr = vdev_disk_dio_alloc(bio_count);
+       if (dr == NULL)
+               return (ENOMEM);
+
+       if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD)))
+               bio_set_flags_failfast(bdev, &flags);
+
+       dr->dr_zio = zio;
+
+       /*
+        * When the IO size exceeds the maximum bio size for the request
+        * queue we are forced to break the IO in multiple bio's and wait
+        * for them all to complete.  Ideally, all pool users will set
+        * their volume block size to match the maximum request size and
+        * the common case will be one bio per vdev IO request.
+        */
+       bio_ptr    = kbuf_ptr;
+       bio_offset = kbuf_offset;
+       bio_size   = kbuf_size;
+       for (i = 0; i <= dr->dr_bio_count; i++) {
+
+               /* Finished constructing bio's for given buffer */
+               if (bio_size <= 0)
+                       break;
+
+               /*
+                * By default only 'bio_count' bio's per dio are allowed.
+                * However, if we find ourselves in a situation where more
+                * are needed we allocate a larger dio and warn the user.
+                */
+               if (dr->dr_bio_count == i) {
+                       vdev_disk_dio_free(dr);
+                       bio_count *= 2;
+                       goto retry;
+               }
+
+               /* bio_alloc() with __GFP_WAIT never returns NULL */
+               dr->dr_bio[i] = bio_alloc(GFP_NOIO,
+                   MIN(bio_nr_pages(bio_ptr, bio_size), BIO_MAX_PAGES));
+               if (unlikely(dr->dr_bio[i] == NULL)) {
+                       vdev_disk_dio_free(dr);
+                       return (ENOMEM);
+               }
+
+               /* Matching put called by vdev_disk_physio_completion */
+               vdev_disk_dio_get(dr);
+
+               dr->dr_bio[i]->bi_bdev = bdev;
+               BIO_BI_SECTOR(dr->dr_bio[i]) = bio_offset >> 9;
+               dr->dr_bio[i]->bi_end_io = vdev_disk_physio_completion;
+               dr->dr_bio[i]->bi_private = dr;
+               bio_set_op_attrs(dr->dr_bio[i], rw, flags);
+
+               /* Remaining size is returned to become the new size */
+               bio_size = bio_map(dr->dr_bio[i], bio_ptr, bio_size);
+
+               /* Advance in buffer and construct another bio if needed */
+               bio_ptr    += BIO_BI_SIZE(dr->dr_bio[i]);
+               bio_offset += BIO_BI_SIZE(dr->dr_bio[i]);
+       }
+
+       /* 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]);
+
+#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);
+}
+
+BIO_END_IO_PROTO(vdev_disk_io_flush_completion, bio, rc)
+{
+       zio_t *zio = bio->bi_private;
+#ifdef HAVE_1ARG_BIO_END_IO_T
+       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;
+
+       bio_put(bio);
+       ASSERT3S(zio->io_error, >=, 0);
+       if (zio->io_error)
+               vdev_disk_error(zio);
+       zio_interrupt(zio);
+}
+
+static int
+vdev_disk_io_flush(struct block_device *bdev, zio_t *zio)
+{
+       struct request_queue *q;
+       struct bio *bio;
+
+       q = bdev_get_queue(bdev);
+       if (!q)
+               return (ENXIO);
+
+       bio = bio_alloc(GFP_NOIO, 0);
+       /* bio_alloc() with __GFP_WAIT never returns NULL */
+       if (unlikely(bio == NULL))
+               return (ENOMEM);
+
+       bio->bi_end_io = vdev_disk_io_flush_completion;
+       bio->bi_private = zio;
+       bio->bi_bdev = bdev;
+       zio->io_delay = jiffies_64;
+       bio_set_flush(bio);
+       vdev_submit_bio(bio);
+       invalidate_bdev(bdev);
+
+       return (0);
+}
+
+static void
+vdev_disk_io_start(zio_t *zio)
+{
+       vdev_t *v = zio->io_vd;
+       vdev_disk_t *vd = v->vdev_tsd;
+       int rw, flags, error;
+
+       switch (zio->io_type) {
+       case ZIO_TYPE_IOCTL:
+
+               if (!vdev_readable(v)) {
+                       zio->io_error = SET_ERROR(ENXIO);
+                       zio_interrupt(zio);
+                       return;
+               }
+
+               switch (zio->io_cmd) {
+               case DKIOCFLUSHWRITECACHE:
+
+                       if (zfs_nocacheflush)
+                               break;
+
+                       if (v->vdev_nowritecache) {
+                               zio->io_error = SET_ERROR(ENOTSUP);
+                               break;
+                       }
+
+                       error = vdev_disk_io_flush(vd->vd_bdev, zio);
+                       if (error == 0)
+                               return;
+
+                       zio->io_error = error;
+                       if (error == ENOTSUP)
+                               v->vdev_nowritecache = B_TRUE;
+
+                       break;
+
+               default:
+                       zio->io_error = SET_ERROR(ENOTSUP);
+               }
+
+               zio_execute(zio);
+               return;
+       case ZIO_TYPE_WRITE:
+               rw = WRITE;
+#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 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:
+               zio->io_error = SET_ERROR(ENOTSUP);
+               zio_interrupt(zio);
+               return;
+       }
+
+       error = __vdev_disk_physio(vd->vd_bdev, zio, zio->io_data,
+           zio->io_size, zio->io_offset, rw, flags);
+       if (error) {
+               zio->io_error = error;
+               zio_interrupt(zio);
+               return;
+       }
+}
+
+static void
+vdev_disk_io_done(zio_t *zio)
+{
+       /*
+        * If the device returned EIO, we revalidate the media.  If it is
+        * determined the media has changed this triggers the asynchronous
+        * removal of the device from the configuration.
+        */
+       if (zio->io_error == EIO) {
+               vdev_t *v = zio->io_vd;
+               vdev_disk_t *vd = v->vdev_tsd;
+
+               if (check_disk_change(vd->vd_bdev)) {
+                       vdev_bdev_invalidate(vd->vd_bdev);
+                       v->vdev_remove_wanted = B_TRUE;
+                       spa_async_request(zio->io_spa, SPA_ASYNC_REMOVE);
+               }
+       }
+}
+
+static void
+vdev_disk_hold(vdev_t *vd)
+{
+       ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER));
+
+       /* We must have a pathname, and it must be absolute. */
+       if (vd->vdev_path == NULL || vd->vdev_path[0] != '/')
+               return;
+
+       /*
+        * Only prefetch path and devid info if the device has
+        * never been opened.
+        */
+       if (vd->vdev_tsd != NULL)
+               return;
+
+       /* XXX: Implement me as a vnode lookup for the device */
+       vd->vdev_name_vp = NULL;
+       vd->vdev_devid_vp = NULL;
+}
+
+static void
+vdev_disk_rele(vdev_t *vd)
+{
+       ASSERT(spa_config_held(vd->vdev_spa, SCL_STATE, RW_WRITER));
+
+       /* XXX: Implement me as a vnode rele for the device */
+}
+
+vdev_ops_t vdev_disk_ops = {
+       vdev_disk_open,
+       vdev_disk_close,
+       vdev_default_asize,
+       vdev_disk_io_start,
+       vdev_disk_io_done,
+       NULL,
+       vdev_disk_hold,
+       vdev_disk_rele,
+       VDEV_TYPE_DISK,         /* name of this vdev type */
+       B_TRUE                  /* leaf vdev */
+};
+
+module_param(zfs_vdev_scheduler, charp, 0644);
+MODULE_PARM_DESC(zfs_vdev_scheduler, "I/O scheduler");
diff --git a/zfs/module/zfs/vdev_file.c b/zfs/module/zfs/vdev_file.c
new file mode 100644 (file)
index 0000000..a29ea7b
--- /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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/vdev_file.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/fs/zfs.h>
+#include <sys/fm/fs/zfs.h>
+
+/*
+ * Virtual device vector for files.
+ */
+
+static void
+vdev_file_hold(vdev_t *vd)
+{
+       ASSERT(vd->vdev_path != NULL);
+}
+
+static void
+vdev_file_rele(vdev_t *vd)
+{
+       ASSERT(vd->vdev_path != NULL);
+}
+
+static int
+vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
+    uint64_t *ashift)
+{
+       vdev_file_t *vf;
+       vnode_t *vp;
+       vattr_t vattr;
+       int error;
+
+       /* Rotational optimizations only make sense on block devices */
+       vd->vdev_nonrot = B_TRUE;
+
+       /*
+        * We must have a pathname, and it must be absolute.
+        */
+       if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
+               vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Reopen the device if it's not currently open.  Otherwise,
+        * just update the physical size of the device.
+        */
+       if (vd->vdev_tsd != NULL) {
+               ASSERT(vd->vdev_reopening);
+               vf = vd->vdev_tsd;
+               goto skip_open;
+       }
+
+       vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP);
+
+       /*
+        * We always open the files from the root of the global zone, even if
+        * we're in a local zone.  If the user has gotten to this point, the
+        * administrator has already decided that the pool should be available
+        * to local zone users, so the underlying devices should be as well.
+        */
+       ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
+       error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE,
+           spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
+
+       if (error) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
+               return (error);
+       }
+
+       vf->vf_vnode = vp;
+
+#ifdef _KERNEL
+       /*
+        * Make sure it's a regular file.
+        */
+       if (vp->v_type != VREG) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
+               return (SET_ERROR(ENODEV));
+       }
+#endif
+
+skip_open:
+       /*
+        * Determine the physical size of the file.
+        */
+       vattr.va_mask = AT_SIZE;
+       error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL);
+       if (error) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
+               return (error);
+       }
+
+       *max_psize = *psize = vattr.va_size;
+       *ashift = SPA_MINBLOCKSHIFT;
+
+       return (0);
+}
+
+static void
+vdev_file_close(vdev_t *vd)
+{
+       vdev_file_t *vf = vd->vdev_tsd;
+
+       if (vd->vdev_reopening || vf == NULL)
+               return;
+
+       if (vf->vf_vnode != NULL) {
+               (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
+               (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0,
+                   kcred, NULL);
+       }
+
+       vd->vdev_delayed_close = B_FALSE;
+       kmem_free(vf, sizeof (vdev_file_t));
+       vd->vdev_tsd = NULL;
+}
+
+static void
+vdev_file_io_strategy(void *arg)
+{
+       zio_t *zio = (zio_t *)arg;
+       vdev_t *vd = zio->io_vd;
+       vdev_file_t *vf = vd->vdev_tsd;
+       ssize_t resid;
+
+       zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ?
+           UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data,
+           zio->io_size, zio->io_offset, UIO_SYSSPACE,
+           0, RLIM64_INFINITY, kcred, &resid);
+
+       if (resid != 0 && zio->io_error == 0)
+               zio->io_error = SET_ERROR(ENOSPC);
+
+       zio_interrupt(zio);
+}
+
+static void
+vdev_file_io_fsync(void *arg)
+{
+       zio_t *zio = (zio_t *)arg;
+       vdev_file_t *vf = zio->io_vd->vdev_tsd;
+
+       zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, kcred, NULL);
+
+       zio_interrupt(zio);
+}
+
+static void
+vdev_file_io_start(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       vdev_file_t *vf = vd->vdev_tsd;
+
+       if (zio->io_type == ZIO_TYPE_IOCTL) {
+               /* XXPOLICY */
+               if (!vdev_readable(vd)) {
+                       zio->io_error = SET_ERROR(ENXIO);
+                       zio_interrupt(zio);
+                       return;
+               }
+
+               switch (zio->io_cmd) {
+               case DKIOCFLUSHWRITECACHE:
+
+                       if (zfs_nocacheflush)
+                               break;
+
+                       /*
+                        * We cannot safely call vfs_fsync() when PF_FSTRANS
+                        * is set in the current context.  Filesystems like
+                        * XFS include sanity checks to verify it is not
+                        * already set, see xfs_vm_writepage().  Therefore
+                        * the sync must be dispatched to a different context.
+                        */
+                       if (spl_fstrans_check()) {
+                               VERIFY3U(taskq_dispatch(system_taskq,
+                                   vdev_file_io_fsync, zio, TQ_SLEEP), !=, 0);
+                               return;
+                       }
+
+                       zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC,
+                           kcred, NULL);
+                       break;
+               default:
+                       zio->io_error = SET_ERROR(ENOTSUP);
+               }
+
+               zio_execute(zio);
+               return;
+       }
+
+       VERIFY3U(taskq_dispatch(system_taskq, vdev_file_io_strategy, zio,
+           TQ_SLEEP), !=, 0);
+}
+
+/* ARGSUSED */
+static void
+vdev_file_io_done(zio_t *zio)
+{
+}
+
+vdev_ops_t vdev_file_ops = {
+       vdev_file_open,
+       vdev_file_close,
+       vdev_default_asize,
+       vdev_file_io_start,
+       vdev_file_io_done,
+       NULL,
+       vdev_file_hold,
+       vdev_file_rele,
+       VDEV_TYPE_FILE,         /* name of this vdev type */
+       B_TRUE                  /* leaf vdev */
+};
+
+/*
+ * From userland we access disks just like files.
+ */
+#ifndef _KERNEL
+
+vdev_ops_t vdev_disk_ops = {
+       vdev_file_open,
+       vdev_file_close,
+       vdev_default_asize,
+       vdev_file_io_start,
+       vdev_file_io_done,
+       NULL,
+       vdev_file_hold,
+       vdev_file_rele,
+       VDEV_TYPE_DISK,         /* name of this vdev type */
+       B_TRUE                  /* leaf vdev */
+};
+
+#endif
diff --git a/zfs/module/zfs/vdev_label.c b/zfs/module/zfs/vdev_label.c
new file mode 100644 (file)
index 0000000..7f588ed
--- /dev/null
@@ -0,0 +1,1282 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/*
+ * Virtual Device Labels
+ * ---------------------
+ *
+ * The vdev label serves several distinct purposes:
+ *
+ *     1. Uniquely identify this device as part of a ZFS pool and confirm its
+ *        identity within the pool.
+ *
+ *     2. Verify that all the devices given in a configuration are present
+ *         within the pool.
+ *
+ *     3. Determine the uberblock for the pool.
+ *
+ *     4. In case of an import operation, determine the configuration of the
+ *         toplevel vdev of which it is a part.
+ *
+ *     5. If an import operation cannot find all the devices in the pool,
+ *         provide enough information to the administrator to determine which
+ *         devices are missing.
+ *
+ * It is important to note that while the kernel is responsible for writing the
+ * label, it only consumes the information in the first three cases.  The
+ * latter information is only consumed in userland when determining the
+ * configuration to import a pool.
+ *
+ *
+ * Label Organization
+ * ------------------
+ *
+ * Before describing the contents of the label, it's important to understand how
+ * the labels are written and updated with respect to the uberblock.
+ *
+ * When the pool configuration is altered, either because it was newly created
+ * or a device was added, we want to update all the labels such that we can deal
+ * with fatal failure at any point.  To this end, each disk has two labels which
+ * are updated before and after the uberblock is synced.  Assuming we have
+ * labels and an uberblock with the following transaction groups:
+ *
+ *              L1          UB          L2
+ *           +------+    +------+    +------+
+ *           |      |    |      |    |      |
+ *           | t10  |    | t10  |    | t10  |
+ *           |      |    |      |    |      |
+ *           +------+    +------+    +------+
+ *
+ * In this stable state, the labels and the uberblock were all updated within
+ * the same transaction group (10).  Each label is mirrored and checksummed, so
+ * that we can detect when we fail partway through writing the label.
+ *
+ * In order to identify which labels are valid, the labels are written in the
+ * following manner:
+ *
+ *     1. For each vdev, update 'L1' to the new label
+ *     2. Update the uberblock
+ *     3. For each vdev, update 'L2' to the new label
+ *
+ * Given arbitrary failure, we can determine the correct label to use based on
+ * the transaction group.  If we fail after updating L1 but before updating the
+ * UB, we will notice that L1's transaction group is greater than the uberblock,
+ * so L2 must be valid.  If we fail after writing the uberblock but before
+ * writing L2, we will notice that L2's transaction group is less than L1, and
+ * therefore L1 is valid.
+ *
+ * Another added complexity is that not every label is updated when the config
+ * is synced.  If we add a single device, we do not want to have to re-write
+ * every label for every device in the pool.  This means that both L1 and L2 may
+ * be older than the pool uberblock, because the necessary information is stored
+ * on another vdev.
+ *
+ *
+ * On-disk Format
+ * --------------
+ *
+ * The vdev label consists of two distinct parts, and is wrapped within the
+ * vdev_label_t structure.  The label includes 8k of padding to permit legacy
+ * VTOC disk labels, but is otherwise ignored.
+ *
+ * The first half of the label is a packed nvlist which contains pool wide
+ * properties, per-vdev properties, and configuration information.  It is
+ * described in more detail below.
+ *
+ * The latter half of the label consists of a redundant array of uberblocks.
+ * These uberblocks are updated whenever a transaction group is committed,
+ * or when the configuration is updated.  When a pool is loaded, we scan each
+ * vdev for the 'best' uberblock.
+ *
+ *
+ * Configuration Information
+ * -------------------------
+ *
+ * The nvlist describing the pool and vdev contains the following elements:
+ *
+ *     version         ZFS on-disk version
+ *     name            Pool name
+ *     state           Pool state
+ *     txg             Transaction group in which this label was written
+ *     pool_guid       Unique identifier for this pool
+ *     vdev_tree       An nvlist describing vdev tree.
+ *     features_for_read
+ *                     An nvlist of the features necessary for reading the MOS.
+ *
+ * Each leaf device label also contains the following:
+ *
+ *     top_guid        Unique ID for top-level vdev in which this is contained
+ *     guid            Unique ID for the leaf vdev
+ *
+ * The 'vs' configuration follows the format described in 'spa_config.c'.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/vdev.h>
+#include <sys/vdev_impl.h>
+#include <sys/uberblock_impl.h>
+#include <sys/metaslab.h>
+#include <sys/zio.h>
+#include <sys/dsl_scan.h>
+#include <sys/fs/zfs.h>
+
+/*
+ * Basic routines to read and write from a vdev label.
+ * Used throughout the rest of this file.
+ */
+uint64_t
+vdev_label_offset(uint64_t psize, int l, uint64_t offset)
+{
+       ASSERT(offset < sizeof (vdev_label_t));
+       ASSERT(P2PHASE_TYPED(psize, sizeof (vdev_label_t), uint64_t) == 0);
+
+       return (offset + l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?
+           0 : psize - VDEV_LABELS * sizeof (vdev_label_t)));
+}
+
+/*
+ * Returns back the vdev label associated with the passed in offset.
+ */
+int
+vdev_label_number(uint64_t psize, uint64_t offset)
+{
+       int l;
+
+       if (offset >= psize - VDEV_LABEL_END_SIZE) {
+               offset -= psize - VDEV_LABEL_END_SIZE;
+               offset += (VDEV_LABELS / 2) * sizeof (vdev_label_t);
+       }
+       l = offset / sizeof (vdev_label_t);
+       return (l < VDEV_LABELS ? l : -1);
+}
+
+static void
+vdev_label_read(zio_t *zio, vdev_t *vd, int l, void *buf, uint64_t offset,
+       uint64_t size, zio_done_func_t *done, void *private, int flags)
+{
+       ASSERT(spa_config_held(zio->io_spa, SCL_STATE_ALL, RW_WRITER) ==
+           SCL_STATE_ALL);
+       ASSERT(flags & ZIO_FLAG_CONFIG_WRITER);
+
+       zio_nowait(zio_read_phys(zio, vd,
+           vdev_label_offset(vd->vdev_psize, l, offset),
+           size, buf, ZIO_CHECKSUM_LABEL, done, private,
+           ZIO_PRIORITY_SYNC_READ, flags, B_TRUE));
+}
+
+static void
+vdev_label_write(zio_t *zio, vdev_t *vd, int l, void *buf, uint64_t offset,
+       uint64_t size, zio_done_func_t *done, void *private, int flags)
+{
+       ASSERT(spa_config_held(zio->io_spa, SCL_ALL, RW_WRITER) == SCL_ALL ||
+           (spa_config_held(zio->io_spa, SCL_CONFIG | SCL_STATE, RW_READER) ==
+           (SCL_CONFIG | SCL_STATE) &&
+           dsl_pool_sync_context(spa_get_dsl(zio->io_spa))));
+       ASSERT(flags & ZIO_FLAG_CONFIG_WRITER);
+
+       zio_nowait(zio_write_phys(zio, vd,
+           vdev_label_offset(vd->vdev_psize, l, offset),
+           size, buf, ZIO_CHECKSUM_LABEL, done, private,
+           ZIO_PRIORITY_SYNC_WRITE, flags, B_TRUE));
+}
+
+/*
+ * Generate the nvlist representing this vdev's config.
+ */
+nvlist_t *
+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);
+       if (!(flags & (VDEV_CONFIG_SPARE | VDEV_CONFIG_L2CACHE)))
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_ID, vd->vdev_id);
+       fnvlist_add_uint64(nv, ZPOOL_CONFIG_GUID, vd->vdev_guid);
+
+       if (vd->vdev_path != NULL)
+               fnvlist_add_string(nv, ZPOOL_CONFIG_PATH, vd->vdev_path);
+
+       if (vd->vdev_devid != NULL)
+               fnvlist_add_string(nv, ZPOOL_CONFIG_DEVID, vd->vdev_devid);
+
+       if (vd->vdev_physpath != NULL)
+               fnvlist_add_string(nv, ZPOOL_CONFIG_PHYS_PATH,
+                   vd->vdev_physpath);
+
+       if (vd->vdev_fru != NULL)
+               fnvlist_add_string(nv, ZPOOL_CONFIG_FRU, vd->vdev_fru);
+
+       if (vd->vdev_nparity != 0) {
+               ASSERT(strcmp(vd->vdev_ops->vdev_op_type,
+                   VDEV_TYPE_RAIDZ) == 0);
+
+               /*
+                * Make sure someone hasn't managed to sneak a fancy new vdev
+                * into a crufty old storage pool.
+                */
+               ASSERT(vd->vdev_nparity == 1 ||
+                   (vd->vdev_nparity <= 2 &&
+                   spa_version(spa) >= SPA_VERSION_RAIDZ2) ||
+                   (vd->vdev_nparity <= 3 &&
+                   spa_version(spa) >= SPA_VERSION_RAIDZ3));
+
+               /*
+                * Note that we'll add the nparity tag even on storage pools
+                * that only support a single parity device -- older software
+                * will just ignore it.
+                */
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_NPARITY, vd->vdev_nparity);
+       }
+
+       if (vd->vdev_wholedisk != -1ULL)
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+                   vd->vdev_wholedisk);
+
+       if (vd->vdev_not_present)
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1);
+
+       if (vd->vdev_isspare)
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 1);
+
+       if (!(flags & (VDEV_CONFIG_SPARE | VDEV_CONFIG_L2CACHE)) &&
+           vd == vd->vdev_top) {
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_METASLAB_ARRAY,
+                   vd->vdev_ms_array);
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_METASLAB_SHIFT,
+                   vd->vdev_ms_shift);
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_ASHIFT, vd->vdev_ashift);
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_ASIZE,
+                   vd->vdev_asize);
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_IS_LOG, vd->vdev_islog);
+               if (vd->vdev_removing)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_REMOVING,
+                           vd->vdev_removing);
+       }
+
+       if (vd->vdev_dtl_sm != NULL) {
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_DTL,
+                   space_map_object(vd->vdev_dtl_sm));
+       }
+
+       if (vd->vdev_crtxg)
+               fnvlist_add_uint64(nv, ZPOOL_CONFIG_CREATE_TXG, vd->vdev_crtxg);
+
+       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));
+
+               /* provide either current or previous scan information */
+               if (spa_scan_get_stats(spa, &ps) == 0) {
+                       fnvlist_add_uint64_array(nv,
+                           ZPOOL_CONFIG_SCAN_STATS, (uint64_t *)&ps,
+                           sizeof (pool_scan_stat_t) / sizeof (uint64_t));
+               }
+       }
+
+       if (!vd->vdev_ops->vdev_op_leaf) {
+               nvlist_t **child;
+               int c, idx;
+
+               ASSERT(!vd->vdev_ishole);
+
+               child = kmem_alloc(vd->vdev_children * sizeof (nvlist_t *),
+                   KM_SLEEP);
+
+               for (c = 0, idx = 0; c < vd->vdev_children; c++) {
+                       vdev_t *cvd = vd->vdev_child[c];
+
+                       /*
+                        * If we're generating an nvlist of removing
+                        * vdevs then skip over any device which is
+                        * not being removed.
+                        */
+                       if ((flags & VDEV_CONFIG_REMOVING) &&
+                           !cvd->vdev_removing)
+                               continue;
+
+                       child[idx++] = vdev_config_generate(spa, cvd,
+                           getstats, flags);
+               }
+
+               if (idx) {
+                       fnvlist_add_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+                           child, idx);
+               }
+
+               for (c = 0; c < idx; c++)
+                       nvlist_free(child[c]);
+
+               kmem_free(child, vd->vdev_children * sizeof (nvlist_t *));
+
+       } else {
+               const char *aux = NULL;
+
+               if (vd->vdev_offline && !vd->vdev_tmpoffline)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_OFFLINE, B_TRUE);
+               if (vd->vdev_resilver_txg != 0)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_RESILVER_TXG,
+                           vd->vdev_resilver_txg);
+               if (vd->vdev_faulted)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_FAULTED, B_TRUE);
+               if (vd->vdev_degraded)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_DEGRADED, B_TRUE);
+               if (vd->vdev_removed)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_REMOVED, B_TRUE);
+               if (vd->vdev_unspare)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_UNSPARE, B_TRUE);
+               if (vd->vdev_ishole)
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_IS_HOLE, B_TRUE);
+
+               switch (vd->vdev_stat.vs_aux) {
+               case VDEV_AUX_ERR_EXCEEDED:
+                       aux = "err_exceeded";
+                       break;
+
+               case VDEV_AUX_EXTERNAL:
+                       aux = "external";
+                       break;
+               }
+
+               if (aux != NULL)
+                       fnvlist_add_string(nv, ZPOOL_CONFIG_AUX_STATE, aux);
+
+               if (vd->vdev_splitting && vd->vdev_orig_guid != 0LL) {
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_ORIG_GUID,
+                           vd->vdev_orig_guid);
+               }
+       }
+
+       return (nv);
+}
+
+/*
+ * Generate a view of the top-level vdevs.  If we currently have holes
+ * in the namespace, then generate an array which contains a list of holey
+ * vdevs.  Additionally, add the number of top-level children that currently
+ * exist.
+ */
+void
+vdev_top_config_generate(spa_t *spa, nvlist_t *config)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       uint64_t *array;
+       uint_t c, idx;
+
+       array = kmem_alloc(rvd->vdev_children * sizeof (uint64_t), KM_SLEEP);
+
+       for (c = 0, idx = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+
+               if (tvd->vdev_ishole)
+                       array[idx++] = c;
+       }
+
+       if (idx) {
+               VERIFY(nvlist_add_uint64_array(config, ZPOOL_CONFIG_HOLE_ARRAY,
+                   array, idx) == 0);
+       }
+
+       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VDEV_CHILDREN,
+           rvd->vdev_children) == 0);
+
+       kmem_free(array, rvd->vdev_children * sizeof (uint64_t));
+}
+
+/*
+ * Returns the configuration from the label of the given vdev. For vdevs
+ * which don't have a txg value stored on their label (i.e. spares/cache)
+ * or have not been completely initialized (txg = 0) just return
+ * the configuration from the first valid label we find. Otherwise,
+ * find the most up-to-date label that does not exceed the specified
+ * 'txg' value.
+ */
+nvlist_t *
+vdev_label_read_config(vdev_t *vd, uint64_t txg)
+{
+       spa_t *spa = vd->vdev_spa;
+       nvlist_t *config = NULL;
+       vdev_phys_t *vp;
+       zio_t *zio;
+       uint64_t best_txg = 0;
+       int error = 0;
+       int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL |
+           ZIO_FLAG_SPECULATIVE;
+       int l;
+
+       ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL);
+
+       if (!vdev_readable(vd))
+               return (NULL);
+
+       vp = zio_buf_alloc(sizeof (vdev_phys_t));
+
+retry:
+       for (l = 0; l < VDEV_LABELS; l++) {
+               nvlist_t *label = NULL;
+
+               zio = zio_root(spa, NULL, NULL, flags);
+
+               vdev_label_read(zio, vd, l, vp,
+                   offsetof(vdev_label_t, vl_vdev_phys),
+                   sizeof (vdev_phys_t), NULL, NULL, flags);
+
+               if (zio_wait(zio) == 0 &&
+                   nvlist_unpack(vp->vp_nvlist, sizeof (vp->vp_nvlist),
+                   &label, 0) == 0) {
+                       uint64_t label_txg = 0;
+
+                       /*
+                        * Auxiliary vdevs won't have txg values in their
+                        * labels and newly added vdevs may not have been
+                        * completely initialized so just return the
+                        * configuration from the first valid label we
+                        * encounter.
+                        */
+                       error = nvlist_lookup_uint64(label,
+                           ZPOOL_CONFIG_POOL_TXG, &label_txg);
+                       if ((error || label_txg == 0) && !config) {
+                               config = label;
+                               break;
+                       } else if (label_txg <= txg && label_txg > best_txg) {
+                               best_txg = label_txg;
+                               nvlist_free(config);
+                               config = fnvlist_dup(label);
+                       }
+               }
+
+               if (label != NULL) {
+                       nvlist_free(label);
+                       label = NULL;
+               }
+       }
+
+       if (config == NULL && !(flags & ZIO_FLAG_TRYHARD)) {
+               flags |= ZIO_FLAG_TRYHARD;
+               goto retry;
+       }
+
+       zio_buf_free(vp, sizeof (vdev_phys_t));
+
+       return (config);
+}
+
+/*
+ * Determine if a device is in use.  The 'spare_guid' parameter will be filled
+ * in with the device guid if this spare is active elsewhere on the system.
+ */
+static boolean_t
+vdev_inuse(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason,
+    uint64_t *spare_guid, uint64_t *l2cache_guid)
+{
+       spa_t *spa = vd->vdev_spa;
+       uint64_t state, pool_guid, device_guid, txg, spare_pool;
+       uint64_t vdtxg = 0;
+       nvlist_t *label;
+
+       if (spare_guid)
+               *spare_guid = 0ULL;
+       if (l2cache_guid)
+               *l2cache_guid = 0ULL;
+
+       /*
+        * Read the label, if any, and perform some basic sanity checks.
+        */
+       if ((label = vdev_label_read_config(vd, -1ULL)) == NULL)
+               return (B_FALSE);
+
+       (void) nvlist_lookup_uint64(label, ZPOOL_CONFIG_CREATE_TXG,
+           &vdtxg);
+
+       if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_STATE,
+           &state) != 0 ||
+           nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID,
+           &device_guid) != 0) {
+               nvlist_free(label);
+               return (B_FALSE);
+       }
+
+       if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+           (nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_GUID,
+           &pool_guid) != 0 ||
+           nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_TXG,
+           &txg) != 0)) {
+               nvlist_free(label);
+               return (B_FALSE);
+       }
+
+       nvlist_free(label);
+
+       /*
+        * Check to see if this device indeed belongs to the pool it claims to
+        * be a part of.  The only way this is allowed is if the device is a hot
+        * spare (which we check for later on).
+        */
+       if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+           !spa_guid_exists(pool_guid, device_guid) &&
+           !spa_spare_exists(device_guid, NULL, NULL) &&
+           !spa_l2cache_exists(device_guid, NULL))
+               return (B_FALSE);
+
+       /*
+        * If the transaction group is zero, then this an initialized (but
+        * unused) label.  This is only an error if the create transaction
+        * on-disk is the same as the one we're using now, in which case the
+        * user has attempted to add the same vdev multiple times in the same
+        * transaction.
+        */
+       if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+           txg == 0 && vdtxg == crtxg)
+               return (B_TRUE);
+
+       /*
+        * Check to see if this is a spare device.  We do an explicit check for
+        * spa_has_spare() here because it may be on our pending list of spares
+        * to add.  We also check if it is an l2cache device.
+        */
+       if (spa_spare_exists(device_guid, &spare_pool, NULL) ||
+           spa_has_spare(spa, device_guid)) {
+               if (spare_guid)
+                       *spare_guid = device_guid;
+
+               switch (reason) {
+               case VDEV_LABEL_CREATE:
+               case VDEV_LABEL_L2CACHE:
+                       return (B_TRUE);
+
+               case VDEV_LABEL_REPLACE:
+                       return (!spa_has_spare(spa, device_guid) ||
+                           spare_pool != 0ULL);
+
+               case VDEV_LABEL_SPARE:
+                       return (spa_has_spare(spa, device_guid));
+               default:
+                       break;
+               }
+       }
+
+       /*
+        * Check to see if this is an l2cache device.
+        */
+       if (spa_l2cache_exists(device_guid, NULL))
+               return (B_TRUE);
+
+       /*
+        * We can't rely on a pool's state if it's been imported
+        * read-only.  Instead we look to see if the pools is marked
+        * read-only in the namespace and set the state to active.
+        */
+       if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+           (spa = spa_by_guid(pool_guid, device_guid)) != NULL &&
+           spa_mode(spa) == FREAD)
+               state = POOL_STATE_ACTIVE;
+
+       /*
+        * If the device is marked ACTIVE, then this device is in use by another
+        * pool on the system.
+        */
+       return (state == POOL_STATE_ACTIVE);
+}
+
+/*
+ * Initialize a vdev label.  We check to make sure each leaf device is not in
+ * use, and writable.  We put down an initial label which we will later
+ * overwrite with a complete label.  Note that it's important to do this
+ * sequentially, not in parallel, so that we catch cases of multiple use of the
+ * same leaf vdev in the vdev we're creating -- e.g. mirroring a disk with
+ * itself.
+ */
+int
+vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason)
+{
+       spa_t *spa = vd->vdev_spa;
+       nvlist_t *label;
+       vdev_phys_t *vp;
+       char *pad2;
+       uberblock_t *ub;
+       zio_t *zio;
+       char *buf;
+       size_t buflen;
+       int error;
+       uint64_t spare_guid = 0, l2cache_guid = 0;
+       int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
+       int c, l;
+       vdev_t *pvd;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               if ((error = vdev_label_init(vd->vdev_child[c],
+                   crtxg, reason)) != 0)
+                       return (error);
+
+       /* Track the creation time for this vdev */
+       vd->vdev_crtxg = crtxg;
+
+       if (!vd->vdev_ops->vdev_op_leaf || !spa_writeable(spa))
+               return (0);
+
+       /*
+        * Dead vdevs cannot be initialized.
+        */
+       if (vdev_is_dead(vd))
+               return (SET_ERROR(EIO));
+
+       /*
+        * Determine if the vdev is in use.
+        */
+       if (reason != VDEV_LABEL_REMOVE && reason != VDEV_LABEL_SPLIT &&
+           vdev_inuse(vd, crtxg, reason, &spare_guid, &l2cache_guid))
+               return (SET_ERROR(EBUSY));
+
+       /*
+        * If this is a request to add or replace a spare or l2cache device
+        * that is in use elsewhere on the system, then we must update the
+        * guid (which was initialized to a random value) to reflect the
+        * actual GUID (which is shared between multiple pools).
+        */
+       if (reason != VDEV_LABEL_REMOVE && reason != VDEV_LABEL_L2CACHE &&
+           spare_guid != 0ULL) {
+               uint64_t guid_delta = spare_guid - vd->vdev_guid;
+
+               vd->vdev_guid += guid_delta;
+
+               for (pvd = vd; pvd != NULL; pvd = pvd->vdev_parent)
+                       pvd->vdev_guid_sum += guid_delta;
+
+               /*
+                * If this is a replacement, then we want to fallthrough to the
+                * rest of the code.  If we're adding a spare, then it's already
+                * labeled appropriately and we can just return.
+                */
+               if (reason == VDEV_LABEL_SPARE)
+                       return (0);
+               ASSERT(reason == VDEV_LABEL_REPLACE ||
+                   reason == VDEV_LABEL_SPLIT);
+       }
+
+       if (reason != VDEV_LABEL_REMOVE && reason != VDEV_LABEL_SPARE &&
+           l2cache_guid != 0ULL) {
+               uint64_t guid_delta = l2cache_guid - vd->vdev_guid;
+
+               vd->vdev_guid += guid_delta;
+
+               for (pvd = vd; pvd != NULL; pvd = pvd->vdev_parent)
+                       pvd->vdev_guid_sum += guid_delta;
+
+               /*
+                * If this is a replacement, then we want to fallthrough to the
+                * rest of the code.  If we're adding an l2cache, then it's
+                * already labeled appropriately and we can just return.
+                */
+               if (reason == VDEV_LABEL_L2CACHE)
+                       return (0);
+               ASSERT(reason == VDEV_LABEL_REPLACE);
+       }
+
+       /*
+        * Initialize its label.
+        */
+       vp = zio_buf_alloc(sizeof (vdev_phys_t));
+       bzero(vp, sizeof (vdev_phys_t));
+
+       /*
+        * Generate a label describing the pool and our top-level vdev.
+        * We mark it as being from txg 0 to indicate that it's not
+        * really part of an active pool just yet.  The labels will
+        * be written again with a meaningful txg by spa_sync().
+        */
+       if (reason == VDEV_LABEL_SPARE ||
+           (reason == VDEV_LABEL_REMOVE && vd->vdev_isspare)) {
+               /*
+                * For inactive hot spares, we generate a special label that
+                * identifies as a mutually shared hot spare.  We write the
+                * label if we are adding a hot spare, or if we are removing an
+                * active hot spare (in which case we want to revert the
+                * labels).
+                */
+               VERIFY(nvlist_alloc(&label, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_VERSION,
+                   spa_version(spa)) == 0);
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_POOL_STATE,
+                   POOL_STATE_SPARE) == 0);
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_GUID,
+                   vd->vdev_guid) == 0);
+       } else if (reason == VDEV_LABEL_L2CACHE ||
+           (reason == VDEV_LABEL_REMOVE && vd->vdev_isl2cache)) {
+               /*
+                * For level 2 ARC devices, add a special label.
+                */
+               VERIFY(nvlist_alloc(&label, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_VERSION,
+                   spa_version(spa)) == 0);
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_POOL_STATE,
+                   POOL_STATE_L2CACHE) == 0);
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_GUID,
+                   vd->vdev_guid) == 0);
+       } else {
+               uint64_t txg = 0ULL;
+
+               if (reason == VDEV_LABEL_SPLIT)
+                       txg = spa->spa_uberblock.ub_txg;
+               label = spa_config_generate(spa, vd, txg, B_FALSE);
+
+               /*
+                * Add our creation time.  This allows us to detect multiple
+                * vdev uses as described above, and automatically expires if we
+                * fail.
+                */
+               VERIFY(nvlist_add_uint64(label, ZPOOL_CONFIG_CREATE_TXG,
+                   crtxg) == 0);
+       }
+
+       buf = vp->vp_nvlist;
+       buflen = sizeof (vp->vp_nvlist);
+
+       error = nvlist_pack(label, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP);
+       if (error != 0) {
+               nvlist_free(label);
+               zio_buf_free(vp, sizeof (vdev_phys_t));
+               /* EFAULT means nvlist_pack ran out of room */
+               return (error == EFAULT ? ENAMETOOLONG : EINVAL);
+       }
+
+       /*
+        * Initialize uberblock template.
+        */
+       ub = zio_buf_alloc(VDEV_UBERBLOCK_RING);
+       bzero(ub, VDEV_UBERBLOCK_RING);
+       *ub = spa->spa_uberblock;
+       ub->ub_txg = 0;
+
+       /* Initialize the 2nd padding area. */
+       pad2 = zio_buf_alloc(VDEV_PAD_SIZE);
+       bzero(pad2, VDEV_PAD_SIZE);
+
+       /*
+        * Write everything in parallel.
+        */
+retry:
+       zio = zio_root(spa, NULL, NULL, flags);
+
+       for (l = 0; l < VDEV_LABELS; l++) {
+
+               vdev_label_write(zio, vd, l, vp,
+                   offsetof(vdev_label_t, vl_vdev_phys),
+                   sizeof (vdev_phys_t), NULL, NULL, flags);
+
+               /*
+                * Skip the 1st padding area.
+                * Zero out the 2nd padding area where it might have
+                * left over data from previous filesystem format.
+                */
+               vdev_label_write(zio, vd, l, pad2,
+                   offsetof(vdev_label_t, vl_pad2),
+                   VDEV_PAD_SIZE, NULL, NULL, flags);
+
+               vdev_label_write(zio, vd, l, ub,
+                   offsetof(vdev_label_t, vl_uberblock),
+                   VDEV_UBERBLOCK_RING, NULL, NULL, flags);
+       }
+
+       error = zio_wait(zio);
+
+       if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) {
+               flags |= ZIO_FLAG_TRYHARD;
+               goto retry;
+       }
+
+       nvlist_free(label);
+       zio_buf_free(pad2, VDEV_PAD_SIZE);
+       zio_buf_free(ub, VDEV_UBERBLOCK_RING);
+       zio_buf_free(vp, sizeof (vdev_phys_t));
+
+       /*
+        * If this vdev hasn't been previously identified as a spare, then we
+        * mark it as such only if a) we are labeling it as a spare, or b) it
+        * exists as a spare elsewhere in the system.  Do the same for
+        * level 2 ARC devices.
+        */
+       if (error == 0 && !vd->vdev_isspare &&
+           (reason == VDEV_LABEL_SPARE ||
+           spa_spare_exists(vd->vdev_guid, NULL, NULL)))
+               spa_spare_add(vd);
+
+       if (error == 0 && !vd->vdev_isl2cache &&
+           (reason == VDEV_LABEL_L2CACHE ||
+           spa_l2cache_exists(vd->vdev_guid, NULL)))
+               spa_l2cache_add(vd);
+
+       return (error);
+}
+
+/*
+ * ==========================================================================
+ * uberblock load/sync
+ * ==========================================================================
+ */
+
+/*
+ * Consider the following situation: txg is safely synced to disk.  We've
+ * written the first uberblock for txg + 1, and then we lose power.  When we
+ * come back up, we fail to see the uberblock for txg + 1 because, say,
+ * it was on a mirrored device and the replica to which we wrote txg + 1
+ * is now offline.  If we then make some changes and sync txg + 1, and then
+ * the missing replica comes back, then for a few seconds we'll have two
+ * conflicting uberblocks on disk with the same txg.  The solution is simple:
+ * among uberblocks with equal txg, choose the one with the latest timestamp.
+ */
+static int
+vdev_uberblock_compare(uberblock_t *ub1, uberblock_t *ub2)
+{
+       if (ub1->ub_txg < ub2->ub_txg)
+               return (-1);
+       if (ub1->ub_txg > ub2->ub_txg)
+               return (1);
+
+       if (ub1->ub_timestamp < ub2->ub_timestamp)
+               return (-1);
+       if (ub1->ub_timestamp > ub2->ub_timestamp)
+               return (1);
+
+       return (0);
+}
+
+struct ubl_cbdata {
+       uberblock_t     *ubl_ubbest;    /* Best uberblock */
+       vdev_t          *ubl_vd;        /* vdev associated with the above */
+};
+
+static void
+vdev_uberblock_load_done(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       spa_t *spa = zio->io_spa;
+       zio_t *rio = zio->io_private;
+       uberblock_t *ub = zio->io_data;
+       struct ubl_cbdata *cbp = rio->io_private;
+
+       ASSERT3U(zio->io_size, ==, VDEV_UBERBLOCK_SIZE(vd));
+
+       if (zio->io_error == 0 && uberblock_verify(ub) == 0) {
+               mutex_enter(&rio->io_lock);
+               if (ub->ub_txg <= spa->spa_load_max_txg &&
+                   vdev_uberblock_compare(ub, cbp->ubl_ubbest) > 0) {
+                       /*
+                        * Keep track of the vdev in which this uberblock
+                        * was found. We will use this information later
+                        * to obtain the config nvlist associated with
+                        * this uberblock.
+                        */
+                       *cbp->ubl_ubbest = *ub;
+                       cbp->ubl_vd = vd;
+               }
+               mutex_exit(&rio->io_lock);
+       }
+
+       zio_buf_free(zio->io_data, zio->io_size);
+}
+
+static void
+vdev_uberblock_load_impl(zio_t *zio, vdev_t *vd, int flags,
+    struct ubl_cbdata *cbp)
+{
+       int c, l, n;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_uberblock_load_impl(zio, vd->vdev_child[c], flags, cbp);
+
+       if (vd->vdev_ops->vdev_op_leaf && vdev_readable(vd)) {
+               for (l = 0; l < VDEV_LABELS; l++) {
+                       for (n = 0; n < VDEV_UBERBLOCK_COUNT(vd); n++) {
+                               vdev_label_read(zio, vd, l,
+                                   zio_buf_alloc(VDEV_UBERBLOCK_SIZE(vd)),
+                                   VDEV_UBERBLOCK_OFFSET(vd, n),
+                                   VDEV_UBERBLOCK_SIZE(vd),
+                                   vdev_uberblock_load_done, zio, flags);
+                       }
+               }
+       }
+}
+
+/*
+ * Reads the 'best' uberblock from disk along with its associated
+ * configuration. First, we read the uberblock array of each label of each
+ * vdev, keeping track of the uberblock with the highest txg in each array.
+ * Then, we read the configuration from the same vdev as the best uberblock.
+ */
+void
+vdev_uberblock_load(vdev_t *rvd, uberblock_t *ub, nvlist_t **config)
+{
+       zio_t *zio;
+       spa_t *spa = rvd->vdev_spa;
+       struct ubl_cbdata cb;
+       int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL |
+           ZIO_FLAG_SPECULATIVE | ZIO_FLAG_TRYHARD;
+
+       ASSERT(ub);
+       ASSERT(config);
+
+       bzero(ub, sizeof (uberblock_t));
+       *config = NULL;
+
+       cb.ubl_ubbest = ub;
+       cb.ubl_vd = NULL;
+
+       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+       zio = zio_root(spa, NULL, &cb, flags);
+       vdev_uberblock_load_impl(zio, rvd, flags, &cb);
+       (void) zio_wait(zio);
+
+       /*
+        * It's possible that the best uberblock was discovered on a label
+        * that has a configuration which was written in a future txg.
+        * Search all labels on this vdev to find the configuration that
+        * matches the txg for our uberblock.
+        */
+       if (cb.ubl_vd != NULL)
+               *config = vdev_label_read_config(cb.ubl_vd, ub->ub_txg);
+       spa_config_exit(spa, SCL_ALL, FTAG);
+}
+
+/*
+ * On success, increment root zio's count of good writes.
+ * We only get credit for writes to known-visible vdevs; see spa_vdev_add().
+ */
+static void
+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);
+}
+
+/*
+ * Write the uberblock to all labels of all leaves of the specified vdev.
+ */
+static void
+vdev_uberblock_sync(zio_t *zio, uberblock_t *ub, vdev_t *vd, int flags)
+{
+       uberblock_t *ubbuf;
+       int c, l, n;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_uberblock_sync(zio, ub, vd->vdev_child[c], flags);
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return;
+
+       if (!vdev_writeable(vd))
+               return;
+
+       n = ub->ub_txg & (VDEV_UBERBLOCK_COUNT(vd) - 1);
+
+       ubbuf = zio_buf_alloc(VDEV_UBERBLOCK_SIZE(vd));
+       bzero(ubbuf, VDEV_UBERBLOCK_SIZE(vd));
+       *ubbuf = *ub;
+
+       for (l = 0; l < VDEV_LABELS; l++)
+               vdev_label_write(zio, vd, l, ubbuf,
+                   VDEV_UBERBLOCK_OFFSET(vd, n), VDEV_UBERBLOCK_SIZE(vd),
+                   vdev_uberblock_sync_done, zio->io_private,
+                   flags | ZIO_FLAG_DONT_PROPAGATE);
+
+       zio_buf_free(ubbuf, VDEV_UBERBLOCK_SIZE(vd));
+}
+
+/* Sync the uberblocks to all vdevs in svd[] */
+int
+vdev_uberblock_sync_list(vdev_t **svd, int svdcount, uberblock_t *ub, int flags)
+{
+       spa_t *spa = svd[0]->vdev_spa;
+       zio_t *zio;
+       uint64_t good_writes = 0;
+       int v;
+
+       zio = zio_root(spa, NULL, &good_writes, flags);
+
+       for (v = 0; v < svdcount; v++)
+               vdev_uberblock_sync(zio, ub, svd[v], flags);
+
+       (void) zio_wait(zio);
+
+       /*
+        * Flush the uberblocks to disk.  This ensures that the odd labels
+        * are no longer needed (because the new uberblocks and the even
+        * labels are safely on disk), so it is safe to overwrite them.
+        */
+       zio = zio_root(spa, NULL, NULL, flags);
+
+       for (v = 0; v < svdcount; v++)
+               zio_flush(zio, svd[v]);
+
+       (void) zio_wait(zio);
+
+       return (good_writes >= 1 ? 0 : EIO);
+}
+
+/*
+ * On success, increment the count of good writes for our top-level vdev.
+ */
+static void
+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);
+}
+
+/*
+ * If there weren't enough good writes, indicate failure to the parent.
+ */
+static void
+vdev_label_sync_top_done(zio_t *zio)
+{
+       uint64_t *good_writes = zio->io_private;
+
+       if (*good_writes == 0)
+               zio->io_error = SET_ERROR(EIO);
+
+       kmem_free(good_writes, sizeof (uint64_t));
+}
+
+/*
+ * We ignore errors for log and cache devices, simply free the private data.
+ */
+static void
+vdev_label_sync_ignore_done(zio_t *zio)
+{
+       kmem_free(zio->io_private, sizeof (uint64_t));
+}
+
+/*
+ * Write all even or odd labels to all leaves of the specified vdev.
+ */
+static void
+vdev_label_sync(zio_t *zio, vdev_t *vd, int l, uint64_t txg, int flags)
+{
+       nvlist_t *label;
+       vdev_phys_t *vp;
+       char *buf;
+       size_t buflen;
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_label_sync(zio, vd->vdev_child[c], l, txg, flags);
+
+       if (!vd->vdev_ops->vdev_op_leaf)
+               return;
+
+       if (!vdev_writeable(vd))
+               return;
+
+       /*
+        * Generate a label describing the top-level config to which we belong.
+        */
+       label = spa_config_generate(vd->vdev_spa, vd, txg, B_FALSE);
+
+       vp = zio_buf_alloc(sizeof (vdev_phys_t));
+       bzero(vp, sizeof (vdev_phys_t));
+
+       buf = vp->vp_nvlist;
+       buflen = sizeof (vp->vp_nvlist);
+
+       if (!nvlist_pack(label, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP)) {
+               for (; l < VDEV_LABELS; l += 2) {
+                       vdev_label_write(zio, vd, l, vp,
+                           offsetof(vdev_label_t, vl_vdev_phys),
+                           sizeof (vdev_phys_t),
+                           vdev_label_sync_done, zio->io_private,
+                           flags | ZIO_FLAG_DONT_PROPAGATE);
+               }
+       }
+
+       zio_buf_free(vp, sizeof (vdev_phys_t));
+       nvlist_free(label);
+}
+
+int
+vdev_label_sync_list(spa_t *spa, int l, uint64_t txg, int flags)
+{
+       list_t *dl = &spa->spa_config_dirty_list;
+       vdev_t *vd;
+       zio_t *zio;
+       int error;
+
+       /*
+        * Write the new labels to disk.
+        */
+       zio = zio_root(spa, NULL, NULL, flags);
+
+       for (vd = list_head(dl); vd != NULL; vd = list_next(dl, vd)) {
+               uint64_t *good_writes;
+               zio_t *vio;
+
+               ASSERT(!vd->vdev_ishole);
+
+               good_writes = kmem_zalloc(sizeof (uint64_t), KM_SLEEP);
+               vio = zio_null(zio, spa, NULL,
+                   (vd->vdev_islog || vd->vdev_aux != NULL) ?
+                   vdev_label_sync_ignore_done : vdev_label_sync_top_done,
+                   good_writes, flags);
+               vdev_label_sync(vio, vd, l, txg, flags);
+               zio_nowait(vio);
+       }
+
+       error = zio_wait(zio);
+
+       /*
+        * Flush the new labels to disk.
+        */
+       zio = zio_root(spa, NULL, NULL, flags);
+
+       for (vd = list_head(dl); vd != NULL; vd = list_next(dl, vd))
+               zio_flush(zio, vd);
+
+       (void) zio_wait(zio);
+
+       return (error);
+}
+
+/*
+ * Sync the uberblock and any changes to the vdev configuration.
+ *
+ * The order of operations is carefully crafted to ensure that
+ * if the system panics or loses power at any time, the state on disk
+ * is still transactionally consistent.  The in-line comments below
+ * describe the failure semantics at each stage.
+ *
+ * Moreover, vdev_config_sync() is designed to be idempotent: if it fails
+ * 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)
+{
+       spa_t *spa = svd[0]->vdev_spa;
+       uberblock_t *ub = &spa->spa_uberblock;
+       vdev_t *vd;
+       zio_t *zio;
+       int error;
+       int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
+
+       /*
+        * 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
+        * sync process to block while we retry.  But if we can't write a
+        * single label out, we should retry with ZIO_FLAG_TRYHARD before
+        * bailing out and declaring the pool faulted.
+        */
+       if (tryhard)
+               flags |= ZIO_FLAG_TRYHARD;
+
+       ASSERT(ub->ub_txg <= txg);
+
+       /*
+        * If this isn't a resync due to I/O errors,
+        * and nothing changed in this transaction group,
+        * and the vdev configuration hasn't changed,
+        * then there's nothing to do.
+        */
+       if (ub->ub_txg < txg &&
+           uberblock_update(ub, spa->spa_root_vdev, txg) == B_FALSE &&
+           list_is_empty(&spa->spa_config_dirty_list))
+               return (0);
+
+       if (txg > spa_freeze_txg(spa))
+               return (0);
+
+       ASSERT(txg <= spa->spa_final_txg);
+
+       /*
+        * Flush the write cache of every disk that's been written to
+        * in this transaction group.  This ensures that all blocks
+        * written in this txg will be committed to stable storage
+        * before any uberblock that references them.
+        */
+       zio = zio_root(spa, NULL, NULL, flags);
+
+       for (vd = txg_list_head(&spa->spa_vdev_txg_list, TXG_CLEAN(txg)); vd;
+           vd = txg_list_next(&spa->spa_vdev_txg_list, vd, TXG_CLEAN(txg)))
+               zio_flush(zio, vd);
+
+       (void) zio_wait(zio);
+
+       /*
+        * Sync out the even labels (L0, L2) for every dirty vdev.  If the
+        * system dies in the middle of this process, that's OK: all of the
+        * even labels that made it to disk will be newer than any uberblock,
+        * and will therefore be considered invalid.  The odd labels (L1, L3),
+        * which have not yet been touched, will still be valid.  We flush
+        * the new labels to disk to ensure that all even-label updates
+        * are committed to stable storage before the uberblock update.
+        */
+       if ((error = vdev_label_sync_list(spa, 0, txg, flags)) != 0)
+               return (error);
+
+       /*
+        * Sync the uberblocks to all vdevs in svd[].
+        * If the system dies in the middle of this step, there are two cases
+        * to consider, and the on-disk state is consistent either way:
+        *
+        * (1)  If none of the new uberblocks made it to disk, then the
+        *      previous uberblock will be the newest, and the odd labels
+        *      (which had not yet been touched) will be valid with respect
+        *      to that uberblock.
+        *
+        * (2)  If one or more new uberblocks made it to disk, then they
+        *      will be the newest, and the even labels (which had all
+        *      been successfully committed) will be valid with respect
+        *      to the new uberblocks.
+        */
+       if ((error = vdev_uberblock_sync_list(svd, svdcount, ub, flags)) != 0)
+               return (error);
+
+       /*
+        * Sync out odd labels for every dirty vdev.  If the system dies
+        * in the middle of this process, the even labels and the new
+        * uberblocks will suffice to open the pool.  The next time
+        * the pool is opened, the first thing we'll do -- before any
+        * user data is modified -- is mark every vdev dirty so that
+        * all labels will be brought up to date.  We flush the new labels
+        * 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));
+}
diff --git a/zfs/module/zfs/vdev_mirror.c b/zfs/module/zfs/vdev_mirror.c
new file mode 100644 (file)
index 0000000..6b699e8
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/fs/zfs.h>
+
+/*
+ * Virtual device vector for mirroring.
+ */
+
+typedef struct mirror_child {
+       vdev_t          *mc_vd;
+       uint64_t        mc_offset;
+       int             mc_error;
+       int             mc_pending;
+       uint8_t         mc_tried;
+       uint8_t         mc_skipped;
+       uint8_t         mc_speculative;
+} mirror_child_t;
+
+typedef struct mirror_map {
+       int             mm_children;
+       int             mm_replacing;
+       int             mm_preferred;
+       int             mm_root;
+       mirror_child_t  mm_child[1];
+} mirror_map_t;
+
+/*
+ * 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.
+ *
+ * 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.
+ */
+int zfs_vdev_mirror_switch_us = 10000;
+
+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]));
+}
+
+static const zio_vsd_ops_t vdev_mirror_vsd_ops = {
+       vdev_mirror_map_free,
+       zio_vsd_default_cksum_report
+};
+
+static int
+vdev_mirror_pending(vdev_t *vd)
+{
+       return (avl_numnodes(&vd->vdev_queue.vq_active_tree));
+}
+
+/*
+ * Avoid inlining the function to keep vdev_mirror_io_start(), which
+ * is this functions only caller, as small as possible on the stack.
+ */
+noinline static mirror_map_t *
+vdev_mirror_map_alloc(zio_t *zio)
+{
+       mirror_map_t *mm = NULL;
+       mirror_child_t *mc;
+       vdev_t *vd = zio->io_vd;
+       int c, d;
+
+       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;
+               }
+
+               for (c = 0; c < mm->mm_children; c++) {
+                       mc = &mm->mm_child[c];
+
+                       mc->mc_vd = vdev_lookup_top(spa, DVA_GET_VDEV(&dva[c]));
+                       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;
+
+               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;
+                               }
+                       }
+               }
+       }
+
+       zio->io_vsd = mm;
+       zio->io_vsd_ops = &vdev_mirror_vsd_ops;
+       return (mm);
+}
+
+static int
+vdev_mirror_open(vdev_t *vd, uint64_t *asize, uint64_t *max_asize,
+    uint64_t *ashift)
+{
+       int numerrors = 0;
+       int lasterror = 0;
+       int c;
+
+       if (vd->vdev_children == 0) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       vdev_open_children(vd);
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               vdev_t *cvd = vd->vdev_child[c];
+
+               if (cvd->vdev_open_error) {
+                       lasterror = cvd->vdev_open_error;
+                       numerrors++;
+                       continue;
+               }
+
+               *asize = MIN(*asize - 1, cvd->vdev_asize - 1) + 1;
+               *max_asize = MIN(*max_asize - 1, cvd->vdev_max_asize - 1) + 1;
+               *ashift = MAX(*ashift, cvd->vdev_ashift);
+       }
+
+       if (numerrors == vd->vdev_children) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_NO_REPLICAS;
+               return (lasterror);
+       }
+
+       return (0);
+}
+
+static void
+vdev_mirror_close(vdev_t *vd)
+{
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_close(vd->vdev_child[c]);
+}
+
+static void
+vdev_mirror_child_done(zio_t *zio)
+{
+       mirror_child_t *mc = zio->io_private;
+
+       mc->mc_error = zio->io_error;
+       mc->mc_tried = 1;
+       mc->mc_skipped = 0;
+}
+
+static void
+vdev_mirror_scrub_done(zio_t *zio)
+{
+       mirror_child_t *mc = zio->io_private;
+
+       if (zio->io_error == 0) {
+               zio_t *pio;
+
+               mutex_enter(&zio->io_lock);
+               while ((pio = zio_walk_parents(zio)) != NULL) {
+                       mutex_enter(&pio->io_lock);
+                       ASSERT3U(zio->io_size, >=, pio->io_size);
+                       bcopy(zio->io_data, pio->io_data, pio->io_size);
+                       mutex_exit(&pio->io_lock);
+               }
+               mutex_exit(&zio->io_lock);
+       }
+
+       zio_buf_free(zio->io_data, zio->io_size);
+
+       mc->mc_error = zio->io_error;
+       mc->mc_tried = 1;
+       mc->mc_skipped = 0;
+}
+
+/*
+ * 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.
+ */
+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;
+
+       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;
+               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;
+       }
+
+       /*
+        * 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)
+                       return (c);
+
+       /*
+        * Every child failed.  There's no place left to look.
+        */
+       return (-1);
+}
+
+static void
+vdev_mirror_io_start(zio_t *zio)
+{
+       mirror_map_t *mm;
+       mirror_child_t *mc;
+       int c, children;
+
+       mm = vdev_mirror_map_alloc(zio);
+
+       if (zio->io_type == ZIO_TYPE_READ) {
+               if ((zio->io_flags & ZIO_FLAG_SCRUB) && !mm->mm_replacing) {
+                       /*
+                        * For scrubbing reads we need to allocate a read
+                        * buffer for each child and issue reads to all
+                        * children.  If any child succeeds, it will copy its
+                        * data into zio->io_data in vdev_mirror_scrub_done.
+                        */
+                       for (c = 0; c < mm->mm_children; c++) {
+                               mc = &mm->mm_child[c];
+                               zio_nowait(zio_vdev_child_io(zio, zio->io_bp,
+                                   mc->mc_vd, mc->mc_offset,
+                                   zio_buf_alloc(zio->io_size), zio->io_size,
+                                   zio->io_type, zio->io_priority, 0,
+                                   vdev_mirror_scrub_done, mc));
+                       }
+                       zio_execute(zio);
+                       return;
+               }
+               /*
+                * For normal reads just pick one child.
+                */
+               c = vdev_mirror_child_select(zio);
+               children = (c >= 0);
+       } else {
+               ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+
+               /*
+                * Writes go to all children.
+                */
+               c = 0;
+               children = mm->mm_children;
+       }
+
+       while (children--) {
+               mc = &mm->mm_child[c];
+               zio_nowait(zio_vdev_child_io(zio, zio->io_bp,
+                   mc->mc_vd, mc->mc_offset, zio->io_data, zio->io_size,
+                   zio->io_type, zio->io_priority, 0,
+                   vdev_mirror_child_done, mc));
+               c++;
+       }
+
+       zio_execute(zio);
+}
+
+static int
+vdev_mirror_worst_error(mirror_map_t *mm)
+{
+       int c, error[2] = { 0, 0 };
+
+       for (c = 0; c < mm->mm_children; c++) {
+               mirror_child_t *mc = &mm->mm_child[c];
+               int s = mc->mc_speculative;
+               error[s] = zio_worst_error(error[s], mc->mc_error);
+       }
+
+       return (error[0] ? error[0] : error[1]);
+}
+
+static void
+vdev_mirror_io_done(zio_t *zio)
+{
+       mirror_map_t *mm = zio->io_vsd;
+       mirror_child_t *mc;
+       int c;
+       int good_copies = 0;
+       int unexpected_errors = 0;
+
+       for (c = 0; c < mm->mm_children; c++) {
+               mc = &mm->mm_child[c];
+
+               if (mc->mc_error) {
+                       if (!mc->mc_skipped)
+                               unexpected_errors++;
+               } else if (mc->mc_tried) {
+                       good_copies++;
+               }
+       }
+
+       if (zio->io_type == ZIO_TYPE_WRITE) {
+               /*
+                * XXX -- for now, treat partial writes as success.
+                *
+                * Now that we support write reallocation, it would be better
+                * to treat partial failure as real failure unless there are
+                * no non-degraded top-level vdevs left, and not update DTLs
+                * if we intend to reallocate.
+                */
+               /* XXPOLICY */
+               if (good_copies != mm->mm_children) {
+                       /*
+                        * Always require at least one good copy.
+                        *
+                        * For ditto blocks (io_vd == NULL), require
+                        * all copies to be good.
+                        *
+                        * XXX -- for replacing vdevs, there's no great answer.
+                        * If the old device is really dead, we may not even
+                        * be able to access it -- so we only want to
+                        * require good writes to the new device.  But if
+                        * the new device turns out to be flaky, we want
+                        * to be able to detach it -- which requires all
+                        * writes to the old device to have succeeded.
+                        */
+                       if (good_copies == 0 || zio->io_vd == NULL)
+                               zio->io_error = vdev_mirror_worst_error(mm);
+               }
+               return;
+       }
+
+       ASSERT(zio->io_type == ZIO_TYPE_READ);
+
+       /*
+        * If we don't have a good copy yet, keep trying other children.
+        */
+       /* XXPOLICY */
+       if (good_copies == 0 && (c = vdev_mirror_child_select(zio)) != -1) {
+               ASSERT(c >= 0 && c < mm->mm_children);
+               mc = &mm->mm_child[c];
+               zio_vdev_io_redone(zio);
+               zio_nowait(zio_vdev_child_io(zio, zio->io_bp,
+                   mc->mc_vd, mc->mc_offset, zio->io_data, zio->io_size,
+                   ZIO_TYPE_READ, zio->io_priority, 0,
+                   vdev_mirror_child_done, mc));
+               return;
+       }
+
+       /* XXPOLICY */
+       if (good_copies == 0) {
+               zio->io_error = vdev_mirror_worst_error(mm);
+               ASSERT(zio->io_error != 0);
+       }
+
+       if (good_copies && spa_writeable(zio->io_spa) &&
+           (unexpected_errors ||
+           (zio->io_flags & ZIO_FLAG_RESILVER) ||
+           ((zio->io_flags & ZIO_FLAG_SCRUB) && mm->mm_replacing))) {
+               /*
+                * Use the good data we have in hand to repair damaged children.
+                */
+               for (c = 0; c < mm->mm_children; c++) {
+                       /*
+                        * Don't rewrite known good children.
+                        * Not only is it unnecessary, it could
+                        * actually be harmful: if the system lost
+                        * power while rewriting the only good copy,
+                        * there would be no good copies left!
+                        */
+                       mc = &mm->mm_child[c];
+
+                       if (mc->mc_error == 0) {
+                               if (mc->mc_tried)
+                                       continue;
+                               if (!(zio->io_flags & ZIO_FLAG_SCRUB) &&
+                                   !vdev_dtl_contains(mc->mc_vd, DTL_PARTIAL,
+                                   zio->io_txg, 1))
+                                       continue;
+                               mc->mc_error = SET_ERROR(ESTALE);
+                       }
+
+                       zio_nowait(zio_vdev_child_io(zio, zio->io_bp,
+                           mc->mc_vd, mc->mc_offset,
+                           zio->io_data, zio->io_size,
+                           ZIO_TYPE_WRITE, ZIO_PRIORITY_ASYNC_WRITE,
+                           ZIO_FLAG_IO_REPAIR | (unexpected_errors ?
+                           ZIO_FLAG_SELF_HEAL : 0), NULL, NULL));
+               }
+       }
+}
+
+static void
+vdev_mirror_state_change(vdev_t *vd, int faulted, int degraded)
+{
+       if (faulted == vd->vdev_children)
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_NO_REPLICAS);
+       else if (degraded + faulted != 0)
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_DEGRADED, VDEV_AUX_NONE);
+       else
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_HEALTHY, VDEV_AUX_NONE);
+}
+
+vdev_ops_t vdev_mirror_ops = {
+       vdev_mirror_open,
+       vdev_mirror_close,
+       vdev_default_asize,
+       vdev_mirror_io_start,
+       vdev_mirror_io_done,
+       vdev_mirror_state_change,
+       NULL,
+       NULL,
+       VDEV_TYPE_MIRROR,       /* name of this vdev type */
+       B_FALSE                 /* not a leaf vdev */
+};
+
+vdev_ops_t vdev_replacing_ops = {
+       vdev_mirror_open,
+       vdev_mirror_close,
+       vdev_default_asize,
+       vdev_mirror_io_start,
+       vdev_mirror_io_done,
+       vdev_mirror_state_change,
+       NULL,
+       NULL,
+       VDEV_TYPE_REPLACING,    /* name of this vdev type */
+       B_FALSE                 /* not a leaf vdev */
+};
+
+vdev_ops_t vdev_spare_ops = {
+       vdev_mirror_open,
+       vdev_mirror_close,
+       vdev_default_asize,
+       vdev_mirror_io_start,
+       vdev_mirror_io_done,
+       vdev_mirror_state_change,
+       NULL,
+       NULL,
+       VDEV_TYPE_SPARE,        /* name of this vdev type */
+       B_FALSE                 /* not a leaf vdev */
+};
+
+#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");
+#endif
diff --git a/zfs/module/zfs/vdev_missing.c b/zfs/module/zfs/vdev_missing.c
new file mode 100644 (file)
index 0000000..2287573
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * The 'missing' vdev is a special vdev type used only during import.  It
+ * signifies a placeholder in the root vdev for some vdev that we know is
+ * missing.  We pass it down to the kernel to allow the rest of the
+ * configuration to parsed and an attempt made to open all available devices.
+ * Because its GUID is always 0, we know that the guid sum will mismatch and we
+ * won't be able to open the pool anyway.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/vdev_impl.h>
+#include <sys/fs/zfs.h>
+#include <sys/zio.h>
+
+/* ARGSUSED */
+static int
+vdev_missing_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
+    uint64_t *ashift)
+{
+       /*
+        * Really this should just fail.  But then the root vdev will be in the
+        * faulted state with VDEV_AUX_NO_REPLICAS, when what we really want is
+        * VDEV_AUX_BAD_GUID_SUM.  So we pretend to succeed, knowing that we
+        * will fail the GUID sum check before ever trying to open the pool.
+        */
+       *psize = 0;
+       *max_psize = 0;
+       *ashift = 0;
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+vdev_missing_close(vdev_t *vd)
+{
+}
+
+/* ARGSUSED */
+static void
+vdev_missing_io_start(zio_t *zio)
+{
+       zio->io_error = SET_ERROR(ENOTSUP);
+       zio_execute(zio);
+}
+
+/* ARGSUSED */
+static void
+vdev_missing_io_done(zio_t *zio)
+{
+}
+
+vdev_ops_t vdev_missing_ops = {
+       vdev_missing_open,
+       vdev_missing_close,
+       vdev_default_asize,
+       vdev_missing_io_start,
+       vdev_missing_io_done,
+       NULL,
+       NULL,
+       NULL,
+       VDEV_TYPE_MISSING,      /* name of this vdev type */
+       B_TRUE                  /* leaf vdev */
+};
+
+vdev_ops_t vdev_hole_ops = {
+       vdev_missing_open,
+       vdev_missing_close,
+       vdev_default_asize,
+       vdev_missing_io_start,
+       vdev_missing_io_done,
+       NULL,
+       NULL,
+       NULL,
+       VDEV_TYPE_HOLE,         /* name of this vdev type */
+       B_TRUE                  /* leaf vdev */
+};
diff --git a/zfs/module/zfs/vdev_queue.c b/zfs/module/zfs/vdev_queue.c
new file mode 100644 (file)
index 0000000..4ed62f9
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/vdev_impl.h>
+#include <sys/spa_impl.h>
+#include <sys/zio.h>
+#include <sys/avl.h>
+#include <sys/dsl_pool.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/kstat.h>
+
+/*
+ * ZFS I/O Scheduler
+ * ---------------
+ *
+ * ZFS issues I/O operations to leaf vdevs to satisfy and complete zios.  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. 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 zfs_vdev_max_active, in which case no
+ * further i/os will be issued regardless of whether all per-queue
+ * minimums have been met.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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 (see txg.c). 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 (see dsl_pool.c). 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.
+ *
+ * Async Writes
+ *
+ * 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.
+ *
+ *        |                   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
+ *
+ * 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.
+ *
+ * Ideally, the amount of dirty data on a busy pool will stay in the sloped
+ * part of the function between zfs_vdev_async_write_active_min_dirty_percent
+ * and zfs_vdev_async_write_active_max_dirty_percent. 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 (see dmu_tx_delay() for details).
+ */
+
+/*
+ * 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.
+ */
+uint32_t zfs_vdev_max_active = 1000;
+
+/*
+ * Per-queue limits on the number of i/os active to each device.  If the
+ * number of active i/os is < zfs_vdev_max_active, then the min_active comes
+ * into play. We will send min_active from each queue, and then select from
+ * queues in the order defined by zio_priority_t.
+ *
+ * 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.
+ *
+ * The ratio of the queues' max_actives determines the balance of performance
+ * between reads, writes, and scrubs.  E.g., increasing
+ * zfs_vdev_scrub_max_active will cause the scrub or resilver to complete
+ * more quickly, but reads and writes to have higher latency and lower
+ * throughput.
+ */
+uint32_t zfs_vdev_sync_read_min_active = 10;
+uint32_t zfs_vdev_sync_read_max_active = 10;
+uint32_t zfs_vdev_sync_write_min_active = 10;
+uint32_t zfs_vdev_sync_write_max_active = 10;
+uint32_t zfs_vdev_async_read_min_active = 1;
+uint32_t zfs_vdev_async_read_max_active = 3;
+uint32_t zfs_vdev_async_write_min_active = 1;
+uint32_t zfs_vdev_async_write_max_active = 10;
+uint32_t zfs_vdev_scrub_min_active = 1;
+uint32_t zfs_vdev_scrub_max_active = 2;
+
+/*
+ * When the pool has less than zfs_vdev_async_write_active_min_dirty_percent
+ * dirty data, use zfs_vdev_async_write_min_active.  When it has more than
+ * zfs_vdev_async_write_active_max_dirty_percent, use
+ * zfs_vdev_async_write_max_active. The value is linearly interpolated
+ * between min and max.
+ */
+int zfs_vdev_async_write_active_min_dirty_percent = 30;
+int zfs_vdev_async_write_active_max_dirty_percent = 60;
+
+/*
+ * To reduce IOPs, we aggregate small adjacent I/Os into one large I/O.
+ * For read I/Os, we also aggregate across small adjacency gaps; for writes
+ * we include spans of optional I/Os to aid aggregation at the disk even when
+ * they aren't able to help us aggregate at this level.
+ */
+int zfs_vdev_aggregation_limit = SPA_OLD_MAXBLOCKSIZE;
+int zfs_vdev_read_gap_limit = 32 << 10;
+int zfs_vdev_write_gap_limit = 4 << 10;
+
+int
+vdev_queue_offset_compare(const void *x1, const void *x2)
+{
+       const zio_t *z1 = x1;
+       const zio_t *z2 = x2;
+
+       if (z1->io_offset < z2->io_offset)
+               return (-1);
+       if (z1->io_offset > z2->io_offset)
+               return (1);
+
+       if (z1 < z2)
+               return (-1);
+       if (z1 > z2)
+               return (1);
+
+       return (0);
+}
+
+static inline avl_tree_t *
+vdev_queue_class_tree(vdev_queue_t *vq, zio_priority_t p)
+{
+       return (&vq->vq_class[p].vqc_queued_tree);
+}
+
+static inline avl_tree_t *
+vdev_queue_type_tree(vdev_queue_t *vq, zio_type_t t)
+{
+       ASSERT(t == ZIO_TYPE_READ || t == ZIO_TYPE_WRITE);
+       if (t == ZIO_TYPE_READ)
+               return (&vq->vq_read_offset_tree);
+       else
+               return (&vq->vq_write_offset_tree);
+}
+
+int
+vdev_queue_timestamp_compare(const void *x1, const void *x2)
+{
+       const zio_t *z1 = x1;
+       const zio_t *z2 = x2;
+
+       if (z1->io_timestamp < z2->io_timestamp)
+               return (-1);
+       if (z1->io_timestamp > z2->io_timestamp)
+               return (1);
+
+       if (z1 < z2)
+               return (-1);
+       if (z1 > z2)
+               return (1);
+
+       return (0);
+}
+
+static int
+vdev_queue_class_min_active(zio_priority_t p)
+{
+       switch (p) {
+       case ZIO_PRIORITY_SYNC_READ:
+               return (zfs_vdev_sync_read_min_active);
+       case ZIO_PRIORITY_SYNC_WRITE:
+               return (zfs_vdev_sync_write_min_active);
+       case ZIO_PRIORITY_ASYNC_READ:
+               return (zfs_vdev_async_read_min_active);
+       case ZIO_PRIORITY_ASYNC_WRITE:
+               return (zfs_vdev_async_write_min_active);
+       case ZIO_PRIORITY_SCRUB:
+               return (zfs_vdev_scrub_min_active);
+       default:
+               panic("invalid priority %u", p);
+               return (0);
+       }
+}
+
+static int
+vdev_queue_max_async_writes(spa_t *spa)
+{
+       int writes;
+       uint64_t dirty = 0;
+       dsl_pool_t *dp = spa_get_dsl(spa);
+       uint64_t min_bytes = zfs_dirty_data_max *
+           zfs_vdev_async_write_active_min_dirty_percent / 100;
+       uint64_t max_bytes = zfs_dirty_data_max *
+           zfs_vdev_async_write_active_max_dirty_percent / 100;
+
+       /*
+        * Async writes may occur before the assignment of the spa's
+        * dsl_pool_t if a self-healing zio is issued prior to the
+        * completion of dmu_objset_open_impl().
+        */
+       if (dp == NULL)
+               return (zfs_vdev_async_write_max_active);
+
+       /*
+        * Sync tasks correspond to interactive user actions. To reduce the
+        * execution time of those actions we push data out as fast as possible.
+        */
+       if (spa_has_pending_synctask(spa))
+               return (zfs_vdev_async_write_max_active);
+
+       dirty = dp->dp_dirty_total;
+       if (dirty < min_bytes)
+               return (zfs_vdev_async_write_min_active);
+       if (dirty > max_bytes)
+               return (zfs_vdev_async_write_max_active);
+
+       /*
+        * linear interpolation:
+        * slope = (max_writes - min_writes) / (max_bytes - min_bytes)
+        * move right by min_bytes
+        * move up by min_writes
+        */
+       writes = (dirty - min_bytes) *
+           (zfs_vdev_async_write_max_active -
+           zfs_vdev_async_write_min_active) /
+           (max_bytes - min_bytes) +
+           zfs_vdev_async_write_min_active;
+       ASSERT3U(writes, >=, zfs_vdev_async_write_min_active);
+       ASSERT3U(writes, <=, zfs_vdev_async_write_max_active);
+       return (writes);
+}
+
+static int
+vdev_queue_class_max_active(spa_t *spa, zio_priority_t p)
+{
+       switch (p) {
+       case ZIO_PRIORITY_SYNC_READ:
+               return (zfs_vdev_sync_read_max_active);
+       case ZIO_PRIORITY_SYNC_WRITE:
+               return (zfs_vdev_sync_write_max_active);
+       case ZIO_PRIORITY_ASYNC_READ:
+               return (zfs_vdev_async_read_max_active);
+       case ZIO_PRIORITY_ASYNC_WRITE:
+               return (vdev_queue_max_async_writes(spa));
+       case ZIO_PRIORITY_SCRUB:
+               return (zfs_vdev_scrub_max_active);
+       default:
+               panic("invalid priority %u", p);
+               return (0);
+       }
+}
+
+/*
+ * Return the i/o class to issue from, or ZIO_PRIORITY_MAX_QUEUEABLE if
+ * there is no eligible class.
+ */
+static zio_priority_t
+vdev_queue_class_to_issue(vdev_queue_t *vq)
+{
+       spa_t *spa = vq->vq_vdev->vdev_spa;
+       zio_priority_t p;
+
+       if (avl_numnodes(&vq->vq_active_tree) >= zfs_vdev_max_active)
+               return (ZIO_PRIORITY_NUM_QUEUEABLE);
+
+       /* find a queue that has not reached its minimum # outstanding i/os */
+       for (p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++) {
+               if (avl_numnodes(vdev_queue_class_tree(vq, p)) > 0 &&
+                   vq->vq_class[p].vqc_active <
+                   vdev_queue_class_min_active(p))
+                       return (p);
+       }
+
+       /*
+        * If we haven't found a queue, look for one that hasn't reached its
+        * maximum # outstanding i/os.
+        */
+       for (p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++) {
+               if (avl_numnodes(vdev_queue_class_tree(vq, p)) > 0 &&
+                   vq->vq_class[p].vqc_active <
+                   vdev_queue_class_max_active(spa, p))
+                       return (p);
+       }
+
+       /* No eligible queued i/os */
+       return (ZIO_PRIORITY_NUM_QUEUEABLE);
+}
+
+void
+vdev_queue_init(vdev_t *vd)
+{
+       vdev_queue_t *vq = &vd->vdev_queue;
+       zio_priority_t p;
+
+       mutex_init(&vq->vq_lock, NULL, MUTEX_DEFAULT, NULL);
+       vq->vq_vdev = vd;
+       taskq_init_ent(&vd->vdev_queue.vq_io_search.io_tqent);
+
+       avl_create(&vq->vq_active_tree, vdev_queue_offset_compare,
+           sizeof (zio_t), offsetof(struct zio, io_queue_node));
+       avl_create(vdev_queue_type_tree(vq, ZIO_TYPE_READ),
+               vdev_queue_offset_compare, sizeof (zio_t),
+               offsetof(struct zio, io_offset_node));
+       avl_create(vdev_queue_type_tree(vq, ZIO_TYPE_WRITE),
+               vdev_queue_offset_compare, sizeof (zio_t),
+               offsetof(struct zio, io_offset_node));
+
+       for (p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++) {
+               int (*compfn) (const void *, const void *);
+
+               /*
+                * The synchronous i/o queues are dispatched in FIFO rather
+                * than LBA order. This provides more consistent latency for
+                * these i/os.
+                */
+               if (p == ZIO_PRIORITY_SYNC_READ || p == ZIO_PRIORITY_SYNC_WRITE)
+                       compfn = vdev_queue_timestamp_compare;
+               else
+                       compfn = vdev_queue_offset_compare;
+               avl_create(vdev_queue_class_tree(vq, p), compfn,
+                       sizeof (zio_t), offsetof(struct zio, io_queue_node));
+       }
+}
+
+void
+vdev_queue_fini(vdev_t *vd)
+{
+       vdev_queue_t *vq = &vd->vdev_queue;
+       zio_priority_t p;
+
+       for (p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++)
+               avl_destroy(vdev_queue_class_tree(vq, p));
+       avl_destroy(&vq->vq_active_tree);
+       avl_destroy(vdev_queue_type_tree(vq, ZIO_TYPE_READ));
+       avl_destroy(vdev_queue_type_tree(vq, ZIO_TYPE_WRITE));
+
+       mutex_destroy(&vq->vq_lock);
+}
+
+static void
+vdev_queue_io_add(vdev_queue_t *vq, zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+       avl_add(vdev_queue_class_tree(vq, zio->io_priority), zio);
+       avl_add(vdev_queue_type_tree(vq, zio->io_type), zio);
+
+       if (ssh->kstat != NULL) {
+               mutex_enter(&ssh->lock);
+               kstat_waitq_enter(ssh->kstat->ks_data);
+               mutex_exit(&ssh->lock);
+       }
+}
+
+static void
+vdev_queue_io_remove(vdev_queue_t *vq, zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+       avl_remove(vdev_queue_class_tree(vq, zio->io_priority), zio);
+       avl_remove(vdev_queue_type_tree(vq, zio->io_type), zio);
+
+       if (ssh->kstat != NULL) {
+               mutex_enter(&ssh->lock);
+               kstat_waitq_exit(ssh->kstat->ks_data);
+               mutex_exit(&ssh->lock);
+       }
+}
+
+static void
+vdev_queue_pending_add(vdev_queue_t *vq, zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       ASSERT(MUTEX_HELD(&vq->vq_lock));
+       ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+       vq->vq_class[zio->io_priority].vqc_active++;
+       avl_add(&vq->vq_active_tree, zio);
+
+       if (ssh->kstat != NULL) {
+               mutex_enter(&ssh->lock);
+               kstat_runq_enter(ssh->kstat->ks_data);
+               mutex_exit(&ssh->lock);
+       }
+}
+
+static void
+vdev_queue_pending_remove(vdev_queue_t *vq, zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+
+       ASSERT(MUTEX_HELD(&vq->vq_lock));
+       ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+       vq->vq_class[zio->io_priority].vqc_active--;
+       avl_remove(&vq->vq_active_tree, zio);
+
+       if (ssh->kstat != NULL) {
+               kstat_io_t *ksio = ssh->kstat->ks_data;
+
+               mutex_enter(&ssh->lock);
+               kstat_runq_exit(ksio);
+               if (zio->io_type == ZIO_TYPE_READ) {
+                       ksio->reads++;
+                       ksio->nread += zio->io_size;
+               } else if (zio->io_type == ZIO_TYPE_WRITE) {
+                       ksio->writes++;
+                       ksio->nwritten += zio->io_size;
+               }
+               mutex_exit(&ssh->lock);
+       }
+}
+
+static void
+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) {
+                       bcopy((char *)aio->io_data + (pio->io_offset -
+                           aio->io_offset), pio->io_data, pio->io_size);
+               }
+       }
+
+       zio_buf_free(aio->io_data, aio->io_size);
+}
+
+/*
+ * Compute the range spanned by two i/os, which is the endpoint of the last
+ * (lio->io_offset + lio->io_size) minus start of the first (fio->io_offset).
+ * Conveniently, the gap between fio and lio is given by -IO_SPAN(lio, fio);
+ * thus fio and lio are adjacent if and only if IO_SPAN(lio, fio) == 0.
+ */
+#define        IO_SPAN(fio, lio) ((lio)->io_offset + (lio)->io_size - (fio)->io_offset)
+#define        IO_GAP(fio, lio) (-IO_SPAN(lio, fio))
+
+static zio_t *
+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;
+       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);
+
+       /*
+        * 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);
+
+       first = last = zio;
+
+       if (zio->io_type == ZIO_TYPE_READ)
+               maxgap = zfs_vdev_read_gap_limit;
+
+       /*
+        * We can aggregate I/Os that are sufficiently adjacent and of
+        * the same flavor, as expressed by the AGG_INHERIT flags.
+        * The latter requirement is necessary so that certain
+        * attributes of the I/O, such as whether it's a normal I/O
+        * or a scrub/resilver, can be preserved in the aggregate.
+        * We can include optional I/Os, but don't allow them
+        * to begin a range as they add no benefit in that situation.
+        */
+
+       /*
+        * We keep track of the last non-optional I/O.
+        */
+       mandatory = (first->io_flags & ZIO_FLAG_OPTIONAL) ? NULL : first;
+
+       /*
+        * Walk backwards through sufficiently contiguous I/Os
+        * recording the last non-option I/O.
+        */
+       while ((dio = AVL_PREV(t, first)) != NULL &&
+           (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
+           IO_SPAN(dio, last) <= zfs_vdev_aggregation_limit &&
+           IO_GAP(dio, first) <= maxgap) {
+               first = dio;
+               if (mandatory == NULL && !(first->io_flags & ZIO_FLAG_OPTIONAL))
+                       mandatory = first;
+       }
+
+       /*
+        * Skip any initial optional I/Os.
+        */
+       while ((first->io_flags & ZIO_FLAG_OPTIONAL) && first != last) {
+               first = AVL_NEXT(t, first);
+               ASSERT(first != NULL);
+       }
+
+
+       /*
+        * Walk forward through sufficiently contiguous I/Os.
+        */
+       while ((dio = AVL_NEXT(t, last)) != NULL &&
+           (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
+           IO_SPAN(first, dio) <= zfs_vdev_aggregation_limit &&
+           IO_GAP(last, dio) <= maxgap) {
+               last = dio;
+               if (!(last->io_flags & ZIO_FLAG_OPTIONAL))
+                       mandatory = last;
+       }
+
+       /*
+        * Now that we've established the range of the I/O aggregation
+        * we must decide what to do with trailing optional I/Os.
+        * For reads, there's nothing to do. While we are unable to
+        * aggregate further, it's possible that a trailing optional
+        * I/O would allow the underlying device to aggregate with
+        * subsequent I/Os. We must therefore determine if the next
+        * non-optional I/O is close enough to make aggregation
+        * worthwhile.
+        */
+       if (zio->io_type == ZIO_TYPE_WRITE && mandatory != NULL) {
+               zio_t *nio = last;
+               while ((dio = AVL_NEXT(t, nio)) != NULL &&
+                   IO_GAP(nio, dio) == 0 &&
+                   IO_GAP(mandatory, dio) <= zfs_vdev_write_gap_limit) {
+                       nio = dio;
+                       if (!(nio->io_flags & ZIO_FLAG_OPTIONAL)) {
+                               stretch = B_TRUE;
+                               break;
+                       }
+               }
+       }
+
+       if (stretch) {
+               /* This may be a no-op. */
+               dio = AVL_NEXT(t, last);
+               dio->io_flags &= ~ZIO_FLAG_OPTIONAL;
+       } else {
+               while (last != mandatory && last != first) {
+                       ASSERT(last->io_flags & ZIO_FLAG_OPTIONAL);
+                       last = AVL_PREV(t, last);
+                       ASSERT(last != NULL);
+               }
+       }
+
+       if (first == last)
+               return (NULL);
+
+       size = IO_SPAN(first, last);
+       ASSERT3U(size, <=, zfs_vdev_aggregation_limit);
+
+       buf = zio_buf_alloc_flags(size, KM_NOSLEEP);
+       if (buf == NULL)
+               return (NULL);
+
+       aio = zio_vdev_delegated_io(first->io_vd, first->io_offset,
+           buf, size, first->io_type, zio->io_priority,
+           flags | ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE,
+           vdev_queue_agg_io_done, NULL);
+       aio->io_timestamp = first->io_timestamp;
+
+       nio = first;
+       do {
+               dio = nio;
+               nio = AVL_NEXT(t, dio);
+               ASSERT3U(dio->io_type, ==, aio->io_type);
+
+               if (dio->io_flags & ZIO_FLAG_NODATA) {
+                       ASSERT3U(dio->io_type, ==, ZIO_TYPE_WRITE);
+                       bzero((char *)aio->io_data + (dio->io_offset -
+                           aio->io_offset), dio->io_size);
+               } else if (dio->io_type == ZIO_TYPE_WRITE) {
+                       bcopy(dio->io_data, (char *)aio->io_data +
+                           (dio->io_offset - aio->io_offset),
+                           dio->io_size);
+               }
+
+               zio_add_child(dio, aio);
+               vdev_queue_io_remove(vq, dio);
+               zio_vdev_io_bypass(dio);
+               zio_execute(dio);
+       } while (dio != last);
+
+       return (aio);
+}
+
+static zio_t *
+vdev_queue_io_to_issue(vdev_queue_t *vq)
+{
+       zio_t *zio, *aio;
+       zio_priority_t p;
+       avl_index_t idx;
+       avl_tree_t *tree;
+
+again:
+       ASSERT(MUTEX_HELD(&vq->vq_lock));
+
+       p = vdev_queue_class_to_issue(vq);
+
+       if (p == ZIO_PRIORITY_NUM_QUEUEABLE) {
+               /* No eligible queued i/os */
+               return (NULL);
+       }
+
+       /*
+        * For LBA-ordered queues (async / scrub), issue the i/o which follows
+        * the most recently issued i/o in LBA (offset) order.
+        *
+        * For FIFO queues (sync), issue the i/o with the lowest timestamp.
+        */
+       tree = vdev_queue_class_tree(vq, p);
+       vq->vq_io_search.io_timestamp = 0;
+       vq->vq_io_search.io_offset = vq->vq_last_offset + 1;
+       VERIFY3P(avl_find(tree, &vq->vq_io_search,
+           &idx), ==, NULL);
+       zio = avl_nearest(tree, idx, AVL_AFTER);
+       if (zio == NULL)
+               zio = avl_first(tree);
+       ASSERT3U(zio->io_priority, ==, p);
+
+       aio = vdev_queue_aggregate(vq, zio);
+       if (aio != NULL)
+               zio = aio;
+       else
+               vdev_queue_io_remove(vq, zio);
+
+       /*
+        * If the I/O is or was optional and therefore has no data, we need to
+        * simply discard it. We need to drop the vdev queue's lock to avoid a
+        * deadlock that we could encounter since this I/O will complete
+        * immediately.
+        */
+       if (zio->io_flags & ZIO_FLAG_NODATA) {
+               mutex_exit(&vq->vq_lock);
+               zio_vdev_io_bypass(zio);
+               zio_execute(zio);
+               mutex_enter(&vq->vq_lock);
+               goto again;
+       }
+
+       vdev_queue_pending_add(vq, zio);
+       vq->vq_last_offset = zio->io_offset;
+
+       return (zio);
+}
+
+zio_t *
+vdev_queue_io(zio_t *zio)
+{
+       vdev_queue_t *vq = &zio->io_vd->vdev_queue;
+       zio_t *nio;
+
+       if (zio->io_flags & ZIO_FLAG_DONT_QUEUE)
+               return (zio);
+
+       /*
+        * Children i/os inherent their parent's priority, which might
+        * not match the child's i/o type.  Fix it up here.
+        */
+       if (zio->io_type == ZIO_TYPE_READ) {
+               if (zio->io_priority != ZIO_PRIORITY_SYNC_READ &&
+                   zio->io_priority != ZIO_PRIORITY_ASYNC_READ &&
+                   zio->io_priority != ZIO_PRIORITY_SCRUB)
+                       zio->io_priority = ZIO_PRIORITY_ASYNC_READ;
+       } else {
+               ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+               if (zio->io_priority != ZIO_PRIORITY_SYNC_WRITE &&
+                   zio->io_priority != ZIO_PRIORITY_ASYNC_WRITE)
+                       zio->io_priority = ZIO_PRIORITY_ASYNC_WRITE;
+       }
+
+       zio->io_flags |= ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE;
+
+       mutex_enter(&vq->vq_lock);
+       zio->io_timestamp = gethrtime();
+       vdev_queue_io_add(vq, zio);
+       nio = vdev_queue_io_to_issue(vq);
+       mutex_exit(&vq->vq_lock);
+
+       if (nio == NULL)
+               return (NULL);
+
+       if (nio->io_done == vdev_queue_agg_io_done) {
+               zio_nowait(nio);
+               return (NULL);
+       }
+
+       return (nio);
+}
+
+void
+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);
+
+       zio->io_delta = gethrtime() - zio->io_timestamp;
+       vq->vq_io_complete_ts = gethrtime();
+       vq->vq_io_delta_ts = vq->vq_io_complete_ts - zio->io_timestamp;
+
+       while ((nio = vdev_queue_io_to_issue(vq)) != NULL) {
+               mutex_exit(&vq->vq_lock);
+               if (nio->io_done == vdev_queue_agg_io_done) {
+                       zio_nowait(nio);
+               } else {
+                       zio_vdev_io_reissue(nio);
+                       zio_execute(nio);
+               }
+               mutex_enter(&vq->vq_lock);
+       }
+
+       mutex_exit(&vq->vq_lock);
+}
+
+#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");
+
+module_param(zfs_vdev_read_gap_limit, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_read_gap_limit, "Aggregate read I/O over gap");
+
+module_param(zfs_vdev_write_gap_limit, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_write_gap_limit, "Aggregate write I/O over gap");
+
+module_param(zfs_vdev_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_max_active, "Maximum number of active I/Os per vdev");
+
+module_param(zfs_vdev_async_write_active_max_dirty_percent, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_async_write_active_max_dirty_percent,
+       "Async write concurrency max threshold");
+
+module_param(zfs_vdev_async_write_active_min_dirty_percent, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_async_write_active_min_dirty_percent,
+       "Async write concurrency min threshold");
+
+module_param(zfs_vdev_async_read_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_async_read_max_active,
+       "Max active async read I/Os per vdev");
+
+module_param(zfs_vdev_async_read_min_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_async_read_min_active,
+       "Min active async read I/Os per vdev");
+
+module_param(zfs_vdev_async_write_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_async_write_max_active,
+       "Max active async write I/Os per vdev");
+
+module_param(zfs_vdev_async_write_min_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_async_write_min_active,
+       "Min active async write I/Os per vdev");
+
+module_param(zfs_vdev_scrub_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_scrub_max_active, "Max active scrub I/Os per vdev");
+
+module_param(zfs_vdev_scrub_min_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_scrub_min_active, "Min active scrub I/Os per vdev");
+
+module_param(zfs_vdev_sync_read_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_sync_read_max_active,
+       "Max active sync read I/Os per vdev");
+
+module_param(zfs_vdev_sync_read_min_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_sync_read_min_active,
+       "Min active sync read I/Os per vdev");
+
+module_param(zfs_vdev_sync_write_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_sync_write_max_active,
+       "Max active sync write I/Os per vdev");
+
+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");
+#endif
diff --git a/zfs/module/zfs/vdev_raidz.c b/zfs/module/zfs/vdev_raidz.c
new file mode 100644 (file)
index 0000000..b947909
--- /dev/null
@@ -0,0 +1,2222 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/zio_checksum.h>
+#include <sys/fs/zfs.h>
+#include <sys/fm/fs/zfs.h>
+
+/*
+ * Virtual device vector for RAID-Z.
+ *
+ * This vdev supports single, double, and triple parity. For single parity,
+ * we use a simple XOR of all the data columns. For double or triple parity,
+ * we use a special case of Reed-Solomon coding. This extends the
+ * technique described in "The mathematics of RAID-6" by H. Peter Anvin by
+ * drawing on the system described in "A Tutorial on Reed-Solomon Coding for
+ * Fault-Tolerance in RAID-like Systems" by James S. Plank on which the
+ * former is also based. The latter is designed to provide higher performance
+ * for writes.
+ *
+ * Note that the Plank paper claimed to support arbitrary N+M, but was then
+ * amended six years later identifying a critical flaw that invalidates its
+ * claims. Nevertheless, the technique can be adapted to work for up to
+ * triple parity. For additional parity, the amendment "Note: Correction to
+ * the 1997 Tutorial on Reed-Solomon Coding" by James S. Plank and Ying Ding
+ * is viable, but the additional complexity means that write performance will
+ * suffer.
+ *
+ * All of the methods above operate on a Galois field, defined over the
+ * integers mod 2^N. In our case we choose N=8 for GF(8) so that all elements
+ * can be expressed with a single byte. Briefly, the operations on the
+ * field are defined as follows:
+ *
+ *   o addition (+) is represented by a bitwise XOR
+ *   o subtraction (-) is therefore identical to addition: A + B = A - B
+ *   o multiplication of A by 2 is defined by the following bitwise expression:
+ *
+ *     (A * 2)_7 = A_6
+ *     (A * 2)_6 = A_5
+ *     (A * 2)_5 = A_4
+ *     (A * 2)_4 = A_3 + A_7
+ *     (A * 2)_3 = A_2 + A_7
+ *     (A * 2)_2 = A_1 + A_7
+ *     (A * 2)_1 = A_0
+ *     (A * 2)_0 = A_7
+ *
+ * In C, multiplying by 2 is therefore ((a << 1) ^ ((a & 0x80) ? 0x1d : 0)).
+ * As an aside, this multiplication is derived from the error correcting
+ * primitive polynomial x^8 + x^4 + x^3 + x^2 + 1.
+ *
+ * Observe that any number in the field (except for 0) can be expressed as a
+ * power of 2 -- a generator for the field. We store a table of the powers of
+ * 2 and logs base 2 for quick look ups, and exploit the fact that A * B can
+ * be rewritten as 2^(log_2(A) + log_2(B)) (where '+' is normal addition rather
+ * than field addition). The inverse of a field element A (A^-1) is therefore
+ * A ^ (255 - 1) = A^254.
+ *
+ * The up-to-three parity columns, P, Q, R over several data columns,
+ * D_0, ... D_n-1, can be expressed by field operations:
+ *
+ *     P = D_0 + D_1 + ... + D_n-2 + D_n-1
+ *     Q = 2^n-1 * D_0 + 2^n-2 * D_1 + ... + 2^1 * D_n-2 + 2^0 * D_n-1
+ *       = ((...((D_0) * 2 + D_1) * 2 + ...) * 2 + D_n-2) * 2 + D_n-1
+ *     R = 4^n-1 * D_0 + 4^n-2 * D_1 + ... + 4^1 * D_n-2 + 4^0 * D_n-1
+ *       = ((...((D_0) * 4 + D_1) * 4 + ...) * 4 + D_n-2) * 4 + D_n-1
+ *
+ * We chose 1, 2, and 4 as our generators because 1 corresponds to the trival
+ * XOR operation, and 2 and 4 can be computed quickly and generate linearly-
+ * independent coefficients. (There are no additional coefficients that have
+ * this property which is why the uncorrected Plank method breaks down.)
+ *
+ * See the reconstruction code below for how P, Q and R can used individually
+ * 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
+
+#define        VDEV_RAIDZ_MUL_2(x)     (((x) << 1) ^ (((x) & 0x80) ? 0x1d : 0))
+#define        VDEV_RAIDZ_MUL_4(x)     (VDEV_RAIDZ_MUL_2(VDEV_RAIDZ_MUL_2(x)))
+
+/*
+ * We provide a mechanism to perform the field multiplication operation on a
+ * 64-bit value all at once rather than a byte at a time. This works by
+ * creating a mask from the top bit in each byte and using that to
+ * conditionally apply the XOR of 0x1d.
+ */
+#define        VDEV_RAIDZ_64MUL_2(x, mask) \
+{ \
+       (mask) = (x) & 0x8080808080808080ULL; \
+       (mask) = ((mask) << 1) - ((mask) >> 7); \
+       (x) = (((x) << 1) & 0xfefefefefefefefeULL) ^ \
+           ((mask) & 0x1d1d1d1d1d1d1d1dULL); \
+}
+
+#define        VDEV_RAIDZ_64MUL_4(x, mask) \
+{ \
+       VDEV_RAIDZ_64MUL_2((x), mask); \
+       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
+vdev_raidz_map_free(raidz_map_t *rm)
+{
+       int c;
+       size_t size;
+
+       for (c = 0; c < rm->rm_firstdatacol; c++) {
+               zio_buf_free(rm->rm_col[c].rc_data, rm->rm_col[c].rc_size);
+
+               if (rm->rm_col[c].rc_gdata != NULL)
+                       zio_buf_free(rm->rm_col[c].rc_gdata,
+                           rm->rm_col[c].rc_size);
+       }
+
+       size = 0;
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++)
+               size += rm->rm_col[c].rc_size;
+
+       if (rm->rm_datacopy != NULL)
+               zio_buf_free(rm->rm_datacopy, size);
+
+       kmem_free(rm, offsetof(raidz_map_t, rm_col[rm->rm_scols]));
+}
+
+static void
+vdev_raidz_map_free_vsd(zio_t *zio)
+{
+       raidz_map_t *rm = zio->io_vsd;
+
+       ASSERT0(rm->rm_freed);
+       rm->rm_freed = 1;
+
+       if (rm->rm_reports == 0)
+               vdev_raidz_map_free(rm);
+}
+
+/*ARGSUSED*/
+static void
+vdev_raidz_cksum_free(void *arg, size_t ignored)
+{
+       raidz_map_t *rm = arg;
+
+       ASSERT3U(rm->rm_reports, >, 0);
+
+       if (--rm->rm_reports == 0 && rm->rm_freed != 0)
+               vdev_raidz_map_free(rm);
+}
+
+static void
+vdev_raidz_cksum_finish(zio_cksum_report_t *zcr, const void *good_data)
+{
+       raidz_map_t *rm = zcr->zcr_cbdata;
+       size_t c = zcr->zcr_cbinfo;
+       size_t x;
+
+       const char *good = NULL;
+       const char *bad = rm->rm_col[c].rc_data;
+
+       if (good_data == NULL) {
+               zfs_ereport_finish_checksum(zcr, NULL, NULL, B_FALSE);
+               return;
+       }
+
+       if (c < rm->rm_firstdatacol) {
+               /*
+                * The first time through, calculate the parity blocks for
+                * the good data (this relies on the fact that the good
+                * data never changes for a given logical ZIO)
+                */
+               if (rm->rm_col[0].rc_gdata == NULL) {
+                       char *bad_parity[VDEV_RAIDZ_MAXPARITY];
+                       char *buf;
+
+                       /*
+                        * Set up the rm_col[]s to generate the parity for
+                        * good_data, first saving the parity bufs and
+                        * replacing them with buffers to hold the result.
+                        */
+                       for (x = 0; x < rm->rm_firstdatacol; x++) {
+                               bad_parity[x] = rm->rm_col[x].rc_data;
+                               rm->rm_col[x].rc_data = rm->rm_col[x].rc_gdata =
+                                   zio_buf_alloc(rm->rm_col[x].rc_size);
+                       }
+
+                       /* fill in the data columns from good_data */
+                       buf = (char *)good_data;
+                       for (; x < rm->rm_cols; x++) {
+                               rm->rm_col[x].rc_data = buf;
+                               buf += rm->rm_col[x].rc_size;
+                       }
+
+                       /*
+                        * Construct the parity from the good data.
+                        */
+                       vdev_raidz_generate_parity(rm);
+
+                       /* restore everything back to its original state */
+                       for (x = 0; x < rm->rm_firstdatacol; x++)
+                               rm->rm_col[x].rc_data = bad_parity[x];
+
+                       buf = rm->rm_datacopy;
+                       for (x = rm->rm_firstdatacol; x < rm->rm_cols; x++) {
+                               rm->rm_col[x].rc_data = buf;
+                               buf += rm->rm_col[x].rc_size;
+                       }
+               }
+
+               ASSERT3P(rm->rm_col[c].rc_gdata, !=, NULL);
+               good = rm->rm_col[c].rc_gdata;
+       } else {
+               /* adjust good_data to point at the start of our column */
+               good = good_data;
+
+               for (x = rm->rm_firstdatacol; x < c; x++)
+                       good += rm->rm_col[x].rc_size;
+       }
+
+       /* we drop the ereport if it ends up that the data was good */
+       zfs_ereport_finish_checksum(zcr, good, bad, B_TRUE);
+}
+
+/*
+ * Invoked indirectly by zfs_ereport_start_checksum(), called
+ * below when our read operation fails completely.  The main point
+ * is to keep a copy of everything we read from disk, so that at
+ * vdev_raidz_cksum_finish() time we can compare it with the good data.
+ */
+static void
+vdev_raidz_cksum_report(zio_t *zio, zio_cksum_report_t *zcr, void *arg)
+{
+       size_t c = (size_t)(uintptr_t)arg;
+       caddr_t buf;
+
+       raidz_map_t *rm = zio->io_vsd;
+       size_t size;
+
+       /* set up the report and bump the refcount  */
+       zcr->zcr_cbdata = rm;
+       zcr->zcr_cbinfo = c;
+       zcr->zcr_finish = vdev_raidz_cksum_finish;
+       zcr->zcr_free = vdev_raidz_cksum_free;
+
+       rm->rm_reports++;
+       ASSERT3U(rm->rm_reports, >, 0);
+
+       if (rm->rm_datacopy != NULL)
+               return;
+
+       /*
+        * It's the first time we're called for this raidz_map_t, so we need
+        * to copy the data aside; there's no guarantee that our zio's buffer
+        * won't be re-used for something else.
+        *
+        * Our parity data is already in separate buffers, so there's no need
+        * to copy them.
+        */
+
+       size = 0;
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++)
+               size += rm->rm_col[c].rc_size;
+
+       buf = rm->rm_datacopy = zio_buf_alloc(size);
+
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               raidz_col_t *col = &rm->rm_col[c];
+
+               bcopy(col->rc_data, buf, col->rc_size);
+               col->rc_data = buf;
+
+               buf += col->rc_size;
+       }
+       ASSERT3P(buf - (caddr_t)rm->rm_datacopy, ==, size);
+}
+
+static const zio_vsd_ops_t vdev_raidz_vsd_ops = {
+       vdev_raidz_map_free_vsd,
+       vdev_raidz_cksum_report
+};
+
+/*
+ * Divides the IO evenly across all child vdevs; usually, dcols is
+ * the number of children in the target vdev.
+ *
+ * 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 *
+vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
+    uint64_t nparity)
+{
+       raidz_map_t *rm;
+       /* The starting RAIDZ (parent) vdev sector of the block. */
+       uint64_t b = zio->io_offset >> unit_shift;
+       /* The zio's size in units of the vdev's minimum sector size. */
+       uint64_t s = zio->io_size >> unit_shift;
+       /* The first column for this stripe. */
+       uint64_t f = b % dcols;
+       /* The starting byte offset on each child vdev. */
+       uint64_t o = (b / dcols) << unit_shift;
+       uint64_t q, r, c, bc, col, acols, scols, coff, devidx, asize, tot;
+
+       /*
+        * "Quotient": The number of data sectors for this stripe on all but
+        * the "big column" child vdevs that also contain "remainder" data.
+        */
+       q = s / (dcols - nparity);
+
+       /*
+        * "Remainder": The number of partial stripe data sectors in this I/O.
+        * This will add a sector to some, but not all, child vdevs.
+        */
+       r = s - q * (dcols - nparity);
+
+       /* The number of "big columns" - those which contain remainder data. */
+       bc = (r == 0 ? 0 : r + nparity);
+
+       /*
+        * The total number of data and parity sectors associated with
+        * this I/O.
+        */
+       tot = s + nparity * (q + (r == 0 ? 0 : 1));
+
+       /* acols: The columns that will be accessed. */
+       /* scols: The columns that will be accessed or skipped. */
+       if (q == 0) {
+               /* Our I/O request doesn't span all child vdevs. */
+               acols = bc;
+               scols = MIN(dcols, roundup(bc, nparity + 1));
+       } else {
+               acols = dcols;
+               scols = dcols;
+       }
+
+       ASSERT3U(acols, <=, scols);
+
+       rm = kmem_alloc(offsetof(raidz_map_t, rm_col[scols]), KM_SLEEP);
+
+       rm->rm_cols = acols;
+       rm->rm_scols = scols;
+       rm->rm_bigcols = bc;
+       rm->rm_skipstart = bc;
+       rm->rm_missingdata = 0;
+       rm->rm_missingparity = 0;
+       rm->rm_firstdatacol = nparity;
+       rm->rm_datacopy = NULL;
+       rm->rm_reports = 0;
+       rm->rm_freed = 0;
+       rm->rm_ecksuminjected = 0;
+
+       asize = 0;
+
+       for (c = 0; c < scols; c++) {
+               col = f + c;
+               coff = o;
+               if (col >= dcols) {
+                       col -= dcols;
+                       coff += 1ULL << unit_shift;
+               }
+               rm->rm_col[c].rc_devidx = col;
+               rm->rm_col[c].rc_offset = coff;
+               rm->rm_col[c].rc_data = NULL;
+               rm->rm_col[c].rc_gdata = NULL;
+               rm->rm_col[c].rc_error = 0;
+               rm->rm_col[c].rc_tried = 0;
+               rm->rm_col[c].rc_skipped = 0;
+
+               if (c >= acols)
+                       rm->rm_col[c].rc_size = 0;
+               else if (c < bc)
+                       rm->rm_col[c].rc_size = (q + 1) << unit_shift;
+               else
+                       rm->rm_col[c].rc_size = q << unit_shift;
+
+               asize += rm->rm_col[c].rc_size;
+       }
+
+       ASSERT3U(asize, ==, tot << unit_shift);
+       rm->rm_asize = roundup(asize, (nparity + 1) << unit_shift);
+       rm->rm_nskip = roundup(tot, nparity + 1) - tot;
+       ASSERT3U(rm->rm_asize - asize, ==, rm->rm_nskip << unit_shift);
+       ASSERT3U(rm->rm_nskip, <=, nparity);
+
+       for (c = 0; c < rm->rm_firstdatacol; c++)
+               rm->rm_col[c].rc_data = zio_buf_alloc(rm->rm_col[c].rc_size);
+
+       rm->rm_col[c].rc_data = zio->io_data;
+
+       for (c = c + 1; c < acols; c++)
+               rm->rm_col[c].rc_data = (char *)rm->rm_col[c - 1].rc_data +
+                   rm->rm_col[c - 1].rc_size;
+
+       /*
+        * If all data stored spans all columns, there's a danger that parity
+        * will always be on the same device and, since parity isn't read
+        * during normal operation, that that device's I/O bandwidth won't be
+        * used effectively. We therefore switch the parity every 1MB.
+        *
+        * ... at least that was, ostensibly, the theory. As a practical
+        * matter unless we juggle the parity between all devices evenly, we
+        * won't see any benefit. Further, occasional writes that aren't a
+        * multiple of the LCM of the number of children and the minimum
+        * stripe width are sufficient to avoid pessimal behavior.
+        * Unfortunately, this decision created an implicit on-disk format
+        * requirement that we need to support for all eternity, but only
+        * for single-parity RAID-Z.
+        *
+        * If we intend to skip a sector in the zeroth column for padding
+        * we must make sure to note this swap. We will never intend to
+        * skip the first column since at least one data and one parity
+        * column must appear in each row.
+        */
+       ASSERT(rm->rm_cols >= 2);
+       ASSERT(rm->rm_col[0].rc_size == rm->rm_col[1].rc_size);
+
+       if (rm->rm_firstdatacol == 1 && (zio->io_offset & (1ULL << 20))) {
+               devidx = rm->rm_col[0].rc_devidx;
+               o = rm->rm_col[0].rc_offset;
+               rm->rm_col[0].rc_devidx = rm->rm_col[1].rc_devidx;
+               rm->rm_col[0].rc_offset = rm->rm_col[1].rc_offset;
+               rm->rm_col[1].rc_devidx = devidx;
+               rm->rm_col[1].rc_offset = o;
+
+               if (rm->rm_skipstart == 0)
+                       rm->rm_skipstart = 1;
+       }
+
+       zio->io_vsd = rm;
+       zio->io_vsd_ops = &vdev_raidz_vsd_ops;
+       return (rm);
+}
+
+static void
+vdev_raidz_generate_parity_p(raidz_map_t *rm)
+{
+       uint64_t *p, *src, pcount, ccount, i;
+       int c;
+
+       pcount = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]);
+
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               src = rm->rm_col[c].rc_data;
+               p = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+               ccount = rm->rm_col[c].rc_size / sizeof (src[0]);
+
+               if (c == rm->rm_firstdatacol) {
+                       ASSERT(ccount == pcount);
+                       for (i = 0; i < ccount; i++, src++, p++) {
+                               *p = *src;
+                       }
+               } else {
+                       ASSERT(ccount <= pcount);
+                       for (i = 0; i < ccount; i++, src++, p++) {
+                               *p ^= *src;
+                       }
+               }
+       }
+}
+
+static void
+vdev_raidz_generate_parity_pq(raidz_map_t *rm)
+{
+       uint64_t *p, *q, *src, pcnt, ccnt, mask, i;
+       int c;
+
+       pcnt = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]);
+       ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size ==
+           rm->rm_col[VDEV_RAIDZ_Q].rc_size);
+
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               src = rm->rm_col[c].rc_data;
+               p = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+               q = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
+
+               ccnt = rm->rm_col[c].rc_size / sizeof (src[0]);
+
+               if (c == rm->rm_firstdatacol) {
+                       ASSERT(ccnt == pcnt || ccnt == 0);
+                       for (i = 0; i < ccnt; i++, src++, p++, q++) {
+                               *p = *src;
+                               *q = *src;
+                       }
+                       for (; i < pcnt; i++, src++, p++, q++) {
+                               *p = 0;
+                               *q = 0;
+                       }
+               } else {
+                       ASSERT(ccnt <= pcnt);
+
+                       /*
+                        * Apply the algorithm described above by multiplying
+                        * the previous result and adding in the new value.
+                        */
+                       for (i = 0; i < ccnt; i++, src++, p++, q++) {
+                               *p ^= *src;
+
+                               VDEV_RAIDZ_64MUL_2(*q, mask);
+                               *q ^= *src;
+                       }
+
+                       /*
+                        * Treat short columns as though they are full of 0s.
+                        * Note that there's therefore nothing needed for P.
+                        */
+                       for (; i < pcnt; i++, q++) {
+                               VDEV_RAIDZ_64MUL_2(*q, mask);
+                       }
+               }
+       }
+}
+
+static void
+vdev_raidz_generate_parity_pqr(raidz_map_t *rm)
+{
+       uint64_t *p, *q, *r, *src, pcnt, ccnt, mask, i;
+       int c;
+
+       pcnt = rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]);
+       ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size ==
+           rm->rm_col[VDEV_RAIDZ_Q].rc_size);
+       ASSERT(rm->rm_col[VDEV_RAIDZ_P].rc_size ==
+           rm->rm_col[VDEV_RAIDZ_R].rc_size);
+
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               src = rm->rm_col[c].rc_data;
+               p = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+               q = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
+               r = rm->rm_col[VDEV_RAIDZ_R].rc_data;
+
+               ccnt = rm->rm_col[c].rc_size / sizeof (src[0]);
+
+               if (c == rm->rm_firstdatacol) {
+                       ASSERT(ccnt == pcnt || ccnt == 0);
+                       for (i = 0; i < ccnt; i++, src++, p++, q++, r++) {
+                               *p = *src;
+                               *q = *src;
+                               *r = *src;
+                       }
+                       for (; i < pcnt; i++, src++, p++, q++, r++) {
+                               *p = 0;
+                               *q = 0;
+                               *r = 0;
+                       }
+               } else {
+                       ASSERT(ccnt <= pcnt);
+
+                       /*
+                        * Apply the algorithm described above by multiplying
+                        * the previous result and adding in the new value.
+                        */
+                       for (i = 0; i < ccnt; i++, src++, p++, q++, r++) {
+                               *p ^= *src;
+
+                               VDEV_RAIDZ_64MUL_2(*q, mask);
+                               *q ^= *src;
+
+                               VDEV_RAIDZ_64MUL_4(*r, mask);
+                               *r ^= *src;
+                       }
+
+                       /*
+                        * Treat short columns as though they are full of 0s.
+                        * Note that there's therefore nothing needed for P.
+                        */
+                       for (; i < pcnt; i++, q++, r++) {
+                               VDEV_RAIDZ_64MUL_2(*q, mask);
+                               VDEV_RAIDZ_64MUL_4(*r, mask);
+                       }
+               }
+       }
+}
+
+/*
+ * Generate RAID parity in the first virtual columns according to the number of
+ * parity columns available.
+ */
+static void
+vdev_raidz_generate_parity(raidz_map_t *rm)
+{
+       switch (rm->rm_firstdatacol) {
+       case 1:
+               vdev_raidz_generate_parity_p(rm);
+               break;
+       case 2:
+               vdev_raidz_generate_parity_pq(rm);
+               break;
+       case 3:
+               vdev_raidz_generate_parity_pqr(rm);
+               break;
+       default:
+               cmn_err(CE_PANIC, "invalid RAID-Z configuration");
+       }
+}
+
+static int
+vdev_raidz_reconstruct_p(raidz_map_t *rm, int *tgts, int ntgts)
+{
+       uint64_t *dst, *src, xcount, ccount, count, i;
+       int x = tgts[0];
+       int c;
+
+       ASSERT(ntgts == 1);
+       ASSERT(x >= rm->rm_firstdatacol);
+       ASSERT(x < rm->rm_cols);
+
+       xcount = rm->rm_col[x].rc_size / sizeof (src[0]);
+       ASSERT(xcount <= rm->rm_col[VDEV_RAIDZ_P].rc_size / sizeof (src[0]));
+       ASSERT(xcount > 0);
+
+       src = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+       dst = rm->rm_col[x].rc_data;
+       for (i = 0; i < xcount; i++, dst++, src++) {
+               *dst = *src;
+       }
+
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               src = rm->rm_col[c].rc_data;
+               dst = rm->rm_col[x].rc_data;
+
+               if (c == x)
+                       continue;
+
+               ccount = rm->rm_col[c].rc_size / sizeof (src[0]);
+               count = MIN(ccount, xcount);
+
+               for (i = 0; i < count; i++, dst++, src++) {
+                       *dst ^= *src;
+               }
+       }
+
+       return (1 << VDEV_RAIDZ_P);
+}
+
+static int
+vdev_raidz_reconstruct_q(raidz_map_t *rm, int *tgts, int ntgts)
+{
+       uint64_t *dst, *src, xcount, ccount, count, mask, i;
+       uint8_t *b;
+       int x = tgts[0];
+       int c, j, exp;
+
+       ASSERT(ntgts == 1);
+
+       xcount = rm->rm_col[x].rc_size / sizeof (src[0]);
+       ASSERT(xcount <= rm->rm_col[VDEV_RAIDZ_Q].rc_size / sizeof (src[0]));
+
+       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               src = rm->rm_col[c].rc_data;
+               dst = rm->rm_col[x].rc_data;
+
+               if (c == x)
+                       ccount = 0;
+               else
+                       ccount = rm->rm_col[c].rc_size / sizeof (src[0]);
+
+               count = MIN(ccount, xcount);
+
+               if (c == rm->rm_firstdatacol) {
+                       for (i = 0; i < count; i++, dst++, src++) {
+                               *dst = *src;
+                       }
+                       for (; i < xcount; i++, dst++) {
+                               *dst = 0;
+                       }
+
+               } else {
+                       for (i = 0; i < count; i++, dst++, src++) {
+                               VDEV_RAIDZ_64MUL_2(*dst, mask);
+                               *dst ^= *src;
+                       }
+
+                       for (; i < xcount; i++, dst++) {
+                               VDEV_RAIDZ_64MUL_2(*dst, mask);
+                       }
+               }
+       }
+
+       src = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
+       dst = rm->rm_col[x].rc_data;
+       exp = 255 - (rm->rm_cols - 1 - x);
+
+       for (i = 0; i < xcount; i++, dst++, src++) {
+               *dst ^= *src;
+               for (j = 0, b = (uint8_t *)dst; j < 8; j++, b++) {
+                       *b = vdev_raidz_exp2(*b, exp);
+               }
+       }
+
+       return (1 << VDEV_RAIDZ_Q);
+}
+
+static int
+vdev_raidz_reconstruct_pq(raidz_map_t *rm, int *tgts, int ntgts)
+{
+       uint8_t *p, *q, *pxy, *qxy, *xd, *yd, tmp, a, b, aexp, bexp;
+       void *pdata, *qdata;
+       uint64_t xsize, ysize, i;
+       int x = tgts[0];
+       int y = tgts[1];
+
+       ASSERT(ntgts == 2);
+       ASSERT(x < y);
+       ASSERT(x >= rm->rm_firstdatacol);
+       ASSERT(y < rm->rm_cols);
+
+       ASSERT(rm->rm_col[x].rc_size >= rm->rm_col[y].rc_size);
+
+       /*
+        * Move the parity data aside -- we're going to compute parity as
+        * though columns x and y were full of zeros -- Pxy and Qxy. We want to
+        * reuse the parity generation mechanism without trashing the actual
+        * parity so we make those columns appear to be full of zeros by
+        * setting their lengths to zero.
+        */
+       pdata = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+       qdata = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
+       xsize = rm->rm_col[x].rc_size;
+       ysize = rm->rm_col[y].rc_size;
+
+       rm->rm_col[VDEV_RAIDZ_P].rc_data =
+           zio_buf_alloc(rm->rm_col[VDEV_RAIDZ_P].rc_size);
+       rm->rm_col[VDEV_RAIDZ_Q].rc_data =
+           zio_buf_alloc(rm->rm_col[VDEV_RAIDZ_Q].rc_size);
+       rm->rm_col[x].rc_size = 0;
+       rm->rm_col[y].rc_size = 0;
+
+       vdev_raidz_generate_parity_pq(rm);
+
+       rm->rm_col[x].rc_size = xsize;
+       rm->rm_col[y].rc_size = ysize;
+
+       p = pdata;
+       q = qdata;
+       pxy = rm->rm_col[VDEV_RAIDZ_P].rc_data;
+       qxy = rm->rm_col[VDEV_RAIDZ_Q].rc_data;
+       xd = rm->rm_col[x].rc_data;
+       yd = rm->rm_col[y].rc_data;
+
+       /*
+        * We now have:
+        *      Pxy = P + D_x + D_y
+        *      Qxy = Q + 2^(ndevs - 1 - x) * D_x + 2^(ndevs - 1 - y) * D_y
+        *
+        * We can then solve for D_x:
+        *      D_x = A * (P + Pxy) + B * (Q + Qxy)
+        * where
+        *      A = 2^(x - y) * (2^(x - y) + 1)^-1
+        *      B = 2^(ndevs - 1 - x) * (2^(x - y) + 1)^-1
+        *
+        * With D_x in hand, we can easily solve for D_y:
+        *      D_y = P + Pxy + D_x
+        */
+
+       a = vdev_raidz_pow2[255 + x - y];
+       b = vdev_raidz_pow2[255 - (rm->rm_cols - 1 - x)];
+       tmp = 255 - vdev_raidz_log2[a ^ 1];
+
+       aexp = vdev_raidz_log2[vdev_raidz_exp2(a, tmp)];
+       bexp = vdev_raidz_log2[vdev_raidz_exp2(b, tmp)];
+
+       for (i = 0; i < xsize; i++, p++, q++, pxy++, qxy++, xd++, yd++) {
+               *xd = vdev_raidz_exp2(*p ^ *pxy, aexp) ^
+                   vdev_raidz_exp2(*q ^ *qxy, bexp);
+
+               if (i < ysize)
+                       *yd = *p ^ *pxy ^ *xd;
+       }
+
+       zio_buf_free(rm->rm_col[VDEV_RAIDZ_P].rc_data,
+           rm->rm_col[VDEV_RAIDZ_P].rc_size);
+       zio_buf_free(rm->rm_col[VDEV_RAIDZ_Q].rc_data,
+           rm->rm_col[VDEV_RAIDZ_Q].rc_size);
+
+       /*
+        * Restore the saved parity data.
+        */
+       rm->rm_col[VDEV_RAIDZ_P].rc_data = pdata;
+       rm->rm_col[VDEV_RAIDZ_Q].rc_data = qdata;
+
+       return ((1 << VDEV_RAIDZ_P) | (1 << VDEV_RAIDZ_Q));
+}
+
+/* BEGIN CSTYLED */
+/*
+ * In the general case of reconstruction, we must solve the system of linear
+ * equations defined by the coeffecients used to generate parity as well as
+ * the contents of the data and parity disks. This can be expressed with
+ * vectors for the original data (D) and the actual data (d) and parity (p)
+ * and a matrix composed of the identity matrix (I) and a dispersal matrix (V):
+ *
+ *            __   __                     __     __
+ *            |     |         __     __   |  p_0  |
+ *            |  V  |         |  D_0  |   | p_m-1 |
+ *            |     |    x    |   :   | = |  d_0  |
+ *            |  I  |         | D_n-1 |   |   :   |
+ *            |     |         ~~     ~~   | d_n-1 |
+ *            ~~   ~~                     ~~     ~~
+ *
+ * I is simply a square identity matrix of size n, and V is a vandermonde
+ * matrix defined by the coeffecients we chose for the various parity columns
+ * (1, 2, 4). Note that these values were chosen both for simplicity, speedy
+ * computation as well as linear separability.
+ *
+ *      __               __               __     __
+ *      |   1   ..  1 1 1 |               |  p_0  |
+ *      | 2^n-1 ..  4 2 1 |   __     __   |   :   |
+ *      | 4^n-1 .. 16 4 1 |   |  D_0  |   | p_m-1 |
+ *      |   1   ..  0 0 0 |   |  D_1  |   |  d_0  |
+ *      |   0   ..  0 0 0 | x |  D_2  | = |  d_1  |
+ *      |   :       : : : |   |   :   |   |  d_2  |
+ *      |   0   ..  1 0 0 |   | D_n-1 |   |   :   |
+ *      |   0   ..  0 1 0 |   ~~     ~~   |   :   |
+ *      |   0   ..  0 0 1 |               | d_n-1 |
+ *      ~~               ~~               ~~     ~~
+ *
+ * Note that I, V, d, and p are known. To compute D, we must invert the
+ * matrix and use the known data and parity values to reconstruct the unknown
+ * data values. We begin by removing the rows in V|I and d|p that correspond
+ * to failed or missing columns; we then make V|I square (n x n) and d|p
+ * sized n by removing rows corresponding to unused parity from the bottom up
+ * to generate (V|I)' and (d|p)'. We can then generate the inverse of (V|I)'
+ * using Gauss-Jordan elimination. In the example below we use m=3 parity
+ * columns, n=8 data columns, with errors in d_1, d_2, and p_1:
+ *           __                               __
+ *           |  1   1   1   1   1   1   1   1  |
+ *           | 128  64  32  16  8   4   2   1  | <-----+-+-- missing disks
+ *           |  19 205 116  29  64  16  4   1  |      / /
+ *           |  1   0   0   0   0   0   0   0  |     / /
+ *           |  0   1   0   0   0   0   0   0  | <--' /
+ *  (V|I)  = |  0   0   1   0   0   0   0   0  | <---'
+ *           |  0   0   0   1   0   0   0   0  |
+ *           |  0   0   0   0   1   0   0   0  |
+ *           |  0   0   0   0   0   1   0   0  |
+ *           |  0   0   0   0   0   0   1   0  |
+ *           |  0   0   0   0   0   0   0   1  |
+ *           ~~                               ~~
+ *           __                               __
+ *           |  1   1   1   1   1   1   1   1  |
+ *           | 128  64  32  16  8   4   2   1  |
+ *           |  19 205 116  29  64  16  4   1  |
+ *           |  1   0   0   0   0   0   0   0  |
+ *           |  0   1   0   0   0   0   0   0  |
+ *  (V|I)' = |  0   0   1   0   0   0   0   0  |
+ *           |  0   0   0   1   0   0   0   0  |
+ *           |  0   0   0   0   1   0   0   0  |
+ *           |  0   0   0   0   0   1   0   0  |
+ *           |  0   0   0   0   0   0   1   0  |
+ *           |  0   0   0   0   0   0   0   1  |
+ *           ~~                               ~~
+ *
+ * Here we employ Gauss-Jordan elimination to find the inverse of (V|I)'. We
+ * have carefully chosen the seed values 1, 2, and 4 to ensure that this
+ * matrix is not singular.
+ * __                                                                 __
+ * |  1   1   1   1   1   1   1   1     1   0   0   0   0   0   0   0  |
+ * |  19 205 116  29  64  16  4   1     0   1   0   0   0   0   0   0  |
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  1   1   1   1   1   1   1   1     1   0   0   0   0   0   0   0  |
+ * |  19 205 116  29  64  16  4   1     0   1   0   0   0   0   0   0  |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   1   0   0   0   0   0     1   0   1   1   1   1   1   1  |
+ * |  0  205 116  0   0   0   0   0     0   1   19  29  64  16  4   1  |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   1   0   0   0   0   0     1   0   1   1   1   1   1   1  |
+ * |  0   0  185  0   0   0   0   0    205  1  222 208 141 221 201 204 |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   1   0   0   0   0   0     1   0   1   1   1   1   1   1  |
+ * |  0   0   1   0   0   0   0   0    166 100  4   40 158 168 216 209 |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ * __                                                                 __
+ * |  1   0   0   0   0   0   0   0     0   0   1   0   0   0   0   0  |
+ * |  0   1   0   0   0   0   0   0    167 100  5   41 159 169 217 208 |
+ * |  0   0   1   0   0   0   0   0    166 100  4   40 158 168 216 209 |
+ * |  0   0   0   1   0   0   0   0     0   0   0   1   0   0   0   0  |
+ * |  0   0   0   0   1   0   0   0     0   0   0   0   1   0   0   0  |
+ * |  0   0   0   0   0   1   0   0     0   0   0   0   0   1   0   0  |
+ * |  0   0   0   0   0   0   1   0     0   0   0   0   0   0   1   0  |
+ * |  0   0   0   0   0   0   0   1     0   0   0   0   0   0   0   1  |
+ * ~~                                                                 ~~
+ *                   __                               __
+ *                   |  0   0   1   0   0   0   0   0  |
+ *                   | 167 100  5   41 159 169 217 208 |
+ *                   | 166 100  4   40 158 168 216 209 |
+ *       (V|I)'^-1 = |  0   0   0   1   0   0   0   0  |
+ *                   |  0   0   0   0   1   0   0   0  |
+ *                   |  0   0   0   0   0   1   0   0  |
+ *                   |  0   0   0   0   0   0   1   0  |
+ *                   |  0   0   0   0   0   0   0   1  |
+ *                   ~~                               ~~
+ *
+ * We can then simply compute D = (V|I)'^-1 x (d|p)' to discover the values
+ * of the missing data.
+ *
+ * As is apparent from the example above, the only non-trivial rows in the
+ * inverse matrix correspond to the data disks that we're trying to
+ * reconstruct. Indeed, those are the only rows we need as the others would
+ * only be useful for reconstructing data known or assumed to be valid. For
+ * that reason, we only build the coefficients in the rows that correspond to
+ * targeted columns.
+ */
+/* END CSTYLED */
+
+static void
+vdev_raidz_matrix_init(raidz_map_t *rm, int n, int nmap, int *map,
+    uint8_t **rows)
+{
+       int i, j;
+       int pow;
+
+       ASSERT(n == rm->rm_cols - rm->rm_firstdatacol);
+
+       /*
+        * Fill in the missing rows of interest.
+        */
+       for (i = 0; i < nmap; i++) {
+               ASSERT3S(0, <=, map[i]);
+               ASSERT3S(map[i], <=, 2);
+
+               pow = map[i] * n;
+               if (pow > 255)
+                       pow -= 255;
+               ASSERT(pow <= 255);
+
+               for (j = 0; j < n; j++) {
+                       pow -= map[i];
+                       if (pow < 0)
+                               pow += 255;
+                       rows[i][j] = vdev_raidz_pow2[pow];
+               }
+       }
+}
+
+static void
+vdev_raidz_matrix_invert(raidz_map_t *rm, int n, int nmissing, int *missing,
+    uint8_t **rows, uint8_t **invrows, const uint8_t *used)
+{
+       int i, j, ii, jj;
+       uint8_t log;
+
+       /*
+        * Assert that the first nmissing entries from the array of used
+        * columns correspond to parity columns and that subsequent entries
+        * correspond to data columns.
+        */
+       for (i = 0; i < nmissing; i++) {
+               ASSERT3S(used[i], <, rm->rm_firstdatacol);
+       }
+       for (; i < n; i++) {
+               ASSERT3S(used[i], >=, rm->rm_firstdatacol);
+       }
+
+       /*
+        * First initialize the storage where we'll compute the inverse rows.
+        */
+       for (i = 0; i < nmissing; i++) {
+               for (j = 0; j < n; j++) {
+                       invrows[i][j] = (i == j) ? 1 : 0;
+               }
+       }
+
+       /*
+        * Subtract all trivial rows from the rows of consequence.
+        */
+       for (i = 0; i < nmissing; i++) {
+               for (j = nmissing; j < n; j++) {
+                       ASSERT3U(used[j], >=, rm->rm_firstdatacol);
+                       jj = used[j] - rm->rm_firstdatacol;
+                       ASSERT3S(jj, <, n);
+                       invrows[i][j] = rows[i][jj];
+                       rows[i][jj] = 0;
+               }
+       }
+
+       /*
+        * For each of the rows of interest, we must normalize it and subtract
+        * a multiple of it from the other rows.
+        */
+       for (i = 0; i < nmissing; i++) {
+               for (j = 0; j < missing[i]; j++) {
+                       ASSERT0(rows[i][j]);
+               }
+               ASSERT3U(rows[i][missing[i]], !=, 0);
+
+               /*
+                * Compute the inverse of the first element and multiply each
+                * element in the row by that value.
+                */
+               log = 255 - vdev_raidz_log2[rows[i][missing[i]]];
+
+               for (j = 0; j < n; j++) {
+                       rows[i][j] = vdev_raidz_exp2(rows[i][j], log);
+                       invrows[i][j] = vdev_raidz_exp2(invrows[i][j], log);
+               }
+
+               for (ii = 0; ii < nmissing; ii++) {
+                       if (i == ii)
+                               continue;
+
+                       ASSERT3U(rows[ii][missing[i]], !=, 0);
+
+                       log = vdev_raidz_log2[rows[ii][missing[i]]];
+
+                       for (j = 0; j < n; j++) {
+                               rows[ii][j] ^=
+                                   vdev_raidz_exp2(rows[i][j], log);
+                               invrows[ii][j] ^=
+                                   vdev_raidz_exp2(invrows[i][j], log);
+                       }
+               }
+       }
+
+       /*
+        * Verify that the data that is left in the rows are properly part of
+        * an identity matrix.
+        */
+       for (i = 0; i < nmissing; i++) {
+               for (j = 0; j < n; j++) {
+                       if (j == missing[i]) {
+                               ASSERT3U(rows[i][j], ==, 1);
+                       } else {
+                               ASSERT0(rows[i][j]);
+                       }
+               }
+       }
+}
+
+static void
+vdev_raidz_matrix_reconstruct(raidz_map_t *rm, int n, int nmissing,
+    int *missing, uint8_t **invrows, const uint8_t *used)
+{
+       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 log = 0;
+       uint8_t val;
+       int ll;
+       uint8_t *invlog[VDEV_RAIDZ_MAXPARITY];
+       uint8_t *p, *pp;
+       size_t psize;
+
+       psize = sizeof (invlog[0][0]) * n * nmissing;
+       p = kmem_alloc(psize, KM_SLEEP);
+
+       for (pp = p, i = 0; i < nmissing; i++) {
+               invlog[i] = pp;
+               pp += n;
+       }
+
+       for (i = 0; i < nmissing; i++) {
+               for (j = 0; j < n; j++) {
+                       ASSERT3U(invrows[i][j], !=, 0);
+                       invlog[i][j] = vdev_raidz_log2[invrows[i][j]];
+               }
+       }
+
+       for (i = 0; i < n; i++) {
+               c = used[i];
+               ASSERT3U(c, <, rm->rm_cols);
+
+               src = rm->rm_col[c].rc_data;
+               ccount = rm->rm_col[c].rc_size;
+               for (j = 0; j < nmissing; j++) {
+                       cc = missing[j] + rm->rm_firstdatacol;
+                       ASSERT3U(cc, >=, rm->rm_firstdatacol);
+                       ASSERT3U(cc, <, rm->rm_cols);
+                       ASSERT3U(cc, !=, c);
+
+                       dst[j] = rm->rm_col[cc].rc_data;
+                       dcount[j] = rm->rm_col[cc].rc_size;
+               }
+
+               ASSERT(ccount >= rm->rm_col[missing[0]].rc_size || i > 0);
+
+               for (x = 0; x < ccount; x++, src++) {
+                       if (*src != 0)
+                               log = vdev_raidz_log2[*src];
+
+                       for (cc = 0; cc < nmissing; cc++) {
+                               if (x >= dcount[cc])
+                                       continue;
+
+                               if (*src == 0) {
+                                       val = 0;
+                               } else {
+                                       if ((ll = log + invlog[cc][i]) >= 255)
+                                               ll -= 255;
+                                       val = vdev_raidz_pow2[ll];
+                               }
+
+                               if (i == 0)
+                                       dst[cc][x] = val;
+                               else
+                                       dst[cc][x] ^= val;
+                       }
+               }
+       }
+
+       kmem_free(p, psize);
+}
+
+static int
+vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts)
+{
+       int n, i, c, t, tt;
+       int nmissing_rows;
+       int missing_rows[VDEV_RAIDZ_MAXPARITY];
+       int parity_map[VDEV_RAIDZ_MAXPARITY];
+
+       uint8_t *p, *pp;
+       size_t psize;
+
+       uint8_t *rows[VDEV_RAIDZ_MAXPARITY];
+       uint8_t *invrows[VDEV_RAIDZ_MAXPARITY];
+       uint8_t *used;
+
+       int code = 0;
+
+
+       n = rm->rm_cols - rm->rm_firstdatacol;
+
+       /*
+        * Figure out which data columns are missing.
+        */
+       nmissing_rows = 0;
+       for (t = 0; t < ntgts; t++) {
+               if (tgts[t] >= rm->rm_firstdatacol) {
+                       missing_rows[nmissing_rows++] =
+                           tgts[t] - rm->rm_firstdatacol;
+               }
+       }
+
+       /*
+        * Figure out which parity columns to use to help generate the missing
+        * data columns.
+        */
+       for (tt = 0, c = 0, i = 0; i < nmissing_rows; c++) {
+               ASSERT(tt < ntgts);
+               ASSERT(c < rm->rm_firstdatacol);
+
+               /*
+                * Skip any targeted parity columns.
+                */
+               if (c == tgts[tt]) {
+                       tt++;
+                       continue;
+               }
+
+               code |= 1 << c;
+
+               parity_map[i] = c;
+               i++;
+       }
+
+       ASSERT(code != 0);
+       ASSERT3U(code, <, 1 << VDEV_RAIDZ_MAXPARITY);
+
+       psize = (sizeof (rows[0][0]) + sizeof (invrows[0][0])) *
+           nmissing_rows * n + sizeof (used[0]) * n;
+       p = kmem_alloc(psize, KM_SLEEP);
+
+       for (pp = p, i = 0; i < nmissing_rows; i++) {
+               rows[i] = pp;
+               pp += n;
+               invrows[i] = pp;
+               pp += n;
+       }
+       used = pp;
+
+       for (i = 0; i < nmissing_rows; i++) {
+               used[i] = parity_map[i];
+       }
+
+       for (tt = 0, c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+               if (tt < nmissing_rows &&
+                   c == missing_rows[tt] + rm->rm_firstdatacol) {
+                       tt++;
+                       continue;
+               }
+
+               ASSERT3S(i, <, n);
+               used[i] = c;
+               i++;
+       }
+
+       /*
+        * Initialize the interesting rows of the matrix.
+        */
+       vdev_raidz_matrix_init(rm, n, nmissing_rows, parity_map, rows);
+
+       /*
+        * Invert the matrix.
+        */
+       vdev_raidz_matrix_invert(rm, n, nmissing_rows, missing_rows, rows,
+           invrows, used);
+
+       /*
+        * Reconstruct the missing data using the generated matrix.
+        */
+       vdev_raidz_matrix_reconstruct(rm, n, nmissing_rows, missing_rows,
+           invrows, used);
+
+       kmem_free(p, psize);
+
+       return (code);
+}
+
+static int
+vdev_raidz_reconstruct(raidz_map_t *rm, int *t, int nt)
+{
+       int tgts[VDEV_RAIDZ_MAXPARITY], *dt;
+       int ntgts;
+       int i, c;
+       int code;
+       int nbadparity, nbaddata;
+       int parity_valid[VDEV_RAIDZ_MAXPARITY];
+
+       /*
+        * The tgts list must already be sorted.
+        */
+       for (i = 1; i < nt; i++) {
+               ASSERT(t[i] > t[i - 1]);
+       }
+
+       nbadparity = rm->rm_firstdatacol;
+       nbaddata = rm->rm_cols - nbadparity;
+       ntgts = 0;
+       for (i = 0, c = 0; c < rm->rm_cols; c++) {
+               if (c < rm->rm_firstdatacol)
+                       parity_valid[c] = B_FALSE;
+
+               if (i < nt && c == t[i]) {
+                       tgts[ntgts++] = c;
+                       i++;
+               } else if (rm->rm_col[c].rc_error != 0) {
+                       tgts[ntgts++] = c;
+               } else if (c >= rm->rm_firstdatacol) {
+                       nbaddata--;
+               } else {
+                       parity_valid[c] = B_TRUE;
+                       nbadparity--;
+               }
+       }
+
+       ASSERT(ntgts >= nt);
+       ASSERT(nbaddata >= 0);
+       ASSERT(nbaddata + nbadparity == ntgts);
+
+       dt = &tgts[nbadparity];
+
+       /*
+        * 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));
+
+                       ASSERT(rm->rm_firstdatacol > 1);
+
+                       if (parity_valid[VDEV_RAIDZ_Q])
+                               return (vdev_raidz_reconstruct_q(rm, dt, 1));
+
+                       ASSERT(rm->rm_firstdatacol > 2);
+                       break;
+
+               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));
+
+                       ASSERT(rm->rm_firstdatacol > 2);
+
+                       break;
+               }
+       }
+
+       code = vdev_raidz_reconstruct_general(rm, tgts, ntgts);
+       ASSERT(code < (1 << VDEV_RAIDZ_MAXPARITY));
+       ASSERT(code > 0);
+       return (code);
+}
+
+static int
+vdev_raidz_open(vdev_t *vd, uint64_t *asize, uint64_t *max_asize,
+    uint64_t *ashift)
+{
+       vdev_t *cvd;
+       uint64_t nparity = vd->vdev_nparity;
+       int c;
+       int lasterror = 0;
+       int numerrors = 0;
+
+       ASSERT(nparity > 0);
+
+       if (nparity > VDEV_RAIDZ_MAXPARITY ||
+           vd->vdev_children < nparity + 1) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       vdev_open_children(vd);
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               cvd = vd->vdev_child[c];
+
+               if (cvd->vdev_open_error != 0) {
+                       lasterror = cvd->vdev_open_error;
+                       numerrors++;
+                       continue;
+               }
+
+               *asize = MIN(*asize - 1, cvd->vdev_asize - 1) + 1;
+               *max_asize = MIN(*max_asize - 1, cvd->vdev_max_asize - 1) + 1;
+               *ashift = MAX(*ashift, cvd->vdev_ashift);
+       }
+
+       *asize *= vd->vdev_children;
+       *max_asize *= vd->vdev_children;
+
+       if (numerrors > nparity) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_NO_REPLICAS;
+               return (lasterror);
+       }
+
+       return (0);
+}
+
+static void
+vdev_raidz_close(vdev_t *vd)
+{
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_close(vd->vdev_child[c]);
+}
+
+static uint64_t
+vdev_raidz_asize(vdev_t *vd, uint64_t psize)
+{
+       uint64_t asize;
+       uint64_t ashift = vd->vdev_top->vdev_ashift;
+       uint64_t cols = vd->vdev_children;
+       uint64_t nparity = vd->vdev_nparity;
+
+       asize = ((psize - 1) >> ashift) + 1;
+       asize += nparity * ((asize + cols - nparity - 1) / (cols - nparity));
+       asize = roundup(asize, nparity + 1) << ashift;
+
+       return (asize);
+}
+
+static void
+vdev_raidz_child_done(zio_t *zio)
+{
+       raidz_col_t *rc = zio->io_private;
+
+       rc->rc_error = zio->io_error;
+       rc->rc_tried = 1;
+       rc->rc_skipped = 0;
+}
+
+/*
+ * Start an IO operation on a RAIDZ VDev
+ *
+ * Outline:
+ * - For write operations:
+ *   1. Generate the parity data
+ *   2. Create child zio write operations to each column's vdev, for both
+ *      data and parity.
+ *   3. If the column skips any sectors for padding, create optional dummy
+ *      write zio children for those areas to improve aggregation continuity.
+ * - For read operations:
+ *   1. Create child zio read operations to each data column's vdev to read
+ *      the range of data required for zio.
+ *   2. If this is a scrub or resilver operation, or if any of the data
+ *      vdevs have had errors, then create zio read operations to the parity
+ *      columns' VDevs as well.
+ */
+static void
+vdev_raidz_io_start(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       vdev_t *tvd = vd->vdev_top;
+       vdev_t *cvd;
+       raidz_map_t *rm;
+       raidz_col_t *rc;
+       int c, i;
+
+       rm = vdev_raidz_map_alloc(zio, tvd->vdev_ashift, vd->vdev_children,
+           vd->vdev_nparity);
+
+       ASSERT3U(rm->rm_asize, ==, vdev_psize_to_asize(vd, zio->io_size));
+
+       if (zio->io_type == ZIO_TYPE_WRITE) {
+               vdev_raidz_generate_parity(rm);
+
+               for (c = 0; c < rm->rm_cols; c++) {
+                       rc = &rm->rm_col[c];
+                       cvd = vd->vdev_child[rc->rc_devidx];
+                       zio_nowait(zio_vdev_child_io(zio, NULL, cvd,
+                           rc->rc_offset, rc->rc_data, rc->rc_size,
+                           zio->io_type, zio->io_priority, 0,
+                           vdev_raidz_child_done, rc));
+               }
+
+               /*
+                * Generate optional I/Os for any skipped sectors to improve
+                * aggregation contiguity.
+                */
+               for (c = rm->rm_skipstart, i = 0; i < rm->rm_nskip; c++, i++) {
+                       ASSERT(c <= rm->rm_scols);
+                       if (c == rm->rm_scols)
+                               c = 0;
+                       rc = &rm->rm_col[c];
+                       cvd = vd->vdev_child[rc->rc_devidx];
+                       zio_nowait(zio_vdev_child_io(zio, NULL, cvd,
+                           rc->rc_offset + rc->rc_size, NULL,
+                           1 << tvd->vdev_ashift,
+                           zio->io_type, zio->io_priority,
+                           ZIO_FLAG_NODATA | ZIO_FLAG_OPTIONAL, NULL, NULL));
+               }
+
+               zio_execute(zio);
+               return;
+       }
+
+       ASSERT(zio->io_type == ZIO_TYPE_READ);
+
+       /*
+        * Iterate over the columns in reverse order so that we hit the parity
+        * last -- any errors along the way will force us to read the parity.
+        */
+       for (c = rm->rm_cols - 1; c >= 0; c--) {
+               rc = &rm->rm_col[c];
+               cvd = vd->vdev_child[rc->rc_devidx];
+               if (!vdev_readable(cvd)) {
+                       if (c >= rm->rm_firstdatacol)
+                               rm->rm_missingdata++;
+                       else
+                               rm->rm_missingparity++;
+                       rc->rc_error = SET_ERROR(ENXIO);
+                       rc->rc_tried = 1;       /* don't even try */
+                       rc->rc_skipped = 1;
+                       continue;
+               }
+               if (vdev_dtl_contains(cvd, DTL_MISSING, zio->io_txg, 1)) {
+                       if (c >= rm->rm_firstdatacol)
+                               rm->rm_missingdata++;
+                       else
+                               rm->rm_missingparity++;
+                       rc->rc_error = SET_ERROR(ESTALE);
+                       rc->rc_skipped = 1;
+                       continue;
+               }
+               if (c >= rm->rm_firstdatacol || rm->rm_missingdata > 0 ||
+                   (zio->io_flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER))) {
+                       zio_nowait(zio_vdev_child_io(zio, NULL, cvd,
+                           rc->rc_offset, rc->rc_data, rc->rc_size,
+                           zio->io_type, zio->io_priority, 0,
+                           vdev_raidz_child_done, rc));
+               }
+       }
+
+       zio_execute(zio);
+}
+
+
+/*
+ * Report a checksum error for a child of a RAID-Z device.
+ */
+static void
+raidz_checksum_error(zio_t *zio, raidz_col_t *rc, void *bad_data)
+{
+       vdev_t *vd = zio->io_vd->vdev_child[rc->rc_devidx];
+
+       if (!(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+               zio_bad_cksum_t zbc;
+               raidz_map_t *rm = zio->io_vsd;
+
+               mutex_enter(&vd->vdev_stat_lock);
+               vd->vdev_stat.vs_checksum_errors++;
+               mutex_exit(&vd->vdev_stat_lock);
+
+               zbc.zbc_has_cksum = 0;
+               zbc.zbc_injected = rm->rm_ecksuminjected;
+
+               zfs_ereport_post_checksum(zio->io_spa, vd, zio,
+                   rc->rc_offset, rc->rc_size, rc->rc_data, bad_data,
+                   &zbc);
+       }
+}
+
+/*
+ * We keep track of whether or not there were any injected errors, so that
+ * any ereports we generate can note it.
+ */
+static int
+raidz_checksum_verify(zio_t *zio)
+{
+       zio_bad_cksum_t zbc;
+       raidz_map_t *rm = zio->io_vsd;
+       int ret;
+
+       bzero(&zbc, sizeof (zio_bad_cksum_t));
+
+       ret = zio_checksum_error(zio, &zbc);
+       if (ret != 0 && zbc.zbc_injected != 0)
+               rm->rm_ecksuminjected = 1;
+
+       return (ret);
+}
+
+/*
+ * Generate the parity from the data columns. If we tried and were able to
+ * read the parity without error, verify that the generated parity matches the
+ * data we read. If it doesn't, we fire off a checksum error. Return the
+ * number such failures.
+ */
+static int
+raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
+{
+       void *orig[VDEV_RAIDZ_MAXPARITY];
+       int c, ret = 0;
+       raidz_col_t *rc;
+
+       for (c = 0; c < rm->rm_firstdatacol; c++) {
+               rc = &rm->rm_col[c];
+               if (!rc->rc_tried || rc->rc_error != 0)
+                       continue;
+               orig[c] = zio_buf_alloc(rc->rc_size);
+               bcopy(rc->rc_data, orig[c], rc->rc_size);
+       }
+
+       vdev_raidz_generate_parity(rm);
+
+       for (c = 0; c < rm->rm_firstdatacol; c++) {
+               rc = &rm->rm_col[c];
+               if (!rc->rc_tried || rc->rc_error != 0)
+                       continue;
+               if (bcmp(orig[c], rc->rc_data, rc->rc_size) != 0) {
+                       raidz_checksum_error(zio, rc, orig[c]);
+                       rc->rc_error = SET_ERROR(ECKSUM);
+                       ret++;
+               }
+               zio_buf_free(orig[c], rc->rc_size);
+       }
+
+       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)
+{
+       int c, error = 0;
+
+       for (c = 0; c < rm->rm_cols; c++)
+               error = zio_worst_error(error, rm->rm_col[c].rc_error);
+
+       return (error);
+}
+
+/*
+ * Iterate over all combinations of bad data and attempt a reconstruction.
+ * Note that the algorithm below is non-optimal because it doesn't take into
+ * account how reconstruction is actually performed. For example, with
+ * triple-parity RAID-Z the reconstruction procedure is the same if column 4
+ * is targeted as invalid as if columns 1 and 4 are targeted since in both
+ * cases we'd only use parity information in column 0.
+ */
+static int
+vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
+{
+       raidz_map_t *rm = zio->io_vsd;
+       raidz_col_t *rc;
+       void *orig[VDEV_RAIDZ_MAXPARITY];
+       int tstore[VDEV_RAIDZ_MAXPARITY + 2];
+       int *tgts = &tstore[1];
+       int curr, next, i, c, n;
+       int code, ret = 0;
+
+       ASSERT(total_errors < rm->rm_firstdatacol);
+
+       /*
+        * This simplifies one edge condition.
+        */
+       tgts[-1] = -1;
+
+       for (n = 1; n <= rm->rm_firstdatacol - total_errors; n++) {
+               /*
+                * Initialize the targets array by finding the first n columns
+                * that contain no error.
+                *
+                * If there were no data errors, we need to ensure that we're
+                * always explicitly attempting to reconstruct at least one
+                * data column. To do this, we simply push the highest target
+                * up into the data columns.
+                */
+               for (c = 0, i = 0; i < n; i++) {
+                       if (i == n - 1 && data_errors == 0 &&
+                           c < rm->rm_firstdatacol) {
+                               c = rm->rm_firstdatacol;
+                       }
+
+                       while (rm->rm_col[c].rc_error != 0) {
+                               c++;
+                               ASSERT3S(c, <, rm->rm_cols);
+                       }
+
+                       tgts[i] = c++;
+               }
+
+               /*
+                * Setting tgts[n] simplifies the other edge condition.
+                */
+               tgts[n] = rm->rm_cols;
+
+               /*
+                * These buffers were allocated in previous iterations.
+                */
+               for (i = 0; i < n - 1; i++) {
+                       ASSERT(orig[i] != NULL);
+               }
+
+               orig[n - 1] = zio_buf_alloc(rm->rm_col[0].rc_size);
+
+               curr = 0;
+               next = tgts[curr];
+
+               while (curr != n) {
+                       tgts[curr] = next;
+                       curr = 0;
+
+                       /*
+                        * Save off the original data that we're going to
+                        * attempt to reconstruct.
+                        */
+                       for (i = 0; i < n; i++) {
+                               ASSERT(orig[i] != NULL);
+                               c = tgts[i];
+                               ASSERT3S(c, >=, 0);
+                               ASSERT3S(c, <, rm->rm_cols);
+                               rc = &rm->rm_col[c];
+                               bcopy(rc->rc_data, orig[i], rc->rc_size);
+                       }
+
+                       /*
+                        * Attempt a reconstruction and exit the outer loop on
+                        * success.
+                        */
+                       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];
+                                       rc = &rm->rm_col[c];
+                                       ASSERT(rc->rc_error == 0);
+                                       if (rc->rc_tried)
+                                               raidz_checksum_error(zio, rc,
+                                                   orig[i]);
+                                       rc->rc_error = SET_ERROR(ECKSUM);
+                               }
+
+                               ret = code;
+                               goto done;
+                       }
+
+                       /*
+                        * Restore the original data.
+                        */
+                       for (i = 0; i < n; i++) {
+                               c = tgts[i];
+                               rc = &rm->rm_col[c];
+                               bcopy(orig[i], rc->rc_data, rc->rc_size);
+                       }
+
+                       do {
+                               /*
+                                * Find the next valid column after the curr
+                                * position..
+                                */
+                               for (next = tgts[curr] + 1;
+                                   next < rm->rm_cols &&
+                                   rm->rm_col[next].rc_error != 0; next++)
+                                       continue;
+
+                               ASSERT(next <= tgts[curr + 1]);
+
+                               /*
+                                * If that spot is available, we're done here.
+                                */
+                               if (next != tgts[curr + 1])
+                                       break;
+
+                               /*
+                                * Otherwise, find the next valid column after
+                                * the previous position.
+                                */
+                               for (c = tgts[curr - 1] + 1;
+                                   rm->rm_col[c].rc_error != 0; c++)
+                                       continue;
+
+                               tgts[curr] = c;
+                               curr++;
+
+                       } while (curr != n);
+               }
+       }
+       n--;
+done:
+       for (i = 0; i < n; i++) {
+               zio_buf_free(orig[i], rm->rm_col[0].rc_size);
+       }
+
+       return (ret);
+}
+
+/*
+ * Complete an IO operation on a RAIDZ VDev
+ *
+ * Outline:
+ * - For write operations:
+ *   1. Check for errors on the child IOs.
+ *   2. Return, setting an error code if too few child VDevs were written
+ *      to reconstruct the data later.  Note that partial writes are
+ *      considered successful if they can be reconstructed at all.
+ * - For read operations:
+ *   1. Check for errors on the child IOs.
+ *   2. If data errors occurred:
+ *      a. Try to reassemble the data from the parity available.
+ *      b. If we haven't yet read the parity drives, read them now.
+ *      c. If all parity drives have been read but the data still doesn't
+ *         reassemble with a correct checksum, then try combinatorial
+ *         reconstruction.
+ *      d. If that doesn't work, return an error.
+ *   3. If there were unexpected errors or this is a resilver operation,
+ *      rewrite the vdevs that had errors.
+ */
+static void
+vdev_raidz_io_done(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       vdev_t *cvd;
+       raidz_map_t *rm = zio->io_vsd;
+       raidz_col_t *rc = NULL;
+       int unexpected_errors = 0;
+       int parity_errors = 0;
+       int parity_untried = 0;
+       int data_errors = 0;
+       int total_errors = 0;
+       int n, c;
+       int tgts[VDEV_RAIDZ_MAXPARITY];
+       int code;
+
+       ASSERT(zio->io_bp != NULL);  /* XXX need to add code to enforce this */
+
+       ASSERT(rm->rm_missingparity <= rm->rm_firstdatacol);
+       ASSERT(rm->rm_missingdata <= rm->rm_cols - rm->rm_firstdatacol);
+
+       for (c = 0; c < rm->rm_cols; c++) {
+               rc = &rm->rm_col[c];
+
+               if (rc->rc_error) {
+                       ASSERT(rc->rc_error != ECKSUM); /* child has no bp */
+
+                       if (c < rm->rm_firstdatacol)
+                               parity_errors++;
+                       else
+                               data_errors++;
+
+                       if (!rc->rc_skipped)
+                               unexpected_errors++;
+
+                       total_errors++;
+               } else if (c < rm->rm_firstdatacol && !rc->rc_tried) {
+                       parity_untried++;
+               }
+       }
+
+       if (zio->io_type == ZIO_TYPE_WRITE) {
+               /*
+                * XXX -- for now, treat partial writes as a success.
+                * (If we couldn't write enough columns to reconstruct
+                * the data, the I/O failed.  Otherwise, good enough.)
+                *
+                * Now that we support write reallocation, it would be better
+                * to treat partial failure as real failure unless there are
+                * no non-degraded top-level vdevs left, and not update DTLs
+                * if we intend to reallocate.
+                */
+               /* XXPOLICY */
+               if (total_errors > rm->rm_firstdatacol)
+                       zio->io_error = vdev_raidz_worst_error(rm);
+
+               return;
+       }
+
+       ASSERT(zio->io_type == ZIO_TYPE_READ);
+       /*
+        * There are three potential phases for a read:
+        *      1. produce valid data from the columns read
+        *      2. read all disks and try again
+        *      3. perform combinatorial reconstruction
+        *
+        * Each phase is progressively both more expensive and less likely to
+        * occur. If we encounter more errors than we can repair or all phases
+        * fail, we have no choice but to return an error.
+        */
+
+       /*
+        * If the number of errors we saw was correctable -- less than or equal
+        * to the number of parity disks read -- attempt to produce data that
+        * has a valid checksum. Naturally, this case applies in the absence of
+        * any errors.
+        */
+       if (total_errors <= rm->rm_firstdatacol - parity_untried) {
+               if (data_errors == 0) {
+                       if (raidz_checksum_verify(zio) == 0) {
+                               /*
+                                * If we read parity information (unnecessarily
+                                * as it happens since no reconstruction was
+                                * needed) regenerate and verify the parity.
+                                * We also regenerate parity when resilvering
+                                * so we can write it out to the failed device
+                                * later.
+                                */
+                               if (parity_errors + parity_untried <
+                                   rm->rm_firstdatacol ||
+                                   (zio->io_flags & ZIO_FLAG_RESILVER)) {
+                                       n = raidz_parity_verify(zio, rm);
+                                       unexpected_errors += n;
+                                       ASSERT(parity_errors + n <=
+                                           rm->rm_firstdatacol);
+                               }
+                               goto done;
+                       }
+               } else {
+                       /*
+                        * We either attempt to read all the parity columns or
+                        * none of them. If we didn't try to read parity, we
+                        * wouldn't be here in the correctable case. There must
+                        * also have been fewer parity errors than parity
+                        * columns or, again, we wouldn't be in this code path.
+                        */
+                       ASSERT(parity_untried == 0);
+                       ASSERT(parity_errors < rm->rm_firstdatacol);
+
+                       /*
+                        * Identify the data columns that reported an error.
+                        */
+                       n = 0;
+                       for (c = rm->rm_firstdatacol; c < rm->rm_cols; c++) {
+                               rc = &rm->rm_col[c];
+                               if (rc->rc_error != 0) {
+                                       ASSERT(n < VDEV_RAIDZ_MAXPARITY);
+                                       tgts[n++] = c;
+                               }
+                       }
+
+                       ASSERT(rm->rm_firstdatacol >= n);
+
+                       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
+                                * parity disks produced correct data. This
+                                * routine is suboptimal in that it regenerates
+                                * the parity that we already used in addition
+                                * to the parity that we're attempting to
+                                * verify, but this should be a relatively
+                                * uncommon case, and can be optimized if it
+                                * becomes a problem. Note that we regenerate
+                                * parity when resilvering so we can write it
+                                * out to failed devices later.
+                                */
+                               if (parity_errors < rm->rm_firstdatacol - n ||
+                                   (zio->io_flags & ZIO_FLAG_RESILVER)) {
+                                       n = raidz_parity_verify(zio, rm);
+                                       unexpected_errors += n;
+                                       ASSERT(parity_errors + n <=
+                                           rm->rm_firstdatacol);
+                               }
+
+                               goto done;
+                       }
+               }
+       }
+
+       /*
+        * This isn't a typical situation -- either we got a read error or
+        * a child silently returned bad data. Read every block so we can
+        * try again with as much data and parity as we can track down. If
+        * we've already been through once before, all children will be marked
+        * as tried so we'll proceed to combinatorial reconstruction.
+        */
+       unexpected_errors = 1;
+       rm->rm_missingdata = 0;
+       rm->rm_missingparity = 0;
+
+       for (c = 0; c < rm->rm_cols; c++) {
+               if (rm->rm_col[c].rc_tried)
+                       continue;
+
+               zio_vdev_io_redone(zio);
+               do {
+                       rc = &rm->rm_col[c];
+                       if (rc->rc_tried)
+                               continue;
+                       zio_nowait(zio_vdev_child_io(zio, NULL,
+                           vd->vdev_child[rc->rc_devidx],
+                           rc->rc_offset, rc->rc_data, rc->rc_size,
+                           zio->io_type, zio->io_priority, 0,
+                           vdev_raidz_child_done, rc));
+               } while (++c < rm->rm_cols);
+
+               return;
+       }
+
+       /*
+        * At this point we've attempted to reconstruct the data given the
+        * errors we detected, and we've attempted to read all columns. There
+        * must, therefore, be one or more additional problems -- silent errors
+        * resulting in invalid data rather than explicit I/O errors resulting
+        * in absent data. We check if there is enough additional data to
+        * possibly reconstruct the data and then perform combinatorial
+        * reconstruction over all possible combinations. If that fails,
+        * we're cooked.
+        */
+       if (total_errors > rm->rm_firstdatacol) {
+               zio->io_error = vdev_raidz_worst_error(rm);
+
+       } else if (total_errors < rm->rm_firstdatacol &&
+           (code = vdev_raidz_combrec(zio, total_errors, data_errors)) != 0) {
+               /*
+                * If we didn't use all the available parity for the
+                * combinatorial reconstruction, verify that the remaining
+                * parity is correct.
+                */
+               if (code != (1 << rm->rm_firstdatacol) - 1)
+                       (void) raidz_parity_verify(zio, rm);
+       } else {
+               /*
+                * We're here because either:
+                *
+                *      total_errors == rm_first_datacol, or
+                *      vdev_raidz_combrec() failed
+                *
+                * In either case, there is enough bad data to prevent
+                * reconstruction.
+                *
+                * Start checksum ereports for all children which haven't
+                * failed, and the IO wasn't speculative.
+                */
+               zio->io_error = SET_ERROR(ECKSUM);
+
+               if (!(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+                       for (c = 0; c < rm->rm_cols; c++) {
+                               rc = &rm->rm_col[c];
+                               if (rc->rc_error == 0) {
+                                       zio_bad_cksum_t zbc;
+                                       zbc.zbc_has_cksum = 0;
+                                       zbc.zbc_injected =
+                                           rm->rm_ecksuminjected;
+
+                                       zfs_ereport_start_checksum(
+                                           zio->io_spa,
+                                           vd->vdev_child[rc->rc_devidx],
+                                           zio, rc->rc_offset, rc->rc_size,
+                                           (void *)(uintptr_t)c, &zbc);
+                               }
+                       }
+               }
+       }
+
+done:
+       zio_checksum_verified(zio);
+
+       if (zio->io_error == 0 && spa_writeable(zio->io_spa) &&
+           (unexpected_errors || (zio->io_flags & ZIO_FLAG_RESILVER))) {
+               /*
+                * Use the good data we have in hand to repair damaged children.
+                */
+               for (c = 0; c < rm->rm_cols; c++) {
+                       rc = &rm->rm_col[c];
+                       cvd = vd->vdev_child[rc->rc_devidx];
+
+                       if (rc->rc_error == 0)
+                               continue;
+
+                       zio_nowait(zio_vdev_child_io(zio, NULL, cvd,
+                           rc->rc_offset, rc->rc_data, rc->rc_size,
+                           ZIO_TYPE_WRITE, ZIO_PRIORITY_ASYNC_WRITE,
+                           ZIO_FLAG_IO_REPAIR | (unexpected_errors ?
+                           ZIO_FLAG_SELF_HEAL : 0), NULL, NULL));
+               }
+       }
+}
+
+static void
+vdev_raidz_state_change(vdev_t *vd, int faulted, int degraded)
+{
+       if (faulted > vd->vdev_nparity)
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_NO_REPLICAS);
+       else if (degraded + faulted != 0)
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_DEGRADED, VDEV_AUX_NONE);
+       else
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_HEALTHY, VDEV_AUX_NONE);
+}
+
+vdev_ops_t vdev_raidz_ops = {
+       vdev_raidz_open,
+       vdev_raidz_close,
+       vdev_raidz_asize,
+       vdev_raidz_io_start,
+       vdev_raidz_io_done,
+       vdev_raidz_state_change,
+       NULL,
+       NULL,
+       VDEV_TYPE_RAIDZ,        /* name of this vdev type */
+       B_FALSE                 /* not a leaf vdev */
+};
diff --git a/zfs/module/zfs/vdev_root.c b/zfs/module/zfs/vdev_root.c
new file mode 100644 (file)
index 0000000..90250b0
--- /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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/fs/zfs.h>
+
+/*
+ * Virtual device vector for the pool's root vdev.
+ */
+
+/*
+ * We should be able to tolerate one failure with absolutely no damage
+ * to our metadata.  Two failures will take out space maps, a bunch of
+ * indirect block trees, meta dnodes, dnodes, etc.  Probably not a happy
+ * place to live.  When we get smarter, we can liberalize this policy.
+ * e.g. If we haven't lost two consecutive top-level vdevs, then we are
+ * probably fine.  Adding bean counters during alloc/free can make this
+ * future guesswork more accurate.
+ */
+static int
+too_many_errors(vdev_t *vd, int numerrors)
+{
+       ASSERT3U(numerrors, <=, vd->vdev_children);
+       return (numerrors > 0);
+}
+
+static int
+vdev_root_open(vdev_t *vd, uint64_t *asize, uint64_t *max_asize,
+    uint64_t *ashift)
+{
+       int lasterror = 0;
+       int numerrors = 0;
+       int c;
+
+       if (vd->vdev_children == 0) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       vdev_open_children(vd);
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               vdev_t *cvd = vd->vdev_child[c];
+
+               if (cvd->vdev_open_error && !cvd->vdev_islog) {
+                       lasterror = cvd->vdev_open_error;
+                       numerrors++;
+               }
+       }
+
+       if (too_many_errors(vd, numerrors)) {
+               vd->vdev_stat.vs_aux = VDEV_AUX_NO_REPLICAS;
+               return (lasterror);
+       }
+
+       *asize = 0;
+       *max_asize = 0;
+       *ashift = 0;
+
+       return (0);
+}
+
+static void
+vdev_root_close(vdev_t *vd)
+{
+       int c;
+
+       for (c = 0; c < vd->vdev_children; c++)
+               vdev_close(vd->vdev_child[c]);
+}
+
+static void
+vdev_root_state_change(vdev_t *vd, int faulted, int degraded)
+{
+       if (too_many_errors(vd, faulted)) {
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
+                   VDEV_AUX_NO_REPLICAS);
+       } else if (degraded) {
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_DEGRADED, VDEV_AUX_NONE);
+       } else {
+               vdev_set_state(vd, B_FALSE, VDEV_STATE_HEALTHY, VDEV_AUX_NONE);
+       }
+}
+
+vdev_ops_t vdev_root_ops = {
+       vdev_root_open,
+       vdev_root_close,
+       vdev_default_asize,
+       NULL,                   /* io_start - not applicable to the root */
+       NULL,                   /* io_done - not applicable to the root */
+       vdev_root_state_change,
+       NULL,
+       NULL,
+       VDEV_TYPE_ROOT,         /* name of this vdev type */
+       B_FALSE                 /* not a leaf vdev */
+};
diff --git a/zfs/module/zfs/zap.c b/zfs/module/zfs/zap.c
new file mode 100644 (file)
index 0000000..c9398e8
--- /dev/null
@@ -0,0 +1,1372 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+/*
+ * This file contains the top half of the zfs directory structure
+ * implementation. The bottom half is in zap_leaf.c.
+ *
+ * The zdir is an extendable hash data structure. There is a table of
+ * pointers to buckets (zap_t->zd_data->zd_leafs). The buckets are
+ * each a constant size and hold a variable number of directory entries.
+ * The buckets (aka "leaf nodes") are implemented in zap_leaf.c.
+ *
+ * The pointer table holds a power of 2 number of pointers.
+ * (1<<zap_t->zd_data->zd_phys->zd_prefix_len).  The bucket pointed to
+ * by the pointer at index i in the table holds entries whose hash value
+ * has a zd_prefix_len - bit prefix
+ */
+
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/zfs_context.h>
+#include <sys/zfs_znode.h>
+#include <sys/fs/zfs.h>
+#include <sys/zap.h>
+#include <sys/refcount.h>
+#include <sys/zap_impl.h>
+#include <sys/zap_leaf.h>
+
+int fzap_default_block_shift = 14; /* 16k blocksize */
+
+extern inline zap_phys_t *zap_f_phys(zap_t *zap);
+
+static uint64_t zap_allocate_blocks(zap_t *zap, int nblocks);
+
+void
+fzap_byteswap(void *vbuf, size_t size)
+{
+       uint64_t block_type;
+
+       block_type = *(uint64_t *)vbuf;
+
+       if (block_type == ZBT_LEAF || block_type == BSWAP_64(ZBT_LEAF))
+               zap_leaf_byteswap(vbuf, size);
+       else {
+               /* it's a ptrtbl block */
+               byteswap_uint64_array(vbuf, size);
+       }
+}
+
+void
+fzap_upgrade(zap_t *zap, dmu_tx_t *tx, zap_flags_t flags)
+{
+       dmu_buf_t *db;
+       zap_leaf_t *l;
+       int i;
+       zap_phys_t *zp;
+
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+       zap->zap_ismicro = FALSE;
+
+       zap->zap_dbu.dbu_evict_func = zap_evict;
+
+       mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
+       zap->zap_f.zap_block_shift = highbit64(zap->zap_dbuf->db_size) - 1;
+
+       zp = zap_f_phys(zap);
+       /*
+        * explicitly zero it since it might be coming from an
+        * initialized microzap
+        */
+       bzero(zap->zap_dbuf->db_data, zap->zap_dbuf->db_size);
+       zp->zap_block_type = ZBT_HEADER;
+       zp->zap_magic = ZAP_MAGIC;
+
+       zp->zap_ptrtbl.zt_shift = ZAP_EMBEDDED_PTRTBL_SHIFT(zap);
+
+       zp->zap_freeblk = 2;            /* block 1 will be the first leaf */
+       zp->zap_num_leafs = 1;
+       zp->zap_num_entries = 0;
+       zp->zap_salt = zap->zap_salt;
+       zp->zap_normflags = zap->zap_normflags;
+       zp->zap_flags = flags;
+
+       /* block 1 will be the first leaf */
+       for (i = 0; i < (1<<zp->zap_ptrtbl.zt_shift); i++)
+               ZAP_EMBEDDED_PTRTBL_ENT(zap, i) = 1;
+
+       /*
+        * set up block 1 - the first leaf
+        */
+       VERIFY(0 == dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           1<<FZAP_BLOCK_SHIFT(zap), FTAG, &db, DMU_READ_NO_PREFETCH));
+       dmu_buf_will_dirty(db, tx);
+
+       l = kmem_zalloc(sizeof (zap_leaf_t), KM_SLEEP);
+       l->l_dbuf = db;
+
+       zap_leaf_init(l, zp->zap_normflags != 0);
+
+       kmem_free(l, sizeof (zap_leaf_t));
+       dmu_buf_rele(db, FTAG);
+}
+
+static int
+zap_tryupgradedir(zap_t *zap, dmu_tx_t *tx)
+{
+       if (RW_WRITE_HELD(&zap->zap_rwlock))
+               return (1);
+       if (rw_tryupgrade(&zap->zap_rwlock)) {
+               dmu_buf_will_dirty(zap->zap_dbuf, tx);
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * Generic routines for dealing with the pointer & cookie tables.
+ */
+
+static int
+zap_table_grow(zap_t *zap, zap_table_phys_t *tbl,
+    void (*transfer_func)(const uint64_t *src, uint64_t *dst, int n),
+    dmu_tx_t *tx)
+{
+       uint64_t b, newblk;
+       dmu_buf_t *db_old, *db_new;
+       int err;
+       int bs = FZAP_BLOCK_SHIFT(zap);
+       int hepb = 1<<(bs-4);
+       /* hepb = half the number of entries in a block */
+
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+       ASSERT(tbl->zt_blk != 0);
+       ASSERT(tbl->zt_numblks > 0);
+
+       if (tbl->zt_nextblk != 0) {
+               newblk = tbl->zt_nextblk;
+       } else {
+               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);
+       }
+
+       /*
+        * Copy the ptrtbl from the old to new location.
+        */
+
+       b = tbl->zt_blks_copied;
+       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           (tbl->zt_blk + b) << bs, FTAG, &db_old, DMU_READ_NO_PREFETCH);
+       if (err)
+               return (err);
+
+       /* first half of entries in old[b] go to new[2*b+0] */
+       VERIFY(0 == dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           (newblk + 2*b+0) << bs, FTAG, &db_new, DMU_READ_NO_PREFETCH));
+       dmu_buf_will_dirty(db_new, tx);
+       transfer_func(db_old->db_data, db_new->db_data, hepb);
+       dmu_buf_rele(db_new, FTAG);
+
+       /* second half of entries in old[b] go to new[2*b+1] */
+       VERIFY(0 == dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           (newblk + 2*b+1) << bs, FTAG, &db_new, DMU_READ_NO_PREFETCH));
+       dmu_buf_will_dirty(db_new, tx);
+       transfer_func((uint64_t *)db_old->db_data + hepb,
+           db_new->db_data, hepb);
+       dmu_buf_rele(db_new, FTAG);
+
+       dmu_buf_rele(db_old, FTAG);
+
+       tbl->zt_blks_copied++;
+
+       dprintf("copied block %llu of %llu\n",
+           tbl->zt_blks_copied, tbl->zt_numblks);
+
+       if (tbl->zt_blks_copied == tbl->zt_numblks) {
+               (void) dmu_free_range(zap->zap_objset, zap->zap_object,
+                   tbl->zt_blk << bs, tbl->zt_numblks << bs, tx);
+
+               tbl->zt_blk = newblk;
+               tbl->zt_numblks *= 2;
+               tbl->zt_shift++;
+               tbl->zt_nextblk = 0;
+               tbl->zt_blks_copied = 0;
+
+               dprintf("finished; numblocks now %llu (%uk entries)\n",
+                   tbl->zt_numblks, 1<<(tbl->zt_shift-10));
+       }
+
+       return (0);
+}
+
+static int
+zap_table_store(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t val,
+    dmu_tx_t *tx)
+{
+       int err;
+       uint64_t blk, off;
+       int bs = FZAP_BLOCK_SHIFT(zap);
+       dmu_buf_t *db;
+
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+       ASSERT(tbl->zt_blk != 0);
+
+       dprintf("storing %llx at index %llx\n", val, idx);
+
+       blk = idx >> (bs-3);
+       off = idx & ((1<<(bs-3))-1);
+
+       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           (tbl->zt_blk + blk) << bs, FTAG, &db, DMU_READ_NO_PREFETCH);
+       if (err)
+               return (err);
+       dmu_buf_will_dirty(db, tx);
+
+       if (tbl->zt_nextblk != 0) {
+               uint64_t idx2 = idx * 2;
+               uint64_t blk2 = idx2 >> (bs-3);
+               uint64_t off2 = idx2 & ((1<<(bs-3))-1);
+               dmu_buf_t *db2;
+
+               err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+                   (tbl->zt_nextblk + blk2) << bs, FTAG, &db2,
+                   DMU_READ_NO_PREFETCH);
+               if (err) {
+                       dmu_buf_rele(db, FTAG);
+                       return (err);
+               }
+               dmu_buf_will_dirty(db2, tx);
+               ((uint64_t *)db2->db_data)[off2] = val;
+               ((uint64_t *)db2->db_data)[off2+1] = val;
+               dmu_buf_rele(db2, FTAG);
+       }
+
+       ((uint64_t *)db->db_data)[off] = val;
+       dmu_buf_rele(db, FTAG);
+
+       return (0);
+}
+
+static int
+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;
+       int bs = FZAP_BLOCK_SHIFT(zap);
+
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+
+       blk = idx >> (bs-3);
+       off = idx & ((1<<(bs-3))-1);
+
+       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           (tbl->zt_blk + blk) << bs, FTAG, &db, DMU_READ_NO_PREFETCH);
+       if (err)
+               return (err);
+       *valp = ((uint64_t *)db->db_data)[off];
+       dmu_buf_rele(db, FTAG);
+
+       if (tbl->zt_nextblk != 0) {
+               /*
+                * read the nextblk for the sake of i/o error checking,
+                * so that zap_table_load() will catch errors for
+                * zap_table_store.
+                */
+               blk = (idx*2) >> (bs-3);
+
+               err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+                   (tbl->zt_nextblk + blk) << bs, FTAG, &db,
+                   DMU_READ_NO_PREFETCH);
+               if (err == 0)
+                       dmu_buf_rele(db, FTAG);
+       }
+       return (err);
+}
+
+/*
+ * Routines for growing the ptrtbl.
+ */
+
+static void
+zap_ptrtbl_transfer(const uint64_t *src, uint64_t *dst, int n)
+{
+       int i;
+       for (i = 0; i < n; i++) {
+               uint64_t lb = src[i];
+               dst[2*i+0] = lb;
+               dst[2*i+1] = lb;
+       }
+}
+
+static int
+zap_grow_ptrtbl(zap_t *zap, dmu_tx_t *tx)
+{
+       /*
+        * The pointer table should never use more hash bits than we
+        * have (otherwise we'd be using useless zero bits to index it).
+        * If we are within 2 bits of running out, stop growing, since
+        * this is already an aberrant condition.
+        */
+       if (zap_f_phys(zap)->zap_ptrtbl.zt_shift >= zap_hashbits(zap) - 2)
+               return (SET_ERROR(ENOSPC));
+
+       if (zap_f_phys(zap)->zap_ptrtbl.zt_numblks == 0) {
+               /*
+                * We are outgrowing the "embedded" ptrtbl (the one
+                * stored in the header block).  Give it its own entire
+                * block, which will double the size of the ptrtbl.
+                */
+               uint64_t newblk;
+               dmu_buf_t *db_new;
+               int err;
+
+               ASSERT3U(zap_f_phys(zap)->zap_ptrtbl.zt_shift, ==,
+                   ZAP_EMBEDDED_PTRTBL_SHIFT(zap));
+               ASSERT0(zap_f_phys(zap)->zap_ptrtbl.zt_blk);
+
+               newblk = zap_allocate_blocks(zap, 1);
+               err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+                   newblk << FZAP_BLOCK_SHIFT(zap), FTAG, &db_new,
+                   DMU_READ_NO_PREFETCH);
+               if (err)
+                       return (err);
+               dmu_buf_will_dirty(db_new, tx);
+               zap_ptrtbl_transfer(&ZAP_EMBEDDED_PTRTBL_ENT(zap, 0),
+                   db_new->db_data, 1 << ZAP_EMBEDDED_PTRTBL_SHIFT(zap));
+               dmu_buf_rele(db_new, FTAG);
+
+               zap_f_phys(zap)->zap_ptrtbl.zt_blk = newblk;
+               zap_f_phys(zap)->zap_ptrtbl.zt_numblks = 1;
+               zap_f_phys(zap)->zap_ptrtbl.zt_shift++;
+
+               ASSERT3U(1ULL << zap_f_phys(zap)->zap_ptrtbl.zt_shift, ==,
+                   zap_f_phys(zap)->zap_ptrtbl.zt_numblks <<
+                   (FZAP_BLOCK_SHIFT(zap)-3));
+
+               return (0);
+       } else {
+               return (zap_table_grow(zap, &zap_f_phys(zap)->zap_ptrtbl,
+                   zap_ptrtbl_transfer, tx));
+       }
+}
+
+static void
+zap_increment_num_entries(zap_t *zap, int delta, dmu_tx_t *tx)
+{
+       dmu_buf_will_dirty(zap->zap_dbuf, tx);
+       mutex_enter(&zap->zap_f.zap_num_entries_mtx);
+       ASSERT(delta > 0 || zap_f_phys(zap)->zap_num_entries >= -delta);
+       zap_f_phys(zap)->zap_num_entries += delta;
+       mutex_exit(&zap->zap_f.zap_num_entries_mtx);
+}
+
+static uint64_t
+zap_allocate_blocks(zap_t *zap, int nblocks)
+{
+       uint64_t newblk;
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+       newblk = zap_f_phys(zap)->zap_freeblk;
+       zap_f_phys(zap)->zap_freeblk += nblocks;
+       return (newblk);
+}
+
+static void
+zap_leaf_pageout(void *dbu)
+{
+       zap_leaf_t *l = dbu;
+
+       rw_destroy(&l->l_rwlock);
+       kmem_free(l, sizeof (zap_leaf_t));
+}
+
+static zap_leaf_t *
+zap_create_leaf(zap_t *zap, dmu_tx_t *tx)
+{
+       void *winner;
+       zap_leaf_t *l = kmem_zalloc(sizeof (zap_leaf_t), KM_SLEEP);
+
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+
+       rw_init(&l->l_rwlock, NULL, RW_DEFAULT, NULL);
+       rw_enter(&l->l_rwlock, RW_WRITER);
+       l->l_blkid = zap_allocate_blocks(zap, 1);
+       l->l_dbuf = NULL;
+
+       VERIFY(0 == dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           l->l_blkid << FZAP_BLOCK_SHIFT(zap), NULL, &l->l_dbuf,
+           DMU_READ_NO_PREFETCH));
+       dmu_buf_init_user(&l->l_dbu, zap_leaf_pageout, &l->l_dbuf);
+       winner = dmu_buf_set_user(l->l_dbuf, &l->l_dbu);
+       ASSERT(winner == NULL);
+       dmu_buf_will_dirty(l->l_dbuf, tx);
+
+       zap_leaf_init(l, zap->zap_normflags != 0);
+
+       zap_f_phys(zap)->zap_num_leafs++;
+
+       return (l);
+}
+
+int
+fzap_count(zap_t *zap, uint64_t *count)
+{
+       ASSERT(!zap->zap_ismicro);
+       mutex_enter(&zap->zap_f.zap_num_entries_mtx); /* unnecessary */
+       *count = zap_f_phys(zap)->zap_num_entries;
+       mutex_exit(&zap->zap_f.zap_num_entries_mtx);
+       return (0);
+}
+
+/*
+ * Routines for obtaining zap_leaf_t's
+ */
+
+void
+zap_put_leaf(zap_leaf_t *l)
+{
+       rw_exit(&l->l_rwlock);
+       dmu_buf_rele(l->l_dbuf, NULL);
+}
+
+static zap_leaf_t *
+zap_open_leaf(uint64_t blkid, dmu_buf_t *db)
+{
+       zap_leaf_t *l, *winner;
+
+       ASSERT(blkid != 0);
+
+       l = kmem_zalloc(sizeof (zap_leaf_t), KM_SLEEP);
+       rw_init(&l->l_rwlock, NULL, RW_DEFAULT, NULL);
+       rw_enter(&l->l_rwlock, RW_WRITER);
+       l->l_blkid = blkid;
+       l->l_bs = highbit64(db->db_size) - 1;
+       l->l_dbuf = db;
+
+       dmu_buf_init_user(&l->l_dbu, zap_leaf_pageout, &l->l_dbuf);
+       winner = dmu_buf_set_user(db, &l->l_dbu);
+
+       rw_exit(&l->l_rwlock);
+       if (winner != NULL) {
+               /* someone else set it first */
+               zap_leaf_pageout(&l->l_dbu);
+               l = winner;
+       }
+
+       /*
+        * lhr_pad was previously used for the next leaf in the leaf
+        * chain.  There should be no chained leafs (as we have removed
+        * support for them).
+        */
+       ASSERT0(zap_leaf_phys(l)->l_hdr.lh_pad1);
+
+       /*
+        * There should be more hash entries than there can be
+        * chunks to put in the hash table
+        */
+       ASSERT3U(ZAP_LEAF_HASH_NUMENTRIES(l), >, ZAP_LEAF_NUMCHUNKS(l) / 3);
+
+       /* The chunks should begin at the end of the hash table */
+       ASSERT3P(&ZAP_LEAF_CHUNK(l, 0), ==, (zap_leaf_chunk_t *)
+           &zap_leaf_phys(l)->l_hash[ZAP_LEAF_HASH_NUMENTRIES(l)]);
+
+       /* The chunks should end at the end of the block */
+       ASSERT3U((uintptr_t)&ZAP_LEAF_CHUNK(l, ZAP_LEAF_NUMCHUNKS(l)) -
+           (uintptr_t)zap_leaf_phys(l), ==, l->l_dbuf->db_size);
+
+       return (l);
+}
+
+static int
+zap_get_leaf_byblk(zap_t *zap, uint64_t blkid, dmu_tx_t *tx, krw_t lt,
+    zap_leaf_t **lp)
+{
+       dmu_buf_t *db;
+       zap_leaf_t *l;
+       int bs = FZAP_BLOCK_SHIFT(zap);
+       int err;
+
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+
+       /*
+        * If system crashed just after dmu_free_long_range in zfs_rmnode, we
+        * would be left with an empty xattr dir in delete queue. blkid=0
+        * would be passed in when doing zfs_purgedir. If that's the case we
+        * should just return immediately. The underlying objects should
+        * already be freed, so this should be perfectly fine.
+        */
+       if (blkid == 0)
+               return (ENOENT);
+
+       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+           blkid << bs, NULL, &db, DMU_READ_NO_PREFETCH);
+       if (err)
+               return (err);
+
+       ASSERT3U(db->db_object, ==, zap->zap_object);
+       ASSERT3U(db->db_offset, ==, blkid << bs);
+       ASSERT3U(db->db_size, ==, 1 << bs);
+       ASSERT(blkid != 0);
+
+       l = dmu_buf_get_user(db);
+
+       if (l == NULL)
+               l = zap_open_leaf(blkid, db);
+
+       rw_enter(&l->l_rwlock, lt);
+       /*
+        * Must lock before dirtying, otherwise zap_leaf_phys(l) could change,
+        * causing ASSERT below to fail.
+        */
+       if (lt == RW_WRITER)
+               dmu_buf_will_dirty(db, tx);
+       ASSERT3U(l->l_blkid, ==, blkid);
+       ASSERT3P(l->l_dbuf, ==, db);
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_block_type, ==, ZBT_LEAF);
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_magic, ==, ZAP_LEAF_MAGIC);
+
+       *lp = l;
+       return (0);
+}
+
+static int
+zap_idx_to_blk(zap_t *zap, uint64_t idx, uint64_t *valp)
+{
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+
+       if (zap_f_phys(zap)->zap_ptrtbl.zt_numblks == 0) {
+               ASSERT3U(idx, <,
+                   (1ULL << zap_f_phys(zap)->zap_ptrtbl.zt_shift));
+               *valp = ZAP_EMBEDDED_PTRTBL_ENT(zap, idx);
+               return (0);
+       } else {
+               return (zap_table_load(zap, &zap_f_phys(zap)->zap_ptrtbl,
+                   idx, valp));
+       }
+}
+
+static int
+zap_set_idx_to_blk(zap_t *zap, uint64_t idx, uint64_t blk, dmu_tx_t *tx)
+{
+       ASSERT(tx != NULL);
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+
+       if (zap_f_phys(zap)->zap_ptrtbl.zt_blk == 0) {
+               ZAP_EMBEDDED_PTRTBL_ENT(zap, idx) = blk;
+               return (0);
+       } else {
+               return (zap_table_store(zap, &zap_f_phys(zap)->zap_ptrtbl,
+                   idx, blk, tx));
+       }
+}
+
+static int
+zap_deref_leaf(zap_t *zap, uint64_t h, dmu_tx_t *tx, krw_t lt, zap_leaf_t **lp)
+{
+       uint64_t idx, blk;
+       int err;
+
+       ASSERT(zap->zap_dbuf == NULL ||
+           zap_f_phys(zap) == zap->zap_dbuf->db_data);
+       ASSERT3U(zap_f_phys(zap)->zap_magic, ==, ZAP_MAGIC);
+       idx = ZAP_HASH_IDX(h, zap_f_phys(zap)->zap_ptrtbl.zt_shift);
+       err = zap_idx_to_blk(zap, idx, &blk);
+       if (err != 0)
+               return (err);
+       err = zap_get_leaf_byblk(zap, blk, tx, lt, lp);
+
+       ASSERT(err ||
+           ZAP_HASH_IDX(h, zap_leaf_phys(*lp)->l_hdr.lh_prefix_len) ==
+           zap_leaf_phys(*lp)->l_hdr.lh_prefix);
+       return (err);
+}
+
+static int
+zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp)
+{
+       zap_t *zap = zn->zn_zap;
+       uint64_t hash = zn->zn_hash;
+       zap_leaf_t *nl;
+       int prefix_diff, i, err;
+       uint64_t sibling;
+       int old_prefix_len = zap_leaf_phys(l)->l_hdr.lh_prefix_len;
+
+       ASSERT3U(old_prefix_len, <=, zap_f_phys(zap)->zap_ptrtbl.zt_shift);
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+
+       ASSERT3U(ZAP_HASH_IDX(hash, old_prefix_len), ==,
+           zap_leaf_phys(l)->l_hdr.lh_prefix);
+
+       if (zap_tryupgradedir(zap, tx) == 0 ||
+           old_prefix_len == zap_f_phys(zap)->zap_ptrtbl.zt_shift) {
+               /* We failed to upgrade, or need to grow the pointer table */
+               objset_t *os = zap->zap_objset;
+               uint64_t object = zap->zap_object;
+
+               zap_put_leaf(l);
+               zap_unlockdir(zap);
+               err = zap_lockdir(os, object, tx, RW_WRITER,
+                   FALSE, FALSE, &zn->zn_zap);
+               zap = zn->zn_zap;
+               if (err)
+                       return (err);
+               ASSERT(!zap->zap_ismicro);
+
+               while (old_prefix_len ==
+                   zap_f_phys(zap)->zap_ptrtbl.zt_shift) {
+                       err = zap_grow_ptrtbl(zap, tx);
+                       if (err)
+                               return (err);
+               }
+
+               err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+               if (err)
+                       return (err);
+
+               if (zap_leaf_phys(l)->l_hdr.lh_prefix_len != old_prefix_len) {
+                       /* it split while our locks were down */
+                       *lp = l;
+                       return (0);
+               }
+       }
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+       ASSERT3U(old_prefix_len, <, zap_f_phys(zap)->zap_ptrtbl.zt_shift);
+       ASSERT3U(ZAP_HASH_IDX(hash, old_prefix_len), ==,
+           zap_leaf_phys(l)->l_hdr.lh_prefix);
+
+       prefix_diff = zap_f_phys(zap)->zap_ptrtbl.zt_shift -
+           (old_prefix_len + 1);
+       sibling = (ZAP_HASH_IDX(hash, old_prefix_len + 1) | 1) << prefix_diff;
+
+       /* check for i/o errors before doing zap_leaf_split */
+       for (i = 0; i < (1ULL<<prefix_diff); i++) {
+               uint64_t blk;
+               err = zap_idx_to_blk(zap, sibling+i, &blk);
+               if (err)
+                       return (err);
+               ASSERT3U(blk, ==, l->l_blkid);
+       }
+
+       nl = zap_create_leaf(zap, tx);
+       zap_leaf_split(l, nl, zap->zap_normflags != 0);
+
+       /* set sibling pointers */
+       for (i = 0; i < (1ULL << prefix_diff); i++) {
+               err = zap_set_idx_to_blk(zap, sibling+i, nl->l_blkid, tx);
+               ASSERT0(err); /* we checked for i/o errors above */
+       }
+
+       if (hash & (1ULL << (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len))) {
+               /* we want the sibling */
+               zap_put_leaf(l);
+               *lp = nl;
+       } else {
+               zap_put_leaf(nl);
+               *lp = l;
+       }
+
+       return (0);
+}
+
+static void
+zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx)
+{
+       zap_t *zap = zn->zn_zap;
+       int shift = zap_f_phys(zap)->zap_ptrtbl.zt_shift;
+       int leaffull = (zap_leaf_phys(l)->l_hdr.lh_prefix_len == shift &&
+           zap_leaf_phys(l)->l_hdr.lh_nfree < ZAP_LEAF_LOW_WATER);
+
+       zap_put_leaf(l);
+
+       if (leaffull || zap_f_phys(zap)->zap_ptrtbl.zt_nextblk) {
+               int err;
+
+               /*
+                * We are in the middle of growing the pointer table, or
+                * this leaf will soon make us grow it.
+                */
+               if (zap_tryupgradedir(zap, tx) == 0) {
+                       objset_t *os = zap->zap_objset;
+                       uint64_t zapobj = zap->zap_object;
+
+                       zap_unlockdir(zap);
+                       err = zap_lockdir(os, zapobj, tx,
+                           RW_WRITER, FALSE, FALSE, &zn->zn_zap);
+                       zap = zn->zn_zap;
+                       if (err)
+                               return;
+               }
+
+               /* could have finished growing while our locks were down */
+               if (zap_f_phys(zap)->zap_ptrtbl.zt_shift == shift)
+                       (void) zap_grow_ptrtbl(zap, tx);
+       }
+}
+
+static int
+fzap_checkname(zap_name_t *zn)
+{
+       if (zn->zn_key_orig_numints * zn->zn_key_intlen > ZAP_MAXNAMELEN)
+               return (SET_ERROR(ENAMETOOLONG));
+       return (0);
+}
+
+static int
+fzap_checksize(uint64_t integer_size, uint64_t num_integers)
+{
+       /* Only integer sizes supported by C */
+       switch (integer_size) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               break;
+       default:
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (integer_size * num_integers > ZAP_MAXVALUELEN)
+               return (E2BIG);
+
+       return (0);
+}
+
+static int
+fzap_check(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers)
+{
+       int err;
+
+       if ((err = fzap_checkname(zn)) != 0)
+               return (err);
+       return (fzap_checksize(integer_size, num_integers));
+}
+
+/*
+ * Routines for manipulating attributes.
+ */
+int
+fzap_lookup(zap_name_t *zn,
+    uint64_t integer_size, uint64_t num_integers, void *buf,
+    char *realname, int rn_len, boolean_t *ncp)
+{
+       zap_leaf_t *l;
+       int err;
+       zap_entry_handle_t zeh;
+
+       if ((err = fzap_checkname(zn)) != 0)
+               return (err);
+
+       err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, NULL, RW_READER, &l);
+       if (err != 0)
+               return (err);
+       err = zap_leaf_lookup(l, zn, &zeh);
+       if (err == 0) {
+               if ((err = fzap_checksize(integer_size, num_integers)) != 0) {
+                       zap_put_leaf(l);
+                       return (err);
+               }
+
+               err = zap_entry_read(&zeh, integer_size, num_integers, buf);
+               (void) zap_entry_read_name(zn->zn_zap, &zeh, rn_len, realname);
+               if (ncp) {
+                       *ncp = zap_entry_normalization_conflict(&zeh,
+                           zn, NULL, zn->zn_zap);
+               }
+       }
+
+       zap_put_leaf(l);
+       return (err);
+}
+
+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)
+{
+       zap_leaf_t *l;
+       int err;
+       zap_entry_handle_t zeh;
+       zap_t *zap = zn->zn_zap;
+
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+       ASSERT(!zap->zap_ismicro);
+       ASSERT(fzap_check(zn, integer_size, num_integers) == 0);
+
+       err = zap_deref_leaf(zap, zn->zn_hash, tx, RW_WRITER, &l);
+       if (err != 0)
+               return (err);
+retry:
+       err = zap_leaf_lookup(l, zn, &zeh);
+       if (err == 0) {
+               err = SET_ERROR(EEXIST);
+               goto out;
+       }
+       if (err != ENOENT)
+               goto out;
+
+       err = zap_entry_create(l, zn, cd,
+           integer_size, num_integers, val, &zeh);
+
+       if (err == 0) {
+               zap_increment_num_entries(zap, 1, tx);
+       } else if (err == EAGAIN) {
+               err = zap_expand_leaf(zn, l, tx, &l);
+               zap = zn->zn_zap;       /* zap_expand_leaf() may change zap */
+               if (err == 0)
+                       goto retry;
+       }
+
+out:
+       if (zap != NULL)
+               zap_put_leaf_maybe_grow_ptrtbl(zn, l, 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)
+{
+       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));
+}
+
+int
+fzap_update(zap_name_t *zn,
+    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx)
+{
+       zap_leaf_t *l;
+       int err, create;
+       zap_entry_handle_t zeh;
+       zap_t *zap = zn->zn_zap;
+
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+       err = fzap_check(zn, integer_size, num_integers);
+       if (err != 0)
+               return (err);
+
+       err = zap_deref_leaf(zap, zn->zn_hash, tx, RW_WRITER, &l);
+       if (err != 0)
+               return (err);
+retry:
+       err = zap_leaf_lookup(l, zn, &zeh);
+       create = (err == ENOENT);
+       ASSERT(err == 0 || err == ENOENT);
+
+       if (create) {
+               err = zap_entry_create(l, zn, ZAP_NEED_CD,
+                   integer_size, num_integers, val, &zeh);
+               if (err == 0)
+                       zap_increment_num_entries(zap, 1, tx);
+       } else {
+               err = zap_entry_update(&zeh, integer_size, num_integers, val);
+       }
+
+       if (err == EAGAIN) {
+               err = zap_expand_leaf(zn, l, 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);
+       return (err);
+}
+
+int
+fzap_length(zap_name_t *zn,
+    uint64_t *integer_size, uint64_t *num_integers)
+{
+       zap_leaf_t *l;
+       int err;
+       zap_entry_handle_t zeh;
+
+       err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, NULL, RW_READER, &l);
+       if (err != 0)
+               return (err);
+       err = zap_leaf_lookup(l, zn, &zeh);
+       if (err != 0)
+               goto out;
+
+       if (integer_size)
+               *integer_size = zeh.zeh_integer_size;
+       if (num_integers)
+               *num_integers = zeh.zeh_num_integers;
+out:
+       zap_put_leaf(l);
+       return (err);
+}
+
+int
+fzap_remove(zap_name_t *zn, dmu_tx_t *tx)
+{
+       zap_leaf_t *l;
+       int err;
+       zap_entry_handle_t zeh;
+
+       err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, tx, RW_WRITER, &l);
+       if (err != 0)
+               return (err);
+       err = zap_leaf_lookup(l, zn, &zeh);
+       if (err == 0) {
+               zap_entry_remove(&zeh);
+               zap_increment_num_entries(zn->zn_zap, -1, tx);
+       }
+       zap_put_leaf(l);
+       return (err);
+}
+
+void
+fzap_prefetch(zap_name_t *zn)
+{
+       uint64_t idx, blk;
+       zap_t *zap = zn->zn_zap;
+       int bs;
+
+       idx = ZAP_HASH_IDX(zn->zn_hash,
+           zap_f_phys(zap)->zap_ptrtbl.zt_shift);
+       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);
+}
+
+/*
+ * Helper functions for consumers.
+ */
+
+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 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);
+
+       return (new_obj);
+}
+
+int
+zap_value_search(objset_t *os, uint64_t zapobj, uint64_t value, uint64_t mask,
+    char *name)
+{
+       zap_cursor_t zc;
+       zap_attribute_t *za;
+       int err;
+
+       if (mask == 0)
+               mask = -1ULL;
+
+       za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+       for (zap_cursor_init(&zc, os, zapobj);
+           (err = zap_cursor_retrieve(&zc, za)) == 0;
+           zap_cursor_advance(&zc)) {
+               if ((za->za_first_integer & mask) == (value & mask)) {
+                       (void) strcpy(name, za->za_name);
+                       break;
+               }
+       }
+       zap_cursor_fini(&zc);
+       kmem_free(za, sizeof (zap_attribute_t));
+       return (err);
+}
+
+int
+zap_join(objset_t *os, uint64_t fromobj, uint64_t intoobj, dmu_tx_t *tx)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int err;
+
+       err = 0;
+       for (zap_cursor_init(&zc, os, fromobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           (void) zap_cursor_advance(&zc)) {
+               if (za.za_integer_length != 8 || za.za_num_integers != 1) {
+                       err = SET_ERROR(EINVAL);
+                       break;
+               }
+               err = zap_add(os, intoobj, za.za_name,
+                   8, 1, &za.za_first_integer, tx);
+               if (err)
+                       break;
+       }
+       zap_cursor_fini(&zc);
+       return (err);
+}
+
+int
+zap_join_key(objset_t *os, uint64_t fromobj, uint64_t intoobj,
+    uint64_t value, dmu_tx_t *tx)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int err;
+
+       err = 0;
+       for (zap_cursor_init(&zc, os, fromobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           (void) zap_cursor_advance(&zc)) {
+               if (za.za_integer_length != 8 || za.za_num_integers != 1) {
+                       err = SET_ERROR(EINVAL);
+                       break;
+               }
+               err = zap_add(os, intoobj, za.za_name,
+                   8, 1, &value, tx);
+               if (err)
+                       break;
+       }
+       zap_cursor_fini(&zc);
+       return (err);
+}
+
+int
+zap_join_increment(objset_t *os, uint64_t fromobj, uint64_t intoobj,
+    dmu_tx_t *tx)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       int err;
+
+       err = 0;
+       for (zap_cursor_init(&zc, os, fromobj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           (void) zap_cursor_advance(&zc)) {
+               uint64_t delta = 0;
+
+               if (za.za_integer_length != 8 || za.za_num_integers != 1) {
+                       err = SET_ERROR(EINVAL);
+                       break;
+               }
+
+               err = zap_lookup(os, intoobj, za.za_name, 8, 1, &delta);
+               if (err != 0 && err != ENOENT)
+                       break;
+               delta += za.za_first_integer;
+               err = zap_update(os, intoobj, za.za_name, 8, 1, &delta, tx);
+               if (err)
+                       break;
+       }
+       zap_cursor_fini(&zc);
+       return (err);
+}
+
+int
+zap_add_int(objset_t *os, uint64_t obj, uint64_t value, dmu_tx_t *tx)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)value);
+       return (zap_add(os, obj, name, 8, 1, &value, tx));
+}
+
+int
+zap_remove_int(objset_t *os, uint64_t obj, uint64_t value, dmu_tx_t *tx)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)value);
+       return (zap_remove(os, obj, name, tx));
+}
+
+int
+zap_lookup_int(objset_t *os, uint64_t obj, uint64_t value)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)value);
+       return (zap_lookup(os, obj, name, 8, 1, &value));
+}
+
+int
+zap_add_int_key(objset_t *os, uint64_t obj,
+    uint64_t key, uint64_t value, dmu_tx_t *tx)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)key);
+       return (zap_add(os, obj, name, 8, 1, &value, tx));
+}
+
+int
+zap_update_int_key(objset_t *os, uint64_t obj,
+    uint64_t key, uint64_t value, dmu_tx_t *tx)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)key);
+       return (zap_update(os, obj, name, 8, 1, &value, tx));
+}
+
+int
+zap_lookup_int_key(objset_t *os, uint64_t obj, uint64_t key, uint64_t *valuep)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)key);
+       return (zap_lookup(os, obj, name, 8, 1, valuep));
+}
+
+int
+zap_increment(objset_t *os, uint64_t obj, const char *name, int64_t delta,
+    dmu_tx_t *tx)
+{
+       uint64_t value = 0;
+       int err;
+
+       if (delta == 0)
+               return (0);
+
+       err = zap_lookup(os, obj, name, 8, 1, &value);
+       if (err != 0 && err != ENOENT)
+               return (err);
+       value += delta;
+       if (value == 0)
+               err = zap_remove(os, obj, name, tx);
+       else
+               err = zap_update(os, obj, name, 8, 1, &value, tx);
+       return (err);
+}
+
+int
+zap_increment_int(objset_t *os, uint64_t obj, uint64_t key, int64_t delta,
+    dmu_tx_t *tx)
+{
+       char name[20];
+
+       (void) snprintf(name, sizeof (name), "%llx", (longlong_t)key);
+       return (zap_increment(os, obj, name, delta, tx));
+}
+
+/*
+ * Routines for iterating over the attributes.
+ */
+
+int
+fzap_cursor_retrieve(zap_t *zap, zap_cursor_t *zc, zap_attribute_t *za)
+{
+       int err = ENOENT;
+       zap_entry_handle_t zeh;
+       zap_leaf_t *l;
+
+       /* retrieve the next entry at or after zc_hash/zc_cd */
+       /* if no entry, return ENOENT */
+
+       if (zc->zc_leaf &&
+           (ZAP_HASH_IDX(zc->zc_hash,
+           zap_leaf_phys(zc->zc_leaf)->l_hdr.lh_prefix_len) !=
+           zap_leaf_phys(zc->zc_leaf)->l_hdr.lh_prefix)) {
+               rw_enter(&zc->zc_leaf->l_rwlock, RW_READER);
+               zap_put_leaf(zc->zc_leaf);
+               zc->zc_leaf = NULL;
+       }
+
+again:
+       if (zc->zc_leaf == NULL) {
+               err = zap_deref_leaf(zap, zc->zc_hash, NULL, RW_READER,
+                   &zc->zc_leaf);
+               if (err != 0)
+                       return (err);
+       } else {
+               rw_enter(&zc->zc_leaf->l_rwlock, RW_READER);
+       }
+       l = zc->zc_leaf;
+
+       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) {
+                       zc->zc_hash = -1ULL;
+               } else {
+                       zap_put_leaf(zc->zc_leaf);
+                       zc->zc_leaf = NULL;
+                       goto again;
+               }
+       }
+
+       if (err == 0) {
+               zc->zc_hash = zeh.zeh_hash;
+               zc->zc_cd = zeh.zeh_cd;
+               za->za_integer_length = zeh.zeh_integer_size;
+               za->za_num_integers = zeh.zeh_num_integers;
+               if (zeh.zeh_num_integers == 0) {
+                       za->za_first_integer = 0;
+               } else {
+                       err = zap_entry_read(&zeh, 8, 1, &za->za_first_integer);
+                       ASSERT(err == 0 || err == EOVERFLOW);
+               }
+               err = zap_entry_read_name(zap, &zeh,
+                   sizeof (za->za_name), za->za_name);
+               ASSERT(err == 0);
+
+               za->za_normalization_conflict =
+                   zap_entry_normalization_conflict(&zeh,
+                   NULL, za->za_name, zap);
+       }
+       rw_exit(&zc->zc_leaf->l_rwlock);
+       return (err);
+}
+
+static void
+zap_stats_ptrtbl(zap_t *zap, uint64_t *tbl, int len, zap_stats_t *zs)
+{
+       int i, err;
+       uint64_t lastblk = 0;
+
+       /*
+        * NB: if a leaf has more pointers than an entire ptrtbl block
+        * can hold, then it'll be accounted for more than once, since
+        * we won't have lastblk.
+        */
+       for (i = 0; i < len; i++) {
+               zap_leaf_t *l;
+
+               if (tbl[i] == lastblk)
+                       continue;
+               lastblk = tbl[i];
+
+               err = zap_get_leaf_byblk(zap, tbl[i], NULL, RW_READER, &l);
+               if (err == 0) {
+                       zap_leaf_stats(zap, l, zs);
+                       zap_put_leaf(l);
+               }
+       }
+}
+
+void
+fzap_get_stats(zap_t *zap, zap_stats_t *zs)
+{
+       int bs = FZAP_BLOCK_SHIFT(zap);
+       zs->zs_blocksize = 1ULL << bs;
+
+       /*
+        * Set zap_phys_t fields
+        */
+       zs->zs_num_leafs = zap_f_phys(zap)->zap_num_leafs;
+       zs->zs_num_entries = zap_f_phys(zap)->zap_num_entries;
+       zs->zs_num_blocks = zap_f_phys(zap)->zap_freeblk;
+       zs->zs_block_type = zap_f_phys(zap)->zap_block_type;
+       zs->zs_magic = zap_f_phys(zap)->zap_magic;
+       zs->zs_salt = zap_f_phys(zap)->zap_salt;
+
+       /*
+        * Set zap_ptrtbl fields
+        */
+       zs->zs_ptrtbl_len = 1ULL << zap_f_phys(zap)->zap_ptrtbl.zt_shift;
+       zs->zs_ptrtbl_nextblk = zap_f_phys(zap)->zap_ptrtbl.zt_nextblk;
+       zs->zs_ptrtbl_blks_copied =
+           zap_f_phys(zap)->zap_ptrtbl.zt_blks_copied;
+       zs->zs_ptrtbl_zt_blk = zap_f_phys(zap)->zap_ptrtbl.zt_blk;
+       zs->zs_ptrtbl_zt_numblks = zap_f_phys(zap)->zap_ptrtbl.zt_numblks;
+       zs->zs_ptrtbl_zt_shift = zap_f_phys(zap)->zap_ptrtbl.zt_shift;
+
+       if (zap_f_phys(zap)->zap_ptrtbl.zt_numblks == 0) {
+               /* the ptrtbl is entirely in the header block. */
+               zap_stats_ptrtbl(zap, &ZAP_EMBEDDED_PTRTBL_ENT(zap, 0),
+                   1 << ZAP_EMBEDDED_PTRTBL_SHIFT(zap), zs);
+       } else {
+               int b;
+
+               dmu_prefetch(zap->zap_objset, zap->zap_object,
+                   zap_f_phys(zap)->zap_ptrtbl.zt_blk << bs,
+                   zap_f_phys(zap)->zap_ptrtbl.zt_numblks << bs);
+
+               for (b = 0; b < zap_f_phys(zap)->zap_ptrtbl.zt_numblks;
+                   b++) {
+                       dmu_buf_t *db;
+                       int err;
+
+                       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+                           (zap_f_phys(zap)->zap_ptrtbl.zt_blk + b) << bs,
+                           FTAG, &db, DMU_READ_NO_PREFETCH);
+                       if (err == 0) {
+                               zap_stats_ptrtbl(zap, db->db_data,
+                                   1<<(bs-3), zs);
+                               dmu_buf_rele(db, FTAG);
+                       }
+               }
+       }
+}
+
+int
+fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
+    uint64_t *tooverwrite)
+{
+       zap_t *zap = zn->zn_zap;
+       zap_leaf_t *l;
+       int err;
+
+       /*
+        * Account for the header block of the fatzap.
+        */
+       if (!add && dmu_buf_freeable(zap->zap_dbuf)) {
+               *tooverwrite += zap->zap_dbuf->db_size;
+       } else {
+               *towrite += zap->zap_dbuf->db_size;
+       }
+
+       /*
+        * Account for the pointer table blocks.
+        * If we are adding we need to account for the following cases :
+        * - If the pointer table is embedded, this operation could force an
+        *   external pointer table.
+        * - If this already has an external pointer table this operation
+        *   could extend the table.
+        */
+       if (add) {
+               if (zap_f_phys(zap)->zap_ptrtbl.zt_blk == 0)
+                       *towrite += zap->zap_dbuf->db_size;
+               else
+                       *towrite += (zap->zap_dbuf->db_size * 3);
+       }
+
+       /*
+        * Now, check if the block containing leaf is freeable
+        * and account accordingly.
+        */
+       err = zap_deref_leaf(zap, zn->zn_hash, NULL, RW_READER, &l);
+       if (err != 0) {
+               return (err);
+       }
+
+       if (!add && dmu_buf_freeable(l->l_dbuf)) {
+               *tooverwrite += l->l_dbuf->db_size;
+       } else {
+               /*
+                * If this an add operation, the leaf block could split.
+                * Hence, we need to account for an additional leaf block.
+                */
+               *towrite += (add ? 2 : 1) * l->l_dbuf->db_size;
+       }
+
+       zap_put_leaf(l);
+       return (0);
+}
diff --git a/zfs/module/zfs/zap_leaf.c b/zfs/module/zfs/zap_leaf.c
new file mode 100644 (file)
index 0000000..3abc08c
--- /dev/null
@@ -0,0 +1,887 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * The 512-byte leaf is broken into 32 16-byte chunks.
+ * chunk number n means l_chunk[n], even though the header precedes it.
+ * the names are stored null-terminated.
+ */
+
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/zfs_context.h>
+#include <sys/fs/zfs.h>
+#include <sys/zap.h>
+#include <sys/zap_impl.h>
+#include <sys/zap_leaf.h>
+#include <sys/arc.h>
+
+static uint16_t *zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry);
+
+#define        CHAIN_END 0xffff /* end of the chunk chain */
+
+/* half the (current) minimum block size */
+#define        MAX_ARRAY_BYTES (8<<10)
+
+#define        LEAF_HASH(l, h) \
+       ((ZAP_LEAF_HASH_NUMENTRIES(l)-1) & \
+       ((h) >> \
+       (64 - ZAP_LEAF_HASH_SHIFT(l) - zap_leaf_phys(l)->l_hdr.lh_prefix_len)))
+
+#define        LEAF_HASH_ENTPTR(l, h) (&zap_leaf_phys(l)->l_hash[LEAF_HASH(l, h)])
+
+extern inline zap_leaf_phys_t *zap_leaf_phys(zap_leaf_t *l);
+
+static void
+zap_memset(void *a, int c, size_t n)
+{
+       char *cp = a;
+       char *cpend = cp + n;
+
+       while (cp < cpend)
+               *cp++ = c;
+}
+
+static void
+stv(int len, void *addr, uint64_t value)
+{
+       switch (len) {
+       case 1:
+               *(uint8_t *)addr = value;
+               return;
+       case 2:
+               *(uint16_t *)addr = value;
+               return;
+       case 4:
+               *(uint32_t *)addr = value;
+               return;
+       case 8:
+               *(uint64_t *)addr = value;
+               return;
+       default:
+               cmn_err(CE_PANIC, "bad int len %d", len);
+       }
+}
+
+static uint64_t
+ldv(int len, const void *addr)
+{
+       switch (len) {
+       case 1:
+               return (*(uint8_t *)addr);
+       case 2:
+               return (*(uint16_t *)addr);
+       case 4:
+               return (*(uint32_t *)addr);
+       case 8:
+               return (*(uint64_t *)addr);
+       default:
+               cmn_err(CE_PANIC, "bad int len %d", len);
+       }
+       return (0xFEEDFACEDEADBEEFULL);
+}
+
+void
+zap_leaf_byteswap(zap_leaf_phys_t *buf, int size)
+{
+       int i;
+       zap_leaf_t l;
+       dmu_buf_t l_dbuf;
+
+       l_dbuf.db_data = buf;
+       l.l_bs = highbit64(size) - 1;
+       l.l_dbuf = &l_dbuf;
+
+       buf->l_hdr.lh_block_type =      BSWAP_64(buf->l_hdr.lh_block_type);
+       buf->l_hdr.lh_prefix =          BSWAP_64(buf->l_hdr.lh_prefix);
+       buf->l_hdr.lh_magic =           BSWAP_32(buf->l_hdr.lh_magic);
+       buf->l_hdr.lh_nfree =           BSWAP_16(buf->l_hdr.lh_nfree);
+       buf->l_hdr.lh_nentries =        BSWAP_16(buf->l_hdr.lh_nentries);
+       buf->l_hdr.lh_prefix_len =      BSWAP_16(buf->l_hdr.lh_prefix_len);
+       buf->l_hdr.lh_freelist =        BSWAP_16(buf->l_hdr.lh_freelist);
+
+       for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(&l); i++)
+               buf->l_hash[i] = BSWAP_16(buf->l_hash[i]);
+
+       for (i = 0; i < ZAP_LEAF_NUMCHUNKS(&l); i++) {
+               zap_leaf_chunk_t *lc = &ZAP_LEAF_CHUNK(&l, i);
+               struct zap_leaf_entry *le;
+
+               switch (lc->l_free.lf_type) {
+               case ZAP_CHUNK_ENTRY:
+                       le = &lc->l_entry;
+
+                       le->le_type =           BSWAP_8(le->le_type);
+                       le->le_value_intlen =   BSWAP_8(le->le_value_intlen);
+                       le->le_next =           BSWAP_16(le->le_next);
+                       le->le_name_chunk =     BSWAP_16(le->le_name_chunk);
+                       le->le_name_numints =   BSWAP_16(le->le_name_numints);
+                       le->le_value_chunk =    BSWAP_16(le->le_value_chunk);
+                       le->le_value_numints =  BSWAP_16(le->le_value_numints);
+                       le->le_cd =             BSWAP_32(le->le_cd);
+                       le->le_hash =           BSWAP_64(le->le_hash);
+                       break;
+               case ZAP_CHUNK_FREE:
+                       lc->l_free.lf_type =    BSWAP_8(lc->l_free.lf_type);
+                       lc->l_free.lf_next =    BSWAP_16(lc->l_free.lf_next);
+                       break;
+               case ZAP_CHUNK_ARRAY:
+                       lc->l_array.la_type =   BSWAP_8(lc->l_array.la_type);
+                       lc->l_array.la_next =   BSWAP_16(lc->l_array.la_next);
+                       /* la_array doesn't need swapping */
+                       break;
+               default:
+                       cmn_err(CE_PANIC, "bad leaf type %d",
+                           lc->l_free.lf_type);
+               }
+       }
+}
+
+void
+zap_leaf_init(zap_leaf_t *l, boolean_t sort)
+{
+       int i;
+
+       l->l_bs = highbit64(l->l_dbuf->db_size) - 1;
+       zap_memset(&zap_leaf_phys(l)->l_hdr, 0,
+           sizeof (struct zap_leaf_header));
+       zap_memset(zap_leaf_phys(l)->l_hash, CHAIN_END,
+           2*ZAP_LEAF_HASH_NUMENTRIES(l));
+       for (i = 0; i < ZAP_LEAF_NUMCHUNKS(l); i++) {
+               ZAP_LEAF_CHUNK(l, i).l_free.lf_type = ZAP_CHUNK_FREE;
+               ZAP_LEAF_CHUNK(l, i).l_free.lf_next = i+1;
+       }
+       ZAP_LEAF_CHUNK(l, ZAP_LEAF_NUMCHUNKS(l)-1).l_free.lf_next = CHAIN_END;
+       zap_leaf_phys(l)->l_hdr.lh_block_type = ZBT_LEAF;
+       zap_leaf_phys(l)->l_hdr.lh_magic = ZAP_LEAF_MAGIC;
+       zap_leaf_phys(l)->l_hdr.lh_nfree = ZAP_LEAF_NUMCHUNKS(l);
+       if (sort)
+               zap_leaf_phys(l)->l_hdr.lh_flags |= ZLF_ENTRIES_CDSORTED;
+}
+
+/*
+ * Routines which manipulate leaf chunks (l_chunk[]).
+ */
+
+static uint16_t
+zap_leaf_chunk_alloc(zap_leaf_t *l)
+{
+       int chunk;
+
+       ASSERT(zap_leaf_phys(l)->l_hdr.lh_nfree > 0);
+
+       chunk = zap_leaf_phys(l)->l_hdr.lh_freelist;
+       ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+       ASSERT3U(ZAP_LEAF_CHUNK(l, chunk).l_free.lf_type, ==, ZAP_CHUNK_FREE);
+
+       zap_leaf_phys(l)->l_hdr.lh_freelist =
+           ZAP_LEAF_CHUNK(l, chunk).l_free.lf_next;
+
+       zap_leaf_phys(l)->l_hdr.lh_nfree--;
+
+       return (chunk);
+}
+
+static void
+zap_leaf_chunk_free(zap_leaf_t *l, uint16_t chunk)
+{
+       struct zap_leaf_free *zlf = &ZAP_LEAF_CHUNK(l, chunk).l_free;
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_nfree, <, ZAP_LEAF_NUMCHUNKS(l));
+       ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+       ASSERT(zlf->lf_type != ZAP_CHUNK_FREE);
+
+       zlf->lf_type = ZAP_CHUNK_FREE;
+       zlf->lf_next = zap_leaf_phys(l)->l_hdr.lh_freelist;
+       bzero(zlf->lf_pad, sizeof (zlf->lf_pad)); /* help it to compress */
+       zap_leaf_phys(l)->l_hdr.lh_freelist = chunk;
+
+       zap_leaf_phys(l)->l_hdr.lh_nfree++;
+}
+
+/*
+ * Routines which manipulate leaf arrays (zap_leaf_array type chunks).
+ */
+
+static uint16_t
+zap_leaf_array_create(zap_leaf_t *l, const char *buf,
+    int integer_size, int num_integers)
+{
+       uint16_t chunk_head;
+       uint16_t *chunkp = &chunk_head;
+       int byten = 0;
+       uint64_t value = 0;
+       int shift = (integer_size-1)*8;
+       int len = num_integers;
+
+       ASSERT3U(num_integers * integer_size, <, MAX_ARRAY_BYTES);
+
+       while (len > 0) {
+               uint16_t chunk = zap_leaf_chunk_alloc(l);
+               struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
+               int i;
+
+               la->la_type = ZAP_CHUNK_ARRAY;
+               for (i = 0; i < ZAP_LEAF_ARRAY_BYTES; i++) {
+                       if (byten == 0)
+                               value = ldv(integer_size, buf);
+                       la->la_array[i] = value >> shift;
+                       value <<= 8;
+                       if (++byten == integer_size) {
+                               byten = 0;
+                               buf += integer_size;
+                               if (--len == 0)
+                                       break;
+                       }
+               }
+
+               *chunkp = chunk;
+               chunkp = &la->la_next;
+       }
+       *chunkp = CHAIN_END;
+
+       return (chunk_head);
+}
+
+static void
+zap_leaf_array_free(zap_leaf_t *l, uint16_t *chunkp)
+{
+       uint16_t chunk = *chunkp;
+
+       *chunkp = CHAIN_END;
+
+       while (chunk != CHAIN_END) {
+               int nextchunk = ZAP_LEAF_CHUNK(l, chunk).l_array.la_next;
+               ASSERT3U(ZAP_LEAF_CHUNK(l, chunk).l_array.la_type, ==,
+                   ZAP_CHUNK_ARRAY);
+               zap_leaf_chunk_free(l, chunk);
+               chunk = nextchunk;
+       }
+}
+
+/* array_len and buf_len are in integers, not bytes */
+static void
+zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
+    int array_int_len, int array_len, int buf_int_len, uint64_t buf_len,
+    void *buf)
+{
+       int len = MIN(array_len, buf_len);
+       int byten = 0;
+       uint64_t value = 0;
+       char *p = buf;
+
+       ASSERT3U(array_int_len, <=, buf_int_len);
+
+       /* Fast path for one 8-byte integer */
+       if (array_int_len == 8 && buf_int_len == 8 && len == 1) {
+               struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
+               uint8_t *ip = la->la_array;
+               uint64_t *buf64 = buf;
+
+               *buf64 = (uint64_t)ip[0] << 56 | (uint64_t)ip[1] << 48 |
+                   (uint64_t)ip[2] << 40 | (uint64_t)ip[3] << 32 |
+                   (uint64_t)ip[4] << 24 | (uint64_t)ip[5] << 16 |
+                   (uint64_t)ip[6] << 8 | (uint64_t)ip[7];
+               return;
+       }
+
+       /* Fast path for an array of 1-byte integers (eg. the entry name) */
+       if (array_int_len == 1 && buf_int_len == 1 &&
+           buf_len > array_len + ZAP_LEAF_ARRAY_BYTES) {
+               while (chunk != CHAIN_END) {
+                       struct zap_leaf_array *la =
+                           &ZAP_LEAF_CHUNK(l, chunk).l_array;
+                       bcopy(la->la_array, p, ZAP_LEAF_ARRAY_BYTES);
+                       p += ZAP_LEAF_ARRAY_BYTES;
+                       chunk = la->la_next;
+               }
+               return;
+       }
+
+       while (len > 0) {
+               struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
+               int i;
+
+               ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+               for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) {
+                       value = (value << 8) | la->la_array[i];
+                       byten++;
+                       if (byten == array_int_len) {
+                               stv(buf_int_len, p, value);
+                               byten = 0;
+                               len--;
+                               if (len == 0)
+                                       return;
+                               p += buf_int_len;
+                       }
+               }
+               chunk = la->la_next;
+       }
+}
+
+static boolean_t
+zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn,
+    int chunk, int array_numints)
+{
+       int bseen = 0;
+
+       if (zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY) {
+               uint64_t *thiskey;
+               boolean_t match;
+
+               ASSERT(zn->zn_key_intlen == sizeof (*thiskey));
+               thiskey = kmem_alloc(array_numints * sizeof (*thiskey),
+                   KM_SLEEP);
+
+               zap_leaf_array_read(l, chunk, sizeof (*thiskey), array_numints,
+                   sizeof (*thiskey), array_numints, thiskey);
+               match = bcmp(thiskey, zn->zn_key_orig,
+                   array_numints * sizeof (*thiskey)) == 0;
+               kmem_free(thiskey, array_numints * sizeof (*thiskey));
+               return (match);
+       }
+
+       ASSERT(zn->zn_key_intlen == 1);
+       if (zn->zn_matchtype == MT_FIRST) {
+               char *thisname = kmem_alloc(array_numints, KM_SLEEP);
+               boolean_t match;
+
+               zap_leaf_array_read(l, chunk, sizeof (char), array_numints,
+                   sizeof (char), array_numints, thisname);
+               match = zap_match(zn, thisname);
+               kmem_free(thisname, array_numints);
+               return (match);
+       }
+
+       /*
+        * Fast path for exact matching.
+        * First check that the lengths match, so that we don't read
+        * past the end of the zn_key_orig array.
+        */
+       if (array_numints != zn->zn_key_orig_numints)
+               return (B_FALSE);
+       while (bseen < array_numints) {
+               struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
+               int toread = MIN(array_numints - bseen, ZAP_LEAF_ARRAY_BYTES);
+               ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+               if (bcmp(la->la_array, (char *)zn->zn_key_orig + bseen, toread))
+                       break;
+               chunk = la->la_next;
+               bseen += toread;
+       }
+       return (bseen == array_numints);
+}
+
+/*
+ * Routines which manipulate leaf entries.
+ */
+
+int
+zap_leaf_lookup(zap_leaf_t *l, zap_name_t *zn, zap_entry_handle_t *zeh)
+{
+       uint16_t *chunkp;
+       struct zap_leaf_entry *le;
+
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_magic, ==, ZAP_LEAF_MAGIC);
+
+again:
+       for (chunkp = LEAF_HASH_ENTPTR(l, zn->zn_hash);
+           *chunkp != CHAIN_END; chunkp = &le->le_next) {
+               uint16_t chunk = *chunkp;
+               le = ZAP_LEAF_ENTRY(l, chunk);
+
+               ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+               ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
+
+               if (le->le_hash != zn->zn_hash)
+                       continue;
+
+               /*
+                * NB: the entry chain is always sorted by cd on
+                * normalized zap objects, so this will find the
+                * lowest-cd match for MT_FIRST.
+                */
+               ASSERT(zn->zn_matchtype == MT_EXACT ||
+                   (zap_leaf_phys(l)->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED));
+               if (zap_leaf_array_match(l, zn, le->le_name_chunk,
+                   le->le_name_numints)) {
+                       zeh->zeh_num_integers = le->le_value_numints;
+                       zeh->zeh_integer_size = le->le_value_intlen;
+                       zeh->zeh_cd = le->le_cd;
+                       zeh->zeh_hash = le->le_hash;
+                       zeh->zeh_chunkp = chunkp;
+                       zeh->zeh_leaf = l;
+                       return (0);
+               }
+       }
+
+       /*
+        * NB: we could of course do this in one pass, but that would be
+        * a pain.  We'll see if MT_BEST is even used much.
+        */
+       if (zn->zn_matchtype == MT_BEST) {
+               zn->zn_matchtype = MT_FIRST;
+               goto again;
+       }
+
+       return (SET_ERROR(ENOENT));
+}
+
+/* Return (h1,cd1 >= h2,cd2) */
+#define        HCD_GTEQ(h1, cd1, h2, cd2) \
+       ((h1 > h2) ? TRUE : ((h1 == h2 && cd1 >= cd2) ? TRUE : FALSE))
+
+int
+zap_leaf_lookup_closest(zap_leaf_t *l,
+    uint64_t h, uint32_t cd, zap_entry_handle_t *zeh)
+{
+       uint16_t chunk;
+       uint64_t besth = -1ULL;
+       uint32_t bestcd = -1U;
+       uint16_t bestlh = ZAP_LEAF_HASH_NUMENTRIES(l)-1;
+       uint16_t lh;
+       struct zap_leaf_entry *le;
+
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_magic, ==, ZAP_LEAF_MAGIC);
+
+       for (lh = LEAF_HASH(l, h); lh <= bestlh; lh++) {
+               for (chunk = zap_leaf_phys(l)->l_hash[lh];
+                   chunk != CHAIN_END; chunk = le->le_next) {
+                       le = ZAP_LEAF_ENTRY(l, chunk);
+
+                       ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+                       ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
+
+                       if (HCD_GTEQ(le->le_hash, le->le_cd, h, cd) &&
+                           HCD_GTEQ(besth, bestcd, le->le_hash, le->le_cd)) {
+                               ASSERT3U(bestlh, >=, lh);
+                               bestlh = lh;
+                               besth = le->le_hash;
+                               bestcd = le->le_cd;
+
+                               zeh->zeh_num_integers = le->le_value_numints;
+                               zeh->zeh_integer_size = le->le_value_intlen;
+                               zeh->zeh_cd = le->le_cd;
+                               zeh->zeh_hash = le->le_hash;
+                               zeh->zeh_fakechunk = chunk;
+                               zeh->zeh_chunkp = &zeh->zeh_fakechunk;
+                               zeh->zeh_leaf = l;
+                       }
+               }
+       }
+
+       return (bestcd == -1U ? ENOENT : 0);
+}
+
+int
+zap_entry_read(const zap_entry_handle_t *zeh,
+    uint8_t integer_size, uint64_t num_integers, void *buf)
+{
+       struct zap_leaf_entry *le =
+           ZAP_LEAF_ENTRY(zeh->zeh_leaf, *zeh->zeh_chunkp);
+       ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
+
+       if (le->le_value_intlen > integer_size)
+               return (SET_ERROR(EINVAL));
+
+       zap_leaf_array_read(zeh->zeh_leaf, le->le_value_chunk,
+           le->le_value_intlen, le->le_value_numints,
+           integer_size, num_integers, buf);
+
+       if (zeh->zeh_num_integers > num_integers)
+               return (SET_ERROR(EOVERFLOW));
+       return (0);
+
+}
+
+int
+zap_entry_read_name(zap_t *zap, const zap_entry_handle_t *zeh, uint16_t buflen,
+    char *buf)
+{
+       struct zap_leaf_entry *le =
+           ZAP_LEAF_ENTRY(zeh->zeh_leaf, *zeh->zeh_chunkp);
+       ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
+
+       if (zap_getflags(zap) & ZAP_FLAG_UINT64_KEY) {
+               zap_leaf_array_read(zeh->zeh_leaf, le->le_name_chunk, 8,
+                   le->le_name_numints, 8, buflen / 8, buf);
+       } else {
+               zap_leaf_array_read(zeh->zeh_leaf, le->le_name_chunk, 1,
+                   le->le_name_numints, 1, buflen, buf);
+       }
+       if (le->le_name_numints > buflen)
+               return (SET_ERROR(EOVERFLOW));
+       return (0);
+}
+
+int
+zap_entry_update(zap_entry_handle_t *zeh,
+       uint8_t integer_size, uint64_t num_integers, const void *buf)
+{
+       int delta_chunks;
+       zap_leaf_t *l = zeh->zeh_leaf;
+       struct zap_leaf_entry *le = ZAP_LEAF_ENTRY(l, *zeh->zeh_chunkp);
+
+       delta_chunks = ZAP_LEAF_ARRAY_NCHUNKS(num_integers * integer_size) -
+           ZAP_LEAF_ARRAY_NCHUNKS(le->le_value_numints * le->le_value_intlen);
+
+       if ((int)zap_leaf_phys(l)->l_hdr.lh_nfree < delta_chunks)
+               return (SET_ERROR(EAGAIN));
+
+       zap_leaf_array_free(l, &le->le_value_chunk);
+       le->le_value_chunk =
+           zap_leaf_array_create(l, buf, integer_size, num_integers);
+       le->le_value_numints = num_integers;
+       le->le_value_intlen = integer_size;
+       return (0);
+}
+
+void
+zap_entry_remove(zap_entry_handle_t *zeh)
+{
+       uint16_t entry_chunk;
+       struct zap_leaf_entry *le;
+       zap_leaf_t *l = zeh->zeh_leaf;
+
+       ASSERT3P(zeh->zeh_chunkp, !=, &zeh->zeh_fakechunk);
+
+       entry_chunk = *zeh->zeh_chunkp;
+       le = ZAP_LEAF_ENTRY(l, entry_chunk);
+       ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
+
+       zap_leaf_array_free(l, &le->le_name_chunk);
+       zap_leaf_array_free(l, &le->le_value_chunk);
+
+       *zeh->zeh_chunkp = le->le_next;
+       zap_leaf_chunk_free(l, entry_chunk);
+
+       zap_leaf_phys(l)->l_hdr.lh_nentries--;
+}
+
+int
+zap_entry_create(zap_leaf_t *l, zap_name_t *zn, uint32_t cd,
+    uint8_t integer_size, uint64_t num_integers, const void *buf,
+    zap_entry_handle_t *zeh)
+{
+       uint16_t chunk;
+       uint16_t *chunkp;
+       struct zap_leaf_entry *le;
+       uint64_t valuelen;
+       int numchunks;
+       uint64_t h = zn->zn_hash;
+
+       valuelen = integer_size * num_integers;
+
+       numchunks = 1 + ZAP_LEAF_ARRAY_NCHUNKS(zn->zn_key_orig_numints *
+           zn->zn_key_intlen) + ZAP_LEAF_ARRAY_NCHUNKS(valuelen);
+       if (numchunks > ZAP_LEAF_NUMCHUNKS(l))
+               return (E2BIG);
+
+       if (cd == ZAP_NEED_CD) {
+               /* find the lowest unused cd */
+               if (zap_leaf_phys(l)->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED) {
+                       cd = 0;
+
+                       for (chunk = *LEAF_HASH_ENTPTR(l, h);
+                           chunk != CHAIN_END; chunk = le->le_next) {
+                               le = ZAP_LEAF_ENTRY(l, chunk);
+                               if (le->le_cd > cd)
+                                       break;
+                               if (le->le_hash == h) {
+                                       ASSERT3U(cd, ==, le->le_cd);
+                                       cd++;
+                               }
+                       }
+               } else {
+                       /* old unsorted format; do it the O(n^2) way */
+                       for (cd = 0; ; cd++) {
+                               for (chunk = *LEAF_HASH_ENTPTR(l, h);
+                                   chunk != CHAIN_END; chunk = le->le_next) {
+                                       le = ZAP_LEAF_ENTRY(l, chunk);
+                                       if (le->le_hash == h &&
+                                           le->le_cd == cd) {
+                                               break;
+                                       }
+                               }
+                               /* If this cd is not in use, we are good. */
+                               if (chunk == CHAIN_END)
+                                       break;
+                       }
+               }
+               /*
+                * We would run out of space in a block before we could
+                * store enough entries to run out of CD values.
+                */
+               ASSERT3U(cd, <, zap_maxcd(zn->zn_zap));
+       }
+
+       if (zap_leaf_phys(l)->l_hdr.lh_nfree < numchunks)
+               return (SET_ERROR(EAGAIN));
+
+       /* make the entry */
+       chunk = zap_leaf_chunk_alloc(l);
+       le = ZAP_LEAF_ENTRY(l, chunk);
+       le->le_type = ZAP_CHUNK_ENTRY;
+       le->le_name_chunk = zap_leaf_array_create(l, zn->zn_key_orig,
+           zn->zn_key_intlen, zn->zn_key_orig_numints);
+       le->le_name_numints = zn->zn_key_orig_numints;
+       le->le_value_chunk =
+           zap_leaf_array_create(l, buf, integer_size, num_integers);
+       le->le_value_numints = num_integers;
+       le->le_value_intlen = integer_size;
+       le->le_hash = h;
+       le->le_cd = cd;
+
+       /* link it into the hash chain */
+       /* XXX if we did the search above, we could just use that */
+       chunkp = zap_leaf_rehash_entry(l, chunk);
+
+       zap_leaf_phys(l)->l_hdr.lh_nentries++;
+
+       zeh->zeh_leaf = l;
+       zeh->zeh_num_integers = num_integers;
+       zeh->zeh_integer_size = le->le_value_intlen;
+       zeh->zeh_cd = le->le_cd;
+       zeh->zeh_hash = le->le_hash;
+       zeh->zeh_chunkp = chunkp;
+
+       return (0);
+}
+
+/*
+ * Determine if there is another entry with the same normalized form.
+ * For performance purposes, either zn or name must be provided (the
+ * other can be NULL).  Note, there usually won't be any hash
+ * conflicts, in which case we don't need the concatenated/normalized
+ * form of the name.  But all callers have one of these on hand anyway,
+ * so might as well take advantage.  A cleaner but slower interface
+ * would accept neither argument, and compute the normalized name as
+ * needed (using zap_name_alloc(zap_entry_read_name(zeh))).
+ */
+boolean_t
+zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn,
+    const char *name, zap_t *zap)
+{
+       uint64_t chunk;
+       struct zap_leaf_entry *le;
+       boolean_t allocdzn = B_FALSE;
+
+       if (zap->zap_normflags == 0)
+               return (B_FALSE);
+
+       for (chunk = *LEAF_HASH_ENTPTR(zeh->zeh_leaf, zeh->zeh_hash);
+           chunk != CHAIN_END; chunk = le->le_next) {
+               le = ZAP_LEAF_ENTRY(zeh->zeh_leaf, chunk);
+               if (le->le_hash != zeh->zeh_hash)
+                       continue;
+               if (le->le_cd == zeh->zeh_cd)
+                       continue;
+
+               if (zn == NULL) {
+                       zn = zap_name_alloc(zap, name, MT_FIRST);
+                       allocdzn = B_TRUE;
+               }
+               if (zap_leaf_array_match(zeh->zeh_leaf, zn,
+                   le->le_name_chunk, le->le_name_numints)) {
+                       if (allocdzn)
+                               zap_name_free(zn);
+                       return (B_TRUE);
+               }
+       }
+       if (allocdzn)
+               zap_name_free(zn);
+       return (B_FALSE);
+}
+
+/*
+ * Routines for transferring entries between leafs.
+ */
+
+static uint16_t *
+zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry)
+{
+       struct zap_leaf_entry *le = ZAP_LEAF_ENTRY(l, entry);
+       struct zap_leaf_entry *le2;
+       uint16_t *chunkp;
+
+       /*
+        * keep the entry chain sorted by cd
+        * NB: this will not cause problems for unsorted leafs, though
+        * it is unnecessary there.
+        */
+       for (chunkp = LEAF_HASH_ENTPTR(l, le->le_hash);
+           *chunkp != CHAIN_END; chunkp = &le2->le_next) {
+               le2 = ZAP_LEAF_ENTRY(l, *chunkp);
+               if (le2->le_cd > le->le_cd)
+                       break;
+       }
+
+       le->le_next = *chunkp;
+       *chunkp = entry;
+       return (chunkp);
+}
+
+static uint16_t
+zap_leaf_transfer_array(zap_leaf_t *l, uint16_t chunk, zap_leaf_t *nl)
+{
+       uint16_t new_chunk;
+       uint16_t *nchunkp = &new_chunk;
+
+       while (chunk != CHAIN_END) {
+               uint16_t nchunk = zap_leaf_chunk_alloc(nl);
+               struct zap_leaf_array *nla =
+                   &ZAP_LEAF_CHUNK(nl, nchunk).l_array;
+               struct zap_leaf_array *la =
+                   &ZAP_LEAF_CHUNK(l, chunk).l_array;
+               int nextchunk = la->la_next;
+
+               ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
+               ASSERT3U(nchunk, <, ZAP_LEAF_NUMCHUNKS(l));
+
+               *nla = *la; /* structure assignment */
+
+               zap_leaf_chunk_free(l, chunk);
+               chunk = nextchunk;
+               *nchunkp = nchunk;
+               nchunkp = &nla->la_next;
+       }
+       *nchunkp = CHAIN_END;
+       return (new_chunk);
+}
+
+static void
+zap_leaf_transfer_entry(zap_leaf_t *l, int entry, zap_leaf_t *nl)
+{
+       struct zap_leaf_entry *le, *nle;
+       uint16_t chunk;
+
+       le = ZAP_LEAF_ENTRY(l, entry);
+       ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
+
+       chunk = zap_leaf_chunk_alloc(nl);
+       nle = ZAP_LEAF_ENTRY(nl, chunk);
+       *nle = *le; /* structure assignment */
+
+       (void) zap_leaf_rehash_entry(nl, chunk);
+
+       nle->le_name_chunk = zap_leaf_transfer_array(l, le->le_name_chunk, nl);
+       nle->le_value_chunk =
+           zap_leaf_transfer_array(l, le->le_value_chunk, nl);
+
+       zap_leaf_chunk_free(l, entry);
+
+       zap_leaf_phys(l)->l_hdr.lh_nentries--;
+       zap_leaf_phys(nl)->l_hdr.lh_nentries++;
+}
+
+/*
+ * Transfer the entries whose hash prefix ends in 1 to the new leaf.
+ */
+void
+zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl, boolean_t sort)
+{
+       int i;
+       int bit = 64 - 1 - zap_leaf_phys(l)->l_hdr.lh_prefix_len;
+
+       /* set new prefix and prefix_len */
+       zap_leaf_phys(l)->l_hdr.lh_prefix <<= 1;
+       zap_leaf_phys(l)->l_hdr.lh_prefix_len++;
+       zap_leaf_phys(nl)->l_hdr.lh_prefix =
+           zap_leaf_phys(l)->l_hdr.lh_prefix | 1;
+       zap_leaf_phys(nl)->l_hdr.lh_prefix_len =
+           zap_leaf_phys(l)->l_hdr.lh_prefix_len;
+
+       /* break existing hash chains */
+       zap_memset(zap_leaf_phys(l)->l_hash, CHAIN_END,
+           2*ZAP_LEAF_HASH_NUMENTRIES(l));
+
+       if (sort)
+               zap_leaf_phys(l)->l_hdr.lh_flags |= ZLF_ENTRIES_CDSORTED;
+
+       /*
+        * Transfer entries whose hash bit 'bit' is set to nl; rehash
+        * the remaining entries
+        *
+        * NB: We could find entries via the hashtable instead. That
+        * would be O(hashents+numents) rather than O(numblks+numents),
+        * but this accesses memory more sequentially, and when we're
+        * called, the block is usually pretty full.
+        */
+       for (i = 0; i < ZAP_LEAF_NUMCHUNKS(l); i++) {
+               struct zap_leaf_entry *le = ZAP_LEAF_ENTRY(l, i);
+               if (le->le_type != ZAP_CHUNK_ENTRY)
+                       continue;
+
+               if (le->le_hash & (1ULL << bit))
+                       zap_leaf_transfer_entry(l, i, nl);
+               else
+                       (void) zap_leaf_rehash_entry(l, i);
+       }
+}
+
+void
+zap_leaf_stats(zap_t *zap, zap_leaf_t *l, zap_stats_t *zs)
+{
+       int i, n;
+
+       n = zap_f_phys(zap)->zap_ptrtbl.zt_shift -
+           zap_leaf_phys(l)->l_hdr.lh_prefix_len;
+       n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
+       zs->zs_leafs_with_2n_pointers[n]++;
+
+
+       n = zap_leaf_phys(l)->l_hdr.lh_nentries/5;
+       n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
+       zs->zs_blocks_with_n5_entries[n]++;
+
+       n = ((1<<FZAP_BLOCK_SHIFT(zap)) -
+           zap_leaf_phys(l)->l_hdr.lh_nfree * (ZAP_LEAF_ARRAY_BYTES+1))*10 /
+           (1<<FZAP_BLOCK_SHIFT(zap));
+       n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
+       zs->zs_blocks_n_tenths_full[n]++;
+
+       for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(l); i++) {
+               int nentries = 0;
+               int chunk = zap_leaf_phys(l)->l_hash[i];
+
+               while (chunk != CHAIN_END) {
+                       struct zap_leaf_entry *le =
+                           ZAP_LEAF_ENTRY(l, chunk);
+
+                       n = 1 + ZAP_LEAF_ARRAY_NCHUNKS(le->le_name_numints) +
+                           ZAP_LEAF_ARRAY_NCHUNKS(le->le_value_numints *
+                           le->le_value_intlen);
+                       n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
+                       zs->zs_entries_using_n_chunks[n]++;
+
+                       chunk = le->le_next;
+                       nentries++;
+               }
+
+               n = nentries;
+               n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
+               zs->zs_buckets_with_n_entries[n]++;
+       }
+}
diff --git a/zfs/module/zfs/zap_micro.c b/zfs/module/zfs/zap_micro.c
new file mode 100644 (file)
index 0000000..85b465b
--- /dev/null
@@ -0,0 +1,1482 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ */
+
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/zfs_context.h>
+#include <sys/zap.h>
+#include <sys/refcount.h>
+#include <sys/zap_impl.h>
+#include <sys/zap_leaf.h>
+#include <sys/avl.h>
+#include <sys/arc.h>
+#include <sys/dmu_objset.h>
+
+#ifdef _KERNEL
+#include <sys/sunddi.h>
+#endif
+
+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);
+
+uint64_t
+zap_getflags(zap_t *zap)
+{
+       if (zap->zap_ismicro)
+               return (0);
+       return (zap_f_phys(zap)->zap_flags);
+}
+
+int
+zap_hashbits(zap_t *zap)
+{
+       if (zap_getflags(zap) & ZAP_FLAG_HASH64)
+               return (48);
+       else
+               return (28);
+}
+
+uint32_t
+zap_maxcd(zap_t *zap)
+{
+       if (zap_getflags(zap) & ZAP_FLAG_HASH64)
+               return ((1<<16)-1);
+       else
+               return (-1U);
+}
+
+static uint64_t
+zap_hash(zap_name_t *zn)
+{
+       zap_t *zap = zn->zn_zap;
+       uint64_t h = 0;
+
+       if (zap_getflags(zap) & ZAP_FLAG_PRE_HASHED_KEY) {
+               ASSERT(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY);
+               h = *(uint64_t *)zn->zn_key_orig;
+       } else {
+               h = zap->zap_salt;
+               ASSERT(h != 0);
+               ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
+
+               if (zap_getflags(zap) & ZAP_FLAG_UINT64_KEY) {
+                       int i;
+                       const uint64_t *wp = zn->zn_key_norm;
+
+                       ASSERT(zn->zn_key_intlen == 8);
+                       for (i = 0; i < zn->zn_key_norm_numints; wp++, i++) {
+                               int j;
+                               uint64_t word = *wp;
+
+                               for (j = 0; j < zn->zn_key_intlen; j++) {
+                                       h = (h >> 8) ^
+                                           zfs_crc64_table[(h ^ word) & 0xFF];
+                                       word >>= NBBY;
+                               }
+                       }
+               } else {
+                       int i, len;
+                       const uint8_t *cp = zn->zn_key_norm;
+
+                       /*
+                        * We previously stored the terminating null on
+                        * disk, but didn't hash it, so we need to
+                        * continue to not hash it.  (The
+                        * zn_key_*_numints includes the terminating
+                        * null for non-binary keys.)
+                        */
+                       len = zn->zn_key_norm_numints - 1;
+
+                       ASSERT(zn->zn_key_intlen == 1);
+                       for (i = 0; i < len; cp++, i++) {
+                               h = (h >> 8) ^
+                                   zfs_crc64_table[(h ^ *cp) & 0xFF];
+                       }
+               }
+       }
+       /*
+        * Don't use all 64 bits, since we need some in the cookie for
+        * the collision differentiator.  We MUST use the high bits,
+        * since those are the ones that we first pay attention to when
+        * chosing the bucket.
+        */
+       h &= ~((1ULL << (64 - zap_hashbits(zap))) - 1);
+
+       return (h);
+}
+
+static int
+zap_normalize(zap_t *zap, const char *name, char *namenorm)
+{
+       size_t inlen, outlen;
+       int err;
+
+       ASSERT(!(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY));
+
+       inlen = strlen(name) + 1;
+       outlen = ZAP_MAXNAMELEN;
+
+       err = 0;
+       (void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
+           zap->zap_normflags | U8_TEXTPREP_IGNORE_NULL |
+           U8_TEXTPREP_IGNORE_INVALID, U8_UNICODE_LATEST, &err);
+
+       return (err);
+}
+
+boolean_t
+zap_match(zap_name_t *zn, const char *matchname)
+{
+       ASSERT(!(zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY));
+
+       if (zn->zn_matchtype == MT_FIRST) {
+               char norm[ZAP_MAXNAMELEN];
+
+               if (zap_normalize(zn->zn_zap, matchname, norm) != 0)
+                       return (B_FALSE);
+
+               return (strcmp(zn->zn_key_norm, norm) == 0);
+       } else {
+               /* MT_BEST or MT_EXACT */
+               return (strcmp(zn->zn_key_orig, matchname) == 0);
+       }
+}
+
+void
+zap_name_free(zap_name_t *zn)
+{
+       kmem_free(zn, sizeof (zap_name_t));
+}
+
+zap_name_t *
+zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt)
+{
+       zap_name_t *zn = kmem_alloc(sizeof (zap_name_t), KM_SLEEP);
+
+       zn->zn_zap = zap;
+       zn->zn_key_intlen = sizeof (*key);
+       zn->zn_key_orig = key;
+       zn->zn_key_orig_numints = strlen(zn->zn_key_orig) + 1;
+       zn->zn_matchtype = mt;
+       if (zap->zap_normflags) {
+               if (zap_normalize(zap, key, zn->zn_normbuf) != 0) {
+                       zap_name_free(zn);
+                       return (NULL);
+               }
+               zn->zn_key_norm = zn->zn_normbuf;
+               zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
+       } else {
+               if (mt != MT_EXACT) {
+                       zap_name_free(zn);
+                       return (NULL);
+               }
+               zn->zn_key_norm = zn->zn_key_orig;
+               zn->zn_key_norm_numints = zn->zn_key_orig_numints;
+       }
+
+       zn->zn_hash = zap_hash(zn);
+       return (zn);
+}
+
+zap_name_t *
+zap_name_alloc_uint64(zap_t *zap, const uint64_t *key, int numints)
+{
+       zap_name_t *zn = kmem_alloc(sizeof (zap_name_t), KM_SLEEP);
+
+       ASSERT(zap->zap_normflags == 0);
+       zn->zn_zap = zap;
+       zn->zn_key_intlen = sizeof (*key);
+       zn->zn_key_orig = zn->zn_key_norm = key;
+       zn->zn_key_orig_numints = zn->zn_key_norm_numints = numints;
+       zn->zn_matchtype = MT_EXACT;
+
+       zn->zn_hash = zap_hash(zn);
+       return (zn);
+}
+
+static void
+mzap_byteswap(mzap_phys_t *buf, size_t size)
+{
+       int i, max;
+       buf->mz_block_type = BSWAP_64(buf->mz_block_type);
+       buf->mz_salt = BSWAP_64(buf->mz_salt);
+       buf->mz_normflags = BSWAP_64(buf->mz_normflags);
+       max = (size / MZAP_ENT_LEN) - 1;
+       for (i = 0; i < max; i++) {
+               buf->mz_chunk[i].mze_value =
+                   BSWAP_64(buf->mz_chunk[i].mze_value);
+               buf->mz_chunk[i].mze_cd =
+                   BSWAP_32(buf->mz_chunk[i].mze_cd);
+       }
+}
+
+void
+zap_byteswap(void *buf, size_t size)
+{
+       uint64_t block_type;
+
+       block_type = *(uint64_t *)buf;
+
+       if (block_type == ZBT_MICRO || block_type == BSWAP_64(ZBT_MICRO)) {
+               /* ASSERT(magic == ZAP_LEAF_MAGIC); */
+               mzap_byteswap(buf, size);
+       } else {
+               fzap_byteswap(buf, size);
+       }
+}
+
+static int
+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);
+}
+
+static void
+mze_insert(zap_t *zap, int chunkid, uint64_t hash)
+{
+       mzap_ent_t *mze;
+
+       ASSERT(zap->zap_ismicro);
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+
+       mze = kmem_alloc(sizeof (mzap_ent_t), KM_SLEEP);
+       mze->mze_chunkid = chunkid;
+       mze->mze_hash = hash;
+       mze->mze_cd = MZE_PHYS(zap, mze)->mze_cd;
+       ASSERT(MZE_PHYS(zap, mze)->mze_name[0] != 0);
+       avl_add(&zap->zap_m.zap_avl, mze);
+}
+
+static mzap_ent_t *
+mze_find(zap_name_t *zn)
+{
+       mzap_ent_t mze_tofind;
+       mzap_ent_t *mze;
+       avl_index_t idx;
+       avl_tree_t *avl = &zn->zn_zap->zap_m.zap_avl;
+
+       ASSERT(zn->zn_zap->zap_ismicro);
+       ASSERT(RW_LOCK_HELD(&zn->zn_zap->zap_rwlock));
+
+       mze_tofind.mze_hash = zn->zn_hash;
+       mze_tofind.mze_cd = 0;
+
+again:
+       mze = avl_find(avl, &mze_tofind, &idx);
+       if (mze == NULL)
+               mze = avl_nearest(avl, idx, AVL_AFTER);
+       for (; mze && mze->mze_hash == zn->zn_hash; mze = AVL_NEXT(avl, mze)) {
+               ASSERT3U(mze->mze_cd, ==, MZE_PHYS(zn->zn_zap, mze)->mze_cd);
+               if (zap_match(zn, MZE_PHYS(zn->zn_zap, mze)->mze_name))
+                       return (mze);
+       }
+       if (zn->zn_matchtype == MT_BEST) {
+               zn->zn_matchtype = MT_FIRST;
+               goto again;
+       }
+       return (NULL);
+}
+
+static uint32_t
+mze_find_unused_cd(zap_t *zap, uint64_t hash)
+{
+       mzap_ent_t mze_tofind;
+       mzap_ent_t *mze;
+       avl_index_t idx;
+       avl_tree_t *avl = &zap->zap_m.zap_avl;
+       uint32_t cd;
+
+       ASSERT(zap->zap_ismicro);
+       ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+
+       mze_tofind.mze_hash = hash;
+       mze_tofind.mze_cd = 0;
+
+       cd = 0;
+       for (mze = avl_find(avl, &mze_tofind, &idx);
+           mze && mze->mze_hash == hash; mze = AVL_NEXT(avl, mze)) {
+               if (mze->mze_cd != cd)
+                       break;
+               cd++;
+       }
+
+       return (cd);
+}
+
+static void
+mze_remove(zap_t *zap, mzap_ent_t *mze)
+{
+       ASSERT(zap->zap_ismicro);
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+
+       avl_remove(&zap->zap_m.zap_avl, mze);
+       kmem_free(mze, sizeof (mzap_ent_t));
+}
+
+static void
+mze_destroy(zap_t *zap)
+{
+       mzap_ent_t *mze;
+       void *avlcookie = NULL;
+
+       while ((mze = avl_destroy_nodes(&zap->zap_m.zap_avl, &avlcookie)))
+               kmem_free(mze, sizeof (mzap_ent_t));
+       avl_destroy(&zap->zap_m.zap_avl);
+}
+
+static zap_t *
+mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
+{
+       zap_t *winner;
+       zap_t *zap;
+       int i;
+
+       ASSERT3U(MZAP_ENT_LEN, ==, sizeof (mzap_ent_phys_t));
+
+       zap = kmem_zalloc(sizeof (zap_t), KM_SLEEP);
+       rw_init(&zap->zap_rwlock, NULL, RW_DEFAULT, NULL);
+       rw_enter(&zap->zap_rwlock, RW_WRITER);
+       zap->zap_objset = os;
+       zap->zap_object = obj;
+       zap->zap_dbuf = db;
+
+       if (*(uint64_t *)db->db_data != 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;
+       } else {
+               zap->zap_ismicro = TRUE;
+       }
+
+       /*
+        * Make sure that zap_ismicro is set before we let others see
+        * it, because zap_lockdir() checks zap_ismicro without the lock
+        * held.
+        */
+       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 (zap->zap_ismicro) {
+               zap->zap_salt = zap_m_phys(zap)->mz_salt;
+               zap->zap_normflags = zap_m_phys(zap)->mz_normflags;
+               zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1;
+               avl_create(&zap->zap_m.zap_avl, mze_compare,
+                   sizeof (mzap_ent_t), offsetof(mzap_ent_t, mze_node));
+
+               for (i = 0; i < zap->zap_m.zap_num_chunks; i++) {
+                       mzap_ent_phys_t *mze =
+                           &zap_m_phys(zap)->mz_chunk[i];
+                       if (mze->mze_name[0]) {
+                               zap_name_t *zn;
+
+                               zap->zap_m.zap_num_entries++;
+                               zn = zap_name_alloc(zap, mze->mze_name,
+                                   MT_EXACT);
+                               mze_insert(zap, i, zn->zn_hash);
+                               zap_name_free(zn);
+                       }
+               }
+       } else {
+               zap->zap_salt = zap_f_phys(zap)->zap_salt;
+               zap->zap_normflags = zap_f_phys(zap)->zap_normflags;
+
+               ASSERT3U(sizeof (struct zap_leaf_header), ==,
+                   2*ZAP_LEAF_CHUNKSIZE);
+
+               /*
+                * The embedded pointer table should not overlap the
+                * other members.
+                */
+               ASSERT3P(&ZAP_EMBEDDED_PTRTBL_ENT(zap, 0), >,
+                   &zap_f_phys(zap)->zap_salt);
+
+               /*
+                * The embedded pointer table should end at the end of
+                * the block
+                */
+               ASSERT3U((uintptr_t)&ZAP_EMBEDDED_PTRTBL_ENT(zap,
+                   1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap)) -
+                   (uintptr_t)zap_f_phys(zap), ==,
+                   zap->zap_dbuf->db_size);
+       }
+       rw_exit(&zap->zap_rwlock);
+       return (zap);
+}
+
+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)
+{
+       dmu_object_info_t doi;
+       zap_t *zap;
+       dmu_buf_t *db;
+       krw_t lt;
+       int err;
+
+       *zapp = NULL;
+
+       err = dmu_buf_hold(os, obj, 0, NULL, &db, DMU_READ_NO_PREFETCH);
+       if (err)
+               return (err);
+
+       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)
+               zap = mzap_open(os, obj, db);
+
+       /*
+        * We're checking zap_ismicro without the lock held, in order to
+        * tell what type of lock we want.  Once we have some sort of
+        * lock, see if it really is the right type.  In practice this
+        * can only be different if it was upgraded from micro to fat,
+        * and micro wanted WRITER but fat only needs READER.
+        */
+       lt = (!zap->zap_ismicro && fatreader) ? RW_READER : lti;
+       rw_enter(&zap->zap_rwlock, lt);
+       if (lt != ((!zap->zap_ismicro && fatreader) ? RW_READER : lti)) {
+               /* it was upgraded, now we only need reader */
+               ASSERT(lt == RW_WRITER);
+               ASSERT(RW_READER ==
+                   ((!zap->zap_ismicro && fatreader) ? RW_READER : lti));
+               rw_downgrade(&zap->zap_rwlock);
+               lt = RW_READER;
+       }
+
+       zap->zap_objset = os;
+
+       if (lt == RW_WRITER)
+               dmu_buf_will_dirty(db, tx);
+
+       ASSERT3P(zap->zap_dbuf, ==, db);
+
+       ASSERT(!zap->zap_ismicro ||
+           zap->zap_m.zap_num_entries <= zap->zap_m.zap_num_chunks);
+       if (zap->zap_ismicro && tx && adding &&
+           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) {
+                       dprintf("upgrading obj %llu: num_entries=%u\n",
+                           obj, zap->zap_m.zap_num_entries);
+                       *zapp = zap;
+                       return (mzap_upgrade(zapp, tx, 0));
+               }
+               err = dmu_object_set_blocksize(os, obj, newsz, 0, tx);
+               ASSERT0(err);
+               zap->zap_m.zap_num_chunks =
+                   db->db_size / MZAP_ENT_LEN - 1;
+       }
+
+       *zapp = zap;
+       return (0);
+}
+
+void
+zap_unlockdir(zap_t *zap)
+{
+       rw_exit(&zap->zap_rwlock);
+       dmu_buf_rele(zap->zap_dbuf, NULL);
+}
+
+static int
+mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags)
+{
+       mzap_phys_t *mzp;
+       int i, sz, nchunks;
+       int err = 0;
+       zap_t *zap = *zapp;
+
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+
+       sz = zap->zap_dbuf->db_size;
+       mzp = zio_buf_alloc(sz);
+       bcopy(zap->zap_dbuf->db_data, mzp, sz);
+       nchunks = zap->zap_m.zap_num_chunks;
+
+       if (!flags) {
+               err = dmu_object_set_blocksize(zap->zap_objset, zap->zap_object,
+                   1ULL << fzap_default_block_shift, 0, tx);
+               if (err) {
+                       zio_buf_free(mzp, sz);
+                       return (err);
+               }
+       }
+
+       dprintf("upgrading obj=%llu with %u chunks\n",
+           zap->zap_object, nchunks);
+       /* XXX destroy the avl later, so we can use the stored hash value */
+       mze_destroy(zap);
+
+       fzap_upgrade(zap, tx, flags);
+
+       for (i = 0; i < nchunks; i++) {
+               mzap_ent_phys_t *mze = &mzp->mz_chunk[i];
+               zap_name_t *zn;
+               if (mze->mze_name[0] == 0)
+                       continue;
+               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);
+               zap = zn->zn_zap;       /* fzap_add_cd() may change zap */
+               zap_name_free(zn);
+               if (err)
+                       break;
+       }
+       zio_buf_free(mzp, sz);
+       *zapp = zap;
+       return (err);
+}
+
+void
+mzap_create_impl(objset_t *os, uint64_t obj, int normflags, zap_flags_t flags,
+    dmu_tx_t *tx)
+{
+       dmu_buf_t *db;
+       mzap_phys_t *zp;
+
+       VERIFY(0 == dmu_buf_hold(os, obj, 0, FTAG, &db, DMU_READ_NO_PREFETCH));
+
+#ifdef ZFS_DEBUG
+       {
+               dmu_object_info_t doi;
+               dmu_object_info_from_db(db, &doi);
+               ASSERT3U(DMU_OT_BYTESWAP(doi.doi_type), ==, DMU_BSWAP_ZAP);
+       }
+#endif
+
+       dmu_buf_will_dirty(db, tx);
+       zp = db->db_data;
+       zp->mz_block_type = ZBT_MICRO;
+       zp->mz_salt = ((uintptr_t)db ^ (uintptr_t)tx ^ (obj << 1)) | 1ULL;
+       zp->mz_normflags = normflags;
+       dmu_buf_rele(db, FTAG);
+
+       if (flags != 0) {
+               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);
+       }
+}
+
+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));
+}
+
+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)
+{
+       int err;
+
+       err = dmu_object_claim(os, obj, ot, 0, bonustype, bonuslen, tx);
+       if (err != 0)
+               return (err);
+       mzap_create_impl(os, obj, normflags, 0, tx);
+       return (0);
+}
+
+uint64_t
+zap_create(objset_t *os, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
+       return (zap_create_norm(os, 0, ot, bonustype, bonuslen, 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);
+
+       mzap_create_impl(os, obj, normflags, 0, tx);
+       return (obj);
+}
+
+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 obj = dmu_object_alloc(os, ot, 0, bonustype, bonuslen, tx);
+
+       ASSERT(leaf_blockshift >= SPA_MINBLOCKSHIFT &&
+           leaf_blockshift <= SPA_OLD_MAXBLOCKSHIFT &&
+           indirect_blockshift >= SPA_MINBLOCKSHIFT &&
+           indirect_blockshift <= SPA_OLD_MAXBLOCKSHIFT);
+
+       VERIFY(dmu_object_set_blocksize(os, obj,
+           1ULL << leaf_blockshift, indirect_blockshift, tx) == 0);
+
+       mzap_create_impl(os, obj, normflags, flags, tx);
+       return (obj);
+}
+
+int
+zap_destroy(objset_t *os, uint64_t zapobj, dmu_tx_t *tx)
+{
+       /*
+        * dmu_object_free will free the object number and free the
+        * data.  Freeing the data will cause our pageout function to be
+        * called, which will destroy our data (zap_leaf_t's and zap_t).
+        */
+
+       return (dmu_object_free(os, zapobj, tx));
+}
+
+void
+zap_evict(void *dbu)
+{
+       zap_t *zap = dbu;
+
+       rw_destroy(&zap->zap_rwlock);
+
+       if (zap->zap_ismicro)
+               mze_destroy(zap);
+       else
+               mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
+
+       kmem_free(zap, sizeof (zap_t));
+}
+
+int
+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);
+       if (err)
+               return (err);
+       if (!zap->zap_ismicro) {
+               err = fzap_count(zap, count);
+       } else {
+               *count = zap->zap_m.zap_num_entries;
+       }
+       zap_unlockdir(zap);
+       return (err);
+}
+
+/*
+ * zn may be NULL; if not specified, it will be computed if needed.
+ * See also the comment above zap_entry_normalization_conflict().
+ */
+static boolean_t
+mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze)
+{
+       mzap_ent_t *other;
+       int direction = AVL_BEFORE;
+       boolean_t allocdzn = B_FALSE;
+
+       if (zap->zap_normflags == 0)
+               return (B_FALSE);
+
+again:
+       for (other = avl_walk(&zap->zap_m.zap_avl, mze, direction);
+           other && other->mze_hash == mze->mze_hash;
+           other = avl_walk(&zap->zap_m.zap_avl, other, direction)) {
+
+               if (zn == NULL) {
+                       zn = zap_name_alloc(zap, MZE_PHYS(zap, mze)->mze_name,
+                           MT_FIRST);
+                       allocdzn = B_TRUE;
+               }
+               if (zap_match(zn, MZE_PHYS(zap, other)->mze_name)) {
+                       if (allocdzn)
+                               zap_name_free(zn);
+                       return (B_TRUE);
+               }
+       }
+
+       if (direction == AVL_BEFORE) {
+               direction = AVL_AFTER;
+               goto again;
+       }
+
+       if (allocdzn)
+               zap_name_free(zn);
+       return (B_FALSE);
+}
+
+/*
+ * Routines for manipulating attributes.
+ */
+
+int
+zap_lookup(objset_t *os, uint64_t zapobj, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf)
+{
+       return (zap_lookup_norm(os, zapobj, name, integer_size,
+           num_integers, buf, MT_EXACT, NULL, 0, NULL));
+}
+
+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;
+       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);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       if (!zap->zap_ismicro) {
+               err = fzap_lookup(zn, integer_size, num_integers, buf,
+                   realname, rn_len, ncp);
+       } else {
+               mze = mze_find(zn);
+               if (mze == NULL) {
+                       err = SET_ERROR(ENOENT);
+               } else {
+                       if (num_integers < 1) {
+                               err = SET_ERROR(EOVERFLOW);
+                       } else if (integer_size != 8) {
+                               err = SET_ERROR(EINVAL);
+                       } else {
+                               *(uint64_t *)buf =
+                                   MZE_PHYS(zap, mze)->mze_value;
+                               (void) strlcpy(realname,
+                                   MZE_PHYS(zap, mze)->mze_name, rn_len);
+                               if (ncp) {
+                                       *ncp = mzap_normalization_conflict(zap,
+                                           zn, mze);
+                               }
+                       }
+               }
+       }
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_prefetch(objset_t *os, uint64_t zapobj, const char *name)
+{
+       zap_t *zap;
+       int err;
+       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_EXACT);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       fzap_prefetch(zn);
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints)
+{
+       zap_t *zap;
+       int err;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc_uint64(zap, key, key_numints);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       fzap_prefetch(zn);
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_lookup_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, uint64_t integer_size, uint64_t num_integers, void *buf)
+{
+       zap_t *zap;
+       int err;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc_uint64(zap, key, key_numints);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       err = fzap_lookup(zn, integer_size, num_integers, buf,
+           NULL, 0, NULL);
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_contains(objset_t *os, uint64_t zapobj, const char *name)
+{
+       int err = zap_lookup_norm(os, zapobj, name, 0,
+           0, NULL, MT_EXACT, NULL, 0, NULL);
+       if (err == EOVERFLOW || err == EINVAL)
+               err = 0; /* found, but skipped reading the value */
+       return (err);
+}
+
+int
+zap_length(objset_t *os, uint64_t zapobj, const char *name,
+    uint64_t *integer_size, uint64_t *num_integers)
+{
+       zap_t *zap;
+       int err;
+       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_EXACT);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       if (!zap->zap_ismicro) {
+               err = fzap_length(zn, integer_size, num_integers);
+       } else {
+               mze = mze_find(zn);
+               if (mze == NULL) {
+                       err = SET_ERROR(ENOENT);
+               } else {
+                       if (integer_size)
+                               *integer_size = 8;
+                       if (num_integers)
+                               *num_integers = 1;
+               }
+       }
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_length_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, uint64_t *integer_size, uint64_t *num_integers)
+{
+       zap_t *zap;
+       int err;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc_uint64(zap, key, key_numints);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       err = fzap_length(zn, integer_size, num_integers);
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+static void
+mzap_addent(zap_name_t *zn, uint64_t value)
+{
+       int i;
+       zap_t *zap = zn->zn_zap;
+       int start = zap->zap_m.zap_alloc_next;
+       uint32_t cd;
+
+       ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
+
+#ifdef ZFS_DEBUG
+       for (i = 0; i < zap->zap_m.zap_num_chunks; i++) {
+               ASSERTV(mzap_ent_phys_t *mze);
+               ASSERT(mze = &zap_m_phys(zap)->mz_chunk[i]);
+               ASSERT(strcmp(zn->zn_key_orig, mze->mze_name) != 0);
+       }
+#endif
+
+       cd = mze_find_unused_cd(zap, zn->zn_hash);
+       /* given the limited size of the microzap, this can't happen */
+       ASSERT(cd < zap_maxcd(zap));
+
+again:
+       for (i = start; i < zap->zap_m.zap_num_chunks; i++) {
+               mzap_ent_phys_t *mze = &zap_m_phys(zap)->mz_chunk[i];
+               if (mze->mze_name[0] == 0) {
+                       mze->mze_value = value;
+                       mze->mze_cd = cd;
+                       (void) strcpy(mze->mze_name, zn->zn_key_orig);
+                       zap->zap_m.zap_num_entries++;
+                       zap->zap_m.zap_alloc_next = i+1;
+                       if (zap->zap_m.zap_alloc_next ==
+                           zap->zap_m.zap_num_chunks)
+                               zap->zap_m.zap_alloc_next = 0;
+                       mze_insert(zap, i, zn->zn_hash);
+                       return;
+               }
+       }
+       if (start != 0) {
+               start = 0;
+               goto again;
+       }
+       cmn_err(CE_PANIC, "out of entries!");
+}
+
+int
+zap_add(objset_t *os, uint64_t zapobj, const char *key,
+    int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+       mzap_ent_t *mze;
+       const uint64_t *intval = val;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc(zap, key, MT_EXACT);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       if (!zap->zap_ismicro) {
+               err = fzap_add(zn, integer_size, num_integers, val, 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);
+               zap = zn->zn_zap;       /* fzap_add() may change zap */
+       } else {
+               mze = mze_find(zn);
+               if (mze != NULL) {
+                       err = SET_ERROR(EEXIST);
+               } else {
+                       mzap_addent(zn, *intval);
+               }
+       }
+       ASSERT(zap == zn->zn_zap);
+       zap_name_free(zn);
+       if (zap != NULL)        /* may be NULL if fzap_add() failed */
+               zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_add_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc_uint64(zap, key, key_numints);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       err = fzap_add(zn, integer_size, num_integers, val, 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);
+       return (err);
+}
+
+int
+zap_update(objset_t *os, uint64_t zapobj, const char *name,
+    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       mzap_ent_t *mze;
+       const uint64_t *intval = val;
+       zap_name_t *zn;
+       int err;
+
+#ifdef ZFS_DEBUG
+       uint64_t oldval;
+
+       /*
+        * If there is an old value, it shouldn't change across the
+        * lockdir (eg, due to bprewrite's xlation).
+        */
+       if (integer_size == 8 && num_integers == 1)
+               (void) zap_lookup(os, zapobj, name, 8, 1, &oldval);
+#endif
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc(zap, name, MT_EXACT);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       if (!zap->zap_ismicro) {
+               err = fzap_update(zn, integer_size, num_integers, val, 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 = fzap_update(zn, integer_size, num_integers,
+                           val, tx);
+               zap = zn->zn_zap;       /* fzap_update() may change zap */
+       } else {
+               mze = mze_find(zn);
+               if (mze != NULL) {
+                       ASSERT3U(MZE_PHYS(zap, mze)->mze_value, ==, oldval);
+                       MZE_PHYS(zap, mze)->mze_value = *intval;
+               } else {
+                       mzap_addent(zn, *intval);
+               }
+       }
+       ASSERT(zap == zn->zn_zap);
+       zap_name_free(zn);
+       if (zap != NULL)        /* may be NULL if fzap_upgrade() failed */
+               zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_update_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints,
+    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       zap_name_t *zn;
+       int err;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc_uint64(zap, key, key_numints);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       err = fzap_update(zn, integer_size, num_integers, val, 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);
+       return (err);
+}
+
+int
+zap_remove(objset_t *os, uint64_t zapobj, const char *name, dmu_tx_t *tx)
+{
+       return (zap_remove_norm(os, zapobj, name, MT_EXACT, tx));
+}
+
+int
+zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
+    matchtype_t mt, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+       mzap_ent_t *mze;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc(zap, name, mt);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       if (!zap->zap_ismicro) {
+               err = fzap_remove(zn, tx);
+       } else {
+               mze = mze_find(zn);
+               if (mze == NULL) {
+                       err = SET_ERROR(ENOENT);
+               } else {
+                       zap->zap_m.zap_num_entries--;
+                       bzero(&zap_m_phys(zap)->mz_chunk[mze->mze_chunkid],
+                           sizeof (mzap_ent_phys_t));
+                       mze_remove(zap, mze);
+               }
+       }
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_remove_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
+    int key_numints, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+       zap_name_t *zn;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, &zap);
+       if (err)
+               return (err);
+       zn = zap_name_alloc_uint64(zap, key, key_numints);
+       if (zn == NULL) {
+               zap_unlockdir(zap);
+               return (SET_ERROR(ENOTSUP));
+       }
+       err = fzap_remove(zn, tx);
+       zap_name_free(zn);
+       zap_unlockdir(zap);
+       return (err);
+}
+
+/*
+ * Routines for iterating over the attributes.
+ */
+
+void
+zap_cursor_init_serialized(zap_cursor_t *zc, objset_t *os, uint64_t zapobj,
+    uint64_t serialized)
+{
+       zc->zc_objset = os;
+       zc->zc_zap = NULL;
+       zc->zc_leaf = NULL;
+       zc->zc_zapobj = zapobj;
+       zc->zc_serialized = serialized;
+       zc->zc_hash = 0;
+       zc->zc_cd = 0;
+}
+
+void
+zap_cursor_init(zap_cursor_t *zc, objset_t *os, uint64_t zapobj)
+{
+       zap_cursor_init_serialized(zc, os, zapobj, 0);
+}
+
+void
+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);
+               zc->zc_zap = NULL;
+       }
+       if (zc->zc_leaf) {
+               rw_enter(&zc->zc_leaf->l_rwlock, RW_READER);
+               zap_put_leaf(zc->zc_leaf);
+               zc->zc_leaf = NULL;
+       }
+       zc->zc_objset = NULL;
+}
+
+uint64_t
+zap_cursor_serialize(zap_cursor_t *zc)
+{
+       if (zc->zc_hash == -1ULL)
+               return (-1ULL);
+       if (zc->zc_zap == NULL)
+               return (zc->zc_serialized);
+       ASSERT((zc->zc_hash & zap_maxcd(zc->zc_zap)) == 0);
+       ASSERT(zc->zc_cd < zap_maxcd(zc->zc_zap));
+
+       /*
+        * We want to keep the high 32 bits of the cursor zero if we can, so
+        * that 32-bit programs can access this.  So usually use a small
+        * (28-bit) hash value so we can fit 4 bits of cd into the low 32-bits
+        * of the cursor.
+        *
+        * [ collision differentiator | zap_hashbits()-bit hash value ]
+        */
+       return ((zc->zc_hash >> (64 - zap_hashbits(zc->zc_zap))) |
+           ((uint64_t)zc->zc_cd << zap_hashbits(zc->zc_zap)));
+}
+
+int
+zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za)
+{
+       int err;
+       avl_index_t idx;
+       mzap_ent_t mze_tofind;
+       mzap_ent_t *mze;
+
+       if (zc->zc_hash == -1ULL)
+               return (SET_ERROR(ENOENT));
+
+       if (zc->zc_zap == NULL) {
+               int hb;
+               err = zap_lockdir(zc->zc_objset, zc->zc_zapobj, NULL,
+                   RW_READER, TRUE, FALSE, &zc->zc_zap);
+               if (err)
+                       return (err);
+
+               /*
+                * To support zap_cursor_init_serialized, advance, retrieve,
+                * we must add to the existing zc_cd, which may already
+                * be 1 due to the zap_cursor_advance.
+                */
+               ASSERT(zc->zc_hash == 0);
+               hb = zap_hashbits(zc->zc_zap);
+               zc->zc_hash = zc->zc_serialized << (64 - hb);
+               zc->zc_cd += zc->zc_serialized >> hb;
+               if (zc->zc_cd >= zap_maxcd(zc->zc_zap)) /* corrupt serialized */
+                       zc->zc_cd = 0;
+       } else {
+               rw_enter(&zc->zc_zap->zap_rwlock, RW_READER);
+       }
+       if (!zc->zc_zap->zap_ismicro) {
+               err = fzap_cursor_retrieve(zc->zc_zap, zc, za);
+       } else {
+               mze_tofind.mze_hash = zc->zc_hash;
+               mze_tofind.mze_cd = zc->zc_cd;
+
+               mze = avl_find(&zc->zc_zap->zap_m.zap_avl, &mze_tofind, &idx);
+               if (mze == NULL) {
+                       mze = avl_nearest(&zc->zc_zap->zap_m.zap_avl,
+                           idx, AVL_AFTER);
+               }
+               if (mze) {
+                       mzap_ent_phys_t *mzep = MZE_PHYS(zc->zc_zap, mze);
+                       ASSERT3U(mze->mze_cd, ==, mzep->mze_cd);
+                       za->za_normalization_conflict =
+                           mzap_normalization_conflict(zc->zc_zap, NULL, mze);
+                       za->za_integer_length = 8;
+                       za->za_num_integers = 1;
+                       za->za_first_integer = mzep->mze_value;
+                       (void) strcpy(za->za_name, mzep->mze_name);
+                       zc->zc_hash = mze->mze_hash;
+                       zc->zc_cd = mze->mze_cd;
+                       err = 0;
+               } else {
+                       zc->zc_hash = -1ULL;
+                       err = SET_ERROR(ENOENT);
+               }
+       }
+       rw_exit(&zc->zc_zap->zap_rwlock);
+       return (err);
+}
+
+void
+zap_cursor_advance(zap_cursor_t *zc)
+{
+       if (zc->zc_hash == -1ULL)
+               return;
+       zc->zc_cd++;
+}
+
+int
+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);
+       if (err)
+               return (err);
+
+       bzero(zs, sizeof (zap_stats_t));
+
+       if (zap->zap_ismicro) {
+               zs->zs_blocksize = zap->zap_dbuf->db_size;
+               zs->zs_num_entries = zap->zap_m.zap_num_entries;
+               zs->zs_num_blocks = 1;
+       } else {
+               fzap_get_stats(zap, zs);
+       }
+       zap_unlockdir(zap);
+       return (0);
+}
+
+int
+zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
+    uint64_t *towrite, uint64_t *tooverwrite)
+{
+       zap_t *zap;
+       int err = 0;
+
+       /*
+        * Since, we don't have a name, we cannot figure out which blocks will
+        * be affected in this operation. So, account for the worst case :
+        * - 3 blocks overwritten: target leaf, ptrtbl block, header block
+        * - 4 new blocks written if adding:
+        *      - 2 blocks for possibly split leaves,
+        *      - 2 grown ptrtbl blocks
+        *
+        * This also accomodates the case where an add operation to a fairly
+        * large microzap results in a promotion to fatzap.
+        */
+       if (name == NULL) {
+               *towrite += (3 + (add ? 4 : 0)) * SPA_OLD_MAXBLOCKSIZE;
+               return (err);
+       }
+
+       /*
+        * 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.
+        */
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       if (err)
+               return (err);
+
+       if (!zap->zap_ismicro) {
+               zap_name_t *zn = zap_name_alloc(zap, name, MT_EXACT);
+               if (zn) {
+                       err = fzap_count_write(zn, add, towrite,
+                           tooverwrite);
+                       zap_name_free(zn);
+               } else {
+                       /*
+                        * We treat this case as similar to (name == NULL)
+                        */
+                       *towrite += (3 + (add ? 4 : 0)) * SPA_OLD_MAXBLOCKSIZE;
+               }
+       } else {
+               /*
+                * We are here if (name != NULL) and this is a micro-zap.
+                * We account for the header block depending on whether it
+                * is freeable.
+                *
+                * Incase of an add-operation it is hard to find out
+                * if this add will promote this microzap to fatzap.
+                * Hence, we consider the worst case and account for the
+                * blocks assuming this microzap would be promoted to a
+                * fatzap.
+                *
+                * 1 block overwritten  : header block
+                * 4 new blocks written : 2 new split leaf, 2 grown
+                *                      ptrtbl blocks
+                */
+               if (dmu_buf_freeable(zap->zap_dbuf))
+                       *tooverwrite += MZAP_MAX_BLKSZ;
+               else
+                       *towrite += MZAP_MAX_BLKSZ;
+
+               if (add) {
+                       *towrite += 4 * MZAP_MAX_BLKSZ;
+               }
+       }
+
+       zap_unlockdir(zap);
+       return (err);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zap_create);
+EXPORT_SYMBOL(zap_create_norm);
+EXPORT_SYMBOL(zap_create_flags);
+EXPORT_SYMBOL(zap_create_claim);
+EXPORT_SYMBOL(zap_create_claim_norm);
+EXPORT_SYMBOL(zap_destroy);
+EXPORT_SYMBOL(zap_lookup);
+EXPORT_SYMBOL(zap_lookup_norm);
+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_add);
+EXPORT_SYMBOL(zap_add_uint64);
+EXPORT_SYMBOL(zap_update);
+EXPORT_SYMBOL(zap_update_uint64);
+EXPORT_SYMBOL(zap_length);
+EXPORT_SYMBOL(zap_length_uint64);
+EXPORT_SYMBOL(zap_remove);
+EXPORT_SYMBOL(zap_remove_norm);
+EXPORT_SYMBOL(zap_remove_uint64);
+EXPORT_SYMBOL(zap_count);
+EXPORT_SYMBOL(zap_value_search);
+EXPORT_SYMBOL(zap_join);
+EXPORT_SYMBOL(zap_join_increment);
+EXPORT_SYMBOL(zap_add_int);
+EXPORT_SYMBOL(zap_remove_int);
+EXPORT_SYMBOL(zap_lookup_int);
+EXPORT_SYMBOL(zap_increment_int);
+EXPORT_SYMBOL(zap_add_int_key);
+EXPORT_SYMBOL(zap_lookup_int_key);
+EXPORT_SYMBOL(zap_increment);
+EXPORT_SYMBOL(zap_cursor_init);
+EXPORT_SYMBOL(zap_cursor_fini);
+EXPORT_SYMBOL(zap_cursor_retrieve);
+EXPORT_SYMBOL(zap_cursor_advance);
+EXPORT_SYMBOL(zap_cursor_serialize);
+EXPORT_SYMBOL(zap_cursor_init_serialized);
+EXPORT_SYMBOL(zap_get_stats);
+#endif
diff --git a/zfs/module/zfs/zfeature.c b/zfs/module/zfs/zfeature.c
new file mode 100644 (file)
index 0000000..352376f
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/zfeature.h>
+#include <sys/dmu.h>
+#include <sys/nvpair.h>
+#include <sys/zap.h>
+#include <sys/dmu_tx.h>
+#include "zfeature_common.h"
+#include <sys/spa_impl.h>
+
+/*
+ * ZFS Feature Flags
+ * -----------------
+ *
+ * ZFS feature flags are used to provide fine-grained versioning to the ZFS
+ * on-disk format. Once enabled on a pool feature flags replace the old
+ * spa_version() number.
+ *
+ * Each new on-disk format change will be given a uniquely identifying string
+ * guid rather than a version number. This avoids the problem of different
+ * organizations creating new on-disk formats with the same version number. To
+ * keep feature guids unique they should consist of the reverse dns name of the
+ * organization which implemented the feature and a short name for the feature,
+ * separated by a colon (e.g. com.delphix:async_destroy).
+ *
+ * Reference Counts
+ * ----------------
+ *
+ * Within each pool features can be in one of three states: disabled, enabled,
+ * or active. These states are differentiated by a reference count stored on
+ * disk for each feature:
+ *
+ *   1) If there is no reference count stored on disk the feature is disabled.
+ *   2) If the reference count is 0 a system administrator has enabled the
+ *      feature, but the feature has not been used yet, so no on-disk
+ *      format changes have been made.
+ *   3) If the reference count is greater than 0 the feature is active.
+ *      The format changes required by the feature are currently on disk.
+ *      Note that if the feature's format changes are reversed the feature
+ *      may choose to set its reference count back to 0.
+ *
+ * Feature flags makes no differentiation between non-zero reference counts
+ * for an active feature (e.g. a reference count of 1 means the same thing as a
+ * reference count of 27834721), but feature implementations may choose to use
+ * the reference count to store meaningful information. For example, a new RAID
+ * implementation might set the reference count to the number of vdevs using
+ * it. If all those disks are removed from the pool the feature goes back to
+ * having a reference count of 0.
+ *
+ * It is the responsibility of the individual features to maintain a non-zero
+ * reference count as long as the feature's format changes are present on disk.
+ *
+ * Dependencies
+ * ------------
+ *
+ * Each feature may depend on other features. The only effect of this
+ * relationship is that when a feature is enabled all of its dependencies are
+ * automatically enabled as well. Any future work to support disabling of
+ * features would need to ensure that features cannot be disabled if other
+ * enabled features depend on them.
+ *
+ * On-disk Format
+ * --------------
+ *
+ * When feature flags are enabled spa_version() is set to SPA_VERSION_FEATURES
+ * (5000). In order for this to work the pool is automatically upgraded to
+ * SPA_VERSION_BEFORE_FEATURES (28) first, so all pre-feature flags on disk
+ * format changes will be in use.
+ *
+ * Information about features is stored in 3 ZAP objects in the pool's MOS.
+ * These objects are linked to by the following names in the pool directory
+ * object:
+ *
+ * 1) features_for_read: feature guid -> reference count
+ *    Features needed to open the pool for reading.
+ * 2) features_for_write: feature guid -> reference count
+ *    Features needed to open the pool for writing.
+ * 3) feature_descriptions: feature guid -> descriptive string
+ *    A human readable string.
+ *
+ * All enabled features appear in either features_for_read or
+ * features_for_write, but not both.
+ *
+ * To open a pool in read-only mode only the features listed in
+ * features_for_read need to be supported.
+ *
+ * To open the pool in read-write mode features in both features_for_read and
+ * features_for_write need to be supported.
+ *
+ * Some features may be required to read the ZAP objects containing feature
+ * information. To allow software to check for compatibility with these features
+ * before the pool is opened their names must be stored in the label in a
+ * new "features_for_read" entry (note that features that are only required
+ * to write to a pool never need to be stored in the label since the
+ * features_for_write ZAP object can be read before the pool is written to).
+ * To save space in the label features must be explicitly marked as needing to
+ * be written to the label. Also, reference counts are not stored in the label,
+ * instead any feature whose reference count drops to 0 is removed from the
+ * label.
+ *
+ * Adding New Features
+ * -------------------
+ *
+ * Features must be registered in zpool_feature_init() function in
+ * zfeature_common.c using the zfeature_register() function. This function
+ * has arguments to specify if the feature should be stored in the
+ * features_for_read or features_for_write ZAP object and if it needs to be
+ * written to the label when active.
+ *
+ * Once a feature is registered it will appear as a "feature@<feature name>"
+ * property which can be set by an administrator. Feature implementors should
+ * use the spa_feature_is_enabled() and spa_feature_is_active() functions to
+ * query the state of a feature and the spa_feature_incr() and
+ * spa_feature_decr() functions to change an enabled feature's reference count.
+ * Reference counts may only be updated in the syncing context.
+ *
+ * Features may not perform enable-time initialization. Instead, any such
+ * initialization should occur when the feature is first used. This design
+ * enforces that on-disk changes be made only when features are used. Code
+ * should only check if a feature is enabled using spa_feature_is_enabled(),
+ * not by relying on any feature specific metadata existing. If a feature is
+ * enabled, but the feature's metadata is not on disk yet then it should be
+ * created as needed.
+ *
+ * As an example, consider the com.delphix:async_destroy feature. This feature
+ * relies on the existence of a bptree in the MOS that store blocks for
+ * asynchronous freeing. This bptree is not created when async_destroy is
+ * enabled. Instead, when a dataset is destroyed spa_feature_is_enabled() is
+ * called to check if async_destroy is enabled. If it is and the bptree object
+ * does not exist yet, the bptree object is created as part of the dataset
+ * destroy and async_destroy's reference count is incremented to indicate it
+ * has made an on-disk format change. Later, after the destroyed dataset's
+ * blocks have all been asynchronously freed there is no longer any use for the
+ * bptree object, so it is destroyed and async_destroy's reference count is
+ * decremented back to 0 to indicate that it has undone its on-disk format
+ * changes.
+ */
+
+typedef enum {
+       FEATURE_ACTION_INCR,
+       FEATURE_ACTION_DECR,
+} feature_action_t;
+
+/*
+ * Checks that the active features in the pool are supported by
+ * this software.  Adds each unsupported feature (name -> description) to
+ * the supplied nvlist.
+ */
+boolean_t
+spa_features_check(spa_t *spa, boolean_t for_write,
+    nvlist_t *unsup_feat, nvlist_t *enabled_feat)
+{
+       objset_t *os = spa->spa_meta_objset;
+       boolean_t supported;
+       zap_cursor_t *zc;
+       zap_attribute_t *za;
+       uint64_t obj = for_write ?
+           spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
+       char *buf;
+
+       zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
+       za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
+       buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+       supported = B_TRUE;
+       for (zap_cursor_init(zc, os, obj);
+           zap_cursor_retrieve(zc, za) == 0;
+           zap_cursor_advance(zc)) {
+               ASSERT(za->za_integer_length == sizeof (uint64_t) &&
+                   za->za_num_integers == 1);
+
+               if (NULL != enabled_feat) {
+                       fnvlist_add_uint64(enabled_feat, za->za_name,
+                           za->za_first_integer);
+               }
+
+               if (za->za_first_integer != 0 &&
+                   !zfeature_is_supported(za->za_name)) {
+                       supported = B_FALSE;
+
+                       if (NULL != unsup_feat) {
+                               char *desc = "";
+
+                               if (zap_lookup(os, spa->spa_feat_desc_obj,
+                                   za->za_name, 1, MAXPATHLEN, buf) == 0)
+                                       desc = buf;
+
+                               VERIFY(nvlist_add_string(unsup_feat,
+                                   za->za_name, desc) == 0);
+                       }
+               }
+       }
+       zap_cursor_fini(zc);
+
+       kmem_free(buf, MAXPATHLEN);
+       kmem_free(za, sizeof (zap_attribute_t));
+       kmem_free(zc, sizeof (zap_cursor_t));
+
+       return (supported);
+}
+
+/*
+ * Use an in-memory cache of feature refcounts for quick retrieval.
+ *
+ * Note: well-designed features will not need to use this; they should
+ * use spa_feature_is_enabled() and spa_feature_is_active() instead.
+ * However, this is non-static for zdb, zhack, and spa_add_feature_stats().
+ */
+int
+feature_get_refcount(spa_t *spa, zfeature_info_t *feature, uint64_t *res)
+{
+       ASSERT(VALID_FEATURE_FID(feature->fi_feature));
+       if (spa->spa_feat_refcount_cache[feature->fi_feature] ==
+           SPA_FEATURE_DISABLED) {
+               return (SET_ERROR(ENOTSUP));
+       }
+       *res = spa->spa_feat_refcount_cache[feature->fi_feature];
+       return (0);
+}
+
+/*
+ * Note: well-designed features will not need to use this; they should
+ * use spa_feature_is_enabled() and spa_feature_is_active() instead.
+ * However, this is non-static for zdb and zhack.
+ */
+int
+feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
+    uint64_t *res)
+{
+       int err;
+       uint64_t refcount;
+       uint64_t zapobj = feature->fi_can_readonly ?
+           spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
+
+       /*
+        * If the pool is currently being created, the feature objects may not
+        * have been allocated yet.  Act as though all features are disabled.
+        */
+       if (zapobj == 0)
+               return (SET_ERROR(ENOTSUP));
+
+       err = zap_lookup(spa->spa_meta_objset, zapobj,
+           feature->fi_guid, sizeof (uint64_t), 1, &refcount);
+       if (err != 0) {
+               if (err == ENOENT)
+                       return (SET_ERROR(ENOTSUP));
+               else
+                       return (err);
+       }
+       *res = refcount;
+       return (0);
+}
+
+
+static int
+feature_get_enabled_txg(spa_t *spa, zfeature_info_t *feature, uint64_t *res) {
+       ASSERTV(uint64_t enabled_txg_obj = spa->spa_feat_enabled_txg_obj);
+
+       ASSERT(zfeature_depends_on(feature->fi_feature,
+           SPA_FEATURE_ENABLED_TXG));
+
+       if (!spa_feature_is_enabled(spa, feature->fi_feature)) {
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       ASSERT(enabled_txg_obj != 0);
+
+       VERIFY0(zap_lookup(spa->spa_meta_objset, spa->spa_feat_enabled_txg_obj,
+           feature->fi_guid, sizeof (uint64_t), 1, res));
+
+       return (0);
+}
+
+/*
+ * This function is non-static for zhack; it should otherwise not be used
+ * outside this file.
+ */
+void
+feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
+    dmu_tx_t *tx)
+{
+       uint64_t zapobj;
+
+       ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature));
+       zapobj = feature->fi_can_readonly ?
+           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));
+
+       /*
+        * feature_sync is called directly from zhack, allowing the
+        * creation of arbitrary features whose fi_feature field may
+        * be greater than SPA_FEATURES. When called from zhack, the
+        * zfeature_info_t object's fi_feature field will be set to
+        * SPA_FEATURE_NONE.
+        */
+       if (feature->fi_feature != SPA_FEATURE_NONE) {
+               uint64_t *refcount_cache =
+                   &spa->spa_feat_refcount_cache[feature->fi_feature];
+               VERIFY3U(*refcount_cache, ==,
+                   atomic_swap_64(refcount_cache, refcount));
+       }
+
+       if (refcount == 0)
+               spa_deactivate_mos_feature(spa, feature->fi_guid);
+       else if (feature->fi_mos)
+               spa_activate_mos_feature(spa, feature->fi_guid, tx);
+}
+
+/*
+ * This function is non-static for zhack; it should otherwise not be used
+ * outside this file.
+ */
+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 ?
+           spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
+       int i;
+
+       ASSERT(0 != zapobj);
+       ASSERT(zfeature_is_valid_guid(feature->fi_guid));
+       ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
+
+       /*
+        * If the feature is already enabled, ignore the request.
+        */
+       if (zap_contains(spa->spa_meta_objset, zapobj, feature->fi_guid) == 0)
+               return;
+
+       for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++)
+               spa_feature_enable(spa, feature->fi_depends[i], tx);
+
+       VERIFY0(zap_update(spa->spa_meta_objset, spa->spa_feat_desc_obj,
+           feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
+           feature->fi_desc, tx));
+
+       feature_sync(spa, feature, initial_refcount, tx);
+
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_ENABLED_TXG)) {
+               uint64_t enabling_txg = dmu_tx_get_txg(tx);
+
+               if (spa->spa_feat_enabled_txg_obj == 0ULL) {
+                       spa->spa_feat_enabled_txg_obj =
+                           zap_create_link(spa->spa_meta_objset,
+                           DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
+                           DMU_POOL_FEATURE_ENABLED_TXG, tx);
+               }
+               spa_feature_incr(spa, SPA_FEATURE_ENABLED_TXG, tx);
+
+               VERIFY0(zap_add(spa->spa_meta_objset,
+                   spa->spa_feat_enabled_txg_obj, feature->fi_guid,
+                   sizeof (uint64_t), 1, &enabling_txg, tx));
+       }
+}
+
+static void
+feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
+    dmu_tx_t *tx)
+{
+       uint64_t refcount = 0;
+       zfeature_info_t *feature = &spa_feature_table[fid];
+       ASSERTV(uint64_t zapobj = feature->fi_can_readonly ?
+           spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj);
+
+       ASSERT(VALID_FEATURE_FID(fid));
+       ASSERT(0 != zapobj);
+       ASSERT(zfeature_is_valid_guid(feature->fi_guid));
+
+       ASSERT(dmu_tx_is_syncing(tx));
+       ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
+
+       VERIFY3U(feature_get_refcount(spa, feature, &refcount), !=, ENOTSUP);
+
+       switch (action) {
+       case FEATURE_ACTION_INCR:
+               VERIFY3U(refcount, !=, UINT64_MAX);
+               refcount++;
+               break;
+       case FEATURE_ACTION_DECR:
+               VERIFY3U(refcount, !=, 0);
+               refcount--;
+               break;
+       default:
+               ASSERT(0);
+               break;
+       }
+
+       feature_sync(spa, feature, refcount, tx);
+}
+
+void
+spa_feature_create_zap_objects(spa_t *spa, dmu_tx_t *tx)
+{
+       /*
+        * We create feature flags ZAP objects in two instances: during pool
+        * creation and during pool upgrade.
+        */
+       ASSERT(dsl_pool_sync_context(spa_get_dsl(spa)) || (!spa->spa_sync_on &&
+           tx->tx_txg == TXG_INITIAL));
+
+       spa->spa_feat_for_read_obj = zap_create_link(spa->spa_meta_objset,
+           DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_FEATURES_FOR_READ, tx);
+       spa->spa_feat_for_write_obj = zap_create_link(spa->spa_meta_objset,
+           DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_FEATURES_FOR_WRITE, tx);
+       spa->spa_feat_desc_obj = zap_create_link(spa->spa_meta_objset,
+           DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_FEATURE_DESCRIPTIONS, tx);
+}
+
+/*
+ * Enable any required dependencies, then enable the requested feature.
+ */
+void
+spa_feature_enable(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
+{
+       ASSERT3U(spa_version(spa), >=, SPA_VERSION_FEATURES);
+       ASSERT(VALID_FEATURE_FID(fid));
+       feature_enable_sync(spa, &spa_feature_table[fid], tx);
+}
+
+void
+spa_feature_incr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
+{
+       feature_do_action(spa, fid, FEATURE_ACTION_INCR, tx);
+}
+
+void
+spa_feature_decr(spa_t *spa, spa_feature_t fid, dmu_tx_t *tx)
+{
+       feature_do_action(spa, fid, FEATURE_ACTION_DECR, tx);
+}
+
+boolean_t
+spa_feature_is_enabled(spa_t *spa, spa_feature_t fid)
+{
+       int err;
+       uint64_t refcount = 0;
+
+       ASSERT(VALID_FEATURE_FID(fid));
+       if (spa_version(spa) < SPA_VERSION_FEATURES)
+               return (B_FALSE);
+
+       err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
+       ASSERT(err == 0 || err == ENOTSUP);
+       return (err == 0);
+}
+
+boolean_t
+spa_feature_is_active(spa_t *spa, spa_feature_t fid)
+{
+       int err;
+       uint64_t refcount = 0;
+
+       ASSERT(VALID_FEATURE_FID(fid));
+       if (spa_version(spa) < SPA_VERSION_FEATURES)
+               return (B_FALSE);
+
+       err = feature_get_refcount(spa, &spa_feature_table[fid], &refcount);
+       ASSERT(err == 0 || err == ENOTSUP);
+       return (err == 0 && refcount > 0);
+}
+
+/*
+ * For the feature specified by fid (which must depend on
+ * SPA_FEATURE_ENABLED_TXG), return the TXG at which it was enabled in the
+ * OUT txg argument.
+ *
+ * Returns B_TRUE if the feature is enabled, in which case txg will be filled
+ * with the transaction group in which the specified feature was enabled.
+ * Returns B_FALSE otherwise (i.e. if the feature is not enabled).
+ */
+boolean_t
+spa_feature_enabled_txg(spa_t *spa, spa_feature_t fid, uint64_t *txg) {
+       int err;
+
+       ASSERT(VALID_FEATURE_FID(fid));
+       if (spa_version(spa) < SPA_VERSION_FEATURES)
+               return (B_FALSE);
+
+       err = feature_get_enabled_txg(spa, &spa_feature_table[fid], txg);
+       ASSERT(err == 0 || err == ENOTSUP);
+
+       return (err == 0);
+}
diff --git a/zfs/module/zfs/zfeature_common.c b/zfs/module/zfs/zfeature_common.c
new file mode 100644 (file)
index 0000000..609a72a
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <errno.h>
+#include <string.h>
+#endif
+#include <sys/debug.h>
+#include <sys/fs/zfs.h>
+#include <sys/inttypes.h>
+#include <sys/types.h>
+#include "zfeature_common.h"
+
+/*
+ * Set to disable all feature checks while opening pools, allowing pools with
+ * unsupported features to be opened. Set for testing only.
+ */
+boolean_t zfeature_checks_disable = B_FALSE;
+
+zfeature_info_t spa_feature_table[SPA_FEATURES];
+
+/*
+ * Valid characters for feature guids. This list is mainly for aesthetic
+ * purposes and could be expanded in the future. There are different allowed
+ * characters in the guids reverse dns portion (before the colon) and its
+ * short name (after the colon).
+ */
+static int
+valid_char(char c, boolean_t after_colon)
+{
+       return ((c >= 'a' && c <= 'z') ||
+           (c >= '0' && c <= '9') ||
+           (after_colon && c == '_') ||
+           (!after_colon && (c == '.' || c == '-')));
+}
+
+/*
+ * Every feature guid must contain exactly one colon which separates a reverse
+ * dns organization name from the feature's "short" name (e.g.
+ * "com.company:feature_name").
+ */
+boolean_t
+zfeature_is_valid_guid(const char *name)
+{
+       int i;
+       boolean_t has_colon = B_FALSE;
+
+       i = 0;
+       while (name[i] != '\0') {
+               char c = name[i++];
+               if (c == ':') {
+                       if (has_colon)
+                               return (B_FALSE);
+                       has_colon = B_TRUE;
+                       continue;
+               }
+               if (!valid_char(c, has_colon))
+                       return (B_FALSE);
+       }
+
+       return (has_colon);
+}
+
+boolean_t
+zfeature_is_supported(const char *guid)
+{
+       spa_feature_t i;
+
+       if (zfeature_checks_disable)
+               return (B_TRUE);
+
+       for (i = 0; i < SPA_FEATURES; i++) {
+               zfeature_info_t *feature = &spa_feature_table[i];
+               if (strcmp(guid, feature->fi_guid) == 0)
+                       return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+int
+zfeature_lookup_name(const char *name, spa_feature_t *res)
+{
+       spa_feature_t i;
+
+       for (i = 0; i < SPA_FEATURES; i++) {
+               zfeature_info_t *feature = &spa_feature_table[i];
+               if (strcmp(name, feature->fi_uname) == 0) {
+                       if (res != NULL)
+                               *res = i;
+                       return (0);
+               }
+       }
+
+       return (ENOENT);
+}
+
+boolean_t
+zfeature_depends_on(spa_feature_t fid, spa_feature_t check) {
+       zfeature_info_t *feature = &spa_feature_table[fid];
+       int i;
+
+       for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
+               if (feature->fi_depends[i] == check)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+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)
+{
+       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);
+       ASSERT3U(fid, <, SPA_FEATURES);
+       ASSERT(zfeature_is_valid_guid(guid));
+
+       if (deps == NULL)
+               deps = nodeps;
+
+       feature->fi_feature = fid;
+       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_depends = deps;
+}
+
+void
+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);
+
+       zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
+           "com.delphix:empty_bpobj", "empty_bpobj",
+           "Snapshots use less space.", B_TRUE, B_FALSE,
+           B_FALSE, NULL);
+
+       zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
+           "org.illumos:lz4_compress", "lz4_compress",
+           "LZ4 compression algorithm support.", B_FALSE, B_FALSE,
+           B_TRUE, NULL);
+
+       zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
+           "com.delphix:spacemap_histogram", "spacemap_histogram",
+           "Spacemaps maintain space histograms.", B_TRUE, B_FALSE,
+           B_FALSE, 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);
+
+       {
+       static const spa_feature_t hole_birth_deps[] = {
+               SPA_FEATURE_ENABLED_TXG,
+               SPA_FEATURE_NONE
+       };
+       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_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);
+
+       {
+       static const spa_feature_t bookmarks_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+
+       zfeature_register(SPA_FEATURE_BOOKMARKS,
+           "com.delphix:bookmarks", "bookmarks",
+           "\"zfs bookmark\" command",
+           B_TRUE, B_FALSE, B_FALSE, bookmarks_deps);
+       }
+
+       {
+       static const spa_feature_t filesystem_limits_deps[] = {
+           SPA_FEATURE_EXTENSIBLE_DATASET,
+           SPA_FEATURE_NONE
+       };
+       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);
+       }
+
+       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);
+
+       {
+       static const spa_feature_t large_blocks_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       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);
+       }
+}
diff --git a/zfs/module/zfs/zfs_acl.c b/zfs/module/zfs/zfs_acl.c
new file mode 100644 (file)
index 0000000..ea8c16e
--- /dev/null
@@ -0,0 +1,2817 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/resource.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/sid.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/unistd.h>
+#include <sys/sdt.h>
+#include <sys/fs/zfs.h>
+#include <sys/mode.h>
+#include <sys/policy.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_fuid.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_dir.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/dmu.h>
+#include <sys/dnode.h>
+#include <sys/zap.h>
+#include <sys/sa.h>
+#include <sys/trace_acl.h>
+#include "fs/fs_subr.h"
+
+#define        ALLOW   ACE_ACCESS_ALLOWED_ACE_TYPE
+#define        DENY    ACE_ACCESS_DENIED_ACE_TYPE
+#define        MAX_ACE_TYPE    ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
+#define        MIN_ACE_TYPE    ALLOW
+
+#define        OWNING_GROUP            (ACE_GROUP|ACE_IDENTIFIER_GROUP)
+#define        EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
+    ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
+#define        EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
+    ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
+#define        OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
+    ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
+
+#define        ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
+    ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
+    ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
+    ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
+
+#define        WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
+#define        WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \
+    ACE_DELETE|ACE_DELETE_CHILD)
+#define        WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS)
+
+#define        OGE_CLEAR       (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
+    ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
+
+#define        OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
+    ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
+
+#define        ALL_INHERIT     (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
+    ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
+
+#define        RESTRICTED_CLEAR        (ACE_WRITE_ACL|ACE_WRITE_OWNER)
+
+#define        V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
+    ZFS_ACL_PROTECTED)
+
+#define        ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
+    ZFS_ACL_OBJ_ACE)
+
+#define        ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH)
+
+static uint16_t
+zfs_ace_v0_get_type(void *acep)
+{
+       return (((zfs_oldace_t *)acep)->z_type);
+}
+
+static uint16_t
+zfs_ace_v0_get_flags(void *acep)
+{
+       return (((zfs_oldace_t *)acep)->z_flags);
+}
+
+static uint32_t
+zfs_ace_v0_get_mask(void *acep)
+{
+       return (((zfs_oldace_t *)acep)->z_access_mask);
+}
+
+static uint64_t
+zfs_ace_v0_get_who(void *acep)
+{
+       return (((zfs_oldace_t *)acep)->z_fuid);
+}
+
+static void
+zfs_ace_v0_set_type(void *acep, uint16_t type)
+{
+       ((zfs_oldace_t *)acep)->z_type = type;
+}
+
+static void
+zfs_ace_v0_set_flags(void *acep, uint16_t flags)
+{
+       ((zfs_oldace_t *)acep)->z_flags = flags;
+}
+
+static void
+zfs_ace_v0_set_mask(void *acep, uint32_t mask)
+{
+       ((zfs_oldace_t *)acep)->z_access_mask = mask;
+}
+
+static void
+zfs_ace_v0_set_who(void *acep, uint64_t who)
+{
+       ((zfs_oldace_t *)acep)->z_fuid = who;
+}
+
+/*ARGSUSED*/
+static size_t
+zfs_ace_v0_size(void *acep)
+{
+       return (sizeof (zfs_oldace_t));
+}
+
+static size_t
+zfs_ace_v0_abstract_size(void)
+{
+       return (sizeof (zfs_oldace_t));
+}
+
+static int
+zfs_ace_v0_mask_off(void)
+{
+       return (offsetof(zfs_oldace_t, z_access_mask));
+}
+
+/*ARGSUSED*/
+static int
+zfs_ace_v0_data(void *acep, void **datap)
+{
+       *datap = NULL;
+       return (0);
+}
+
+static acl_ops_t zfs_acl_v0_ops = {
+       zfs_ace_v0_get_mask,
+       zfs_ace_v0_set_mask,
+       zfs_ace_v0_get_flags,
+       zfs_ace_v0_set_flags,
+       zfs_ace_v0_get_type,
+       zfs_ace_v0_set_type,
+       zfs_ace_v0_get_who,
+       zfs_ace_v0_set_who,
+       zfs_ace_v0_size,
+       zfs_ace_v0_abstract_size,
+       zfs_ace_v0_mask_off,
+       zfs_ace_v0_data
+};
+
+static uint16_t
+zfs_ace_fuid_get_type(void *acep)
+{
+       return (((zfs_ace_hdr_t *)acep)->z_type);
+}
+
+static uint16_t
+zfs_ace_fuid_get_flags(void *acep)
+{
+       return (((zfs_ace_hdr_t *)acep)->z_flags);
+}
+
+static uint32_t
+zfs_ace_fuid_get_mask(void *acep)
+{
+       return (((zfs_ace_hdr_t *)acep)->z_access_mask);
+}
+
+static uint64_t
+zfs_ace_fuid_get_who(void *args)
+{
+       uint16_t entry_type;
+       zfs_ace_t *acep = args;
+
+       entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+
+       if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
+           entry_type == ACE_EVERYONE)
+               return (-1);
+       return (((zfs_ace_t *)acep)->z_fuid);
+}
+
+static void
+zfs_ace_fuid_set_type(void *acep, uint16_t type)
+{
+       ((zfs_ace_hdr_t *)acep)->z_type = type;
+}
+
+static void
+zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
+{
+       ((zfs_ace_hdr_t *)acep)->z_flags = flags;
+}
+
+static void
+zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
+{
+       ((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
+}
+
+static void
+zfs_ace_fuid_set_who(void *arg, uint64_t who)
+{
+       zfs_ace_t *acep = arg;
+
+       uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+
+       if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
+           entry_type == ACE_EVERYONE)
+               return;
+       acep->z_fuid = who;
+}
+
+static size_t
+zfs_ace_fuid_size(void *acep)
+{
+       zfs_ace_hdr_t *zacep = acep;
+       uint16_t entry_type;
+
+       switch (zacep->z_type) {
+       case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+       case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+       case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+       case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+               return (sizeof (zfs_object_ace_t));
+       case ALLOW:
+       case DENY:
+               entry_type =
+                   (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
+               if (entry_type == ACE_OWNER ||
+                   entry_type == OWNING_GROUP ||
+                   entry_type == ACE_EVERYONE)
+                       return (sizeof (zfs_ace_hdr_t));
+               /*FALLTHROUGH*/
+       default:
+               return (sizeof (zfs_ace_t));
+       }
+}
+
+static size_t
+zfs_ace_fuid_abstract_size(void)
+{
+       return (sizeof (zfs_ace_hdr_t));
+}
+
+static int
+zfs_ace_fuid_mask_off(void)
+{
+       return (offsetof(zfs_ace_hdr_t, z_access_mask));
+}
+
+static int
+zfs_ace_fuid_data(void *acep, void **datap)
+{
+       zfs_ace_t *zacep = acep;
+       zfs_object_ace_t *zobjp;
+
+       switch (zacep->z_hdr.z_type) {
+       case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+       case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+       case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+       case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+               zobjp = acep;
+               *datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
+               return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
+       default:
+               *datap = NULL;
+               return (0);
+       }
+}
+
+static acl_ops_t zfs_acl_fuid_ops = {
+       zfs_ace_fuid_get_mask,
+       zfs_ace_fuid_set_mask,
+       zfs_ace_fuid_get_flags,
+       zfs_ace_fuid_set_flags,
+       zfs_ace_fuid_get_type,
+       zfs_ace_fuid_set_type,
+       zfs_ace_fuid_get_who,
+       zfs_ace_fuid_set_who,
+       zfs_ace_fuid_size,
+       zfs_ace_fuid_abstract_size,
+       zfs_ace_fuid_mask_off,
+       zfs_ace_fuid_data
+};
+
+/*
+ * The following three functions are provided for compatibility with
+ * older ZPL version in order to determine if the file use to have
+ * an external ACL and what version of ACL previously existed on the
+ * file.  Would really be nice to not need this, sigh.
+ */
+uint64_t
+zfs_external_acl(znode_t *zp)
+{
+       zfs_acl_phys_t acl_phys;
+       int error;
+
+       if (zp->z_is_sa)
+               return (0);
+
+       /*
+        * Need to deal with a potential
+        * race where zfs_sa_upgrade could cause
+        * z_isa_sa to change.
+        *
+        * If the lookup fails then the state of z_is_sa should have
+        * changed.
+        */
+
+       if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(ZTOZSB(zp)),
+           &acl_phys, sizeof (acl_phys))) == 0)
+               return (acl_phys.z_acl_extern_obj);
+       else {
+               /*
+                * after upgrade the SA_ZPL_ZNODE_ACL should have been
+                * removed
+                */
+               VERIFY(zp->z_is_sa && error == ENOENT);
+               return (0);
+       }
+}
+
+/*
+ * Determine size of ACL in bytes
+ *
+ * This is more complicated than it should be since we have to deal
+ * with old external ACLs.
+ */
+static int
+zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount,
+    zfs_acl_phys_t *aclphys)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       uint64_t acl_count;
+       int size;
+       int error;
+
+       ASSERT(MUTEX_HELD(&zp->z_acl_lock));
+       if (zp->z_is_sa) {
+               if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zsb),
+                   &size)) != 0)
+                       return (error);
+               *aclsize = size;
+               if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zsb),
+                   &acl_count, sizeof (acl_count))) != 0)
+                       return (error);
+               *aclcount = acl_count;
+       } else {
+               if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zsb),
+                   aclphys, sizeof (*aclphys))) != 0)
+                       return (error);
+
+               if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) {
+                       *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size);
+                       *aclcount = aclphys->z_acl_size;
+               } else {
+                       *aclsize = aclphys->z_acl_size;
+                       *aclcount = aclphys->z_acl_count;
+               }
+       }
+       return (0);
+}
+
+int
+zfs_znode_acl_version(znode_t *zp)
+{
+       zfs_acl_phys_t acl_phys;
+
+       if (zp->z_is_sa)
+               return (ZFS_ACL_VERSION_FUID);
+       else {
+               int error;
+
+               /*
+                * Need to deal with a potential
+                * race where zfs_sa_upgrade could cause
+                * z_isa_sa to change.
+                *
+                * If the lookup fails then the state of z_is_sa should have
+                * changed.
+                */
+               if ((error = sa_lookup(zp->z_sa_hdl,
+                   SA_ZPL_ZNODE_ACL(ZTOZSB(zp)),
+                   &acl_phys, sizeof (acl_phys))) == 0)
+                       return (acl_phys.z_acl_version);
+               else {
+                       /*
+                        * After upgrade SA_ZPL_ZNODE_ACL should have
+                        * been removed.
+                        */
+                       VERIFY(zp->z_is_sa && error == ENOENT);
+                       return (ZFS_ACL_VERSION_FUID);
+               }
+       }
+}
+
+static int
+zfs_acl_version(int version)
+{
+       if (version < ZPL_VERSION_FUID)
+               return (ZFS_ACL_VERSION_INITIAL);
+       else
+               return (ZFS_ACL_VERSION_FUID);
+}
+
+static int
+zfs_acl_version_zp(znode_t *zp)
+{
+       return (zfs_acl_version(ZTOZSB(zp)->z_version));
+}
+
+zfs_acl_t *
+zfs_acl_alloc(int vers)
+{
+       zfs_acl_t *aclp;
+
+       aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
+       list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
+           offsetof(zfs_acl_node_t, z_next));
+       aclp->z_version = vers;
+       if (vers == ZFS_ACL_VERSION_FUID)
+               aclp->z_ops = &zfs_acl_fuid_ops;
+       else
+               aclp->z_ops = &zfs_acl_v0_ops;
+       return (aclp);
+}
+
+zfs_acl_node_t *
+zfs_acl_node_alloc(size_t bytes)
+{
+       zfs_acl_node_t *aclnode;
+
+       aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
+       if (bytes) {
+               aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
+               aclnode->z_allocdata = aclnode->z_acldata;
+               aclnode->z_allocsize = bytes;
+               aclnode->z_size = bytes;
+       }
+
+       return (aclnode);
+}
+
+static void
+zfs_acl_node_free(zfs_acl_node_t *aclnode)
+{
+       if (aclnode->z_allocsize)
+               kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
+       kmem_free(aclnode, sizeof (zfs_acl_node_t));
+}
+
+static void
+zfs_acl_release_nodes(zfs_acl_t *aclp)
+{
+       zfs_acl_node_t *aclnode;
+
+       while ((aclnode = list_head(&aclp->z_acl))) {
+               list_remove(&aclp->z_acl, aclnode);
+               zfs_acl_node_free(aclnode);
+       }
+       aclp->z_acl_count = 0;
+       aclp->z_acl_bytes = 0;
+}
+
+void
+zfs_acl_free(zfs_acl_t *aclp)
+{
+       zfs_acl_release_nodes(aclp);
+       list_destroy(&aclp->z_acl);
+       kmem_free(aclp, sizeof (zfs_acl_t));
+}
+
+static boolean_t
+zfs_acl_valid_ace_type(uint_t type, uint_t flags)
+{
+       uint16_t entry_type;
+
+       switch (type) {
+       case ALLOW:
+       case DENY:
+       case ACE_SYSTEM_AUDIT_ACE_TYPE:
+       case ACE_SYSTEM_ALARM_ACE_TYPE:
+               entry_type = flags & ACE_TYPE_FLAGS;
+               return (entry_type == ACE_OWNER ||
+                   entry_type == OWNING_GROUP ||
+                   entry_type == ACE_EVERYONE || entry_type == 0 ||
+                   entry_type == ACE_IDENTIFIER_GROUP);
+       default:
+               if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+static boolean_t
+zfs_ace_valid(umode_t obj_mode, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
+{
+       /*
+        * first check type of entry
+        */
+
+       if (!zfs_acl_valid_ace_type(type, iflags))
+               return (B_FALSE);
+
+       switch (type) {
+       case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+       case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+       case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+       case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+               if (aclp->z_version < ZFS_ACL_VERSION_FUID)
+                       return (B_FALSE);
+               aclp->z_hints |= ZFS_ACL_OBJ_ACE;
+       }
+
+       /*
+        * next check inheritance level flags
+        */
+
+       if (S_ISDIR(obj_mode) &&
+           (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
+               aclp->z_hints |= ZFS_INHERIT_ACE;
+
+       if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
+               if ((iflags & (ACE_FILE_INHERIT_ACE|
+                   ACE_DIRECTORY_INHERIT_ACE)) == 0) {
+                       return (B_FALSE);
+               }
+       }
+
+       return (B_TRUE);
+}
+
+static void *
+zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
+    uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
+{
+       zfs_acl_node_t *aclnode;
+
+       ASSERT(aclp);
+
+       if (start == NULL) {
+               aclnode = list_head(&aclp->z_acl);
+               if (aclnode == NULL)
+                       return (NULL);
+
+               aclp->z_next_ace = aclnode->z_acldata;
+               aclp->z_curr_node = aclnode;
+               aclnode->z_ace_idx = 0;
+       }
+
+       aclnode = aclp->z_curr_node;
+
+       if (aclnode == NULL)
+               return (NULL);
+
+       if (aclnode->z_ace_idx >= aclnode->z_ace_count) {
+               aclnode = list_next(&aclp->z_acl, aclnode);
+               if (aclnode == NULL)
+                       return (NULL);
+               else {
+                       aclp->z_curr_node = aclnode;
+                       aclnode->z_ace_idx = 0;
+                       aclp->z_next_ace = aclnode->z_acldata;
+               }
+       }
+
+       if (aclnode->z_ace_idx < aclnode->z_ace_count) {
+               void *acep = aclp->z_next_ace;
+               size_t ace_size;
+
+               /*
+                * Make sure we don't overstep our bounds
+                */
+               ace_size = aclp->z_ops->ace_size(acep);
+
+               if (((caddr_t)acep + ace_size) >
+                   ((caddr_t)aclnode->z_acldata + aclnode->z_size)) {
+                       return (NULL);
+               }
+
+               *iflags = aclp->z_ops->ace_flags_get(acep);
+               *type = aclp->z_ops->ace_type_get(acep);
+               *access_mask = aclp->z_ops->ace_mask_get(acep);
+               *who = aclp->z_ops->ace_who_get(acep);
+               aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size;
+               aclnode->z_ace_idx++;
+
+               return ((void *)acep);
+       }
+       return (NULL);
+}
+
+/*ARGSUSED*/
+static uint64_t
+zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
+    uint16_t *flags, uint16_t *type, uint32_t *mask)
+{
+       zfs_acl_t *aclp = datap;
+       zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
+       uint64_t who;
+
+       acep = zfs_acl_next_ace(aclp, acep, &who, mask,
+           flags, type);
+       return ((uint64_t)(uintptr_t)acep);
+}
+
+/*
+ * Copy ACE to internal ZFS format.
+ * While processing the ACL each ACE will be validated for correctness.
+ * ACE FUIDs will be created later.
+ */
+int
+zfs_copy_ace_2_fuid(zfs_sb_t *zsb, umode_t obj_mode, zfs_acl_t *aclp,
+    void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size,
+    zfs_fuid_info_t **fuidp, cred_t *cr)
+{
+       int i;
+       uint16_t entry_type;
+       zfs_ace_t *aceptr = z_acl;
+       ace_t *acep = datap;
+       zfs_object_ace_t *zobjacep;
+       ace_object_t *aceobjp;
+
+       for (i = 0; i != aclcnt; i++) {
+               aceptr->z_hdr.z_access_mask = acep->a_access_mask;
+               aceptr->z_hdr.z_flags = acep->a_flags;
+               aceptr->z_hdr.z_type = acep->a_type;
+               entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
+               if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
+                   entry_type != ACE_EVERYONE) {
+                       aceptr->z_fuid = zfs_fuid_create(zsb, acep->a_who,
+                           cr, (entry_type == 0) ?
+                           ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp);
+               }
+
+               /*
+                * Make sure ACE is valid
+                */
+               if (zfs_ace_valid(obj_mode, aclp, aceptr->z_hdr.z_type,
+                   aceptr->z_hdr.z_flags) != B_TRUE)
+                       return (SET_ERROR(EINVAL));
+
+               switch (acep->a_type) {
+               case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+               case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+               case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+               case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+                       zobjacep = (zfs_object_ace_t *)aceptr;
+                       aceobjp = (ace_object_t *)acep;
+
+                       bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
+                           sizeof (aceobjp->a_obj_type));
+                       bcopy(aceobjp->a_inherit_obj_type,
+                           zobjacep->z_inherit_type,
+                           sizeof (aceobjp->a_inherit_obj_type));
+                       acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
+                       break;
+               default:
+                       acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
+               }
+
+               aceptr = (zfs_ace_t *)((caddr_t)aceptr +
+                   aclp->z_ops->ace_size(aceptr));
+       }
+
+       *size = (caddr_t)aceptr - (caddr_t)z_acl;
+
+       return (0);
+}
+
+/*
+ * Copy ZFS ACEs to fixed size ace_t layout
+ */
+static void
+zfs_copy_fuid_2_ace(zfs_sb_t *zsb, zfs_acl_t *aclp, cred_t *cr,
+    void *datap, int filter)
+{
+       uint64_t who;
+       uint32_t access_mask;
+       uint16_t iflags, type;
+       zfs_ace_hdr_t *zacep = NULL;
+       ace_t *acep = datap;
+       ace_object_t *objacep;
+       zfs_object_ace_t *zobjacep;
+       size_t ace_size;
+       uint16_t entry_type;
+
+       while ((zacep = zfs_acl_next_ace(aclp, zacep,
+           &who, &access_mask, &iflags, &type))) {
+
+               switch (type) {
+               case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+               case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+               case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+               case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+                       if (filter) {
+                               continue;
+                       }
+                       zobjacep = (zfs_object_ace_t *)zacep;
+                       objacep = (ace_object_t *)acep;
+                       bcopy(zobjacep->z_object_type,
+                           objacep->a_obj_type,
+                           sizeof (zobjacep->z_object_type));
+                       bcopy(zobjacep->z_inherit_type,
+                           objacep->a_inherit_obj_type,
+                           sizeof (zobjacep->z_inherit_type));
+                       ace_size = sizeof (ace_object_t);
+                       break;
+               default:
+                       ace_size = sizeof (ace_t);
+                       break;
+               }
+
+               entry_type = (iflags & ACE_TYPE_FLAGS);
+               if ((entry_type != ACE_OWNER &&
+                   entry_type != OWNING_GROUP &&
+                   entry_type != ACE_EVERYONE)) {
+                       acep->a_who = zfs_fuid_map_id(zsb, who,
+                           cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
+                           ZFS_ACE_GROUP : ZFS_ACE_USER);
+               } else {
+                       acep->a_who = (uid_t)(int64_t)who;
+               }
+               acep->a_access_mask = access_mask;
+               acep->a_flags = iflags;
+               acep->a_type = type;
+               acep = (ace_t *)((caddr_t)acep + ace_size);
+       }
+}
+
+static int
+zfs_copy_ace_2_oldace(umode_t obj_mode, zfs_acl_t *aclp, ace_t *acep,
+    zfs_oldace_t *z_acl, int aclcnt, size_t *size)
+{
+       int i;
+       zfs_oldace_t *aceptr = z_acl;
+
+       for (i = 0; i != aclcnt; i++, aceptr++) {
+               aceptr->z_access_mask = acep[i].a_access_mask;
+               aceptr->z_type = acep[i].a_type;
+               aceptr->z_flags = acep[i].a_flags;
+               aceptr->z_fuid = acep[i].a_who;
+               /*
+                * Make sure ACE is valid
+                */
+               if (zfs_ace_valid(obj_mode, aclp, aceptr->z_type,
+                   aceptr->z_flags) != B_TRUE)
+                       return (SET_ERROR(EINVAL));
+       }
+       *size = (caddr_t)aceptr - (caddr_t)z_acl;
+       return (0);
+}
+
+/*
+ * convert old ACL format to new
+ */
+void
+zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
+{
+       zfs_oldace_t *oldaclp;
+       int i;
+       uint16_t type, iflags;
+       uint32_t access_mask;
+       uint64_t who;
+       void *cookie = NULL;
+       zfs_acl_node_t *newaclnode;
+
+       ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
+       /*
+        * First create the ACE in a contiguous piece of memory
+        * for zfs_copy_ace_2_fuid().
+        *
+        * We only convert an ACL once, so this won't happen
+        * everytime.
+        */
+       oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
+           KM_SLEEP);
+       i = 0;
+       while ((cookie = zfs_acl_next_ace(aclp, cookie, &who,
+           &access_mask, &iflags, &type))) {
+               oldaclp[i].z_flags = iflags;
+               oldaclp[i].z_type = type;
+               oldaclp[i].z_fuid = who;
+               oldaclp[i++].z_access_mask = access_mask;
+       }
+
+       newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
+           sizeof (zfs_object_ace_t));
+       aclp->z_ops = &zfs_acl_fuid_ops;
+       VERIFY(zfs_copy_ace_2_fuid(ZTOZSB(zp), ZTOI(zp)->i_mode,
+           aclp, oldaclp, newaclnode->z_acldata, aclp->z_acl_count,
+           &newaclnode->z_size, NULL, cr) == 0);
+       newaclnode->z_ace_count = aclp->z_acl_count;
+       aclp->z_version = ZFS_ACL_VERSION;
+       kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
+
+       /*
+        * Release all previous ACL nodes
+        */
+
+       zfs_acl_release_nodes(aclp);
+
+       list_insert_head(&aclp->z_acl, newaclnode);
+
+       aclp->z_acl_bytes = newaclnode->z_size;
+       aclp->z_acl_count = newaclnode->z_ace_count;
+
+}
+
+/*
+ * Convert unix access mask to v4 access mask
+ */
+static uint32_t
+zfs_unix_to_v4(uint32_t access_mask)
+{
+       uint32_t new_mask = 0;
+
+       if (access_mask & S_IXOTH)
+               new_mask |= ACE_EXECUTE;
+       if (access_mask & S_IWOTH)
+               new_mask |= ACE_WRITE_DATA;
+       if (access_mask & S_IROTH)
+               new_mask |= ACE_READ_DATA;
+       return (new_mask);
+}
+
+static void
+zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
+    uint16_t access_type, uint64_t fuid, uint16_t entry_type)
+{
+       uint16_t type = entry_type & ACE_TYPE_FLAGS;
+
+       aclp->z_ops->ace_mask_set(acep, access_mask);
+       aclp->z_ops->ace_type_set(acep, access_type);
+       aclp->z_ops->ace_flags_set(acep, entry_type);
+       if ((type != ACE_OWNER && type != OWNING_GROUP &&
+           type != ACE_EVERYONE))
+               aclp->z_ops->ace_who_set(acep, fuid);
+}
+
+/*
+ * Determine mode of file based on ACL.
+ * Also, create FUIDs for any User/Group ACEs
+ */
+uint64_t
+zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
+    uint64_t *pflags, uint64_t fuid, uint64_t fgid)
+{
+       int             entry_type;
+       mode_t          mode;
+       mode_t          seen = 0;
+       zfs_ace_hdr_t   *acep = NULL;
+       uint64_t        who;
+       uint16_t        iflags, type;
+       uint32_t        access_mask;
+       boolean_t       an_exec_denied = B_FALSE;
+
+       mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
+
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who,
+           &access_mask, &iflags, &type))) {
+
+               if (!zfs_acl_valid_ace_type(type, iflags))
+                       continue;
+
+               entry_type = (iflags & ACE_TYPE_FLAGS);
+
+               /*
+                * Skip over owner@, group@ or everyone@ inherit only ACEs
+                */
+               if ((iflags & ACE_INHERIT_ONLY_ACE) &&
+                   (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
+                   entry_type == OWNING_GROUP))
+                       continue;
+
+               if (entry_type == ACE_OWNER || (entry_type == 0 &&
+                   who == fuid)) {
+                       if ((access_mask & ACE_READ_DATA) &&
+                           (!(seen & S_IRUSR))) {
+                               seen |= S_IRUSR;
+                               if (type == ALLOW) {
+                                       mode |= S_IRUSR;
+                               }
+                       }
+                       if ((access_mask & ACE_WRITE_DATA) &&
+                           (!(seen & S_IWUSR))) {
+                               seen |= S_IWUSR;
+                               if (type == ALLOW) {
+                                       mode |= S_IWUSR;
+                               }
+                       }
+                       if ((access_mask & ACE_EXECUTE) &&
+                           (!(seen & S_IXUSR))) {
+                               seen |= S_IXUSR;
+                               if (type == ALLOW) {
+                                       mode |= S_IXUSR;
+                               }
+                       }
+               } else if (entry_type == OWNING_GROUP ||
+                   (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) {
+                       if ((access_mask & ACE_READ_DATA) &&
+                           (!(seen & S_IRGRP))) {
+                               seen |= S_IRGRP;
+                               if (type == ALLOW) {
+                                       mode |= S_IRGRP;
+                               }
+                       }
+                       if ((access_mask & ACE_WRITE_DATA) &&
+                           (!(seen & S_IWGRP))) {
+                               seen |= S_IWGRP;
+                               if (type == ALLOW) {
+                                       mode |= S_IWGRP;
+                               }
+                       }
+                       if ((access_mask & ACE_EXECUTE) &&
+                           (!(seen & S_IXGRP))) {
+                               seen |= S_IXGRP;
+                               if (type == ALLOW) {
+                                       mode |= S_IXGRP;
+                               }
+                       }
+               } else if (entry_type == ACE_EVERYONE) {
+                       if ((access_mask & ACE_READ_DATA)) {
+                               if (!(seen & S_IRUSR)) {
+                                       seen |= S_IRUSR;
+                                       if (type == ALLOW) {
+                                               mode |= S_IRUSR;
+                                       }
+                               }
+                               if (!(seen & S_IRGRP)) {
+                                       seen |= S_IRGRP;
+                                       if (type == ALLOW) {
+                                               mode |= S_IRGRP;
+                                       }
+                               }
+                               if (!(seen & S_IROTH)) {
+                                       seen |= S_IROTH;
+                                       if (type == ALLOW) {
+                                               mode |= S_IROTH;
+                                       }
+                               }
+                       }
+                       if ((access_mask & ACE_WRITE_DATA)) {
+                               if (!(seen & S_IWUSR)) {
+                                       seen |= S_IWUSR;
+                                       if (type == ALLOW) {
+                                               mode |= S_IWUSR;
+                                       }
+                               }
+                               if (!(seen & S_IWGRP)) {
+                                       seen |= S_IWGRP;
+                                       if (type == ALLOW) {
+                                               mode |= S_IWGRP;
+                                       }
+                               }
+                               if (!(seen & S_IWOTH)) {
+                                       seen |= S_IWOTH;
+                                       if (type == ALLOW) {
+                                               mode |= S_IWOTH;
+                                       }
+                               }
+                       }
+                       if ((access_mask & ACE_EXECUTE)) {
+                               if (!(seen & S_IXUSR)) {
+                                       seen |= S_IXUSR;
+                                       if (type == ALLOW) {
+                                               mode |= S_IXUSR;
+                                       }
+                               }
+                               if (!(seen & S_IXGRP)) {
+                                       seen |= S_IXGRP;
+                                       if (type == ALLOW) {
+                                               mode |= S_IXGRP;
+                                       }
+                               }
+                               if (!(seen & S_IXOTH)) {
+                                       seen |= S_IXOTH;
+                                       if (type == ALLOW) {
+                                               mode |= S_IXOTH;
+                                       }
+                               }
+                       }
+               } else {
+                       /*
+                        * Only care if this IDENTIFIER_GROUP or
+                        * USER ACE denies execute access to someone,
+                        * mode is not affected
+                        */
+                       if ((access_mask & ACE_EXECUTE) && type == DENY)
+                               an_exec_denied = B_TRUE;
+               }
+       }
+
+       /*
+        * Failure to allow is effectively a deny, so execute permission
+        * is denied if it was never mentioned or if we explicitly
+        * weren't allowed it.
+        */
+       if (!an_exec_denied &&
+           ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS ||
+           (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS))
+               an_exec_denied = B_TRUE;
+
+       if (an_exec_denied)
+               *pflags &= ~ZFS_NO_EXECS_DENIED;
+       else
+               *pflags |= ZFS_NO_EXECS_DENIED;
+
+       return (mode);
+}
+
+/*
+ * Read an external acl object.  If the intent is to modify, always
+ * create a new acl and leave any cached acl in place.
+ */
+static int
+zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp,
+    boolean_t will_modify)
+{
+       zfs_acl_t       *aclp;
+       int             aclsize = 0;
+       int             acl_count = 0;
+       zfs_acl_node_t  *aclnode;
+       zfs_acl_phys_t  znode_acl;
+       int             version;
+       int             error;
+       boolean_t       drop_lock = B_FALSE;
+
+       ASSERT(MUTEX_HELD(&zp->z_acl_lock));
+
+       if (zp->z_acl_cached && !will_modify) {
+               *aclpp = zp->z_acl_cached;
+               return (0);
+       }
+
+       /*
+        * close race where znode could be upgrade while trying to
+        * read the znode attributes.
+        *
+        * But this could only happen if the file isn't already an SA
+        * znode
+        */
+       if (!zp->z_is_sa && !have_lock) {
+               mutex_enter(&zp->z_lock);
+               drop_lock = B_TRUE;
+       }
+       version = zfs_znode_acl_version(zp);
+
+       if ((error = zfs_acl_znode_info(zp, &aclsize,
+           &acl_count, &znode_acl)) != 0) {
+               goto done;
+       }
+
+       aclp = zfs_acl_alloc(version);
+
+       aclp->z_acl_count = acl_count;
+       aclp->z_acl_bytes = aclsize;
+
+       aclnode = zfs_acl_node_alloc(aclsize);
+       aclnode->z_ace_count = aclp->z_acl_count;
+       aclnode->z_size = aclsize;
+
+       if (!zp->z_is_sa) {
+               if (znode_acl.z_acl_extern_obj) {
+                       error = dmu_read(ZTOZSB(zp)->z_os,
+                           znode_acl.z_acl_extern_obj, 0, aclnode->z_size,
+                           aclnode->z_acldata, DMU_READ_PREFETCH);
+               } else {
+                       bcopy(znode_acl.z_ace_data, aclnode->z_acldata,
+                           aclnode->z_size);
+               }
+       } else {
+               error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(ZTOZSB(zp)),
+                   aclnode->z_acldata, aclnode->z_size);
+       }
+
+       if (error != 0) {
+               zfs_acl_free(aclp);
+               zfs_acl_node_free(aclnode);
+               /* convert checksum errors into IO errors */
+               if (error == ECKSUM)
+                       error = SET_ERROR(EIO);
+               goto done;
+       }
+
+       list_insert_head(&aclp->z_acl, aclnode);
+
+       *aclpp = aclp;
+       if (!will_modify)
+               zp->z_acl_cached = aclp;
+done:
+       if (drop_lock)
+               mutex_exit(&zp->z_lock);
+       return (error);
+}
+
+/*ARGSUSED*/
+void
+zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
+    boolean_t start, void *userdata)
+{
+       zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
+
+       if (start) {
+               cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl);
+       } else {
+               cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl,
+                   cb->cb_acl_node);
+       }
+       *dataptr = cb->cb_acl_node->z_acldata;
+       *length = cb->cb_acl_node->z_size;
+}
+
+int
+zfs_acl_chown_setattr(znode_t *zp)
+{
+       int error;
+       zfs_acl_t *aclp;
+
+       if (ZTOZSB(zp)->z_acl_type == ZFS_ACLTYPE_POSIXACL)
+               return (0);
+
+       ASSERT(MUTEX_HELD(&zp->z_lock));
+       ASSERT(MUTEX_HELD(&zp->z_acl_lock));
+
+       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);
+
+       /*
+        * Some ZFS implementations (ZEVO) create neither a ZNODE_ACL
+        * nor a DACL_ACES SA in which case ENOENT is returned from
+        * zfs_acl_node_read() when the SA can't be located.
+        * Allow chown/chgrp to succeed in these cases rather than
+        * returning an error that makes no sense in the context of
+        * the caller.
+        */
+       if (error == ENOENT)
+               return (0);
+
+       return (error);
+}
+
+static void
+acl_trivial_access_masks(mode_t mode, uint32_t *allow0, uint32_t *deny1,
+    uint32_t *deny2, uint32_t *owner, uint32_t *group, uint32_t *everyone)
+{
+       *deny1 = *deny2 = *allow0 = *group = 0;
+
+       if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
+               *deny1 |= ACE_READ_DATA;
+       if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
+               *deny1 |= ACE_WRITE_DATA;
+       if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
+               *deny1 |= ACE_EXECUTE;
+
+       if (!(mode & S_IRGRP) && (mode & S_IROTH))
+               *deny2 = ACE_READ_DATA;
+       if (!(mode & S_IWGRP) && (mode & S_IWOTH))
+               *deny2 |= ACE_WRITE_DATA;
+       if (!(mode & S_IXGRP) && (mode & S_IXOTH))
+               *deny2 |= ACE_EXECUTE;
+
+       if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
+               *allow0 |= ACE_READ_DATA;
+       if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
+               *allow0 |= ACE_WRITE_DATA;
+       if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
+               *allow0 |= ACE_EXECUTE;
+
+       *owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
+           ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
+           ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE;
+       if (mode & S_IRUSR)
+               *owner |= ACE_READ_DATA;
+       if (mode & S_IWUSR)
+               *owner |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXUSR)
+               *owner |= ACE_EXECUTE;
+
+       *group = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
+           ACE_SYNCHRONIZE;
+       if (mode & S_IRGRP)
+               *group |= ACE_READ_DATA;
+       if (mode & S_IWGRP)
+               *group |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXGRP)
+               *group |= ACE_EXECUTE;
+
+       *everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
+           ACE_SYNCHRONIZE;
+       if (mode & S_IROTH)
+               *everyone |= ACE_READ_DATA;
+       if (mode & S_IWOTH)
+               *everyone |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXOTH)
+               *everyone |= ACE_EXECUTE;
+}
+
+/*
+ * ace_trivial:
+ * determine whether an ace_t acl is trivial
+ *
+ * Trivialness implies that the acl is composed of only
+ * owner, group, everyone entries.  ACL can't
+ * have read_acl denied, and write_owner/write_acl/write_attributes
+ * can only be owner@ entry.
+ */
+static int
+ace_trivial_common(void *acep, int aclcnt,
+    uint64_t (*walk)(void *, uint64_t, int aclcnt,
+    uint16_t *, uint16_t *, uint32_t *))
+{
+       uint16_t flags;
+       uint32_t mask;
+       uint16_t type;
+       uint64_t cookie = 0;
+
+       while ((cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask))) {
+               switch (flags & ACE_TYPE_FLAGS) {
+               case ACE_OWNER:
+               case ACE_GROUP|ACE_IDENTIFIER_GROUP:
+               case ACE_EVERYONE:
+                       break;
+               default:
+                       return (1);
+               }
+
+               if (flags & (ACE_FILE_INHERIT_ACE|
+                   ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
+                   ACE_INHERIT_ONLY_ACE))
+                       return (1);
+
+               /*
+                * Special check for some special bits
+                *
+                * Don't allow anybody to deny reading basic
+                * attributes or a files ACL.
+                */
+               if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
+                   (type == ACE_ACCESS_DENIED_ACE_TYPE))
+                       return (1);
+
+               /*
+                * Delete permissions are never set by default
+                */
+               if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
+                       return (1);
+               /*
+                * only allow owner@ to have
+                * write_acl/write_owner/write_attributes/write_xattr/
+                */
+               if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
+                   (!(flags & ACE_OWNER) && (mask &
+                   (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
+                   ACE_WRITE_NAMED_ATTRS))))
+                       return (1);
+
+       }
+
+       return (0);
+}
+
+/*
+ * common code for setting ACLs.
+ *
+ * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
+ * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
+ * already checked the acl and knows whether to inherit.
+ */
+int
+zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
+{
+       int                     error;
+       zfs_sb_t                *zsb = ZTOZSB(zp);
+       dmu_object_type_t       otype;
+       zfs_acl_locator_cb_t    locate = { 0 };
+       uint64_t                mode;
+       sa_bulk_attr_t          bulk[5];
+       uint64_t                ctime[2];
+       int                     count = 0;
+
+       mode = zp->z_mode;
+
+       mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
+           zp->z_uid, zp->z_gid);
+
+       zp->z_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,
+           &zp->z_pflags, sizeof (zp->z_pflags));
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
+           &ctime, sizeof (ctime));
+
+       if (zp->z_acl_cached) {
+               zfs_acl_free(zp->z_acl_cached);
+               zp->z_acl_cached = NULL;
+       }
+
+       /*
+        * Upgrade needed?
+        */
+       if (!zsb->z_use_fuids) {
+               otype = DMU_OT_OLDACL;
+       } else {
+               if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
+                   (zsb->z_version >= ZPL_VERSION_FUID))
+                       zfs_acl_xform(zp, aclp, cr);
+               ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
+               otype = DMU_OT_ACL;
+       }
+
+       /*
+        * Arrgh, we have to handle old on disk format
+        * as well as newer (preferred) SA format.
+        */
+
+       if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */
+               locate.cb_aclp = aclp;
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zsb),
+                   zfs_acl_data_locator, &locate, aclp->z_acl_bytes);
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zsb),
+                   NULL, &aclp->z_acl_count, sizeof (uint64_t));
+       } else { /* Painful legacy way */
+               zfs_acl_node_t *aclnode;
+               uint64_t off = 0;
+               zfs_acl_phys_t acl_phys;
+               uint64_t aoid;
+
+               if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zsb),
+                   &acl_phys, sizeof (acl_phys))) != 0)
+                       return (error);
+
+               aoid = acl_phys.z_acl_extern_obj;
+
+               if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+                       /*
+                        * If ACL was previously external and we are now
+                        * converting to new ACL format then release old
+                        * ACL object and create a new one.
+                        */
+                       if (aoid &&
+                           aclp->z_version != acl_phys.z_acl_version) {
+                               error = dmu_object_free(zsb->z_os, aoid, tx);
+                               if (error)
+                                       return (error);
+                               aoid = 0;
+                       }
+                       if (aoid == 0) {
+                               aoid = dmu_object_alloc(zsb->z_os,
+                                   otype, aclp->z_acl_bytes,
+                                   otype == DMU_OT_ACL ?
+                                   DMU_OT_SYSACL : DMU_OT_NONE,
+                                   otype == DMU_OT_ACL ?
+                                   DN_MAX_BONUSLEN : 0, tx);
+                       } else {
+                               (void) dmu_object_set_blocksize(zsb->z_os,
+                                   aoid, aclp->z_acl_bytes, 0, tx);
+                       }
+                       acl_phys.z_acl_extern_obj = aoid;
+                       for (aclnode = list_head(&aclp->z_acl); aclnode;
+                           aclnode = list_next(&aclp->z_acl, aclnode)) {
+                               if (aclnode->z_ace_count == 0)
+                                       continue;
+                               dmu_write(zsb->z_os, aoid, off,
+                                   aclnode->z_size, aclnode->z_acldata, tx);
+                               off += aclnode->z_size;
+                       }
+               } else {
+                       void *start = acl_phys.z_ace_data;
+                       /*
+                        * Migrating back embedded?
+                        */
+                       if (acl_phys.z_acl_extern_obj) {
+                               error = dmu_object_free(zsb->z_os,
+                                   acl_phys.z_acl_extern_obj, tx);
+                               if (error)
+                                       return (error);
+                               acl_phys.z_acl_extern_obj = 0;
+                       }
+
+                       for (aclnode = list_head(&aclp->z_acl); aclnode;
+                           aclnode = list_next(&aclp->z_acl, aclnode)) {
+                               if (aclnode->z_ace_count == 0)
+                                       continue;
+                               bcopy(aclnode->z_acldata, start,
+                                   aclnode->z_size);
+                               start = (caddr_t)start + aclnode->z_size;
+                       }
+               }
+               /*
+                * If Old version then swap count/bytes to match old
+                * layout of znode_acl_phys_t.
+                */
+               if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
+                       acl_phys.z_acl_size = aclp->z_acl_count;
+                       acl_phys.z_acl_count = aclp->z_acl_bytes;
+               } else {
+                       acl_phys.z_acl_size = aclp->z_acl_bytes;
+                       acl_phys.z_acl_count = aclp->z_acl_count;
+               }
+               acl_phys.z_acl_version = aclp->z_version;
+
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zsb), NULL,
+                   &acl_phys, sizeof (acl_phys));
+       }
+
+       /*
+        * Replace ACL wide bits, but first clear them.
+        */
+       zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS;
+
+       zp->z_pflags |= aclp->z_hints;
+
+       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);
+       return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
+}
+
+static void
+zfs_acl_chmod(zfs_sb_t *zsb, uint64_t mode, zfs_acl_t *aclp)
+{
+       void            *acep = NULL;
+       uint64_t        who;
+       int             new_count, new_bytes;
+       int             ace_size;
+       int             entry_type;
+       uint16_t        iflags, type;
+       uint32_t        access_mask;
+       zfs_acl_node_t  *newnode;
+       size_t          abstract_size = aclp->z_ops->ace_abstract_size();
+       void            *zacep;
+       uint32_t        owner, group, everyone;
+       uint32_t        deny1, deny2, allow0;
+
+       new_count = new_bytes = 0;
+
+       acl_trivial_access_masks((mode_t)mode, &allow0, &deny1, &deny2,
+           &owner, &group, &everyone);
+
+       newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);
+
+       zacep = newnode->z_acldata;
+       if (allow0) {
+               zfs_set_ace(aclp, zacep, allow0, ALLOW, -1, ACE_OWNER);
+               zacep = (void *)((uintptr_t)zacep + abstract_size);
+               new_count++;
+               new_bytes += abstract_size;
+       }
+       if (deny1) {
+               zfs_set_ace(aclp, zacep, deny1, DENY, -1, ACE_OWNER);
+               zacep = (void *)((uintptr_t)zacep + abstract_size);
+               new_count++;
+               new_bytes += abstract_size;
+       }
+       if (deny2) {
+               zfs_set_ace(aclp, zacep, deny2, DENY, -1, OWNING_GROUP);
+               zacep = (void *)((uintptr_t)zacep + abstract_size);
+               new_count++;
+               new_bytes += abstract_size;
+       }
+
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+           &iflags, &type))) {
+               uint16_t inherit_flags;
+
+               entry_type = (iflags & ACE_TYPE_FLAGS);
+               inherit_flags = (iflags & ALL_INHERIT);
+
+               if ((entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
+                   (entry_type == OWNING_GROUP)) &&
+                   ((inherit_flags & ACE_INHERIT_ONLY_ACE) == 0)) {
+                       continue;
+               }
+
+               if ((type != ALLOW && type != DENY) ||
+                   (inherit_flags & ACE_INHERIT_ONLY_ACE)) {
+                       if (inherit_flags)
+                               aclp->z_hints |= ZFS_INHERIT_ACE;
+                       switch (type) {
+                       case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+                       case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+                       case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+                       case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+                               aclp->z_hints |= ZFS_ACL_OBJ_ACE;
+                               break;
+                       }
+               } else {
+
+                       /*
+                        * Limit permissions to be no greater than
+                        * group permissions
+                        */
+                       if (zsb->z_acl_inherit == ZFS_ACL_RESTRICTED) {
+                               if (!(mode & S_IRGRP))
+                                       access_mask &= ~ACE_READ_DATA;
+                               if (!(mode & S_IWGRP))
+                                       access_mask &=
+                                           ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+                               if (!(mode & S_IXGRP))
+                                       access_mask &= ~ACE_EXECUTE;
+                               access_mask &=
+                                   ~(ACE_WRITE_OWNER|ACE_WRITE_ACL|
+                                   ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS);
+                       }
+               }
+               zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
+               ace_size = aclp->z_ops->ace_size(acep);
+               zacep = (void *)((uintptr_t)zacep + ace_size);
+               new_count++;
+               new_bytes += ace_size;
+       }
+       zfs_set_ace(aclp, zacep, owner, 0, -1, ACE_OWNER);
+       zacep = (void *)((uintptr_t)zacep + abstract_size);
+       zfs_set_ace(aclp, zacep, group, 0, -1, OWNING_GROUP);
+       zacep = (void *)((uintptr_t)zacep + abstract_size);
+       zfs_set_ace(aclp, zacep, everyone, 0, -1, ACE_EVERYONE);
+
+       new_count += 3;
+       new_bytes += abstract_size * 3;
+       zfs_acl_release_nodes(aclp);
+       aclp->z_acl_count = new_count;
+       aclp->z_acl_bytes = new_bytes;
+       newnode->z_ace_count = new_count;
+       newnode->z_size = new_bytes;
+       list_insert_tail(&aclp->z_acl, newnode);
+}
+
+void
+zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
+{
+       mutex_enter(&zp->z_acl_lock);
+       mutex_enter(&zp->z_lock);
+       *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
+       (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
+       zfs_acl_chmod(ZTOZSB(zp), mode, *aclp);
+       mutex_exit(&zp->z_lock);
+       mutex_exit(&zp->z_acl_lock);
+       ASSERT(*aclp);
+}
+
+/*
+ * strip off write_owner and write_acl
+ */
+static void
+zfs_restricted_update(zfs_sb_t *zsb, zfs_acl_t *aclp, void *acep)
+{
+       uint32_t mask = aclp->z_ops->ace_mask_get(acep);
+
+       if ((zsb->z_acl_inherit == ZFS_ACL_RESTRICTED) &&
+           (aclp->z_ops->ace_type_get(acep) == ALLOW)) {
+               mask &= ~RESTRICTED_CLEAR;
+               aclp->z_ops->ace_mask_set(acep, mask);
+       }
+}
+
+/*
+ * Should ACE be inherited?
+ */
+static int
+zfs_ace_can_use(umode_t obj_mode, uint16_t acep_flags)
+{
+       int     iflags = (acep_flags & 0xf);
+
+       if (S_ISDIR(obj_mode) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
+               return (1);
+       else if (iflags & ACE_FILE_INHERIT_ACE)
+               return (!(S_ISDIR(obj_mode) &&
+                   (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
+       return (0);
+}
+
+/*
+ * inherit inheritable ACEs from parent
+ */
+static zfs_acl_t *
+zfs_acl_inherit(zfs_sb_t *zsb, umode_t obj_mode, zfs_acl_t *paclp,
+    uint64_t mode, boolean_t *need_chmod)
+{
+       void            *pacep;
+       void            *acep;
+       zfs_acl_node_t  *aclnode;
+       zfs_acl_t       *aclp = NULL;
+       uint64_t        who;
+       uint32_t        access_mask;
+       uint16_t        iflags, newflags, type;
+       size_t          ace_size;
+       void            *data1, *data2;
+       size_t          data1sz, data2sz;
+       boolean_t       vdir = S_ISDIR(obj_mode);
+       boolean_t       vreg = S_ISREG(obj_mode);
+       boolean_t       passthrough, passthrough_x, noallow;
+
+       passthrough_x =
+           zsb->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X;
+       passthrough = passthrough_x ||
+           zsb->z_acl_inherit == ZFS_ACL_PASSTHROUGH;
+       noallow =
+           zsb->z_acl_inherit == ZFS_ACL_NOALLOW;
+
+       *need_chmod = B_TRUE;
+       pacep = NULL;
+       aclp = zfs_acl_alloc(paclp->z_version);
+       if (zsb->z_acl_inherit == ZFS_ACL_DISCARD || S_ISLNK(obj_mode))
+               return (aclp);
+       while ((pacep = zfs_acl_next_ace(paclp, pacep, &who,
+           &access_mask, &iflags, &type))) {
+
+               /*
+                * don't inherit bogus ACEs
+                */
+               if (!zfs_acl_valid_ace_type(type, iflags))
+                       continue;
+
+               if (noallow && type == ALLOW)
+                       continue;
+
+               ace_size = aclp->z_ops->ace_size(pacep);
+
+               if (!zfs_ace_can_use(obj_mode, iflags))
+                       continue;
+
+               /*
+                * If owner@, group@, or everyone@ inheritable
+                * then zfs_acl_chmod() isn't needed.
+                */
+               if (passthrough &&
+                   ((iflags & (ACE_OWNER|ACE_EVERYONE)) ||
+                   ((iflags & OWNING_GROUP) ==
+                   OWNING_GROUP)) && (vreg || (vdir && (iflags &
+                   ACE_DIRECTORY_INHERIT_ACE)))) {
+                       *need_chmod = B_FALSE;
+               }
+
+               if (!vdir && passthrough_x &&
+                   ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) {
+                       access_mask &= ~ACE_EXECUTE;
+               }
+
+               aclnode = zfs_acl_node_alloc(ace_size);
+               list_insert_tail(&aclp->z_acl, aclnode);
+               acep = aclnode->z_acldata;
+
+               zfs_set_ace(aclp, acep, access_mask, type,
+                   who, iflags|ACE_INHERITED_ACE);
+
+               /*
+                * Copy special opaque data if any
+                */
+               if ((data1sz = paclp->z_ops->ace_data(pacep, &data1)) != 0) {
+                       VERIFY((data2sz = aclp->z_ops->ace_data(acep,
+                           &data2)) == data1sz);
+                       bcopy(data1, data2, data2sz);
+               }
+
+               aclp->z_acl_count++;
+               aclnode->z_ace_count++;
+               aclp->z_acl_bytes += aclnode->z_size;
+               newflags = aclp->z_ops->ace_flags_get(acep);
+
+               if (vdir)
+                       aclp->z_hints |= ZFS_INHERIT_ACE;
+
+               if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) {
+                       newflags &= ~ALL_INHERIT;
+                       aclp->z_ops->ace_flags_set(acep,
+                           newflags|ACE_INHERITED_ACE);
+                       zfs_restricted_update(zsb, aclp, acep);
+                       continue;
+               }
+
+               ASSERT(vdir);
+
+               /*
+                * If only FILE_INHERIT is set then turn on
+                * inherit_only
+                */
+               if ((iflags & (ACE_FILE_INHERIT_ACE |
+                   ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) {
+                       newflags |= ACE_INHERIT_ONLY_ACE;
+                       aclp->z_ops->ace_flags_set(acep,
+                           newflags|ACE_INHERITED_ACE);
+               } else {
+                       newflags &= ~ACE_INHERIT_ONLY_ACE;
+                       aclp->z_ops->ace_flags_set(acep,
+                           newflags|ACE_INHERITED_ACE);
+               }
+       }
+       return (aclp);
+}
+
+/*
+ * Create file system object initial permissions
+ * including inheritable ACEs.
+ */
+int
+zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
+    vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
+{
+       int             error;
+       zfs_sb_t        *zsb = ZTOZSB(dzp);
+       zfs_acl_t       *paclp;
+#ifdef HAVE_KSID
+       gid_t           gid;
+#endif /* HAVE_KSID */
+       boolean_t       need_chmod = B_TRUE;
+       boolean_t       inherited = B_FALSE;
+
+       bzero(acl_ids, sizeof (zfs_acl_ids_t));
+       acl_ids->z_mode = vap->va_mode;
+
+       if (vsecp)
+               if ((error = zfs_vsec_2_aclp(zsb, vap->va_mode, vsecp,
+                   cr, &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0)
+                       return (error);
+
+       acl_ids->z_fuid = vap->va_uid;
+       acl_ids->z_fgid = vap->va_gid;
+#ifdef HAVE_KSID
+       /*
+        * Determine uid and gid.
+        */
+       if ((flag & IS_ROOT_NODE) || zsb->z_replay ||
+           ((flag & IS_XATTR) && (S_ISDIR(vap->va_mode)))) {
+               acl_ids->z_fuid = zfs_fuid_create(zsb, (uint64_t)vap->va_uid,
+                   cr, ZFS_OWNER, &acl_ids->z_fuidp);
+               acl_ids->z_fgid = zfs_fuid_create(zsb, (uint64_t)vap->va_gid,
+                   cr, ZFS_GROUP, &acl_ids->z_fuidp);
+               gid = vap->va_gid;
+       } else {
+               acl_ids->z_fuid = zfs_fuid_create_cred(zsb, ZFS_OWNER,
+                   cr, &acl_ids->z_fuidp);
+               acl_ids->z_fgid = 0;
+               if (vap->va_mask & AT_GID)  {
+                       acl_ids->z_fgid = zfs_fuid_create(zsb,
+                           (uint64_t)vap->va_gid,
+                           cr, ZFS_GROUP, &acl_ids->z_fuidp);
+                       gid = vap->va_gid;
+                       if (acl_ids->z_fgid != dzp->z_gid &&
+                           !groupmember(vap->va_gid, cr) &&
+                           secpolicy_vnode_create_gid(cr) != 0)
+                               acl_ids->z_fgid = 0;
+               }
+               if (acl_ids->z_fgid == 0) {
+                       if (dzp->z_mode & S_ISGID) {
+                               char            *domain;
+                               uint32_t        rid;
+
+                               acl_ids->z_fgid = dzp->z_gid;
+                               gid = zfs_fuid_map_id(zsb, acl_ids->z_fgid,
+                                   cr, ZFS_GROUP);
+
+                               if (zsb->z_use_fuids &&
+                                   IS_EPHEMERAL(acl_ids->z_fgid)) {
+                                       domain = zfs_fuid_idx_domain(
+                                           &zsb->z_fuid_idx,
+                                           FUID_INDEX(acl_ids->z_fgid));
+                                       rid = FUID_RID(acl_ids->z_fgid);
+                                       zfs_fuid_node_add(&acl_ids->z_fuidp,
+                                           domain, rid,
+                                           FUID_INDEX(acl_ids->z_fgid),
+                                           acl_ids->z_fgid, ZFS_GROUP);
+                               }
+                       } else {
+                               acl_ids->z_fgid = zfs_fuid_create_cred(zsb,
+                                   ZFS_GROUP, cr, &acl_ids->z_fuidp);
+                               gid = crgetgid(cr);
+                       }
+               }
+       }
+#endif /* HAVE_KSID */
+
+       /*
+        * If we're creating a directory, and the parent directory has the
+        * set-GID bit set, set in on the new directory.
+        * Otherwise, if the user is neither privileged nor a member of the
+        * file's new group, clear the file's set-GID bit.
+        */
+
+       if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) &&
+           (S_ISDIR(vap->va_mode))) {
+               acl_ids->z_mode |= S_ISGID;
+       } else {
+               if ((acl_ids->z_mode & S_ISGID) &&
+                   secpolicy_vnode_setids_setgids(cr, gid) != 0)
+                       acl_ids->z_mode &= ~S_ISGID;
+       }
+
+       if (acl_ids->z_aclp == NULL) {
+               mutex_enter(&dzp->z_acl_lock);
+               mutex_enter(&dzp->z_lock);
+               if (!(flag & IS_ROOT_NODE) && (S_ISDIR(ZTOI(dzp)->i_mode) &&
+                   (dzp->z_pflags & ZFS_INHERIT_ACE)) &&
+                   !(dzp->z_pflags & ZFS_XATTR)) {
+                       VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE,
+                           &paclp, B_FALSE));
+                       acl_ids->z_aclp = zfs_acl_inherit(zsb,
+                           vap->va_mode, paclp, acl_ids->z_mode, &need_chmod);
+                       inherited = B_TRUE;
+               } else {
+                       acl_ids->z_aclp =
+                           zfs_acl_alloc(zfs_acl_version_zp(dzp));
+                       acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
+               }
+               mutex_exit(&dzp->z_lock);
+               mutex_exit(&dzp->z_acl_lock);
+               if (need_chmod) {
+                       acl_ids->z_aclp->z_hints |= S_ISDIR(vap->va_mode) ?
+                           ZFS_ACL_AUTO_INHERIT : 0;
+                       zfs_acl_chmod(zsb, acl_ids->z_mode, acl_ids->z_aclp);
+               }
+       }
+
+       if (inherited || vsecp) {
+               acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode,
+                   acl_ids->z_aclp, &acl_ids->z_aclp->z_hints,
+                   acl_ids->z_fuid, acl_ids->z_fgid);
+               if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0)
+                       acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
+       }
+
+       return (0);
+}
+
+/*
+ * Free ACL and fuid_infop, but not the acl_ids structure
+ */
+void
+zfs_acl_ids_free(zfs_acl_ids_t *acl_ids)
+{
+       if (acl_ids->z_aclp)
+               zfs_acl_free(acl_ids->z_aclp);
+       if (acl_ids->z_fuidp)
+               zfs_fuid_info_free(acl_ids->z_fuidp);
+       acl_ids->z_aclp = NULL;
+       acl_ids->z_fuidp = NULL;
+}
+
+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));
+}
+
+/*
+ * Retrieve a file's ACL
+ */
+int
+zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
+{
+       zfs_acl_t       *aclp;
+       ulong_t         mask;
+       int             error;
+       int             count = 0;
+       int             largeace = 0;
+
+       mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
+           VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
+
+       if (mask == 0)
+               return (SET_ERROR(ENOSYS));
+
+       if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)))
+               return (error);
+
+       mutex_enter(&zp->z_acl_lock);
+
+       error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
+       if (error != 0) {
+               mutex_exit(&zp->z_acl_lock);
+               return (error);
+       }
+
+       /*
+        * Scan ACL to determine number of ACEs
+        */
+       if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) {
+               void *zacep = NULL;
+               uint64_t who;
+               uint32_t access_mask;
+               uint16_t type, iflags;
+
+               while ((zacep = zfs_acl_next_ace(aclp, zacep,
+                   &who, &access_mask, &iflags, &type))) {
+                       switch (type) {
+                       case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+                       case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+                       case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+                       case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+                               largeace++;
+                               continue;
+                       default:
+                               count++;
+                       }
+               }
+               vsecp->vsa_aclcnt = count;
+       } else
+               count = (int)aclp->z_acl_count;
+
+       if (mask & VSA_ACECNT) {
+               vsecp->vsa_aclcnt = count;
+       }
+
+       if (mask & VSA_ACE) {
+               size_t aclsz;
+
+               aclsz = count * sizeof (ace_t) +
+                   sizeof (ace_object_t) * largeace;
+
+               vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
+               vsecp->vsa_aclentsz = aclsz;
+
+               if (aclp->z_version == ZFS_ACL_VERSION_FUID)
+                       zfs_copy_fuid_2_ace(ZTOZSB(zp), aclp, cr,
+                           vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
+               else {
+                       zfs_acl_node_t *aclnode;
+                       void *start = vsecp->vsa_aclentp;
+
+                       for (aclnode = list_head(&aclp->z_acl); aclnode;
+                           aclnode = list_next(&aclp->z_acl, aclnode)) {
+                               bcopy(aclnode->z_acldata, start,
+                                   aclnode->z_size);
+                               start = (caddr_t)start + aclnode->z_size;
+                       }
+                       ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp ==
+                           aclp->z_acl_bytes);
+               }
+       }
+       if (mask & VSA_ACE_ACLFLAGS) {
+               vsecp->vsa_aclflags = 0;
+               if (zp->z_pflags & ZFS_ACL_DEFAULTED)
+                       vsecp->vsa_aclflags |= ACL_DEFAULTED;
+               if (zp->z_pflags & ZFS_ACL_PROTECTED)
+                       vsecp->vsa_aclflags |= ACL_PROTECTED;
+               if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT)
+                       vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
+       }
+
+       mutex_exit(&zp->z_acl_lock);
+
+       return (0);
+}
+
+int
+zfs_vsec_2_aclp(zfs_sb_t *zsb, umode_t obj_mode,
+    vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp)
+{
+       zfs_acl_t *aclp;
+       zfs_acl_node_t *aclnode;
+       int aclcnt = vsecp->vsa_aclcnt;
+       int error;
+
+       if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
+               return (SET_ERROR(EINVAL));
+
+       aclp = zfs_acl_alloc(zfs_acl_version(zsb->z_version));
+
+       aclp->z_hints = 0;
+       aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
+       if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
+               if ((error = zfs_copy_ace_2_oldace(obj_mode, aclp,
+                   (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
+                   aclcnt, &aclnode->z_size)) != 0) {
+                       zfs_acl_free(aclp);
+                       zfs_acl_node_free(aclnode);
+                       return (error);
+               }
+       } else {
+               if ((error = zfs_copy_ace_2_fuid(zsb, obj_mode, aclp,
+                   vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
+                   &aclnode->z_size, fuidp, cr)) != 0) {
+                       zfs_acl_free(aclp);
+                       zfs_acl_node_free(aclnode);
+                       return (error);
+               }
+       }
+       aclp->z_acl_bytes = aclnode->z_size;
+       aclnode->z_ace_count = aclcnt;
+       aclp->z_acl_count = aclcnt;
+       list_insert_head(&aclp->z_acl, aclnode);
+
+       /*
+        * If flags are being set then add them to z_hints
+        */
+       if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
+               if (vsecp->vsa_aclflags & ACL_PROTECTED)
+                       aclp->z_hints |= ZFS_ACL_PROTECTED;
+               if (vsecp->vsa_aclflags & ACL_DEFAULTED)
+                       aclp->z_hints |= ZFS_ACL_DEFAULTED;
+               if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
+                       aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
+       }
+
+       *zaclp = aclp;
+
+       return (0);
+}
+
+/*
+ * Set a file's ACL
+ */
+int
+zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
+{
+       zfs_sb_t        *zsb = ZTOZSB(zp);
+       zilog_t         *zilog = zsb->z_log;
+       ulong_t         mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
+       dmu_tx_t        *tx;
+       int             error;
+       zfs_acl_t       *aclp;
+       zfs_fuid_info_t *fuidp = NULL;
+       boolean_t       fuid_dirtied;
+       uint64_t        acl_obj;
+
+       if (mask == 0)
+               return (SET_ERROR(ENOSYS));
+
+       if (zp->z_pflags & ZFS_IMMUTABLE)
+               return (SET_ERROR(EPERM));
+
+       if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)))
+               return (error);
+
+       error = zfs_vsec_2_aclp(zsb, ZTOI(zp)->i_mode, vsecp, cr, &fuidp,
+           &aclp);
+       if (error)
+               return (error);
+
+       /*
+        * If ACL wide flags aren't being set then preserve any
+        * existing flags.
+        */
+       if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
+               aclp->z_hints |=
+                   (zp->z_pflags & V4_ACL_WIDE_FLAGS);
+       }
+top:
+       mutex_enter(&zp->z_acl_lock);
+       mutex_enter(&zp->z_lock);
+
+       tx = dmu_tx_create(zsb->z_os);
+
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+
+       fuid_dirtied = zsb->z_fuid_dirty;
+       if (fuid_dirtied)
+               zfs_fuid_txhold(zsb, tx);
+
+       /*
+        * If old version and ACL won't fit in bonus and we aren't
+        * upgrading then take out necessary DMU holds
+        */
+
+       if ((acl_obj = zfs_external_acl(zp)) != 0) {
+               if (zsb->z_version >= ZPL_VERSION_FUID &&
+                   zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
+                       dmu_tx_hold_free(tx, acl_obj, 0,
+                           DMU_OBJECT_END);
+                       dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+                           aclp->z_acl_bytes);
+               } else {
+                       dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
+               }
+       } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+               dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
+       }
+
+       zfs_sa_upgrade_txholds(tx, zp);
+       error = dmu_tx_assign(tx, TXG_NOWAIT);
+       if (error) {
+               mutex_exit(&zp->z_acl_lock);
+               mutex_exit(&zp->z_lock);
+
+               if (error == ERESTART) {
+                       dmu_tx_wait(tx);
+                       dmu_tx_abort(tx);
+                       goto top;
+               }
+               dmu_tx_abort(tx);
+               zfs_acl_free(aclp);
+               return (error);
+       }
+
+       error = zfs_aclset_common(zp, aclp, cr, tx);
+       ASSERT(error == 0);
+       ASSERT(zp->z_acl_cached == NULL);
+       zp->z_acl_cached = aclp;
+
+       if (fuid_dirtied)
+               zfs_fuid_sync(zsb, tx);
+
+       zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
+
+       if (fuidp)
+               zfs_fuid_info_free(fuidp);
+       dmu_tx_commit(tx);
+
+       mutex_exit(&zp->z_lock);
+       mutex_exit(&zp->z_acl_lock);
+
+       return (error);
+}
+
+/*
+ * Check accesses of interest (AoI) against attributes of the dataset
+ * such as read-only.  Returns zero if no AoI conflict with dataset
+ * attributes, otherwise an appropriate errno is returned.
+ */
+static int
+zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
+{
+       if ((v4_mode & WRITE_MASK) && (zfs_is_readonly(ZTOZSB(zp))) &&
+           (!S_ISDEV(ZTOI(zp)->i_mode) ||
+           (S_ISDEV(ZTOI(zp)->i_mode) && (v4_mode & WRITE_MASK_ATTRS)))) {
+               return (SET_ERROR(EROFS));
+       }
+
+       /*
+        * Only check for READONLY on non-directories.
+        */
+       if ((v4_mode & WRITE_MASK_DATA) &&
+           ((!S_ISDIR(ZTOI(zp)->i_mode) &&
+           (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
+           (S_ISDIR(ZTOI(zp)->i_mode) &&
+           (zp->z_pflags & ZFS_IMMUTABLE)))) {
+               return (SET_ERROR(EPERM));
+       }
+
+       if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
+           (zp->z_pflags & ZFS_NOUNLINK)) {
+               return (SET_ERROR(EPERM));
+       }
+
+       if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
+           (zp->z_pflags & ZFS_AV_QUARANTINED))) {
+               return (SET_ERROR(EACCES));
+       }
+
+       return (0);
+}
+
+/*
+ * The primary usage of this function is to loop through all of the
+ * ACEs in the znode, determining what accesses of interest (AoI) to
+ * the caller are allowed or denied.  The AoI are expressed as bits in
+ * the working_mode parameter.  As each ACE is processed, bits covered
+ * by that ACE are removed from the working_mode.  This removal
+ * facilitates two things.  The first is that when the working mode is
+ * empty (= 0), we know we've looked at all the AoI. The second is
+ * that the ACE interpretation rules don't allow a later ACE to undo
+ * something granted or denied by an earlier ACE.  Removing the
+ * discovered access or denial enforces this rule.  At the end of
+ * processing the ACEs, all AoI that were found to be denied are
+ * placed into the working_mode, giving the caller a mask of denied
+ * accesses.  Returns:
+ *     0               if all AoI granted
+ *     EACCESS         if the denied mask is non-zero
+ *     other error     if abnormal failure (e.g., IO error)
+ *
+ * A secondary usage of the function is to determine if any of the
+ * AoI are granted.  If an ACE grants any access in
+ * the working_mode, we immediately short circuit out of the function.
+ * This mode is chosen by setting anyaccess to B_TRUE.  The
+ * working_mode is not a denied access mask upon exit if the function
+ * is used in this manner.
+ */
+static int
+zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
+    boolean_t anyaccess, cred_t *cr)
+{
+       zfs_sb_t        *zsb = ZTOZSB(zp);
+       zfs_acl_t       *aclp;
+       int             error;
+       uid_t           uid = crgetuid(cr);
+       uint64_t        who;
+       uint16_t        type, iflags;
+       uint16_t        entry_type;
+       uint32_t        access_mask;
+       uint32_t        deny_mask = 0;
+       zfs_ace_hdr_t   *acep = NULL;
+       boolean_t       checkit;
+       uid_t           gowner;
+       uid_t           fowner;
+
+       zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
+
+       mutex_enter(&zp->z_acl_lock);
+
+       error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
+       if (error != 0) {
+               mutex_exit(&zp->z_acl_lock);
+               return (error);
+       }
+
+       ASSERT(zp->z_acl_cached);
+
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+           &iflags, &type))) {
+               uint32_t mask_matched;
+
+               if (!zfs_acl_valid_ace_type(type, iflags))
+                       continue;
+
+               if (S_ISDIR(ZTOI(zp)->i_mode) &&
+                   (iflags & ACE_INHERIT_ONLY_ACE))
+                       continue;
+
+               /* Skip ACE if it does not affect any AoI */
+               mask_matched = (access_mask & *working_mode);
+               if (!mask_matched)
+                       continue;
+
+               entry_type = (iflags & ACE_TYPE_FLAGS);
+
+               checkit = B_FALSE;
+
+               switch (entry_type) {
+               case ACE_OWNER:
+                       if (uid == fowner)
+                               checkit = B_TRUE;
+                       break;
+               case OWNING_GROUP:
+                       who = gowner;
+                       /*FALLTHROUGH*/
+               case ACE_IDENTIFIER_GROUP:
+                       checkit = zfs_groupmember(zsb, who, cr);
+                       break;
+               case ACE_EVERYONE:
+                       checkit = B_TRUE;
+                       break;
+
+               /* USER Entry */
+               default:
+                       if (entry_type == 0) {
+                               uid_t newid;
+
+                               newid = zfs_fuid_map_id(zsb, who, cr,
+                                   ZFS_ACE_USER);
+                               if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
+                                   uid == newid)
+                                       checkit = B_TRUE;
+                               break;
+                       } else {
+                               mutex_exit(&zp->z_acl_lock);
+                               return (SET_ERROR(EIO));
+                       }
+               }
+
+               if (checkit) {
+                       if (type == DENY) {
+                               DTRACE_PROBE3(zfs__ace__denies,
+                                   znode_t *, zp,
+                                   zfs_ace_hdr_t *, acep,
+                                   uint32_t, mask_matched);
+                               deny_mask |= mask_matched;
+                       } else {
+                               DTRACE_PROBE3(zfs__ace__allows,
+                                   znode_t *, zp,
+                                   zfs_ace_hdr_t *, acep,
+                                   uint32_t, mask_matched);
+                               if (anyaccess) {
+                                       mutex_exit(&zp->z_acl_lock);
+                                       return (0);
+                               }
+                       }
+                       *working_mode &= ~mask_matched;
+               }
+
+               /* Are we done? */
+               if (*working_mode == 0)
+                       break;
+       }
+
+       mutex_exit(&zp->z_acl_lock);
+
+       /* Put the found 'denies' back on the working mode */
+       if (deny_mask) {
+               *working_mode |= deny_mask;
+               return (SET_ERROR(EACCES));
+       } else if (*working_mode) {
+               return (-1);
+       }
+
+       return (0);
+}
+
+/*
+ * Return true if any access whatsoever granted, we don't actually
+ * care what access is granted.
+ */
+boolean_t
+zfs_has_access(znode_t *zp, cred_t *cr)
+{
+       uint32_t have = ACE_ALL_PERMS;
+
+       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);
+               return (secpolicy_vnode_any_access(cr, ZTOI(zp), owner) == 0);
+       }
+       return (B_TRUE);
+}
+
+static int
+zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
+    boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       int err;
+
+       *working_mode = v4_mode;
+       *check_privs = B_TRUE;
+
+       /*
+        * Short circuit empty requests
+        */
+       if (v4_mode == 0 || zsb->z_replay) {
+               *working_mode = 0;
+               return (0);
+       }
+
+       if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) {
+               *check_privs = B_FALSE;
+               return (err);
+       }
+
+       /*
+        * The caller requested that the ACL check be skipped.  This
+        * would only happen if the caller checked VOP_ACCESS() with a
+        * 32 bit ACE mask and already had the appropriate permissions.
+        */
+       if (skipaclchk) {
+               *working_mode = 0;
+               return (0);
+       }
+
+       return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
+}
+
+static int
+zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
+    cred_t *cr)
+{
+       if (*working_mode != ACE_WRITE_DATA)
+               return (SET_ERROR(EACCES));
+
+       return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
+           check_privs, B_FALSE, cr));
+}
+
+int
+zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
+{
+       boolean_t owner = B_FALSE;
+       boolean_t groupmbr = B_FALSE;
+       boolean_t is_attr;
+       uid_t uid = crgetuid(cr);
+       int error;
+
+       if (zdp->z_pflags & ZFS_AV_QUARANTINED)
+               return (SET_ERROR(EACCES));
+
+       is_attr = ((zdp->z_pflags & ZFS_XATTR) &&
+           (S_ISDIR(ZTOI(zdp)->i_mode)));
+       if (is_attr)
+               goto slow;
+
+
+       mutex_enter(&zdp->z_acl_lock);
+
+       if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) {
+               mutex_exit(&zdp->z_acl_lock);
+               return (0);
+       }
+
+       if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
+               mutex_exit(&zdp->z_acl_lock);
+               goto slow;
+       }
+
+       if (uid == zdp->z_uid) {
+               owner = B_TRUE;
+               if (zdp->z_mode & S_IXUSR) {
+                       mutex_exit(&zdp->z_acl_lock);
+                       return (0);
+               } else {
+                       mutex_exit(&zdp->z_acl_lock);
+                       goto slow;
+               }
+       }
+       if (groupmember(zdp->z_gid, cr)) {
+               groupmbr = B_TRUE;
+               if (zdp->z_mode & S_IXGRP) {
+                       mutex_exit(&zdp->z_acl_lock);
+                       return (0);
+               } else {
+                       mutex_exit(&zdp->z_acl_lock);
+                       goto slow;
+               }
+       }
+       if (!owner && !groupmbr) {
+               if (zdp->z_mode & S_IXOTH) {
+                       mutex_exit(&zdp->z_acl_lock);
+                       return (0);
+               }
+       }
+
+       mutex_exit(&zdp->z_acl_lock);
+
+slow:
+       DTRACE_PROBE(zfs__fastpath__execute__access__miss);
+       ZFS_ENTER(ZTOZSB(zdp));
+       error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr);
+       ZFS_EXIT(ZTOZSB(zdp));
+       return (error);
+}
+
+/*
+ * Determine whether Access should be granted/denied.
+ *
+ * The least priv subsytem is always consulted as a basic privilege
+ * can define any form of access.
+ */
+int
+zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
+{
+       uint32_t        working_mode;
+       int             error;
+       int             is_attr;
+       boolean_t       check_privs;
+       znode_t         *xzp;
+       znode_t         *check_zp = zp;
+       mode_t          needed_bits;
+       uid_t           owner;
+
+       is_attr = ((zp->z_pflags & ZFS_XATTR) && S_ISDIR(ZTOI(zp)->i_mode));
+
+       /*
+        * If attribute then validate against base file
+        */
+       if (is_attr) {
+               uint64_t        parent;
+
+               if ((error = sa_lookup(zp->z_sa_hdl,
+                   SA_ZPL_PARENT(ZTOZSB(zp)), &parent,
+                   sizeof (parent))) != 0)
+                       return (error);
+
+               if ((error = zfs_zget(ZTOZSB(zp),
+                   parent, &xzp)) != 0)        {
+                       return (error);
+               }
+
+               check_zp = xzp;
+
+               /*
+                * fixup mode to map to xattr perms
+                */
+
+               if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
+                       mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+                       mode |= ACE_WRITE_NAMED_ATTRS;
+               }
+
+               if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
+                       mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
+                       mode |= ACE_READ_NAMED_ATTRS;
+               }
+       }
+
+       owner = zfs_fuid_map_id(ZTOZSB(zp), zp->z_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
+        * mapped by working_mode (currently missing) in missing_bits.
+        * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode),
+        * needed_bits.
+        */
+       needed_bits = 0;
+
+       working_mode = mode;
+       if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
+           owner == crgetuid(cr))
+               working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
+
+       if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
+           ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
+               needed_bits |= S_IRUSR;
+       if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
+           ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
+               needed_bits |= S_IWUSR;
+       if (working_mode & ACE_EXECUTE)
+               needed_bits |= S_IXUSR;
+
+       if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
+           &check_privs, skipaclchk, cr)) == 0) {
+               if (is_attr)
+                       iput(ZTOI(xzp));
+               return (secpolicy_vnode_access2(cr, ZTOI(zp), owner,
+                   needed_bits, needed_bits));
+       }
+
+       if (error && !check_privs) {
+               if (is_attr)
+                       iput(ZTOI(xzp));
+               return (error);
+       }
+
+       if (error && (flags & V_APPEND)) {
+               error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
+       }
+
+       if (error && check_privs) {
+               mode_t          checkmode = 0;
+
+               /*
+                * First check for implicit owner permission on
+                * read_acl/read_attributes
+                */
+
+               error = 0;
+               ASSERT(working_mode != 0);
+
+               if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
+                   owner == crgetuid(cr)))
+                       working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
+
+               if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
+                   ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
+                       checkmode |= S_IRUSR;
+               if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
+                   ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
+                       checkmode |= S_IWUSR;
+               if (working_mode & ACE_EXECUTE)
+                       checkmode |= S_IXUSR;
+
+               error = secpolicy_vnode_access2(cr, ZTOI(check_zp), owner,
+                   needed_bits & ~checkmode, needed_bits);
+
+               if (error == 0 && (working_mode & ACE_WRITE_OWNER))
+                       error = secpolicy_vnode_chown(cr, owner);
+               if (error == 0 && (working_mode & ACE_WRITE_ACL))
+                       error = secpolicy_vnode_setdac(cr, owner);
+
+               if (error == 0 && (working_mode &
+                   (ACE_DELETE|ACE_DELETE_CHILD)))
+                       error = secpolicy_vnode_remove(cr);
+
+               if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
+                       error = secpolicy_vnode_chown(cr, owner);
+               }
+               if (error == 0) {
+                       /*
+                        * See if any bits other than those already checked
+                        * for are still present.  If so then return EACCES
+                        */
+                       if (working_mode & ~(ZFS_CHECKED_MASKS)) {
+                               error = SET_ERROR(EACCES);
+                       }
+               }
+       } else if (error == 0) {
+               error = secpolicy_vnode_access2(cr, ZTOI(zp), owner,
+                   needed_bits, needed_bits);
+       }
+
+       if (is_attr)
+               iput(ZTOI(xzp));
+
+       return (error);
+}
+
+/*
+ * Translate traditional unix S_IRUSR/S_IWUSR/S_IXUSR mode into
+ * native ACL format and call zfs_zaccess()
+ */
+int
+zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
+{
+       return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
+}
+
+/*
+ * Access function for secpolicy_vnode_setattr
+ */
+int
+zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
+{
+       int v4_mode = zfs_unix_to_v4(mode >> 6);
+
+       return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
+}
+
+static int
+zfs_delete_final_check(znode_t *zp, znode_t *dzp,
+    mode_t available_perms, cred_t *cr)
+{
+       int error;
+       uid_t downer;
+
+       downer = zfs_fuid_map_id(ZTOZSB(dzp), dzp->z_uid, cr, ZFS_OWNER);
+
+       error = secpolicy_vnode_access2(cr, ZTOI(dzp),
+           downer, available_perms, S_IWUSR|S_IXUSR);
+
+       if (error == 0)
+               error = zfs_sticky_remove_access(dzp, zp, cr);
+
+       return (error);
+}
+
+/*
+ * Determine whether Access should be granted/deny, without
+ * consulting least priv subsystem.
+ *
+ * The following chart is the recommended NFSv4 enforcement for
+ * ability to delete an object.
+ *
+ *      -------------------------------------------------------
+ *      |   Parent Dir  |           Target Object Permissions |
+ *      |  permissions  |                                     |
+ *      -------------------------------------------------------
+ *      |               | ACL Allows | ACL Denies| Delete     |
+ *      |               |  Delete    |  Delete   | unspecified|
+ *      -------------------------------------------------------
+ *      |  ACL Allows   | Permit     | Permit    | Permit     |
+ *      |  DELETE_CHILD |                                     |
+ *      -------------------------------------------------------
+ *      |  ACL Denies   | Permit     | Deny      | Deny       |
+ *      |  DELETE_CHILD |            |           |            |
+ *      -------------------------------------------------------
+ *      | ACL specifies |            |           |            |
+ *      | only allow    | Permit     | Permit    | Permit     |
+ *      | write and     |            |           |            |
+ *      | execute       |            |           |            |
+ *      -------------------------------------------------------
+ *      | ACL denies    |            |           |            |
+ *      | write and     | Permit     | Deny      | Deny       |
+ *      | execute       |            |           |            |
+ *      -------------------------------------------------------
+ *         ^
+ *         |
+ *         No search privilege, can't even look up file?
+ *
+ */
+int
+zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
+{
+       uint32_t dzp_working_mode = 0;
+       uint32_t zp_working_mode = 0;
+       int dzp_error, zp_error;
+       mode_t available_perms;
+       boolean_t dzpcheck_privs = B_TRUE;
+       boolean_t zpcheck_privs = B_TRUE;
+
+       /*
+        * We want specific DELETE permissions to
+        * take precedence over WRITE/EXECUTE.  We don't
+        * want an ACL such as this to mess us up.
+        * user:joe:write_data:deny,user:joe:delete:allow
+        *
+        * However, deny permissions may ultimately be overridden
+        * by secpolicy_vnode_access().
+        *
+        * We will ask for all of the necessary permissions and then
+        * look at the working modes from the directory and target object
+        * to determine what was found.
+        */
+
+       if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
+               return (SET_ERROR(EPERM));
+
+       /*
+        * First row
+        * If the directory permissions allow the delete, we are done.
+        */
+       if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
+           &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
+               return (0);
+
+       /*
+        * If target object has delete permission then we are done
+        */
+       if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
+           &zpcheck_privs, B_FALSE, cr)) == 0)
+               return (0);
+
+       ASSERT(dzp_error && zp_error);
+
+       if (!dzpcheck_privs)
+               return (dzp_error);
+       if (!zpcheck_privs)
+               return (zp_error);
+
+       /*
+        * Second row
+        *
+        * If directory returns EACCES then delete_child was denied
+        * due to deny delete_child.  In this case send the request through
+        * secpolicy_vnode_remove().  We don't use zfs_delete_final_check()
+        * since that *could* allow the delete based on write/execute permission
+        * and we want delete permissions to override write/execute.
+        */
+
+       if (dzp_error == EACCES)
+               return (secpolicy_vnode_remove(cr));
+
+       /*
+        * Third Row
+        * only need to see if we have write/execute on directory.
+        */
+
+       dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
+           &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
+
+       if (dzp_error != 0 && !dzpcheck_privs)
+               return (dzp_error);
+
+       /*
+        * Fourth row
+        */
+
+       available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : S_IWUSR;
+       available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : S_IXUSR;
+
+       return (zfs_delete_final_check(zp, dzp, available_perms, cr));
+
+}
+
+int
+zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
+    znode_t *tzp, cred_t *cr)
+{
+       int add_perm;
+       int error;
+
+       if (szp->z_pflags & ZFS_AV_QUARANTINED)
+               return (SET_ERROR(EACCES));
+
+       add_perm = S_ISDIR(ZTOI(szp)->i_mode) ?
+           ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
+
+       /*
+        * Rename permissions are combination of delete permission +
+        * add file/subdir permission.
+        */
+
+       /*
+        * first make sure we do the delete portion.
+        *
+        * If that succeeds then check for add_file/add_subdir permissions
+        */
+
+       if ((error = zfs_zaccess_delete(sdzp, szp, cr)))
+               return (error);
+
+       /*
+        * If we have a tzp, see if we can delete it?
+        */
+       if (tzp) {
+               if ((error = zfs_zaccess_delete(tdzp, tzp, cr)))
+                       return (error);
+       }
+
+       /*
+        * Now check for add permissions
+        */
+       error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
+
+       return (error);
+}
diff --git a/zfs/module/zfs/zfs_byteswap.c b/zfs/module/zfs/zfs_byteswap.c
new file mode 100644 (file)
index 0000000..16327a2
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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/vfs.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_sa.h>
+#include <sys/zfs_acl.h>
+
+void
+zfs_oldace_byteswap(ace_t *ace, int ace_cnt)
+{
+       int i;
+
+       for (i = 0; i != ace_cnt; i++, ace++) {
+               ace->a_who = BSWAP_32(ace->a_who);
+               ace->a_access_mask = BSWAP_32(ace->a_access_mask);
+               ace->a_flags = BSWAP_16(ace->a_flags);
+               ace->a_type = BSWAP_16(ace->a_type);
+       }
+}
+
+/*
+ * swap ace_t and ace_oject_t
+ */
+void
+zfs_ace_byteswap(void *buf, size_t size, boolean_t zfs_layout)
+{
+       caddr_t end;
+       caddr_t ptr;
+       zfs_ace_t *zacep = NULL;
+       ace_t *acep;
+       uint16_t entry_type;
+       size_t entry_size;
+       int ace_type;
+
+       end = (caddr_t)buf + size;
+       ptr = buf;
+
+       while (ptr < end) {
+               if (zfs_layout) {
+                       /*
+                        * Avoid overrun.  Embedded aces can have one
+                        * of several sizes.  We don't know exactly
+                        * how many our present, only the size of the
+                        * buffer containing them.  That size may be
+                        * larger than needed to hold the aces
+                        * present.  As long as we do not do any
+                        * swapping beyond the end of our block we are
+                        * okay.  It it safe to swap any non-ace data
+                        * within the block since it is just zeros.
+                        */
+                       if (ptr + sizeof (zfs_ace_hdr_t) > end) {
+                               break;
+                       }
+                       zacep = (zfs_ace_t *)ptr;
+                       zacep->z_hdr.z_access_mask =
+                           BSWAP_32(zacep->z_hdr.z_access_mask);
+                       zacep->z_hdr.z_flags = BSWAP_16(zacep->z_hdr.z_flags);
+                       ace_type = zacep->z_hdr.z_type =
+                           BSWAP_16(zacep->z_hdr.z_type);
+                       entry_type = zacep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+               } else {
+                       /* Overrun avoidance */
+                       if (ptr + sizeof (ace_t) > end) {
+                               break;
+                       }
+                       acep = (ace_t *)ptr;
+                       acep->a_access_mask = BSWAP_32(acep->a_access_mask);
+                       acep->a_flags = BSWAP_16(acep->a_flags);
+                       ace_type = acep->a_type = BSWAP_16(acep->a_type);
+                       acep->a_who = BSWAP_32(acep->a_who);
+                       entry_type = acep->a_flags & ACE_TYPE_FLAGS;
+               }
+               switch (entry_type) {
+               case ACE_OWNER:
+               case ACE_EVERYONE:
+               case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+                       entry_size = zfs_layout ?
+                           sizeof (zfs_ace_hdr_t) : sizeof (ace_t);
+                       break;
+               case ACE_IDENTIFIER_GROUP:
+               default:
+                       /* Overrun avoidance */
+                       if (zfs_layout) {
+                               if (ptr + sizeof (zfs_ace_t) <= end) {
+                                       zacep->z_fuid = BSWAP_64(zacep->z_fuid);
+                               } else {
+                                       entry_size = sizeof (zfs_ace_t);
+                                       break;
+                               }
+                       }
+                       switch (ace_type) {
+                       case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+                       case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+                       case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+                       case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+                               entry_size = zfs_layout ?
+                                   sizeof (zfs_object_ace_t) :
+                                   sizeof (ace_object_t);
+                               break;
+                       default:
+                               entry_size = zfs_layout ? sizeof (zfs_ace_t) :
+                                   sizeof (ace_t);
+                               break;
+                       }
+               }
+               ptr = ptr + entry_size;
+       }
+}
+
+/* ARGSUSED */
+void
+zfs_oldacl_byteswap(void *buf, size_t size)
+{
+       int cnt;
+
+       /*
+        * Arggh, since we don't know how many ACEs are in
+        * the array, we have to swap the entire block
+        */
+
+       cnt = size / sizeof (ace_t);
+
+       zfs_oldace_byteswap((ace_t *)buf, cnt);
+}
+
+/* ARGSUSED */
+void
+zfs_acl_byteswap(void *buf, size_t size)
+{
+       zfs_ace_byteswap(buf, size, B_TRUE);
+}
+
+void
+zfs_znode_byteswap(void *buf, size_t size)
+{
+       znode_phys_t *zp = buf;
+
+       ASSERT(size >= sizeof (znode_phys_t));
+
+       zp->zp_crtime[0] = BSWAP_64(zp->zp_crtime[0]);
+       zp->zp_crtime[1] = BSWAP_64(zp->zp_crtime[1]);
+       zp->zp_atime[0] = BSWAP_64(zp->zp_atime[0]);
+       zp->zp_atime[1] = BSWAP_64(zp->zp_atime[1]);
+       zp->zp_mtime[0] = BSWAP_64(zp->zp_mtime[0]);
+       zp->zp_mtime[1] = BSWAP_64(zp->zp_mtime[1]);
+       zp->zp_ctime[0] = BSWAP_64(zp->zp_ctime[0]);
+       zp->zp_ctime[1] = BSWAP_64(zp->zp_ctime[1]);
+       zp->zp_gen = BSWAP_64(zp->zp_gen);
+       zp->zp_mode = BSWAP_64(zp->zp_mode);
+       zp->zp_size = BSWAP_64(zp->zp_size);
+       zp->zp_parent = BSWAP_64(zp->zp_parent);
+       zp->zp_links = BSWAP_64(zp->zp_links);
+       zp->zp_xattr = BSWAP_64(zp->zp_xattr);
+       zp->zp_rdev = BSWAP_64(zp->zp_rdev);
+       zp->zp_flags = BSWAP_64(zp->zp_flags);
+       zp->zp_uid = BSWAP_64(zp->zp_uid);
+       zp->zp_gid = BSWAP_64(zp->zp_gid);
+       zp->zp_zap = BSWAP_64(zp->zp_zap);
+       zp->zp_pad[0] = BSWAP_64(zp->zp_pad[0]);
+       zp->zp_pad[1] = BSWAP_64(zp->zp_pad[1]);
+       zp->zp_pad[2] = BSWAP_64(zp->zp_pad[2]);
+
+       zp->zp_acl.z_acl_extern_obj = BSWAP_64(zp->zp_acl.z_acl_extern_obj);
+       zp->zp_acl.z_acl_size = BSWAP_32(zp->zp_acl.z_acl_size);
+       zp->zp_acl.z_acl_version = BSWAP_16(zp->zp_acl.z_acl_version);
+       zp->zp_acl.z_acl_count = BSWAP_16(zp->zp_acl.z_acl_count);
+       if (zp->zp_acl.z_acl_version == ZFS_ACL_VERSION) {
+               zfs_acl_byteswap((void *)&zp->zp_acl.z_ace_data[0],
+                   ZFS_ACE_SPACE);
+       } else {
+               zfs_oldace_byteswap((ace_t *)&zp->zp_acl.z_ace_data[0],
+                   ACE_SLOT_CNT);
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zfs_oldacl_byteswap);
+EXPORT_SYMBOL(zfs_acl_byteswap);
+EXPORT_SYMBOL(zfs_znode_byteswap);
+#endif
diff --git a/zfs/module/zfs/zfs_ctldir.c b/zfs/module/zfs/zfs_ctldir.c
new file mode 100644 (file)
index 0000000..2767b23
--- /dev/null
@@ -0,0 +1,1290 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * LLNL-CODE-403049.
+ * Rewritten for Linux by:
+ *   Rohan Puri <rohan.puri15@gmail.com>
+ *   Brian Behlendorf <behlendorf1@llnl.gov>
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+/*
+ * ZFS control directory (a.k.a. ".zfs")
+ *
+ * This directory provides a common location for all ZFS meta-objects.
+ * Currently, this is only the 'snapshot' and 'shares' directory, but this may
+ * expand in the future.  The elements are built dynamically, as the hierarchy
+ * does not actually exist on disk.
+ *
+ * For 'snapshot', we don't want to have all snapshots always mounted, because
+ * this would take up a huge amount of space in /etc/mnttab.  We have three
+ * types of objects:
+ *
+ *     ctldir ------> snapshotdir -------> snapshot
+ *                                             |
+ *                                             |
+ *                                             V
+ *                                         mounted fs
+ *
+ * The 'snapshot' node contains just enough information to lookup '..' and act
+ * as a mountpoint for the snapshot.  Whenever we lookup a specific snapshot, we
+ * perform an automount of the underlying filesystem and return the
+ * corresponding inode.
+ *
+ * All mounts are handled automatically by an user mode helper which invokes
+ * the mount mount procedure.  Unmounts are handled by allowing the mount
+ * point to expire so the kernel may automatically unmount it.
+ *
+ * The '.zfs', '.zfs/snapshot', and all directories created under
+ * '.zfs/snapshot' (ie: '.zfs/snapshot/<snapname>') all share the same
+ * share the same zfs_sb_t as the head filesystem (what '.zfs' lives under).
+ *
+ * File systems mounted on top of the '.zfs/snapshot/<snapname>' paths
+ * (ie: snapshots) are complete ZFS filesystems and have their own unique
+ * zfs_sb_t.  However, the fsid reported by these mounts will be the same
+ * as that used by the parent zfs_sb_t to make NFS happy.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_vnops.h>
+#include <sys/stat.h>
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_destroy.h>
+#include <sys/dsl_deleg.h>
+#include <sys/mount.h>
+#include <sys/zpl.h>
+#include "zfs_namecheck.h"
+
+/*
+ * Two AVL trees are maintained which contain all currently automounted
+ * snapshots.  Every automounted snapshots maps to a single zfs_snapentry_t
+ * entry which MUST:
+ *
+ *   - be attached to both trees, and
+ *   - be unique, no duplicate entries are allowed.
+ *
+ * The zfs_snapshots_by_name tree is indexed by the full dataset name
+ * while the zfs_snapshots_by_objsetid tree is indexed by the unique
+ * objsetid.  This allows for fast lookups either by name or objsetid.
+ */
+static avl_tree_t zfs_snapshots_by_name;
+static avl_tree_t zfs_snapshots_by_objsetid;
+static krwlock_t zfs_snapshot_lock;
+
+/*
+ * Control Directory Tunables (.zfs)
+ */
+int zfs_expire_snapshot = ZFSCTL_EXPIRE_SNAPSHOT;
+int zfs_admin_snapshot = 0;
+
+/*
+ * Dedicated task queue for unmounting snapshots.
+ */
+static taskq_t *zfs_expire_taskq;
+
+typedef struct {
+       char            *se_name;       /* full snapshot name */
+       char            *se_path;       /* full mount path */
+       spa_t           *se_spa;        /* pool spa */
+       uint64_t        se_objsetid;    /* snapshot objset id */
+       struct dentry   *se_root_dentry; /* snapshot root dentry */
+       taskqid_t       se_taskqid;     /* scheduled unmount taskqid */
+       avl_node_t      se_node_name;   /* zfs_snapshots_by_name link */
+       avl_node_t      se_node_objsetid; /* zfs_snapshots_by_objsetid link */
+       refcount_t      se_refcount;    /* reference count */
+} zfs_snapentry_t;
+
+static void zfsctl_snapshot_unmount_delay_impl(zfs_snapentry_t *se, int delay);
+
+/*
+ * Allocate a new zfs_snapentry_t being careful to make a copy of the
+ * the snapshot name and provided mount point.  No reference is taken.
+ */
+static zfs_snapentry_t *
+zfsctl_snapshot_alloc(char *full_name, char *full_path, spa_t *spa,
+    uint64_t objsetid, struct dentry *root_dentry)
+{
+       zfs_snapentry_t *se;
+
+       se = kmem_zalloc(sizeof (zfs_snapentry_t), KM_SLEEP);
+
+       se->se_name = strdup(full_name);
+       se->se_path = strdup(full_path);
+       se->se_spa = spa;
+       se->se_objsetid = objsetid;
+       se->se_root_dentry = root_dentry;
+       se->se_taskqid = -1;
+
+       refcount_create(&se->se_refcount);
+
+       return (se);
+}
+
+/*
+ * Free a zfs_snapentry_t the called must ensure there are no active
+ * references.
+ */
+static void
+zfsctl_snapshot_free(zfs_snapentry_t *se)
+{
+       refcount_destroy(&se->se_refcount);
+       strfree(se->se_name);
+       strfree(se->se_path);
+
+       kmem_free(se, sizeof (zfs_snapentry_t));
+}
+
+/*
+ * Hold a reference on the zfs_snapentry_t.
+ */
+static void
+zfsctl_snapshot_hold(zfs_snapentry_t *se)
+{
+       refcount_add(&se->se_refcount, NULL);
+}
+
+/*
+ * Release a reference on the zfs_snapentry_t.  When the number of
+ * references drops to zero the structure will be freed.
+ */
+static void
+zfsctl_snapshot_rele(zfs_snapentry_t *se)
+{
+       if (refcount_remove(&se->se_refcount, NULL) == 0)
+               zfsctl_snapshot_free(se);
+}
+
+/*
+ * Add a zfs_snapentry_t to both the zfs_snapshots_by_name and
+ * zfs_snapshots_by_objsetid trees.  While the zfs_snapentry_t is part
+ * of the trees a reference is held.
+ */
+static void
+zfsctl_snapshot_add(zfs_snapentry_t *se)
+{
+       ASSERT(RW_WRITE_HELD(&zfs_snapshot_lock));
+       refcount_add(&se->se_refcount, NULL);
+       avl_add(&zfs_snapshots_by_name, se);
+       avl_add(&zfs_snapshots_by_objsetid, se);
+}
+
+/*
+ * Remove a zfs_snapentry_t from both the zfs_snapshots_by_name and
+ * zfs_snapshots_by_objsetid trees.  Upon removal a reference is dropped,
+ * this can result in the structure being freed if that was the last
+ * remaining reference.
+ */
+static void
+zfsctl_snapshot_remove(zfs_snapentry_t *se)
+{
+       ASSERT(RW_WRITE_HELD(&zfs_snapshot_lock));
+       avl_remove(&zfs_snapshots_by_name, se);
+       avl_remove(&zfs_snapshots_by_objsetid, se);
+       zfsctl_snapshot_rele(se);
+}
+
+/*
+ * Snapshot name comparison function for the zfs_snapshots_by_name.
+ */
+static int
+snapentry_compare_by_name(const void *a, const void *b)
+{
+       const zfs_snapentry_t *se_a = a;
+       const zfs_snapentry_t *se_b = b;
+       int ret;
+
+       ret = strcmp(se_a->se_name, se_b->se_name);
+
+       if (ret < 0)
+               return (-1);
+       else if (ret > 0)
+               return (1);
+       else
+               return (0);
+}
+
+/*
+ * Snapshot name comparison function for the zfs_snapshots_by_objsetid.
+ */
+static int
+snapentry_compare_by_objsetid(const void *a, const void *b)
+{
+       const zfs_snapentry_t *se_a = a;
+       const zfs_snapentry_t *se_b = b;
+
+       if (se_a->se_spa != se_b->se_spa)
+               return ((ulong_t)se_a->se_spa < (ulong_t)se_b->se_spa ? -1 : 1);
+
+       if (se_a->se_objsetid < se_b->se_objsetid)
+               return (-1);
+       else if (se_a->se_objsetid > se_b->se_objsetid)
+               return (1);
+       else
+               return (0);
+}
+
+/*
+ * Find a zfs_snapentry_t in zfs_snapshots_by_name.  If the snapname
+ * is found a pointer to the zfs_snapentry_t is returned and a reference
+ * taken on the structure.  The caller is responsible for dropping the
+ * reference with zfsctl_snapshot_rele().  If the snapname is not found
+ * NULL will be returned.
+ */
+static zfs_snapentry_t *
+zfsctl_snapshot_find_by_name(char *snapname)
+{
+       zfs_snapentry_t *se, search;
+
+       ASSERT(RW_LOCK_HELD(&zfs_snapshot_lock));
+
+       search.se_name = snapname;
+       se = avl_find(&zfs_snapshots_by_name, &search, NULL);
+       if (se)
+               refcount_add(&se->se_refcount, NULL);
+
+       return (se);
+}
+
+/*
+ * Find a zfs_snapentry_t in zfs_snapshots_by_objsetid given the objset id
+ * rather than the snapname.  In all other respects it behaves the same
+ * as zfsctl_snapshot_find_by_name().
+ */
+static zfs_snapentry_t *
+zfsctl_snapshot_find_by_objsetid(spa_t *spa, uint64_t objsetid)
+{
+       zfs_snapentry_t *se, search;
+
+       ASSERT(RW_LOCK_HELD(&zfs_snapshot_lock));
+
+       search.se_spa = spa;
+       search.se_objsetid = objsetid;
+       se = avl_find(&zfs_snapshots_by_objsetid, &search, NULL);
+       if (se)
+               refcount_add(&se->se_refcount, NULL);
+
+       return (se);
+}
+
+/*
+ * Rename a zfs_snapentry_t in the zfs_snapshots_by_name.  The structure is
+ * removed, renamed, and added back to the new correct location in the tree.
+ */
+static int
+zfsctl_snapshot_rename(char *old_snapname, char *new_snapname)
+{
+       zfs_snapentry_t *se;
+
+       ASSERT(RW_WRITE_HELD(&zfs_snapshot_lock));
+
+       se = zfsctl_snapshot_find_by_name(old_snapname);
+       if (se == NULL)
+               return (ENOENT);
+
+       zfsctl_snapshot_remove(se);
+       strfree(se->se_name);
+       se->se_name = strdup(new_snapname);
+       zfsctl_snapshot_add(se);
+       zfsctl_snapshot_rele(se);
+
+       return (0);
+}
+
+/*
+ * Delayed task responsible for unmounting an expired automounted snapshot.
+ */
+static void
+snapentry_expire(void *data)
+{
+       zfs_snapentry_t *se = (zfs_snapentry_t *)data;
+       spa_t *spa = se->se_spa;
+       uint64_t objsetid = se->se_objsetid;
+
+       if (zfs_expire_snapshot <= 0) {
+               zfsctl_snapshot_rele(se);
+               return;
+       }
+
+       se->se_taskqid = -1;
+       (void) zfsctl_snapshot_unmount(se->se_name, MNT_EXPIRE);
+       zfsctl_snapshot_rele(se);
+
+       /*
+        * Reschedule the unmount if the zfs_snapentry_t wasn't removed.
+        * This can occur when the snapshot is busy.
+        */
+       rw_enter(&zfs_snapshot_lock, RW_READER);
+       if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
+               zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
+               zfsctl_snapshot_rele(se);
+       }
+       rw_exit(&zfs_snapshot_lock);
+}
+
+/*
+ * Cancel an automatic unmount of a snapname.  This callback is responsible
+ * for dropping the reference on the zfs_snapentry_t which was taken when
+ * during dispatch.
+ */
+static void
+zfsctl_snapshot_unmount_cancel(zfs_snapentry_t *se)
+{
+       ASSERT(RW_LOCK_HELD(&zfs_snapshot_lock));
+
+       if (taskq_cancel_id(zfs_expire_taskq, se->se_taskqid) == 0) {
+               se->se_taskqid = -1;
+               zfsctl_snapshot_rele(se);
+       }
+}
+
+/*
+ * Dispatch the unmount task for delayed handling with a hold protecting it.
+ */
+static void
+zfsctl_snapshot_unmount_delay_impl(zfs_snapentry_t *se, int delay)
+{
+       ASSERT3S(se->se_taskqid, ==, -1);
+
+       if (delay <= 0)
+               return;
+
+       zfsctl_snapshot_hold(se);
+       se->se_taskqid = taskq_dispatch_delay(zfs_expire_taskq,
+           snapentry_expire, se, TQ_SLEEP, ddi_get_lbolt() + delay * HZ);
+}
+
+/*
+ * Schedule an automatic unmount of objset id to occur in delay seconds from
+ * now.  Any previous delayed unmount will be cancelled in favor of the
+ * updated deadline.  A reference is taken by zfsctl_snapshot_find_by_name()
+ * and held until the outstanding task is handled or cancelled.
+ */
+int
+zfsctl_snapshot_unmount_delay(spa_t *spa, uint64_t objsetid, int delay)
+{
+       zfs_snapentry_t *se;
+       int error = ENOENT;
+
+       rw_enter(&zfs_snapshot_lock, RW_READER);
+       if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
+               zfsctl_snapshot_unmount_cancel(se);
+               zfsctl_snapshot_unmount_delay_impl(se, delay);
+               zfsctl_snapshot_rele(se);
+               error = 0;
+       }
+       rw_exit(&zfs_snapshot_lock);
+
+       return (error);
+}
+
+/*
+ * Check if snapname is currently mounted.  Returned non-zero when mounted
+ * and zero when unmounted.
+ */
+static boolean_t
+zfsctl_snapshot_ismounted(char *snapname)
+{
+       zfs_snapentry_t *se;
+       boolean_t ismounted = B_FALSE;
+
+       rw_enter(&zfs_snapshot_lock, RW_READER);
+       if ((se = zfsctl_snapshot_find_by_name(snapname)) != NULL) {
+               zfsctl_snapshot_rele(se);
+               ismounted = B_TRUE;
+       }
+       rw_exit(&zfs_snapshot_lock);
+
+       return (ismounted);
+}
+
+/*
+ * Check if the given inode is a part of the virtual .zfs directory.
+ */
+boolean_t
+zfsctl_is_node(struct inode *ip)
+{
+       return (ITOZ(ip)->z_is_ctldir);
+}
+
+/*
+ * Check if the given inode is a .zfs/snapshots/snapname directory.
+ */
+boolean_t
+zfsctl_is_snapdir(struct inode *ip)
+{
+       return (zfsctl_is_node(ip) && (ip->i_ino <= ZFSCTL_INO_SNAPDIRS));
+}
+
+/*
+ * Allocate a new inode with the passed id and ops.
+ */
+static struct inode *
+zfsctl_inode_alloc(zfs_sb_t *zsb, uint64_t id,
+    const struct file_operations *fops, const struct inode_operations *ops)
+{
+       struct timespec now = current_fs_time(zsb->z_sb);
+       struct inode *ip;
+       znode_t *zp;
+
+       ip = new_inode(zsb->z_sb);
+       if (ip == NULL)
+               return (NULL);
+
+       zp = ITOZ(ip);
+       ASSERT3P(zp->z_dirlocks, ==, NULL);
+       ASSERT3P(zp->z_acl_cached, ==, NULL);
+       ASSERT3P(zp->z_xattr_cached, ==, NULL);
+       zp->z_id = id;
+       zp->z_unlinked = 0;
+       zp->z_atime_dirty = 0;
+       zp->z_zn_prefetch = 0;
+       zp->z_moved = 0;
+       zp->z_sa_hdl = NULL;
+       zp->z_blksz = 0;
+       zp->z_seq = 0;
+       zp->z_mapcnt = 0;
+       zp->z_gen = 0;
+       zp->z_size = 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_ino = id;
+       ip->i_mode = (S_IFDIR | S_IRUGO | S_IXUGO);
+       ip->i_uid = SUID_TO_KUID(0);
+       ip->i_gid = SGID_TO_KGID(0);
+       ip->i_blkbits = SPA_MINBLOCKSHIFT;
+       ip->i_atime = now;
+       ip->i_mtime = now;
+       ip->i_ctime = now;
+       ip->i_fop = fops;
+       ip->i_op = ops;
+
+       if (insert_inode_locked(ip)) {
+               unlock_new_inode(ip);
+               iput(ip);
+               return (NULL);
+       }
+
+       mutex_enter(&zsb->z_znodes_lock);
+       list_insert_tail(&zsb->z_all_znodes, zp);
+       zsb->z_nr_znodes++;
+       membar_producer();
+       mutex_exit(&zsb->z_znodes_lock);
+
+       unlock_new_inode(ip);
+
+       return (ip);
+}
+
+/*
+ * Lookup the inode with given id, it will be allocated if needed.
+ */
+static struct inode *
+zfsctl_inode_lookup(zfs_sb_t *zsb, uint64_t id,
+    const struct file_operations *fops, const struct inode_operations *ops)
+{
+       struct inode *ip = NULL;
+
+       while (ip == NULL) {
+               ip = ilookup(zsb->z_sb, (unsigned long)id);
+               if (ip)
+                       break;
+
+               /* May fail due to concurrent zfsctl_inode_alloc() */
+               ip = zfsctl_inode_alloc(zsb, id, fops, ops);
+       }
+
+       return (ip);
+}
+
+/*
+ * Create the '.zfs' directory.  This directory is cached as part of the VFS
+ * structure.  This results in a hold on the zfs_sb_t.  The code in zfs_umount()
+ * therefore checks against a vfs_count of 2 instead of 1.  This reference
+ * is removed when the ctldir is destroyed in the unmount.  All other entities
+ * under the '.zfs' directory are created dynamically as needed.
+ *
+ * Because the dynamically created '.zfs' directory entries assume the use
+ * of 64-bit inode numbers this support must be disabled on 32-bit systems.
+ */
+int
+zfsctl_create(zfs_sb_t *zsb)
+{
+#if defined(CONFIG_64BIT)
+       ASSERT(zsb->z_ctldir == NULL);
+
+       zsb->z_ctldir = zfsctl_inode_alloc(zsb, ZFSCTL_INO_ROOT,
+           &zpl_fops_root, &zpl_ops_root);
+       if (zsb->z_ctldir == NULL)
+               return (SET_ERROR(ENOENT));
+
+       return (0);
+#else
+       return (SET_ERROR(EOPNOTSUPP));
+#endif /* CONFIG_64BIT */
+}
+
+/*
+ * Destroy the '.zfs' directory or remove a snapshot from zfs_snapshots_by_name.
+ * Only called when the filesystem is unmounted.
+ */
+void
+zfsctl_destroy(zfs_sb_t *zsb)
+{
+       if (zsb->z_issnap) {
+               zfs_snapentry_t *se;
+               spa_t *spa = zsb->z_os->os_spa;
+               uint64_t objsetid = dmu_objset_id(zsb->z_os);
+
+               rw_enter(&zfs_snapshot_lock, RW_WRITER);
+               if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid))
+                   != NULL) {
+                       zfsctl_snapshot_unmount_cancel(se);
+                       zfsctl_snapshot_remove(se);
+                       zfsctl_snapshot_rele(se);
+               }
+               rw_exit(&zfs_snapshot_lock);
+       } else if (zsb->z_ctldir) {
+               iput(zsb->z_ctldir);
+               zsb->z_ctldir = NULL;
+       }
+}
+
+/*
+ * Given a root znode, retrieve the associated .zfs directory.
+ * Add a hold to the vnode and return it.
+ */
+struct inode *
+zfsctl_root(znode_t *zp)
+{
+       ASSERT(zfs_has_ctldir(zp));
+       igrab(ZTOZSB(zp)->z_ctldir);
+       return (ZTOZSB(zp)->z_ctldir);
+}
+/*
+ * Generate a long fid which includes the root object and objset of a
+ * snapshot but not the generation number.  For the root object the
+ * generation number is ignored when zero to avoid needing to open
+ * the dataset when generating fids for the snapshot names.
+ */
+static int
+zfsctl_snapdir_fid(struct inode *ip, fid_t *fidp)
+{
+       zfs_sb_t *zsb = ITOZSB(ip);
+       zfid_short_t *zfid = (zfid_short_t *)fidp;
+       zfid_long_t *zlfid = (zfid_long_t *)fidp;
+       uint32_t gen = 0;
+       uint64_t object;
+       uint64_t objsetid;
+       int i;
+
+       object = zsb->z_root;
+       objsetid = ZFSCTL_INO_SNAPDIRS - ip->i_ino;
+       zfid->zf_len = LONG_FID_LEN;
+
+       for (i = 0; i < sizeof (zfid->zf_object); i++)
+               zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
+
+       for (i = 0; i < sizeof (zfid->zf_gen); i++)
+               zfid->zf_gen[i] = (uint8_t)(gen >> (8 * i));
+
+       for (i = 0; i < sizeof (zlfid->zf_setid); i++)
+               zlfid->zf_setid[i] = (uint8_t)(objsetid >> (8 * i));
+
+       for (i = 0; i < sizeof (zlfid->zf_setgen); i++)
+               zlfid->zf_setgen[i] = 0;
+
+       return (0);
+}
+
+/*
+ * Generate an appropriate fid for an entry in the .zfs directory.
+ */
+int
+zfsctl_fid(struct inode *ip, fid_t *fidp)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       uint64_t        object = zp->z_id;
+       zfid_short_t    *zfid;
+       int             i;
+
+       ZFS_ENTER(zsb);
+
+       if (fidp->fid_len < SHORT_FID_LEN) {
+               fidp->fid_len = SHORT_FID_LEN;
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENOSPC));
+       }
+
+       if (zfsctl_is_snapdir(ip)) {
+               ZFS_EXIT(zsb);
+               return (zfsctl_snapdir_fid(ip, fidp));
+       }
+
+       zfid = (zfid_short_t *)fidp;
+
+       zfid->zf_len = SHORT_FID_LEN;
+
+       for (i = 0; i < sizeof (zfid->zf_object); i++)
+               zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
+
+       /* .zfs znodes always have a generation number of 0 */
+       for (i = 0; i < sizeof (zfid->zf_gen); i++)
+               zfid->zf_gen[i] = 0;
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+
+/*
+ * Construct a full dataset name in full_name: "pool/dataset@snap_name"
+ */
+static int
+zfsctl_snapshot_name(zfs_sb_t *zsb, const char *snap_name, int len,
+    char *full_name)
+{
+       objset_t *os = zsb->z_os;
+
+       if (zfs_component_namecheck(snap_name, NULL, NULL) != 0)
+               return (SET_ERROR(EILSEQ));
+
+       dmu_objset_name(os, full_name);
+       if ((strlen(full_name) + 1 + strlen(snap_name)) >= len)
+               return (SET_ERROR(ENAMETOOLONG));
+
+       (void) strcat(full_name, "@");
+       (void) strcat(full_name, snap_name);
+
+       return (0);
+}
+
+/*
+ * Returns full path in full_path: "/pool/dataset/.zfs/snapshot/snap_name/"
+ */
+static int
+zfsctl_snapshot_path(struct path *path, int len, char *full_path)
+{
+       char *path_buffer, *path_ptr;
+       int path_len, error = 0;
+
+       path_buffer = kmem_alloc(len, KM_SLEEP);
+
+       path_ptr = d_path(path, path_buffer, len);
+       if (IS_ERR(path_ptr)) {
+               error = -PTR_ERR(path_ptr);
+               goto out;
+       }
+
+       path_len = path_buffer + len - 1 - path_ptr;
+       if (path_len > len) {
+               error = SET_ERROR(EFAULT);
+               goto out;
+       }
+
+       memcpy(full_path, path_ptr, path_len);
+       full_path[path_len] = '\0';
+out:
+       kmem_free(path_buffer, len);
+
+       return (error);
+}
+
+/*
+ * Returns full path in full_path: "/pool/dataset/.zfs/snapshot/snap_name/"
+ */
+static int
+zfsctl_snapshot_path_objset(zfs_sb_t *zsb, uint64_t objsetid,
+    int path_len, char *full_path)
+{
+       objset_t *os = zsb->z_os;
+       fstrans_cookie_t cookie;
+       char *snapname;
+       boolean_t case_conflict;
+       uint64_t id, pos = 0;
+       int error = 0;
+
+       if (zsb->z_mntopts->z_mntpoint == NULL)
+               return (ENOENT);
+
+       cookie = spl_fstrans_mark();
+       snapname = kmem_alloc(MAXNAMELEN, 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);
+               dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+               if (error)
+                       goto out;
+
+               if (id == objsetid)
+                       break;
+       }
+
+       memset(full_path, 0, path_len);
+       snprintf(full_path, path_len - 1, "%s/.zfs/snapshot/%s",
+           zsb->z_mntopts->z_mntpoint, snapname);
+out:
+       kmem_free(snapname, MAXNAMELEN);
+       spl_fstrans_unmark(cookie);
+
+       return (error);
+}
+
+/*
+ * Special case the handling of "..".
+ */
+int
+zfsctl_root_lookup(struct inode *dip, char *name, struct inode **ipp,
+    int flags, cred_t *cr, int *direntflags, pathname_t *realpnp)
+{
+       zfs_sb_t *zsb = ITOZSB(dip);
+       int error = 0;
+
+       ZFS_ENTER(zsb);
+
+       if (strcmp(name, "..") == 0) {
+               *ipp = dip->i_sb->s_root->d_inode;
+       } else if (strcmp(name, ZFS_SNAPDIR_NAME) == 0) {
+               *ipp = zfsctl_inode_lookup(zsb, ZFSCTL_INO_SNAPDIR,
+                   &zpl_fops_snapdir, &zpl_ops_snapdir);
+       } else if (strcmp(name, ZFS_SHAREDIR_NAME) == 0) {
+               *ipp = zfsctl_inode_lookup(zsb, ZFSCTL_INO_SHARES,
+                   &zpl_fops_shares, &zpl_ops_shares);
+       } else {
+               *ipp = NULL;
+       }
+
+       if (*ipp == NULL)
+               error = SET_ERROR(ENOENT);
+
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+/*
+ * Lookup entry point for the 'snapshot' directory.  Try to open the
+ * snapshot if it exist, creating the pseudo filesystem inode as necessary.
+ * Perform a mount of the associated dataset on top of the inode.
+ */
+int
+zfsctl_snapdir_lookup(struct inode *dip, char *name, struct inode **ipp,
+    int flags, cred_t *cr, int *direntflags, pathname_t *realpnp)
+{
+       zfs_sb_t *zsb = ITOZSB(dip);
+       uint64_t id;
+       int error;
+
+       ZFS_ENTER(zsb);
+
+       error = dmu_snapshot_lookup(zsb->z_os, name, &id);
+       if (error) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       *ipp = zfsctl_inode_lookup(zsb, ZFSCTL_INO_SNAPDIRS - id,
+           &simple_dir_operations, &simple_dir_inode_operations);
+       if (*ipp == NULL)
+               error = SET_ERROR(ENOENT);
+
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+/*
+ * Renaming a directory under '.zfs/snapshot' will automatically trigger
+ * a rename of the snapshot to the new given name.  The rename is confined
+ * to the '.zfs/snapshot' directory snapshots cannot be moved elsewhere.
+ */
+int
+zfsctl_snapdir_rename(struct inode *sdip, char *snm,
+    struct inode *tdip, char *tnm, cred_t *cr, int flags)
+{
+       zfs_sb_t *zsb = ITOZSB(sdip);
+       char *to, *from, *real, *fsname;
+       int error;
+
+       if (!zfs_admin_snapshot)
+               return (EACCES);
+
+       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);
+
+       if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
+               error = dmu_snapshot_realname(zsb->z_os, snm, real,
+                   MAXNAMELEN, NULL);
+               if (error == 0) {
+                       snm = real;
+               } else if (error != ENOTSUP) {
+                       goto out;
+               }
+       }
+
+       dmu_objset_name(zsb->z_os, fsname);
+
+       error = zfsctl_snapshot_name(ITOZSB(sdip), snm, MAXNAMELEN, from);
+       if (error == 0)
+               error = zfsctl_snapshot_name(ITOZSB(tdip), tnm, MAXNAMELEN, to);
+       if (error == 0)
+               error = zfs_secpolicy_rename_perms(from, to, cr);
+       if (error != 0)
+               goto out;
+
+       /*
+        * Cannot move snapshots out of the snapdir.
+        */
+       if (sdip != tdip) {
+               error = SET_ERROR(EINVAL);
+               goto out;
+       }
+
+       /*
+        * No-op when names are identical.
+        */
+       if (strcmp(snm, tnm) == 0) {
+               error = 0;
+               goto out;
+       }
+
+       rw_enter(&zfs_snapshot_lock, RW_WRITER);
+
+       error = dsl_dataset_rename_snapshot(fsname, snm, tnm, B_FALSE);
+       if (error == 0)
+               (void) zfsctl_snapshot_rename(snm, tnm);
+
+       rw_exit(&zfs_snapshot_lock);
+out:
+       kmem_free(from, MAXNAMELEN);
+       kmem_free(to, MAXNAMELEN);
+       kmem_free(real, MAXNAMELEN);
+       kmem_free(fsname, MAXNAMELEN);
+
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+/*
+ * Removing a directory under '.zfs/snapshot' will automatically trigger
+ * the removal of the snapshot with the given name.
+ */
+int
+zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
+{
+       zfs_sb_t *zsb = ITOZSB(dip);
+       char *snapname, *real;
+       int error;
+
+       if (!zfs_admin_snapshot)
+               return (EACCES);
+
+       ZFS_ENTER(zsb);
+
+       snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       real = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+       if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
+               error = dmu_snapshot_realname(zsb->z_os, name, real,
+                   MAXNAMELEN, NULL);
+               if (error == 0) {
+                       name = real;
+               } else if (error != ENOTSUP) {
+                       goto out;
+               }
+       }
+
+       error = zfsctl_snapshot_name(ITOZSB(dip), name, MAXNAMELEN, snapname);
+       if (error == 0)
+               error = zfs_secpolicy_destroy_perms(snapname, cr);
+       if (error != 0)
+               goto out;
+
+       error = zfsctl_snapshot_unmount(snapname, MNT_FORCE);
+       if ((error == 0) || (error == ENOENT))
+               error = dsl_destroy_snapshot(snapname, B_FALSE);
+out:
+       kmem_free(snapname, MAXNAMELEN);
+       kmem_free(real, MAXNAMELEN);
+
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+/*
+ * Creating a directory under '.zfs/snapshot' will automatically trigger
+ * the creation of a new snapshot with the given name.
+ */
+int
+zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
+       struct inode **ipp, cred_t *cr, int flags)
+{
+       zfs_sb_t *zsb = ITOZSB(dip);
+       char *dsname;
+       int error;
+
+       if (!zfs_admin_snapshot)
+               return (EACCES);
+
+       dsname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+       if (zfs_component_namecheck(dirname, NULL, NULL) != 0) {
+               error = SET_ERROR(EILSEQ);
+               goto out;
+       }
+
+       dmu_objset_name(zsb->z_os, dsname);
+
+       error = zfs_secpolicy_snapshot_perms(dsname, cr);
+       if (error != 0)
+               goto out;
+
+       if (error == 0) {
+               error = dmu_objset_snapshot_one(dsname, dirname);
+               if (error != 0)
+                       goto out;
+
+               error = zfsctl_snapdir_lookup(dip, dirname, ipp,
+                   0, cr, NULL, NULL);
+       }
+out:
+       kmem_free(dsname, MAXNAMELEN);
+
+       return (error);
+}
+
+/*
+ * Attempt to unmount a snapshot by making a call to user space.
+ * There is no assurance that this can or will succeed, is just a
+ * best effort.  In the case where it does fail, perhaps because
+ * it's in use, the unmount will fail harmlessly.
+ */
+int
+zfsctl_snapshot_unmount(char *snapname, int flags)
+{
+       char *argv[] = { "/usr/bin/env", "umount", "-t", "zfs", "-n", NULL,
+           NULL };
+       char *envp[] = { NULL };
+       zfs_snapentry_t *se;
+       int error;
+
+       rw_enter(&zfs_snapshot_lock, RW_READER);
+       if ((se = zfsctl_snapshot_find_by_name(snapname)) == NULL) {
+               rw_exit(&zfs_snapshot_lock);
+               return (ENOENT);
+       }
+       rw_exit(&zfs_snapshot_lock);
+
+       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);
+       zfsctl_snapshot_rele(se);
+
+
+       /*
+        * The umount system utility will return 256 on error.  We must
+        * assume this error is because the file system is busy so it is
+        * converted to the more sensible EBUSY.
+        */
+       if (error)
+               error = SET_ERROR(EBUSY);
+
+       return (error);
+}
+
+#define        MOUNT_BUSY 0x80         /* Mount failed due to EBUSY (from mntent.h) */
+
+int
+zfsctl_snapshot_mount(struct path *path, int flags)
+{
+       struct dentry *dentry = path->dentry;
+       struct inode *ip = dentry->d_inode;
+       zfs_sb_t *zsb;
+       zfs_sb_t *snap_zsb;
+       zfs_snapentry_t *se;
+       char *full_name, *full_path;
+       char *argv[] = { "/usr/bin/env", "mount", "-t", "zfs", "-n", NULL, NULL,
+           NULL };
+       char *envp[] = { NULL };
+       int error;
+       struct path spath;
+
+       if (ip == NULL)
+               return (EISDIR);
+
+       zsb = ITOZSB(ip);
+       ZFS_ENTER(zsb);
+
+       full_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+       full_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+       error = zfsctl_snapshot_name(zsb, dname(dentry),
+           MAXNAMELEN, full_name);
+       if (error)
+               goto error;
+
+       error = zfsctl_snapshot_path(path, MAXPATHLEN, full_path);
+       if (error)
+               goto error;
+
+       /*
+        * Multiple concurrent automounts of a snapshot are never allowed.
+        * The snapshot may be manually mounted as many times as desired.
+        */
+       if (zfsctl_snapshot_ismounted(full_name)) {
+               error = 0;
+               goto error;
+       }
+
+       /*
+        * Attempt to mount the snapshot from user space.  Normally this
+        * would be done using the vfs_kern_mount() function, however that
+        * function is marked GPL-only and cannot be used.  On error we
+        * careful to log the real error to the console and return EISDIR
+        * to safely abort the automount.  This should be very rare.
+        *
+        * If the user mode helper happens to return EBUSY, a concurrent
+        * mount is already in progress in which case the error is ignored.
+        * Take note that if the program was executed successfully the return
+        * value from call_usermodehelper() will be (exitcode << 8 + signal).
+        */
+       dprintf("mount; name=%s path=%s\n", full_name, full_path);
+       argv[5] = full_name;
+       argv[6] = full_path;
+       error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+       if (error) {
+               if (!(error & MOUNT_BUSY << 8)) {
+                       cmn_err(CE_WARN, "Unable to automount %s/%s: %d",
+                           full_path, full_name, error);
+                       error = SET_ERROR(EISDIR);
+               } else {
+                       /*
+                        * EBUSY, this could mean a concurrent mount, or the
+                        * snapshot has already been mounted at completely
+                        * different place. We return 0 so VFS will retry. For
+                        * the latter case the VFS will retry several times
+                        * and return ELOOP, which is probably not a very good
+                        * behavior.
+                        */
+                       error = 0;
+               }
+               goto error;
+       }
+
+       /*
+        * Follow down in to the mounted snapshot and set MNT_SHRINKABLE
+        * to identify this as an automounted filesystem.
+        */
+       spath = *path;
+       path_get(&spath);
+       if (zpl_follow_down_one(&spath)) {
+               snap_zsb = ITOZSB(spath.dentry->d_inode);
+               snap_zsb->z_parent = zsb;
+               dentry = spath.dentry;
+               spath.mnt->mnt_flags |= MNT_SHRINKABLE;
+
+               rw_enter(&zfs_snapshot_lock, RW_WRITER);
+               se = zfsctl_snapshot_alloc(full_name, full_path,
+                   snap_zsb->z_os->os_spa, dmu_objset_id(snap_zsb->z_os),
+                   dentry);
+               zfsctl_snapshot_add(se);
+               zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
+               rw_exit(&zfs_snapshot_lock);
+       }
+       path_put(&spath);
+error:
+       kmem_free(full_name, MAXNAMELEN);
+       kmem_free(full_path, MAXPATHLEN);
+
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+/*
+ * Given the objset id of the snapshot return its zfs_sb_t as zsbp.
+ */
+int
+zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
+{
+       zfs_snapentry_t *se;
+       int error;
+       spa_t *spa = ((zfs_sb_t *)(sb->s_fs_info))->z_os->os_spa;
+
+       /*
+        * Verify that the snapshot is mounted then lookup the mounted root
+        * rather than the covered mount point.  This may fail if the
+        * snapshot has just been unmounted by an unrelated user space
+        * process.  This race cannot occur to an expired mount point
+        * because we hold the zfs_snapshot_lock to prevent the race.
+        */
+       rw_enter(&zfs_snapshot_lock, RW_READER);
+       if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
+               zfs_sb_t *zsb;
+
+               zsb = ITOZSB(se->se_root_dentry->d_inode);
+               ASSERT3U(dmu_objset_id(zsb->z_os), ==, objsetid);
+
+               if (time_after(jiffies, zsb->z_snap_defer_time +
+                   MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
+                       zsb->z_snap_defer_time = jiffies;
+                       zfsctl_snapshot_unmount_cancel(se);
+                       zfsctl_snapshot_unmount_delay_impl(se,
+                           zfs_expire_snapshot);
+               }
+
+               *zsbp = zsb;
+               zfsctl_snapshot_rele(se);
+               error = SET_ERROR(0);
+       } else {
+               error = SET_ERROR(ENOENT);
+       }
+       rw_exit(&zfs_snapshot_lock);
+
+       /*
+        * Automount the snapshot given the objset id by constructing the
+        * full mount point and performing a traversal.
+        */
+       if (error == ENOENT) {
+               struct path path;
+               char *mnt;
+
+               mnt = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+               error = zfsctl_snapshot_path_objset(sb->s_fs_info, objsetid,
+                   MAXPATHLEN, mnt);
+               if (error) {
+                       kmem_free(mnt, MAXPATHLEN);
+                       return (SET_ERROR(error));
+               }
+
+               error = kern_path(mnt, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &path);
+               if (error == 0) {
+                       *zsbp = ITOZSB(path.dentry->d_inode);
+                       path_put(&path);
+               }
+
+               kmem_free(mnt, MAXPATHLEN);
+       }
+
+       return (error);
+}
+
+int
+zfsctl_shares_lookup(struct inode *dip, char *name, struct inode **ipp,
+    int flags, cred_t *cr, int *direntflags, pathname_t *realpnp)
+{
+       zfs_sb_t *zsb = ITOZSB(dip);
+       struct inode *ip;
+       znode_t *dzp;
+       int error;
+
+       ZFS_ENTER(zsb);
+
+       if (zsb->z_shares_dir == 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       error = zfs_zget(zsb, zsb->z_shares_dir, &dzp);
+       if (error) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       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.
+ */
+void
+zfsctl_init(void)
+{
+       avl_create(&zfs_snapshots_by_name, snapentry_compare_by_name,
+           sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t,
+           se_node_name));
+       avl_create(&zfs_snapshots_by_objsetid, snapentry_compare_by_objsetid,
+           sizeof (zfs_snapentry_t), offsetof(zfs_snapentry_t,
+           se_node_objsetid));
+       rw_init(&zfs_snapshot_lock, NULL, RW_DEFAULT, NULL);
+
+       zfs_expire_taskq = taskq_create("z_unmount", 1, defclsyspri,
+           1, 8, TASKQ_PREPOPULATE);
+}
+
+/*
+ * Cleanup the various pieces we needed for .zfs directories.  In particular
+ * ensure the expiry timer is canceled safely.
+ */
+void
+zfsctl_fini(void)
+{
+       taskq_destroy(zfs_expire_taskq);
+
+       avl_destroy(&zfs_snapshots_by_name);
+       avl_destroy(&zfs_snapshots_by_objsetid);
+       rw_destroy(&zfs_snapshot_lock);
+}
+
+module_param(zfs_admin_snapshot, int, 0644);
+MODULE_PARM_DESC(zfs_admin_snapshot, "Enable mkdir/rmdir/mv in .zfs/snapshot");
+
+module_param(zfs_expire_snapshot, int, 0644);
+MODULE_PARM_DESC(zfs_expire_snapshot, "Seconds to expire .zfs/snapshot");
diff --git a/zfs/module/zfs/zfs_debug.c b/zfs/module/zfs/zfs_debug.c
new file mode 100644 (file)
index 0000000..2770359
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012, 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/kstat.h>
+
+list_t zfs_dbgmsgs;
+int zfs_dbgmsg_size = 0;
+kmutex_t zfs_dbgmsgs_lock;
+int zfs_dbgmsg_maxsize = 4<<20; /* 4MB */
+kstat_t *zfs_dbgmsg_kstat;
+
+/*
+ * By default only enable the internal ZFS debug messages when running
+ * in userspace (ztest).  The kernel log must be manually enabled.
+ *
+ * # Enable the kernel debug message log.
+ * echo 1 > /sys/module/zfs/parameters/zfs_dbgmsg_enable
+ *
+ * # Clear the kernel debug message log.
+ * echo 0 >/proc/spl/kstat/zfs/dbgmsg
+ */
+#if defined(_KERNEL)
+int zfs_dbgmsg_enable = 0;
+#else
+int zfs_dbgmsg_enable = 1;
+#endif
+
+static int
+zfs_dbgmsg_headers(char *buf, size_t size)
+{
+       (void) snprintf(buf, size, "%-12s %-8s\n", "timestamp", "message");
+
+       return (0);
+}
+
+static int
+zfs_dbgmsg_data(char *buf, size_t size, void *data)
+{
+       zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)data;
+
+       (void) snprintf(buf, size, "%-12llu %-s\n",
+           (u_longlong_t) zdm->zdm_timestamp, zdm->zdm_msg);
+
+       return (0);
+}
+
+static void *
+zfs_dbgmsg_addr(kstat_t *ksp, loff_t n)
+{
+       zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)ksp->ks_private;
+
+       ASSERT(MUTEX_HELD(&zfs_dbgmsgs_lock));
+
+       if (n == 0)
+               ksp->ks_private = list_head(&zfs_dbgmsgs);
+       else if (zdm)
+               ksp->ks_private = list_next(&zfs_dbgmsgs, zdm);
+
+       return (ksp->ks_private);
+}
+
+static void
+zfs_dbgmsg_purge(int max_size)
+{
+       zfs_dbgmsg_t *zdm;
+       int size;
+
+       ASSERT(MUTEX_HELD(&zfs_dbgmsgs_lock));
+
+       while (zfs_dbgmsg_size > max_size) {
+               zdm = list_remove_head(&zfs_dbgmsgs);
+               if (zdm == NULL)
+                       return;
+
+               size = zdm->zdm_size;
+               kmem_free(zdm, size);
+               zfs_dbgmsg_size -= size;
+       }
+}
+
+static int
+zfs_dbgmsg_update(kstat_t *ksp, int rw)
+{
+       if (rw == KSTAT_WRITE)
+               zfs_dbgmsg_purge(0);
+
+       return (0);
+}
+
+void
+zfs_dbgmsg_init(void)
+{
+       list_create(&zfs_dbgmsgs, sizeof (zfs_dbgmsg_t),
+           offsetof(zfs_dbgmsg_t, zdm_node));
+       mutex_init(&zfs_dbgmsgs_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       zfs_dbgmsg_kstat = kstat_create("zfs", 0, "dbgmsg", "misc",
+           KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+       if (zfs_dbgmsg_kstat) {
+               zfs_dbgmsg_kstat->ks_lock = &zfs_dbgmsgs_lock;
+               zfs_dbgmsg_kstat->ks_ndata = UINT32_MAX;
+               zfs_dbgmsg_kstat->ks_private = NULL;
+               zfs_dbgmsg_kstat->ks_update = zfs_dbgmsg_update;
+               kstat_set_raw_ops(zfs_dbgmsg_kstat, zfs_dbgmsg_headers,
+                   zfs_dbgmsg_data, zfs_dbgmsg_addr);
+               kstat_install(zfs_dbgmsg_kstat);
+       }
+}
+
+void
+zfs_dbgmsg_fini(void)
+{
+       if (zfs_dbgmsg_kstat)
+               kstat_delete(zfs_dbgmsg_kstat);
+
+       mutex_enter(&zfs_dbgmsgs_lock);
+       zfs_dbgmsg_purge(0);
+       mutex_exit(&zfs_dbgmsgs_lock);
+       mutex_destroy(&zfs_dbgmsgs_lock);
+}
+
+void
+__zfs_dbgmsg(char *buf)
+{
+       zfs_dbgmsg_t *zdm;
+       int size;
+
+       size = sizeof (zfs_dbgmsg_t) + strlen(buf);
+       zdm = kmem_zalloc(size, KM_SLEEP);
+       zdm->zdm_size = size;
+       zdm->zdm_timestamp = gethrestime_sec();
+       strcpy(zdm->zdm_msg, buf);
+
+       mutex_enter(&zfs_dbgmsgs_lock);
+       list_insert_tail(&zfs_dbgmsgs, zdm);
+       zfs_dbgmsg_size += size;
+       zfs_dbgmsg_purge(MAX(zfs_dbgmsg_maxsize, 0));
+       mutex_exit(&zfs_dbgmsgs_lock);
+}
+
+#ifdef _KERNEL
+void
+__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
+{
+       const char *newfile;
+       va_list adx;
+       size_t size;
+       char *buf;
+       char *nl;
+
+       if (!zfs_dbgmsg_enable && !(zfs_flags & ZFS_DEBUG_DPRINTF))
+               return;
+
+       size = 1024;
+       buf = kmem_alloc(size, KM_SLEEP);
+
+       /*
+        * Get rid of annoying prefix to filename.
+        */
+       newfile = strrchr(file, '/');
+       if (newfile != NULL) {
+               newfile = newfile + 1; /* Get rid of leading / */
+       } else {
+               newfile = file;
+       }
+
+       va_start(adx, fmt);
+       (void) vsnprintf(buf, size, fmt, adx);
+       va_end(adx);
+
+       /*
+        * Get rid of trailing newline.
+        */
+       nl = strrchr(buf, '\n');
+       if (nl != NULL)
+               *nl = '\0';
+
+       /*
+        * To get this data enable the zfs__dprintf trace point as shown:
+        *
+        * # Enable zfs__dprintf tracepoint, clear the tracepoint ring buffer
+        * $ echo 1 > /sys/module/zfs/parameters/zfs_flags
+        * $ echo 1 > /sys/kernel/debug/tracing/events/zfs/enable
+        * $ echo 0 > /sys/kernel/debug/tracing/trace
+        *
+        * # Dump the ring buffer.
+        * $ cat /sys/kernel/debug/tracing/trace
+        */
+       if (zfs_flags & ZFS_DEBUG_DPRINTF)
+               DTRACE_PROBE4(zfs__dprintf,
+                   char *, newfile, char *, func, int, line, char *, buf);
+
+       /*
+        * To get this data enable the zfs debug log as shown:
+        *
+        * # Set zfs_dbgmsg enable, clear the log buffer
+        * $ echo 1 > /sys/module/zfs/parameters/zfs_dbgmsg_enable
+        * $ echo 0 > /proc/spl/kstat/zfs/dbgmsg
+        *
+        * # Dump the log buffer.
+        * $ cat /proc/spl/kstat/zfs/dbgmsg
+        */
+       if (zfs_dbgmsg_enable)
+               __zfs_dbgmsg(buf);
+
+       kmem_free(buf, size);
+}
+#endif /* _KERNEL */
+
+#ifdef _KERNEL
+module_param(zfs_dbgmsg_enable, int, 0644);
+MODULE_PARM_DESC(zfs_dbgmsg_enable, "Enable ZFS debug message log");
+
+module_param(zfs_dbgmsg_maxsize, int, 0644);
+MODULE_PARM_DESC(zfs_dbgmsg_maxsize, "Maximum ZFS debug log size");
+#endif
diff --git a/zfs/module/zfs/zfs_dir.c b/zfs/module/zfs/zfs_dir.c
new file mode 100644 (file)
index 0000000..b3f98ef
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/resource.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/mode.h>
+#include <sys/kmem.h>
+#include <sys/uio.h>
+#include <sys/pathname.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/unistd.h>
+#include <sys/sunddi.h>
+#include <sys/random.h>
+#include <sys/policy.h>
+#include <sys/zfs_dir.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_vnops.h>
+#include <sys/fs/zfs.h>
+#include "fs/fs_subr.h"
+#include <sys/zap.h>
+#include <sys/dmu.h>
+#include <sys/atomic.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
+#include <sys/sa.h>
+#include <sys/zfs_sa.h>
+#include <sys/dnlc.h>
+#include <sys/extdirent.h>
+
+/*
+ * zfs_match_find() is used by zfs_dirent_lock() to peform zap lookups
+ * of names after deciding which is the appropriate lookup interface.
+ */
+static int
+zfs_match_find(zfs_sb_t *zsb, znode_t *dzp, char *name, boolean_t exact,
+    boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
+{
+       boolean_t conflict = B_FALSE;
+       int error;
+
+       if (zsb->z_norm) {
+               matchtype_t mt = MT_FIRST;
+               size_t bufsz = 0;
+               char *buf = NULL;
+
+               if (rpnp) {
+                       buf = rpnp->pn_buf;
+                       bufsz = rpnp->pn_bufsize;
+               }
+               if (exact)
+                       mt = MT_EXACT;
+               /*
+                * In the non-mixed case we only expect there would ever
+                * be one match, but we need to use the normalizing lookup.
+                */
+               error = zap_lookup_norm(zsb->z_os, dzp->z_id, name, 8, 1,
+                   zoid, mt, buf, bufsz, &conflict);
+       } else {
+               error = zap_lookup(zsb->z_os, dzp->z_id, name, 8, 1, zoid);
+       }
+
+       /*
+        * Allow multiple entries provided the first entry is
+        * the object id.  Non-zpl consumers may safely make
+        * use of the additional space.
+        *
+        * XXX: This should be a feature flag for compatibility
+        */
+       if (error == EOVERFLOW)
+               error = 0;
+
+       if (zsb->z_norm && !error && deflags)
+               *deflags = conflict ? ED_CASE_CONFLICT : 0;
+
+       *zoid = ZFS_DIRENT_OBJ(*zoid);
+
+#ifdef HAVE_DNLC
+       if (error == ENOENT && update)
+               dnlc_update(ZTOI(dzp), name, DNLC_NO_VNODE);
+#endif /* HAVE_DNLC */
+
+       return (error);
+}
+
+/*
+ * Lock a directory entry.  A dirlock on <dzp, name> protects that name
+ * in dzp's directory zap object.  As long as you hold a dirlock, you can
+ * assume two things: (1) dzp cannot be reaped, and (2) no other thread
+ * can change the zap entry for (i.e. link or unlink) this name.
+ *
+ * Input arguments:
+ *     dzp     - znode for directory
+ *     name    - name of entry to lock
+ *     flag    - ZNEW: if the entry already exists, fail with EEXIST.
+ *               ZEXISTS: if the entry does not exist, fail with ENOENT.
+ *               ZSHARED: allow concurrent access with other ZSHARED callers.
+ *               ZXATTR: we want dzp's xattr directory
+ *               ZCILOOK: On a mixed sensitivity file system,
+ *                        this lookup should be case-insensitive.
+ *               ZCIEXACT: On a purely case-insensitive file system,
+ *                         this lookup should be case-sensitive.
+ *               ZRENAMING: we are locking for renaming, force narrow locks
+ *               ZHAVELOCK: Don't grab the z_name_lock for this call. The
+ *                          current thread already holds it.
+ *
+ * Output arguments:
+ *     zpp     - pointer to the znode for the entry (NULL if there isn't one)
+ *     dlpp    - pointer to the dirlock for this entry (NULL on error)
+ *      direntflags - (case-insensitive lookup only)
+ *             flags if multiple case-sensitive matches exist in directory
+ *      realpnp     - (case-insensitive lookup only)
+ *             actual name matched within the directory
+ *
+ * Return value: 0 on success or errno on failure.
+ *
+ * NOTE: Always checks for, and rejects, '.' and '..'.
+ * NOTE: For case-insensitive file systems we take wide locks (see below),
+ *      but return znode pointers to a single match.
+ */
+int
+zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
+    int flag, int *direntflags, pathname_t *realpnp)
+{
+       zfs_sb_t        *zsb = ZTOZSB(dzp);
+       zfs_dirlock_t   *dl;
+       boolean_t       update;
+       boolean_t       exact;
+       uint64_t        zoid;
+#ifdef HAVE_DNLC
+       vnode_t         *vp = NULL;
+#endif /* HAVE_DNLC */
+       int             error = 0;
+       int             cmpflags;
+
+       *zpp = NULL;
+       *dlpp = NULL;
+
+       /*
+        * Verify that we are not trying to lock '.', '..', or '.zfs'
+        */
+       if ((name[0] == '.' &&
+           (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) ||
+           (zfs_has_ctldir(dzp) && strcmp(name, ZFS_CTLDIR_NAME) == 0))
+               return (SET_ERROR(EEXIST));
+
+       /*
+        * Case sensitivity and normalization preferences are set when
+        * the file system is created.  These are stored in the
+        * zsb->z_case and zsb->z_norm fields.  These choices
+        * affect what vnodes can be cached in the DNLC, how we
+        * perform zap lookups, and the "width" of our dirlocks.
+        *
+        * A normal dirlock locks a single name.  Note that with
+        * normalization a name can be composed multiple ways, but
+        * when normalized, these names all compare equal.  A wide
+        * dirlock locks multiple names.  We need these when the file
+        * system is supporting mixed-mode access.  It is sometimes
+        * necessary to lock all case permutations of file name at
+        * once so that simultaneous case-insensitive/case-sensitive
+        * behaves as rationally as possible.
+        */
+
+       /*
+        * Decide if exact matches should be requested when performing
+        * a zap lookup on file systems supporting case-insensitive
+        * access.
+        */
+       exact =
+           ((zsb->z_case == ZFS_CASE_INSENSITIVE) && (flag & ZCIEXACT)) ||
+           ((zsb->z_case == ZFS_CASE_MIXED) && !(flag & ZCILOOK));
+
+       /*
+        * Only look in or update the DNLC if we are looking for the
+        * name on a file system that does not require normalization
+        * or case folding.  We can also look there if we happen to be
+        * on a non-normalizing, mixed sensitivity file system IF we
+        * are looking for the exact name.
+        *
+        * Maybe can add TO-UPPERed version of name to dnlc in ci-only
+        * case for performance improvement?
+        */
+       update = !zsb->z_norm ||
+           ((zsb->z_case == ZFS_CASE_MIXED) &&
+           !(zsb->z_norm & ~U8_TEXTPREP_TOUPPER) && !(flag & ZCILOOK));
+
+       /*
+        * ZRENAMING indicates we are in a situation where we should
+        * take narrow locks regardless of the file system's
+        * preferences for normalizing and case folding.  This will
+        * prevent us deadlocking trying to grab the same wide lock
+        * twice if the two names happen to be case-insensitive
+        * matches.
+        */
+       if (flag & ZRENAMING)
+               cmpflags = 0;
+       else
+               cmpflags = zsb->z_norm;
+
+       /*
+        * Wait until there are no locks on this name.
+        *
+        * Don't grab the the lock if it is already held. However, cannot
+        * have both ZSHARED and ZHAVELOCK together.
+        */
+       ASSERT(!(flag & ZSHARED) || !(flag & ZHAVELOCK));
+       if (!(flag & ZHAVELOCK))
+               rw_enter(&dzp->z_name_lock, RW_READER);
+
+       mutex_enter(&dzp->z_lock);
+       for (;;) {
+               if (dzp->z_unlinked) {
+                       mutex_exit(&dzp->z_lock);
+                       if (!(flag & ZHAVELOCK))
+                               rw_exit(&dzp->z_name_lock);
+                       return (SET_ERROR(ENOENT));
+               }
+               for (dl = dzp->z_dirlocks; dl != NULL; dl = dl->dl_next) {
+                       if ((u8_strcmp(name, dl->dl_name, 0, cmpflags,
+                           U8_UNICODE_LATEST, &error) == 0) || error != 0)
+                               break;
+               }
+               if (error != 0) {
+                       mutex_exit(&dzp->z_lock);
+                       if (!(flag & ZHAVELOCK))
+                               rw_exit(&dzp->z_name_lock);
+                       return (SET_ERROR(ENOENT));
+               }
+               if (dl == NULL) {
+                       /*
+                        * Allocate a new dirlock and add it to the list.
+                        */
+                       dl = kmem_alloc(sizeof (zfs_dirlock_t), KM_SLEEP);
+                       cv_init(&dl->dl_cv, NULL, CV_DEFAULT, NULL);
+                       dl->dl_name = name;
+                       dl->dl_sharecnt = 0;
+                       dl->dl_namelock = 0;
+                       dl->dl_namesize = 0;
+                       dl->dl_dzp = dzp;
+                       dl->dl_next = dzp->z_dirlocks;
+                       dzp->z_dirlocks = dl;
+                       break;
+               }
+               if ((flag & ZSHARED) && dl->dl_sharecnt != 0)
+                       break;
+               cv_wait(&dl->dl_cv, &dzp->z_lock);
+       }
+
+       /*
+        * If the z_name_lock was NOT held for this dirlock record it.
+        */
+       if (flag & ZHAVELOCK)
+               dl->dl_namelock = 1;
+
+       if ((flag & ZSHARED) && ++dl->dl_sharecnt > 1 && dl->dl_namesize == 0) {
+               /*
+                * We're the second shared reference to dl.  Make a copy of
+                * dl_name in case the first thread goes away before we do.
+                * Note that we initialize the new name before storing its
+                * pointer into dl_name, because the first thread may load
+                * dl->dl_name at any time.  He'll either see the old value,
+                * which is his, or the new shared copy; either is OK.
+                */
+               dl->dl_namesize = strlen(dl->dl_name) + 1;
+               name = kmem_alloc(dl->dl_namesize, KM_SLEEP);
+               bcopy(dl->dl_name, name, dl->dl_namesize);
+               dl->dl_name = name;
+       }
+
+       mutex_exit(&dzp->z_lock);
+
+       /*
+        * We have a dirlock on the name.  (Note that it is the dirlock,
+        * not the dzp's z_lock, that protects the name in the zap object.)
+        * See if there's an object by this name; if so, put a hold on it.
+        */
+       if (flag & ZXATTR) {
+               error = sa_lookup(dzp->z_sa_hdl, SA_ZPL_XATTR(zsb), &zoid,
+                   sizeof (zoid));
+               if (error == 0)
+                       error = (zoid == 0 ? SET_ERROR(ENOENT) : 0);
+       } else {
+#ifdef HAVE_DNLC
+               if (update)
+                       vp = dnlc_lookup(ZTOI(dzp), name);
+               if (vp == DNLC_NO_VNODE) {
+                       iput(vp);
+                       error = SET_ERROR(ENOENT);
+               } else if (vp) {
+                       if (flag & ZNEW) {
+                               zfs_dirent_unlock(dl);
+                               iput(vp);
+                               return (SET_ERROR(EEXIST));
+                       }
+                       *dlpp = dl;
+                       *zpp = VTOZ(vp);
+                       return (0);
+               } else {
+                       error = zfs_match_find(zsb, dzp, name, exact,
+                           update, direntflags, realpnp, &zoid);
+               }
+#else
+               error = zfs_match_find(zsb, dzp, name, exact,
+                   update, direntflags, realpnp, &zoid);
+#endif /* HAVE_DNLC */
+       }
+       if (error) {
+               if (error != ENOENT || (flag & ZEXISTS)) {
+                       zfs_dirent_unlock(dl);
+                       return (error);
+               }
+       } else {
+               if (flag & ZNEW) {
+                       zfs_dirent_unlock(dl);
+                       return (SET_ERROR(EEXIST));
+               }
+               error = zfs_zget(zsb, zoid, zpp);
+               if (error) {
+                       zfs_dirent_unlock(dl);
+                       return (error);
+               }
+#ifdef HAVE_DNLC
+               if (!(flag & ZXATTR) && update)
+                       dnlc_update(ZTOI(dzp), name, ZTOI(*zpp));
+#endif /* HAVE_DNLC */
+       }
+
+       *dlpp = dl;
+
+       return (0);
+}
+
+/*
+ * Unlock this directory entry and wake anyone who was waiting for it.
+ */
+void
+zfs_dirent_unlock(zfs_dirlock_t *dl)
+{
+       znode_t *dzp = dl->dl_dzp;
+       zfs_dirlock_t **prev_dl, *cur_dl;
+
+       mutex_enter(&dzp->z_lock);
+
+       if (!dl->dl_namelock)
+               rw_exit(&dzp->z_name_lock);
+
+       if (dl->dl_sharecnt > 1) {
+               dl->dl_sharecnt--;
+               mutex_exit(&dzp->z_lock);
+               return;
+       }
+       prev_dl = &dzp->z_dirlocks;
+       while ((cur_dl = *prev_dl) != dl)
+               prev_dl = &cur_dl->dl_next;
+       *prev_dl = dl->dl_next;
+       cv_broadcast(&dl->dl_cv);
+       mutex_exit(&dzp->z_lock);
+
+       if (dl->dl_namesize != 0)
+               kmem_free(dl->dl_name, dl->dl_namesize);
+       cv_destroy(&dl->dl_cv);
+       kmem_free(dl, sizeof (*dl));
+}
+
+/*
+ * Look up an entry in a directory.
+ *
+ * NOTE: '.' and '..' are handled as special cases because
+ *     no directory entries are actually stored for them.  If this is
+ *     the root of a filesystem, then '.zfs' is also treated as a
+ *     special pseudo-directory.
+ */
+int
+zfs_dirlook(znode_t *dzp, char *name, struct inode **ipp, int flags,
+    int *deflg, pathname_t *rpnp)
+{
+       zfs_dirlock_t *dl;
+       znode_t *zp;
+       int error = 0;
+       uint64_t parent;
+
+       if (name[0] == 0 || (name[0] == '.' && name[1] == 0)) {
+               *ipp = ZTOI(dzp);
+               igrab(*ipp);
+       } else if (name[0] == '.' && name[1] == '.' && name[2] == 0) {
+               zfs_sb_t *zsb = ZTOZSB(dzp);
+
+               /*
+                * If we are a snapshot mounted under .zfs, return
+                * the inode pointer for the snapshot directory.
+                */
+               if ((error = sa_lookup(dzp->z_sa_hdl,
+                   SA_ZPL_PARENT(zsb), &parent, sizeof (parent))) != 0)
+                       return (error);
+
+               if (parent == dzp->z_id && zsb->z_parent != zsb) {
+                       error = zfsctl_root_lookup(zsb->z_parent->z_ctldir,
+                           "snapshot", ipp, 0, kcred, NULL, NULL);
+                       return (error);
+               }
+               rw_enter(&dzp->z_parent_lock, RW_READER);
+               error = zfs_zget(zsb, parent, &zp);
+               if (error == 0)
+                       *ipp = ZTOI(zp);
+               rw_exit(&dzp->z_parent_lock);
+       } else if (zfs_has_ctldir(dzp) && strcmp(name, ZFS_CTLDIR_NAME) == 0) {
+               *ipp = zfsctl_root(dzp);
+       } else {
+               int zf;
+
+               zf = ZEXISTS | ZSHARED;
+               if (flags & FIGNORECASE)
+                       zf |= ZCILOOK;
+
+               error = zfs_dirent_lock(&dl, dzp, name, &zp, zf, deflg, rpnp);
+               if (error == 0) {
+                       *ipp = ZTOI(zp);
+                       zfs_dirent_unlock(dl);
+                       dzp->z_zn_prefetch = B_TRUE; /* enable prefetching */
+               }
+               rpnp = NULL;
+       }
+
+       if ((flags & FIGNORECASE) && rpnp && !error)
+               (void) strlcpy(rpnp->pn_buf, name, rpnp->pn_bufsize);
+
+       return (error);
+}
+
+/*
+ * unlinked Set (formerly known as the "delete queue") Error Handling
+ *
+ * When dealing with the unlinked set, we dmu_tx_hold_zap(), but we
+ * don't specify the name of the entry that we will be manipulating.  We
+ * also fib and say that we won't be adding any new entries to the
+ * unlinked set, even though we might (this is to lower the minimum file
+ * size that can be deleted in a full filesystem).  So on the small
+ * chance that the nlink list is using a fat zap (ie. has more than
+ * 2000 entries), we *may* not pre-read a block that's needed.
+ * Therefore it is remotely possible for some of the assertions
+ * regarding the unlinked set below to fail due to i/o error.  On a
+ * nondebug system, this will result in the space being leaked.
+ */
+void
+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);
+
+       VERIFY3U(0, ==,
+           zap_add_int(zsb->z_os, zsb->z_unlinkedobj, zp->z_id, tx));
+}
+
+/*
+ * Clean up any znodes that had no links when we either crashed or
+ * (force) umounted the file system.
+ */
+void
+zfs_unlinked_drain(zfs_sb_t *zsb)
+{
+       zap_cursor_t    zc;
+       zap_attribute_t zap;
+       dmu_object_info_t doi;
+       znode_t         *zp;
+       int             error;
+
+       /*
+        * Iterate over the contents of the unlinked set.
+        */
+       for (zap_cursor_init(&zc, zsb->z_os, zsb->z_unlinkedobj);
+           zap_cursor_retrieve(&zc, &zap) == 0;
+           zap_cursor_advance(&zc)) {
+
+               /*
+                * See what kind of object we have in list
+                */
+
+               error = dmu_object_info(zsb->z_os, zap.za_first_integer, &doi);
+               if (error != 0)
+                       continue;
+
+               ASSERT((doi.doi_type == DMU_OT_PLAIN_FILE_CONTENTS) ||
+                   (doi.doi_type == DMU_OT_DIRECTORY_CONTENTS));
+               /*
+                * We need to re-mark these list entries for deletion,
+                * so we pull them back into core and set zp->z_unlinked.
+                */
+               error = zfs_zget(zsb, zap.za_first_integer, &zp);
+
+               /*
+                * We may pick up znodes that are already marked for deletion.
+                * This could happen during the purge of an extended attribute
+                * directory.  All we need to do is skip over them, since they
+                * are already in the system marked z_unlinked.
+                */
+               if (error != 0)
+                       continue;
+
+               zp->z_unlinked = B_TRUE;
+               iput(ZTOI(zp));
+       }
+       zap_cursor_fini(&zc);
+}
+
+/*
+ * Delete the entire contents of a directory.  Return a count
+ * of the number of entries that could not be deleted. If we encounter
+ * an error, return a count of at least one so that the directory stays
+ * in the unlinked set.
+ *
+ * NOTE: this function assumes that the directory is inactive,
+ *     so there is no need to lock its entries before deletion.
+ *     Also, it assumes the directory contents is *only* regular
+ *     files.
+ */
+static int
+zfs_purgedir(znode_t *dzp)
+{
+       zap_cursor_t    zc;
+       zap_attribute_t zap;
+       znode_t         *xzp;
+       dmu_tx_t        *tx;
+       zfs_sb_t        *zsb = ZTOZSB(dzp);
+       zfs_dirlock_t   dl;
+       int skipped = 0;
+       int error;
+
+       for (zap_cursor_init(&zc, zsb->z_os, dzp->z_id);
+           (error = zap_cursor_retrieve(&zc, &zap)) == 0;
+           zap_cursor_advance(&zc)) {
+               error = zfs_zget(zsb,
+                   ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
+               if (error) {
+                       skipped += 1;
+                       continue;
+               }
+
+               ASSERT(S_ISREG(ZTOI(xzp)->i_mode) ||
+                   S_ISLNK(ZTOI(xzp)->i_mode));
+
+               tx = dmu_tx_create(zsb->z_os);
+               dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
+               dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap.za_name);
+               dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
+               dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
+               /* Is this really needed ? */
+               zfs_sa_upgrade_txholds(tx, xzp);
+               error = dmu_tx_assign(tx, TXG_WAIT);
+               if (error) {
+                       dmu_tx_abort(tx);
+                       zfs_iput_async(ZTOI(xzp));
+                       skipped += 1;
+                       continue;
+               }
+               bzero(&dl, sizeof (dl));
+               dl.dl_dzp = dzp;
+               dl.dl_name = zap.za_name;
+
+               error = zfs_link_destroy(&dl, xzp, tx, 0, NULL);
+               if (error)
+                       skipped += 1;
+               dmu_tx_commit(tx);
+               set_nlink(ZTOI(xzp), xzp->z_links);
+               zfs_iput_async(ZTOI(xzp));
+       }
+       zap_cursor_fini(&zc);
+       if (error != ENOENT)
+               skipped += 1;
+       return (skipped);
+}
+
+void
+zfs_rmnode(znode_t *zp)
+{
+       zfs_sb_t        *zsb = ZTOZSB(zp);
+       objset_t        *os = zsb->z_os;
+       znode_t         *xzp = NULL;
+       dmu_tx_t        *tx;
+       uint64_t        acl_obj;
+       uint64_t        xattr_obj;
+       int             error;
+
+       ASSERT(zp->z_links == 0);
+       ASSERT(atomic_read(&ZTOI(zp)->i_count) == 0);
+
+       /*
+        * If this is an attribute directory, purge its contents.
+        */
+       if (S_ISDIR(ZTOI(zp)->i_mode) && (zp->z_pflags & ZFS_XATTR)) {
+               if (zfs_purgedir(zp) != 0) {
+                       /*
+                        * Not enough space to delete some xattrs.
+                        * Leave it in the unlinked set.
+                        */
+                       zfs_znode_dmu_fini(zp);
+
+                       return;
+               }
+       }
+
+       /*
+        * Free up all the data in the file.  We don't do this for directories
+        * because we need truncate and remove to be in the same tx, like in
+        * zfs_znode_delete(). Otherwise, if we crash here we'll end up with
+        * an inconsistent truncated zap object in the delete queue.  Note a
+        * truncated file is harmless since it only contains user data.
+        */
+       if (S_ISREG(ZTOI(zp)->i_mode)) {
+               error = dmu_free_long_range(os, zp->z_id, 0, DMU_OBJECT_END);
+               if (error) {
+                       /*
+                        * Not enough space.  Leave the file in the unlinked
+                        * set.
+                        */
+                       zfs_znode_dmu_fini(zp);
+                       return;
+               }
+       }
+
+       /*
+        * If the file has extended attributes, we're going to unlink
+        * the xattr dir.
+        */
+       error = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
+           &xattr_obj, sizeof (xattr_obj));
+       if (error == 0 && xattr_obj) {
+               error = zfs_zget(zsb, xattr_obj, &xzp);
+               ASSERT(error == 0);
+       }
+
+       acl_obj = zfs_external_acl(zp);
+
+       /*
+        * Set up the final transaction.
+        */
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_free(tx, zp->z_id, 0, DMU_OBJECT_END);
+       dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
+       if (xzp) {
+               dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, TRUE, NULL);
+               dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
+       }
+       if (acl_obj)
+               dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END);
+
+       zfs_sa_upgrade_txholds(tx, zp);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               /*
+                * Not enough space to delete the file.  Leave it in the
+                * unlinked set, leaking it until the fs is remounted (at
+                * which point we'll call zfs_unlinked_drain() to process it).
+                */
+               dmu_tx_abort(tx);
+               zfs_znode_dmu_fini(zp);
+               goto out;
+       }
+
+       if (xzp) {
+               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 */
+               VERIFY(0 == sa_update(xzp->z_sa_hdl, SA_ZPL_LINKS(zsb),
+                   &xzp->z_links, sizeof (xzp->z_links), tx));
+               mutex_exit(&xzp->z_lock);
+               zfs_unlinked_add(xzp, tx);
+       }
+
+       /* Remove this znode from the unlinked set */
+       VERIFY3U(0, ==,
+           zap_remove_int(zsb->z_os, zsb->z_unlinkedobj, zp->z_id, tx));
+
+       zfs_znode_delete(zp, tx);
+
+       dmu_tx_commit(tx);
+out:
+       if (xzp)
+               zfs_iput_async(ZTOI(xzp));
+}
+
+static uint64_t
+zfs_dirent(znode_t *zp, uint64_t mode)
+{
+       uint64_t de = zp->z_id;
+
+       if (ZTOZSB(zp)->z_version >= ZPL_VERSION_DIRENT_TYPE)
+               de |= IFTODT(mode) << 60;
+       return (de);
+}
+
+/*
+ * Link zp into dl.  Can only fail if zp has been unlinked.
+ */
+int
+zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
+{
+       znode_t *dzp = dl->dl_dzp;
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       uint64_t value;
+       int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode);
+       sa_bulk_attr_t bulk[5];
+       uint64_t mtime[2], ctime[2];
+       int count = 0;
+       int error;
+
+       mutex_enter(&zp->z_lock);
+
+       if (!(flag & ZRENAMING)) {
+               if (zp->z_unlinked) {   /* no new links to unlinked zp */
+                       ASSERT(!(flag & (ZNEW | ZEXISTS)));
+                       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));
+
+       }
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zsb), NULL,
+           &dzp->z_id, sizeof (dzp->z_id));
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
+           &zp->z_pflags, sizeof (zp->z_pflags));
+
+       if (!(flag & ZNEW)) {
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
+                   ctime, sizeof (ctime));
+               zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime,
+                   ctime);
+       }
+       error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+       ASSERT(error == 0);
+
+       mutex_exit(&zp->z_lock);
+
+       mutex_enter(&dzp->z_lock);
+       dzp->z_size++;
+       dzp->z_links += zp_is_dir;
+       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));
+       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);
+       error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
+       ASSERT(error == 0);
+       mutex_exit(&dzp->z_lock);
+
+       value = zfs_dirent(zp, zp->z_mode);
+       error = zap_add(ZTOZSB(zp)->z_os, dzp->z_id, dl->dl_name,
+           8, 1, &value, tx);
+       ASSERT(error == 0);
+
+       return (0);
+}
+
+static int
+zfs_dropname(zfs_dirlock_t *dl, znode_t *zp, znode_t *dzp, dmu_tx_t *tx,
+    int flag)
+{
+       int error;
+
+       if (ZTOZSB(zp)->z_norm) {
+               if (((ZTOZSB(zp)->z_case == ZFS_CASE_INSENSITIVE) &&
+                   (flag & ZCIEXACT)) ||
+                   ((ZTOZSB(zp)->z_case == ZFS_CASE_MIXED) &&
+                   !(flag & ZCILOOK)))
+                       error = zap_remove_norm(ZTOZSB(zp)->z_os,
+                           dzp->z_id, dl->dl_name, MT_EXACT, tx);
+               else
+                       error = zap_remove_norm(ZTOZSB(zp)->z_os,
+                           dzp->z_id, dl->dl_name, MT_FIRST, tx);
+       } else {
+               error = zap_remove(ZTOZSB(zp)->z_os,
+                   dzp->z_id, dl->dl_name, tx);
+       }
+
+       return (error);
+}
+
+/*
+ * Unlink zp from dl, and mark zp for deletion if this was the last link. Can
+ * fail if zp is a mount point (EBUSY) or a non-empty directory (ENOTEMPTY).
+ * If 'unlinkedp' is NULL, we put unlinked znodes on the unlinked list.
+ * If it's non-NULL, we use it to indicate whether the znode needs deletion,
+ * and it's the caller's job to do it.
+ */
+int
+zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
+       boolean_t *unlinkedp)
+{
+       znode_t *dzp = dl->dl_dzp;
+       zfs_sb_t *zsb = ZTOZSB(dzp);
+       int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode);
+       boolean_t unlinked = B_FALSE;
+       sa_bulk_attr_t bulk[5];
+       uint64_t mtime[2], ctime[2];
+       int count = 0;
+       int error;
+
+#ifdef HAVE_DNLC
+       dnlc_remove(ZTOI(dzp), dl->dl_name);
+#endif /* HAVE_DNLC */
+
+       if (!(flag & ZRENAMING)) {
+               mutex_enter(&zp->z_lock);
+
+               if (zp_is_dir && !zfs_dirempty(zp)) {
+                       mutex_exit(&zp->z_lock);
+                       return (SET_ERROR(ENOTEMPTY));
+               }
+
+               /*
+                * If we get here, we are going to try to remove the object.
+                * First try removing the name from the directory; if that
+                * fails, return the error.
+                */
+               error = zfs_dropname(dl, zp, dzp, tx, flag);
+               if (error != 0) {
+                       mutex_exit(&zp->z_lock);
+                       return (error);
+               }
+
+               if (zp->z_links <= 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;
+               }
+               if (--zp->z_links == zp_is_dir) {
+                       zp->z_unlinked = B_TRUE;
+                       zp->z_links = 0;
+                       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);
+               }
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb),
+                   NULL, &zp->z_links, sizeof (zp->z_links));
+               error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+               count = 0;
+               ASSERT(error == 0);
+               mutex_exit(&zp->z_lock);
+       } else {
+               error = zfs_dropname(dl, zp, dzp, tx, flag);
+               if (error != 0)
+                       return (error);
+       }
+
+       mutex_enter(&dzp->z_lock);
+       dzp->z_size--;          /* one dirent removed */
+       dzp->z_links -= zp_is_dir;      /* ".." link from zp */
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb),
+           NULL, &dzp->z_links, sizeof (dzp->z_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),
+           NULL, ctime, sizeof (ctime));
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb),
+           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);
+       error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
+       ASSERT(error == 0);
+       mutex_exit(&dzp->z_lock);
+
+       if (unlinkedp != NULL)
+               *unlinkedp = unlinked;
+       else if (unlinked)
+               zfs_unlinked_add(zp, tx);
+
+       return (0);
+}
+
+/*
+ * Indicate whether the directory is empty.  Works with or without z_lock
+ * held, but can only be consider a hint in the latter case.  Returns true
+ * if only "." and ".." remain and there's no work in progress.
+ */
+boolean_t
+zfs_dirempty(znode_t *dzp)
+{
+       return (dzp->z_size == 2 && dzp->z_dirlocks == 0);
+}
+
+int
+zfs_make_xattrdir(znode_t *zp, vattr_t *vap, struct inode **xipp, cred_t *cr)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       znode_t *xzp;
+       dmu_tx_t *tx;
+       int error;
+       zfs_acl_ids_t acl_ids;
+       boolean_t fuid_dirtied;
+#ifdef DEBUG
+       uint64_t parent;
+#endif
+
+       *xipp = NULL;
+
+       if ((error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr)))
+               return (error);
+
+       if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL,
+           &acl_ids)) != 0)
+               return (error);
+       if (zfs_acl_ids_overquota(zsb, &acl_ids)) {
+               zfs_acl_ids_free(&acl_ids);
+               return (SET_ERROR(EDQUOT));
+       }
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
+           ZFS_SA_BASE_ATTR_SIZE);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+       dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
+       fuid_dirtied = zsb->z_fuid_dirty;
+       if (fuid_dirtied)
+               zfs_fuid_txhold(zsb, tx);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               zfs_acl_ids_free(&acl_ids);
+               dmu_tx_abort(tx);
+               return (error);
+       }
+       zfs_mknode(zp, vap, tx, cr, IS_XATTR, &xzp, &acl_ids);
+
+       if (fuid_dirtied)
+               zfs_fuid_sync(zsb, tx);
+
+#ifdef DEBUG
+       error = sa_lookup(xzp->z_sa_hdl, SA_ZPL_PARENT(zsb),
+           &parent, sizeof (parent));
+       ASSERT(error == 0 && parent == zp->z_id);
+#endif
+
+       VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_XATTR(zsb), &xzp->z_id,
+           sizeof (xzp->z_id), tx));
+
+       (void) zfs_log_create(zsb->z_log, tx, TX_MKXATTR, zp,
+           xzp, "", NULL, acl_ids.z_fuidp, vap);
+
+       zfs_acl_ids_free(&acl_ids);
+       dmu_tx_commit(tx);
+
+       *xipp = ZTOI(xzp);
+
+       return (0);
+}
+
+/*
+ * Return a znode for the extended attribute directory for zp.
+ * ** If the directory does not already exist, it is created **
+ *
+ *     IN:     zp      - znode to obtain attribute directory from
+ *             cr      - credentials of caller
+ *             flags   - flags from the VOP_LOOKUP call
+ *
+ *     OUT:    xipp    - pointer to extended attribute znode
+ *
+ *     RETURN: 0 on success
+ *             error number on failure
+ */
+int
+zfs_get_xattrdir(znode_t *zp, struct inode **xipp, cred_t *cr, int flags)
+{
+       zfs_sb_t        *zsb = ZTOZSB(zp);
+       znode_t         *xzp;
+       zfs_dirlock_t   *dl;
+       vattr_t         va;
+       int             error;
+top:
+       error = zfs_dirent_lock(&dl, zp, "", &xzp, ZXATTR, NULL, NULL);
+       if (error)
+               return (error);
+
+       if (xzp != NULL) {
+               *xipp = ZTOI(xzp);
+               zfs_dirent_unlock(dl);
+               return (0);
+       }
+
+       if (!(flags & CREATE_XATTR_DIR)) {
+               zfs_dirent_unlock(dl);
+               return (SET_ERROR(ENOENT));
+       }
+
+       if (zfs_is_readonly(zsb)) {
+               zfs_dirent_unlock(dl);
+               return (SET_ERROR(EROFS));
+       }
+
+       /*
+        * The ability to 'create' files in an attribute
+        * directory comes from the write_xattr permission on the base file.
+        *
+        * The ability to 'search' an attribute directory requires
+        * read_xattr permission on the base file.
+        *
+        * Once in a directory the ability to read/write attributes
+        * is controlled by the permissions on the attribute file.
+        */
+       va.va_mask = ATTR_MODE | ATTR_UID | ATTR_GID;
+       va.va_mode = S_IFDIR | S_ISVTX | 0777;
+       zfs_fuid_map_ids(zp, cr, &va.va_uid, &va.va_gid);
+
+       va.va_dentry = NULL;
+       error = zfs_make_xattrdir(zp, &va, xipp, cr);
+       zfs_dirent_unlock(dl);
+
+       if (error == ERESTART) {
+               /* NB: we already did dmu_tx_wait() if necessary */
+               goto top;
+       }
+
+       return (error);
+}
+
+/*
+ * Decide whether it is okay to remove within a sticky directory.
+ *
+ * In sticky directories, write access is not sufficient;
+ * you can remove entries from a directory only if:
+ *
+ *     you own the directory,
+ *     you own the entry,
+ *     the entry is a plain file and you have write access,
+ *     or you are privileged (checked in secpolicy...).
+ *
+ * The function returns 0 if remove access is granted.
+ */
+int
+zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
+{
+       uid_t           uid;
+       uid_t           downer;
+       uid_t           fowner;
+       zfs_sb_t        *zsb = ZTOZSB(zdp);
+
+       if (zsb->z_replay)
+               return (0);
+
+       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);
+
+       if ((uid = crgetuid(cr)) == downer || uid == fowner ||
+           (S_ISDIR(ZTOI(zp)->i_mode) &&
+           zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0))
+               return (0);
+       else
+               return (secpolicy_vnode_remove(cr));
+}
diff --git a/zfs/module/zfs/zfs_fm.c b/zfs/module/zfs/zfs_fm.c
new file mode 100644 (file)
index 0000000..c7b7180
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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.
+ */
+
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/vdev.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio.h>
+#include <sys/zio_checksum.h>
+
+#include <sys/fm/fs/zfs.h>
+#include <sys/fm/protocol.h>
+#include <sys/fm/util.h>
+#include <sys/sysevent.h>
+
+/*
+ * This general routine is responsible for generating all the different ZFS
+ * ereports.  The payload is dependent on the class, and which arguments are
+ * supplied to the function:
+ *
+ *     EREPORT                 POOL    VDEV    IO
+ *     block                   X       X       X
+ *     data                    X               X
+ *     device                  X       X
+ *     pool                    X
+ *
+ * If we are in a loading state, all errors are chained together by the same
+ * SPA-wide ENA (Error Numeric Association).
+ *
+ * For isolated I/O requests, we get the ENA from the zio_t. The propagation
+ * gets very complicated due to RAID-Z, gang blocks, and vdev caching.  We want
+ * to chain together all ereports associated with a logical piece of data.  For
+ * read I/Os, there  are basically three 'types' of I/O, which form a roughly
+ * layered diagram:
+ *
+ *      +---------------+
+ *     | Aggregate I/O |       No associated logical data or device
+ *     +---------------+
+ *              |
+ *              V
+ *     +---------------+       Reads associated with a piece of logical data.
+ *     |   Read I/O    |       This includes reads on behalf of RAID-Z,
+ *     +---------------+       mirrors, gang blocks, retries, etc.
+ *              |
+ *              V
+ *     +---------------+       Reads associated with a particular device, but
+ *     | Physical I/O  |       no logical data.  Issued as part of vdev caching
+ *     +---------------+       and I/O aggregation.
+ *
+ * Note that 'physical I/O' here is not the same terminology as used in the rest
+ * of ZIO.  Typically, 'physical I/O' simply means that there is no attached
+ * blockpointer.  But I/O with no associated block pointer can still be related
+ * to a logical piece of data (i.e. RAID-Z requests).
+ *
+ * Purely physical I/O always have unique ENAs.  They are not related to a
+ * particular piece of logical data, and therefore cannot be chained together.
+ * We still generate an ereport, but the DE doesn't correlate it with any
+ * logical piece of data.  When such an I/O fails, the delegated I/O requests
+ * will issue a retry, which will trigger the 'real' ereport with the correct
+ * ENA.
+ *
+ * We keep track of the ENA for a ZIO chain through the 'io_logical' member.
+ * When a new logical I/O is issued, we set this to point to itself.  Child I/Os
+ * then inherit this pointer, so that when it is first set subsequent failures
+ * will use the same ENA.  For vdev cache fill and queue aggregation I/O,
+ * this pointer is set to NULL, and no ereport will be generated (since it
+ * doesn't actually correspond to any particular device or piece of data,
+ * and the caller will always retry without caching or queueing anyway).
+ *
+ * For checksum errors, we want to include more information about the actual
+ * error which occurs.  Accordingly, we build an ereport when the error is
+ * noticed, but instead of sending it in immediately, we hang it off of the
+ * io_cksum_report field of the logical IO.  When the logical IO completes
+ * (successfully or not), zfs_ereport_finish_checksum() is called with the
+ * good and bad versions of the buffer (if available), and we annotate the
+ * ereport with information about the differences.
+ */
+#ifdef _KERNEL
+static void
+zfs_zevent_post_cb(nvlist_t *nvl, nvlist_t *detector)
+{
+       if (nvl)
+               fm_nvlist_destroy(nvl, FM_NVA_FREE);
+
+       if (detector)
+               fm_nvlist_destroy(detector, FM_NVA_FREE);
+}
+
+static void
+zfs_zevent_post_cb_noop(nvlist_t *nvl, nvlist_t *detector)
+{
+}
+
+static void
+zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
+    const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
+    uint64_t stateoroffset, uint64_t size)
+{
+       nvlist_t *ereport, *detector;
+
+       uint64_t ena;
+       char class[64];
+
+       /*
+        * If we are doing a spa_tryimport() or in recovery mode,
+        * ignore errors.
+        */
+       if (spa_load_state(spa) == SPA_LOAD_TRYIMPORT ||
+           spa_load_state(spa) == SPA_LOAD_RECOVER)
+               return;
+
+       /*
+        * If we are in the middle of opening a pool, and the previous attempt
+        * failed, don't bother logging any new ereports - we're just going to
+        * get the same diagnosis anyway.
+        */
+       if (spa_load_state(spa) != SPA_LOAD_NONE &&
+           spa->spa_last_open_failed)
+               return;
+
+       if (zio != NULL) {
+               /*
+                * If this is not a read or write zio, ignore the error.  This
+                * can occur if the DKIOCFLUSHWRITECACHE ioctl fails.
+                */
+               if (zio->io_type != ZIO_TYPE_READ &&
+                   zio->io_type != ZIO_TYPE_WRITE)
+                       return;
+
+               if (vd != NULL) {
+                       /*
+                        * If the vdev has already been marked as failing due
+                        * to a failed probe, then ignore any subsequent I/O
+                        * errors, as the DE will automatically fault the vdev
+                        * on the first such failure.  This also catches cases
+                        * where vdev_remove_wanted is set and the device has
+                        * not yet been asynchronously placed into the REMOVED
+                        * state.
+                        */
+                       if (zio->io_vd == vd && !vdev_accessible(vd, zio))
+                               return;
+
+                       /*
+                        * Ignore checksum errors for reads from DTL regions of
+                        * leaf vdevs.
+                        */
+                       if (zio->io_type == ZIO_TYPE_READ &&
+                           zio->io_error == ECKSUM &&
+                           vd->vdev_ops->vdev_op_leaf &&
+                           vdev_dtl_contains(vd, DTL_MISSING, zio->io_txg, 1))
+                               return;
+               }
+       }
+
+       /*
+        * For probe failure, we want to avoid posting ereports if we've
+        * already removed the device in the meantime.
+        */
+       if (vd != NULL &&
+           strcmp(subclass, FM_EREPORT_ZFS_PROBE_FAILURE) == 0 &&
+           (vd->vdev_remove_wanted || vd->vdev_state == VDEV_STATE_REMOVED))
+               return;
+
+       if ((ereport = fm_nvlist_create(NULL)) == NULL)
+               return;
+
+       if ((detector = fm_nvlist_create(NULL)) == NULL) {
+               fm_nvlist_destroy(ereport, FM_NVA_FREE);
+               return;
+       }
+
+       /*
+        * Serialize ereport generation
+        */
+       mutex_enter(&spa->spa_errlist_lock);
+
+       /*
+        * Determine the ENA to use for this event.  If we are in a loading
+        * state, use a SPA-wide ENA.  Otherwise, if we are in an I/O state, use
+        * a root zio-wide ENA.  Otherwise, simply use a unique ENA.
+        */
+       if (spa_load_state(spa) != SPA_LOAD_NONE) {
+               if (spa->spa_ena == 0)
+                       spa->spa_ena = fm_ena_generate(0, FM_ENA_FMT1);
+               ena = spa->spa_ena;
+       } else if (zio != NULL && zio->io_logical != NULL) {
+               if (zio->io_logical->io_ena == 0)
+                       zio->io_logical->io_ena =
+                           fm_ena_generate(0, FM_ENA_FMT1);
+               ena = zio->io_logical->io_ena;
+       } else {
+               ena = fm_ena_generate(0, FM_ENA_FMT1);
+       }
+
+       /*
+        * Construct the full class, detector, and other standard FMA fields.
+        */
+       (void) snprintf(class, sizeof (class), "%s.%s",
+           ZFS_ERROR_CLASS, subclass);
+
+       fm_fmri_zfs_set(detector, FM_ZFS_SCHEME_VERSION, spa_guid(spa),
+           vd != NULL ? vd->vdev_guid : 0);
+
+       fm_ereport_set(ereport, FM_EREPORT_VERSION, class, ena, detector, NULL);
+
+       /*
+        * Construct the per-ereport payload, depending on which parameters are
+        * passed in.
+        */
+
+       /*
+        * Generic payload members common to all ereports.
+        */
+       fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_POOL,
+           DATA_TYPE_STRING, spa_name(spa), FM_EREPORT_PAYLOAD_ZFS_POOL_GUID,
+           DATA_TYPE_UINT64, spa_guid(spa),
+           FM_EREPORT_PAYLOAD_ZFS_POOL_CONTEXT, DATA_TYPE_INT32,
+           spa_load_state(spa), NULL);
+
+       if (spa != NULL) {
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_POOL_FAILMODE,
+                   DATA_TYPE_STRING,
+                   spa_get_failmode(spa) == ZIO_FAILURE_MODE_WAIT ?
+                   FM_EREPORT_FAILMODE_WAIT :
+                   spa_get_failmode(spa) == ZIO_FAILURE_MODE_CONTINUE ?
+                   FM_EREPORT_FAILMODE_CONTINUE : FM_EREPORT_FAILMODE_PANIC,
+                   NULL);
+       }
+
+       if (vd != NULL) {
+               vdev_t *pvd = vd->vdev_parent;
+               vdev_queue_t *vq = &vd->vdev_queue;
+               vdev_stat_t *vs = &vd->vdev_stat;
+               vdev_t *spare_vd;
+               uint64_t *spare_guids;
+               char **spare_paths;
+               int i, spare_count;
+
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID,
+                   DATA_TYPE_UINT64, vd->vdev_guid,
+                   FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
+                   DATA_TYPE_STRING, vd->vdev_ops->vdev_op_type, NULL);
+               if (vd->vdev_path != NULL)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH,
+                           DATA_TYPE_STRING, vd->vdev_path, NULL);
+               if (vd->vdev_devid != NULL)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_DEVID,
+                           DATA_TYPE_STRING, vd->vdev_devid, NULL);
+               if (vd->vdev_fru != NULL)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU,
+                           DATA_TYPE_STRING, vd->vdev_fru, NULL);
+               if (vd->vdev_ashift)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_ASHIFT,
+                           DATA_TYPE_UINT64, vd->vdev_ashift, NULL);
+
+               if (vq != NULL) {
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_COMP_TS,
+                           DATA_TYPE_UINT64, vq->vq_io_complete_ts, NULL);
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_DELTA_TS,
+                           DATA_TYPE_UINT64, vq->vq_io_delta_ts, NULL);
+               }
+
+               if (vs != NULL) {
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_READ_ERRORS,
+                           DATA_TYPE_UINT64, vs->vs_read_errors,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_WRITE_ERRORS,
+                           DATA_TYPE_UINT64, vs->vs_write_errors,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_CKSUM_ERRORS,
+                           DATA_TYPE_UINT64, vs->vs_checksum_errors, NULL);
+               }
+
+               if (pvd != NULL) {
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_PARENT_GUID,
+                           DATA_TYPE_UINT64, pvd->vdev_guid,
+                           FM_EREPORT_PAYLOAD_ZFS_PARENT_TYPE,
+                           DATA_TYPE_STRING, pvd->vdev_ops->vdev_op_type,
+                           NULL);
+                       if (pvd->vdev_path)
+                               fm_payload_set(ereport,
+                                   FM_EREPORT_PAYLOAD_ZFS_PARENT_PATH,
+                                   DATA_TYPE_STRING, pvd->vdev_path, NULL);
+                       if (pvd->vdev_devid)
+                               fm_payload_set(ereport,
+                                   FM_EREPORT_PAYLOAD_ZFS_PARENT_DEVID,
+                                   DATA_TYPE_STRING, pvd->vdev_devid, NULL);
+               }
+
+               spare_count = spa->spa_spares.sav_count;
+               spare_paths = kmem_zalloc(sizeof (char *) * spare_count,
+                   KM_SLEEP);
+               spare_guids = kmem_zalloc(sizeof (uint64_t) * spare_count,
+                   KM_SLEEP);
+
+               for (i = 0; i < spare_count; i++) {
+                       spare_vd = spa->spa_spares.sav_vdevs[i];
+                       if (spare_vd) {
+                               spare_paths[i] = spare_vd->vdev_path;
+                               spare_guids[i] = spare_vd->vdev_guid;
+                       }
+               }
+
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_VDEV_SPARE_PATHS,
+                   DATA_TYPE_STRING_ARRAY, spare_count, spare_paths,
+                   FM_EREPORT_PAYLOAD_ZFS_VDEV_SPARE_GUIDS,
+                   DATA_TYPE_UINT64_ARRAY, spare_count, spare_guids, NULL);
+
+               kmem_free(spare_guids, sizeof (uint64_t) * spare_count);
+               kmem_free(spare_paths, sizeof (char *) * spare_count);
+       }
+
+       if (zio != NULL) {
+               /*
+                * Payload common to all I/Os.
+                */
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_ERR,
+                   DATA_TYPE_INT32, zio->io_error, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS,
+                   DATA_TYPE_INT32, zio->io_flags, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_STAGE,
+                   DATA_TYPE_UINT32, zio->io_stage, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_PIPELINE,
+                   DATA_TYPE_UINT32, zio->io_pipeline, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_DELAY,
+                   DATA_TYPE_UINT64, zio->io_delay, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_TIMESTAMP,
+                   DATA_TYPE_UINT64, zio->io_timestamp, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_DELTA,
+                   DATA_TYPE_UINT64, zio->io_delta, NULL);
+
+               /*
+                * If the 'size' parameter is non-zero, it indicates this is a
+                * RAID-Z or other I/O where the physical offset and length are
+                * provided for us, instead of within the zio_t.
+                */
+               if (vd != NULL) {
+                       if (size)
+                               fm_payload_set(ereport,
+                                   FM_EREPORT_PAYLOAD_ZFS_ZIO_OFFSET,
+                                   DATA_TYPE_UINT64, stateoroffset,
+                                   FM_EREPORT_PAYLOAD_ZFS_ZIO_SIZE,
+                                   DATA_TYPE_UINT64, size, NULL);
+                       else
+                               fm_payload_set(ereport,
+                                   FM_EREPORT_PAYLOAD_ZFS_ZIO_OFFSET,
+                                   DATA_TYPE_UINT64, zio->io_offset,
+                                   FM_EREPORT_PAYLOAD_ZFS_ZIO_SIZE,
+                                   DATA_TYPE_UINT64, zio->io_size, NULL);
+               }
+
+               /*
+                * Payload for I/Os with corresponding logical information.
+                */
+               if (zio->io_logical != NULL)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJSET,
+                           DATA_TYPE_UINT64,
+                           zio->io_logical->io_bookmark.zb_objset,
+                           FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJECT,
+                           DATA_TYPE_UINT64,
+                           zio->io_logical->io_bookmark.zb_object,
+                           FM_EREPORT_PAYLOAD_ZFS_ZIO_LEVEL,
+                           DATA_TYPE_INT64,
+                           zio->io_logical->io_bookmark.zb_level,
+                           FM_EREPORT_PAYLOAD_ZFS_ZIO_BLKID,
+                           DATA_TYPE_UINT64,
+                           zio->io_logical->io_bookmark.zb_blkid, NULL);
+       } else if (vd != NULL) {
+               /*
+                * If we have a vdev but no zio, this is a device fault, and the
+                * 'stateoroffset' parameter indicates the previous state of the
+                * vdev.
+                */
+               fm_payload_set(ereport,
+                   FM_EREPORT_PAYLOAD_ZFS_PREV_STATE,
+                   DATA_TYPE_UINT64, stateoroffset, NULL);
+       }
+
+       mutex_exit(&spa->spa_errlist_lock);
+
+       *ereport_out = ereport;
+       *detector_out = detector;
+}
+
+/* if it's <= 128 bytes, save the corruption directly */
+#define        ZFM_MAX_INLINE          (128 / sizeof (uint64_t))
+
+#define        MAX_RANGES              16
+
+typedef struct zfs_ecksum_info {
+       /* histograms of set and cleared bits by bit number in a 64-bit word */
+       uint16_t zei_histogram_set[sizeof (uint64_t) * NBBY];
+       uint16_t zei_histogram_cleared[sizeof (uint64_t) * NBBY];
+
+       /* inline arrays of bits set and cleared. */
+       uint64_t zei_bits_set[ZFM_MAX_INLINE];
+       uint64_t zei_bits_cleared[ZFM_MAX_INLINE];
+
+       /*
+        * for each range, the number of bits set and cleared.  The Hamming
+        * distance between the good and bad buffers is the sum of them all.
+        */
+       uint32_t zei_range_sets[MAX_RANGES];
+       uint32_t zei_range_clears[MAX_RANGES];
+
+       struct zei_ranges {
+               uint32_t        zr_start;
+               uint32_t        zr_end;
+       } zei_ranges[MAX_RANGES];
+
+       size_t  zei_range_count;
+       uint32_t zei_mingap;
+       uint32_t zei_allowed_mingap;
+
+} zfs_ecksum_info_t;
+
+static void
+update_histogram(uint64_t value_arg, uint16_t *hist, uint32_t *count)
+{
+       size_t i;
+       size_t bits = 0;
+       uint64_t value = BE_64(value_arg);
+
+       /* We store the bits in big-endian (largest-first) order */
+       for (i = 0; i < 64; i++) {
+               if (value & (1ull << i)) {
+                       if (hist[63 - i] < UINT16_MAX)
+                               hist[63 - i]++;
+                       ++bits;
+               }
+       }
+       /* update the count of bits changed */
+       *count += bits;
+}
+
+/*
+ * We've now filled up the range array, and need to increase "mingap" and
+ * shrink the range list accordingly.  zei_mingap is always the smallest
+ * distance between array entries, so we set the new_allowed_gap to be
+ * one greater than that.  We then go through the list, joining together
+ * any ranges which are closer than the new_allowed_gap.
+ *
+ * By construction, there will be at least one.  We also update zei_mingap
+ * to the new smallest gap, to prepare for our next invocation.
+ */
+static void
+zei_shrink_ranges(zfs_ecksum_info_t *eip)
+{
+       uint32_t mingap = UINT32_MAX;
+       uint32_t new_allowed_gap = eip->zei_mingap + 1;
+
+       size_t idx, output;
+       size_t max = eip->zei_range_count;
+
+       struct zei_ranges *r = eip->zei_ranges;
+
+       ASSERT3U(eip->zei_range_count, >, 0);
+       ASSERT3U(eip->zei_range_count, <=, MAX_RANGES);
+
+       output = idx = 0;
+       while (idx < max - 1) {
+               uint32_t start = r[idx].zr_start;
+               uint32_t end = r[idx].zr_end;
+
+               while (idx < max - 1) {
+                       uint32_t nstart, nend, gap;
+
+                       idx++;
+                       nstart = r[idx].zr_start;
+                       nend = r[idx].zr_end;
+
+                       gap = nstart - end;
+                       if (gap < new_allowed_gap) {
+                               end = nend;
+                               continue;
+                       }
+                       if (gap < mingap)
+                               mingap = gap;
+                       break;
+               }
+               r[output].zr_start = start;
+               r[output].zr_end = end;
+               output++;
+       }
+       ASSERT3U(output, <, eip->zei_range_count);
+       eip->zei_range_count = output;
+       eip->zei_mingap = mingap;
+       eip->zei_allowed_mingap = new_allowed_gap;
+}
+
+static void
+zei_add_range(zfs_ecksum_info_t *eip, int start, int end)
+{
+       struct zei_ranges *r = eip->zei_ranges;
+       size_t count = eip->zei_range_count;
+
+       if (count >= MAX_RANGES) {
+               zei_shrink_ranges(eip);
+               count = eip->zei_range_count;
+       }
+       if (count == 0) {
+               eip->zei_mingap = UINT32_MAX;
+               eip->zei_allowed_mingap = 1;
+       } else {
+               int gap = start - r[count - 1].zr_end;
+
+               if (gap < eip->zei_allowed_mingap) {
+                       r[count - 1].zr_end = end;
+                       return;
+               }
+               if (gap < eip->zei_mingap)
+                       eip->zei_mingap = gap;
+       }
+       r[count].zr_start = start;
+       r[count].zr_end = end;
+       eip->zei_range_count++;
+}
+
+static size_t
+zei_range_total_size(zfs_ecksum_info_t *eip)
+{
+       struct zei_ranges *r = eip->zei_ranges;
+       size_t count = eip->zei_range_count;
+       size_t result = 0;
+       size_t idx;
+
+       for (idx = 0; idx < count; idx++)
+               result += (r[idx].zr_end - r[idx].zr_start);
+
+       return (result);
+}
+
+static zfs_ecksum_info_t *
+annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
+    const uint8_t *goodbuf, const uint8_t *badbuf, size_t size,
+    boolean_t drop_if_identical)
+{
+       const uint64_t *good = (const uint64_t *)goodbuf;
+       const uint64_t *bad = (const uint64_t *)badbuf;
+
+       uint64_t allset = 0;
+       uint64_t allcleared = 0;
+
+       size_t nui64s = size / sizeof (uint64_t);
+
+       size_t inline_size;
+       int no_inline = 0;
+       size_t idx;
+       size_t range;
+
+       size_t offset = 0;
+       ssize_t start = -1;
+
+       zfs_ecksum_info_t *eip = kmem_zalloc(sizeof (*eip), KM_SLEEP);
+
+       /* don't do any annotation for injected checksum errors */
+       if (info != NULL && info->zbc_injected)
+               return (eip);
+
+       if (info != NULL && info->zbc_has_cksum) {
+               fm_payload_set(ereport,
+                   FM_EREPORT_PAYLOAD_ZFS_CKSUM_EXPECTED,
+                   DATA_TYPE_UINT64_ARRAY,
+                   sizeof (info->zbc_expected) / sizeof (uint64_t),
+                   (uint64_t *)&info->zbc_expected,
+                   FM_EREPORT_PAYLOAD_ZFS_CKSUM_ACTUAL,
+                   DATA_TYPE_UINT64_ARRAY,
+                   sizeof (info->zbc_actual) / sizeof (uint64_t),
+                   (uint64_t *)&info->zbc_actual,
+                   FM_EREPORT_PAYLOAD_ZFS_CKSUM_ALGO,
+                   DATA_TYPE_STRING,
+                   info->zbc_checksum_name,
+                   NULL);
+
+               if (info->zbc_byteswapped) {
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_CKSUM_BYTESWAP,
+                           DATA_TYPE_BOOLEAN, 1,
+                           NULL);
+               }
+       }
+
+       if (badbuf == NULL || goodbuf == NULL)
+               return (eip);
+
+       ASSERT3U(size, ==, nui64s * sizeof (uint64_t));
+       ASSERT3U(size, <=, SPA_MAXBLOCKSIZE);
+       ASSERT3U(size, <=, UINT32_MAX);
+
+       /* build up the range list by comparing the two buffers. */
+       for (idx = 0; idx < nui64s; idx++) {
+               if (good[idx] == bad[idx]) {
+                       if (start == -1)
+                               continue;
+
+                       zei_add_range(eip, start, idx);
+                       start = -1;
+               } else {
+                       if (start != -1)
+                               continue;
+
+                       start = idx;
+               }
+       }
+       if (start != -1)
+               zei_add_range(eip, start, idx);
+
+       /* See if it will fit in our inline buffers */
+       inline_size = zei_range_total_size(eip);
+       if (inline_size > ZFM_MAX_INLINE)
+               no_inline = 1;
+
+       /*
+        * If there is no change and we want to drop if the buffers are
+        * identical, do so.
+        */
+       if (inline_size == 0 && drop_if_identical) {
+               kmem_free(eip, sizeof (*eip));
+               return (NULL);
+       }
+
+       /*
+        * Now walk through the ranges, filling in the details of the
+        * differences.  Also convert our uint64_t-array offsets to byte
+        * offsets.
+        */
+       for (range = 0; range < eip->zei_range_count; range++) {
+               size_t start = eip->zei_ranges[range].zr_start;
+               size_t end = eip->zei_ranges[range].zr_end;
+
+               for (idx = start; idx < end; idx++) {
+                       uint64_t set, cleared;
+
+                       // bits set in bad, but not in good
+                       set = ((~good[idx]) & bad[idx]);
+                       // bits set in good, but not in bad
+                       cleared = (good[idx] & (~bad[idx]));
+
+                       allset |= set;
+                       allcleared |= cleared;
+
+                       if (!no_inline) {
+                               ASSERT3U(offset, <, inline_size);
+                               eip->zei_bits_set[offset] = set;
+                               eip->zei_bits_cleared[offset] = cleared;
+                               offset++;
+                       }
+
+                       update_histogram(set, eip->zei_histogram_set,
+                           &eip->zei_range_sets[range]);
+                       update_histogram(cleared, eip->zei_histogram_cleared,
+                           &eip->zei_range_clears[range]);
+               }
+
+               /* convert to byte offsets */
+               eip->zei_ranges[range].zr_start *= sizeof (uint64_t);
+               eip->zei_ranges[range].zr_end   *= sizeof (uint64_t);
+       }
+       eip->zei_allowed_mingap *= sizeof (uint64_t);
+       inline_size             *= sizeof (uint64_t);
+
+       /* fill in ereport */
+       fm_payload_set(ereport,
+           FM_EREPORT_PAYLOAD_ZFS_BAD_OFFSET_RANGES,
+           DATA_TYPE_UINT32_ARRAY, 2 * eip->zei_range_count,
+           (uint32_t *)eip->zei_ranges,
+           FM_EREPORT_PAYLOAD_ZFS_BAD_RANGE_MIN_GAP,
+           DATA_TYPE_UINT32, eip->zei_allowed_mingap,
+           FM_EREPORT_PAYLOAD_ZFS_BAD_RANGE_SETS,
+           DATA_TYPE_UINT32_ARRAY, eip->zei_range_count, eip->zei_range_sets,
+           FM_EREPORT_PAYLOAD_ZFS_BAD_RANGE_CLEARS,
+           DATA_TYPE_UINT32_ARRAY, eip->zei_range_count, eip->zei_range_clears,
+           NULL);
+
+       if (!no_inline) {
+               fm_payload_set(ereport,
+                   FM_EREPORT_PAYLOAD_ZFS_BAD_SET_BITS,
+                   DATA_TYPE_UINT8_ARRAY,
+                   inline_size, (uint8_t *)eip->zei_bits_set,
+                   FM_EREPORT_PAYLOAD_ZFS_BAD_CLEARED_BITS,
+                   DATA_TYPE_UINT8_ARRAY,
+                   inline_size, (uint8_t *)eip->zei_bits_cleared,
+                   NULL);
+       } else {
+               fm_payload_set(ereport,
+                   FM_EREPORT_PAYLOAD_ZFS_BAD_SET_HISTOGRAM,
+                   DATA_TYPE_UINT16_ARRAY,
+                   NBBY * sizeof (uint64_t), eip->zei_histogram_set,
+                   FM_EREPORT_PAYLOAD_ZFS_BAD_CLEARED_HISTOGRAM,
+                   DATA_TYPE_UINT16_ARRAY,
+                   NBBY * sizeof (uint64_t), eip->zei_histogram_cleared,
+                   NULL);
+       }
+       return (eip);
+}
+#endif
+
+void
+zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
+    uint64_t stateoroffset, uint64_t size)
+{
+#ifdef _KERNEL
+       nvlist_t *ereport = NULL;
+       nvlist_t *detector = NULL;
+
+       zfs_ereport_start(&ereport, &detector,
+           subclass, spa, vd, zio, stateoroffset, size);
+
+       if (ereport == NULL)
+               return;
+
+       /* Cleanup is handled by the callback function */
+       zfs_zevent_post(ereport, detector, zfs_zevent_post_cb);
+#endif
+}
+
+void
+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);
+
+       if (zio->io_vsd != NULL)
+               zio->io_vsd_ops->vsd_cksum_report(zio, report, arg);
+       else
+               zio_vsd_default_cksum_report(zio, report, arg);
+
+       /* copy the checksum failure information if it was provided */
+       if (info != NULL) {
+               report->zcr_ckinfo = kmem_zalloc(sizeof (*info), KM_SLEEP);
+               bcopy(info, report->zcr_ckinfo, sizeof (*info));
+       }
+
+       report->zcr_align = 1ULL << vd->vdev_top->vdev_ashift;
+       report->zcr_length = length;
+
+#ifdef _KERNEL
+       zfs_ereport_start(&report->zcr_ereport, &report->zcr_detector,
+           FM_EREPORT_ZFS_CHECKSUM, spa, vd, zio, offset, length);
+
+       if (report->zcr_ereport == NULL) {
+               zfs_ereport_free_checksum(report);
+               return;
+       }
+#endif
+
+       mutex_enter(&spa->spa_errlist_lock);
+       report->zcr_next = zio->io_logical->io_cksum_report;
+       zio->io_logical->io_cksum_report = report;
+       mutex_exit(&spa->spa_errlist_lock);
+}
+
+void
+zfs_ereport_finish_checksum(zio_cksum_report_t *report,
+    const void *good_data, const void *bad_data, boolean_t drop_if_identical)
+{
+#ifdef _KERNEL
+       zfs_ecksum_info_t *info;
+
+       info = annotate_ecksum(report->zcr_ereport, report->zcr_ckinfo,
+           good_data, bad_data, report->zcr_length, drop_if_identical);
+       if (info != NULL)
+               zfs_zevent_post(report->zcr_ereport,
+                   report->zcr_detector, zfs_zevent_post_cb);
+       else
+               zfs_zevent_post_cb(report->zcr_ereport, report->zcr_detector);
+
+       report->zcr_ereport = report->zcr_detector = NULL;
+       if (info != NULL)
+               kmem_free(info, sizeof (*info));
+#endif
+}
+
+void
+zfs_ereport_free_checksum(zio_cksum_report_t *rpt)
+{
+#ifdef _KERNEL
+       if (rpt->zcr_ereport != NULL) {
+               fm_nvlist_destroy(rpt->zcr_ereport,
+                   FM_NVA_FREE);
+               fm_nvlist_destroy(rpt->zcr_detector,
+                   FM_NVA_FREE);
+       }
+#endif
+       rpt->zcr_free(rpt->zcr_cbdata, rpt->zcr_cbinfo);
+
+       if (rpt->zcr_ckinfo != NULL)
+               kmem_free(rpt->zcr_ckinfo, sizeof (*rpt->zcr_ckinfo));
+
+       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,
+    struct zio *zio, uint64_t offset, uint64_t length,
+    const void *good_data, const void *bad_data, zio_bad_cksum_t *zbc)
+{
+#ifdef _KERNEL
+       nvlist_t *ereport = NULL;
+       nvlist_t *detector = NULL;
+       zfs_ecksum_info_t *info;
+
+       zfs_ereport_start(&ereport, &detector,
+           FM_EREPORT_ZFS_CHECKSUM, spa, vd, zio, offset, length);
+
+       if (ereport == NULL)
+               return;
+
+       info = annotate_ecksum(ereport, zbc, good_data, bad_data, length,
+           B_FALSE);
+
+       if (info != NULL) {
+               zfs_zevent_post(ereport, detector, zfs_zevent_post_cb);
+               kmem_free(info, sizeof (*info));
+       }
+#endif
+}
+
+static void
+zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
+{
+#ifdef _KERNEL
+       nvlist_t *resource;
+       char class[64];
+
+       if (spa_load_state(spa) == SPA_LOAD_TRYIMPORT)
+               return;
+
+       if ((resource = fm_nvlist_create(NULL)) == NULL)
+               return;
+
+       (void) snprintf(class, sizeof (class), "%s.%s.%s", FM_RSRC_RESOURCE,
+           ZFS_ERROR_CLASS, name);
+       VERIFY0(nvlist_add_uint8(resource, FM_VERSION, FM_RSRC_VERSION));
+       VERIFY0(nvlist_add_string(resource, FM_CLASS, class));
+       VERIFY0(nvlist_add_uint64(resource,
+           FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, spa_guid(spa)));
+       VERIFY0(nvlist_add_int32(resource,
+           FM_EREPORT_PAYLOAD_ZFS_POOL_CONTEXT, spa_load_state(spa)));
+
+       if (vd) {
+               VERIFY0(nvlist_add_uint64(resource,
+                   FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vd->vdev_guid));
+               VERIFY0(nvlist_add_uint64(resource,
+                   FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE, vd->vdev_state));
+       }
+
+       zfs_zevent_post(resource, NULL, zfs_zevent_post_cb);
+#endif
+}
+
+/*
+ * The 'resource.fs.zfs.removed' event is an internal signal that the given vdev
+ * has been removed from the system.  This will cause the DE to ignore any
+ * recent I/O errors, inferring that they are due to the asynchronous device
+ * removal.
+ */
+void
+zfs_post_remove(spa_t *spa, vdev_t *vd)
+{
+       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_REMOVED);
+}
+
+/*
+ * The 'resource.fs.zfs.autoreplace' event is an internal signal that the pool
+ * has the 'autoreplace' property set, and therefore any broken vdevs will be
+ * handled by higher level logic, and no vdev fault should be generated.
+ */
+void
+zfs_post_autoreplace(spa_t *spa, vdev_t *vd)
+{
+       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_AUTOREPLACE);
+}
+
+/*
+ * The 'resource.fs.zfs.statechange' event is an internal signal that the
+ * given vdev has transitioned its state to DEGRADED or HEALTHY.  This will
+ * cause the retire agent to repair any outstanding fault management cases
+ * open because the device was not found (fault.fs.zfs.device).
+ */
+void
+zfs_post_state_change(spa_t *spa, vdev_t *vd)
+{
+       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_STATECHANGE);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zfs_ereport_post);
+EXPORT_SYMBOL(zfs_ereport_post_checksum);
+EXPORT_SYMBOL(zfs_post_remove);
+EXPORT_SYMBOL(zfs_post_autoreplace);
+EXPORT_SYMBOL(zfs_post_state_change);
+#endif /* _KERNEL */
diff --git a/zfs/module/zfs/zfs_fuid.c b/zfs/module/zfs/zfs_fuid.c
new file mode 100644 (file)
index 0000000..6ca61b8
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dmu.h>
+#include <sys/avl.h>
+#include <sys/zap.h>
+#include <sys/refcount.h>
+#include <sys/nvpair.h>
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#include <sys/sid.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_znode.h>
+#endif
+#include <sys/zfs_fuid.h>
+
+/*
+ * FUID Domain table(s).
+ *
+ * The FUID table is stored as a packed nvlist of an array
+ * of nvlists which contain an index, domain string and offset
+ *
+ * During file system initialization the nvlist(s) are read and
+ * two AVL trees are created.  One tree is keyed by the index number
+ * and the other by the domain string.  Nodes are never removed from
+ * trees, but new entries may be added.  If a new entry is added then
+ * the zsb->z_fuid_dirty flag is set to true and the caller will then
+ * be responsible for calling zfs_fuid_sync() to sync the changes to disk.
+ *
+ */
+
+#define        FUID_IDX        "fuid_idx"
+#define        FUID_DOMAIN     "fuid_domain"
+#define        FUID_OFFSET     "fuid_offset"
+#define        FUID_NVP_ARRAY  "fuid_nvlist"
+
+typedef struct fuid_domain {
+       avl_node_t      f_domnode;
+       avl_node_t      f_idxnode;
+       ksiddomain_t    *f_ksid;
+       uint64_t        f_idx;
+} fuid_domain_t;
+
+static char *nulldomain = "";
+
+/*
+ * Compare two indexes.
+ */
+static int
+idx_compare(const void *arg1, const void *arg2)
+{
+       const fuid_domain_t *node1 = arg1;
+       const fuid_domain_t *node2 = arg2;
+
+       if (node1->f_idx < node2->f_idx)
+               return (-1);
+       else if (node1->f_idx > node2->f_idx)
+               return (1);
+       return (0);
+}
+
+/*
+ * Compare two domain strings.
+ */
+static int
+domain_compare(const void *arg1, const void *arg2)
+{
+       const fuid_domain_t *node1 = arg1;
+       const fuid_domain_t *node2 = 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);
+}
+
+void
+zfs_fuid_avl_tree_create(avl_tree_t *idx_tree, avl_tree_t *domain_tree)
+{
+       avl_create(idx_tree, idx_compare,
+           sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_idxnode));
+       avl_create(domain_tree, domain_compare,
+           sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_domnode));
+}
+
+/*
+ * load initial fuid domain and idx trees.  This function is used by
+ * both the kernel and zdb.
+ */
+uint64_t
+zfs_fuid_table_load(objset_t *os, uint64_t fuid_obj, avl_tree_t *idx_tree,
+    avl_tree_t *domain_tree)
+{
+       dmu_buf_t *db;
+       uint64_t fuid_size;
+
+       ASSERT(fuid_obj != 0);
+       VERIFY(0 == dmu_bonus_hold(os, fuid_obj,
+           FTAG, &db));
+       fuid_size = *(uint64_t *)db->db_data;
+       dmu_buf_rele(db, FTAG);
+
+       if (fuid_size)  {
+               nvlist_t **fuidnvp;
+               nvlist_t *nvp = NULL;
+               uint_t count;
+               char *packed;
+               int i;
+
+               packed = kmem_alloc(fuid_size, KM_SLEEP);
+               VERIFY(dmu_read(os, fuid_obj, 0,
+                   fuid_size, packed, DMU_READ_PREFETCH) == 0);
+               VERIFY(nvlist_unpack(packed, fuid_size,
+                   &nvp, 0) == 0);
+               VERIFY(nvlist_lookup_nvlist_array(nvp, FUID_NVP_ARRAY,
+                   &fuidnvp, &count) == 0);
+
+               for (i = 0; i != count; i++) {
+                       fuid_domain_t *domnode;
+                       char *domain;
+                       uint64_t idx;
+
+                       VERIFY(nvlist_lookup_string(fuidnvp[i], FUID_DOMAIN,
+                           &domain) == 0);
+                       VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_IDX,
+                           &idx) == 0);
+
+                       domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+
+                       domnode->f_idx = idx;
+                       domnode->f_ksid = ksid_lookupdomain(domain);
+                       avl_add(idx_tree, domnode);
+                       avl_add(domain_tree, domnode);
+               }
+               nvlist_free(nvp);
+               kmem_free(packed, fuid_size);
+       }
+       return (fuid_size);
+}
+
+void
+zfs_fuid_table_destroy(avl_tree_t *idx_tree, avl_tree_t *domain_tree)
+{
+       fuid_domain_t *domnode;
+       void *cookie;
+
+       cookie = NULL;
+       while ((domnode = avl_destroy_nodes(domain_tree, &cookie)))
+               ksiddomain_rele(domnode->f_ksid);
+
+       avl_destroy(domain_tree);
+       cookie = NULL;
+       while ((domnode = avl_destroy_nodes(idx_tree, &cookie)))
+               kmem_free(domnode, sizeof (fuid_domain_t));
+       avl_destroy(idx_tree);
+}
+
+char *
+zfs_fuid_idx_domain(avl_tree_t *idx_tree, uint32_t idx)
+{
+       fuid_domain_t searchnode, *findnode;
+       avl_index_t loc;
+
+       searchnode.f_idx = idx;
+
+       findnode = avl_find(idx_tree, &searchnode, &loc);
+
+       return (findnode ? findnode->f_ksid->kd_name : nulldomain);
+}
+
+#ifdef _KERNEL
+/*
+ * Load the fuid table(s) into memory.
+ */
+static void
+zfs_fuid_init(zfs_sb_t *zsb)
+{
+       rw_enter(&zsb->z_fuid_lock, RW_WRITER);
+
+       if (zsb->z_fuid_loaded) {
+               rw_exit(&zsb->z_fuid_lock);
+               return;
+       }
+
+       zfs_fuid_avl_tree_create(&zsb->z_fuid_idx, &zsb->z_fuid_domain);
+
+       (void) zap_lookup(zsb->z_os, MASTER_NODE_OBJ,
+           ZFS_FUID_TABLES, 8, 1, &zsb->z_fuid_obj);
+       if (zsb->z_fuid_obj != 0) {
+               zsb->z_fuid_size = zfs_fuid_table_load(zsb->z_os,
+                   zsb->z_fuid_obj, &zsb->z_fuid_idx,
+                   &zsb->z_fuid_domain);
+       }
+
+       zsb->z_fuid_loaded = B_TRUE;
+       rw_exit(&zsb->z_fuid_lock);
+}
+
+/*
+ * sync out AVL trees to persistent storage.
+ */
+void
+zfs_fuid_sync(zfs_sb_t *zsb, dmu_tx_t *tx)
+{
+       nvlist_t *nvp;
+       nvlist_t **fuids;
+       size_t nvsize = 0;
+       char *packed;
+       dmu_buf_t *db;
+       fuid_domain_t *domnode;
+       int numnodes;
+       int i;
+
+       if (!zsb->z_fuid_dirty) {
+               return;
+       }
+
+       rw_enter(&zsb->z_fuid_lock, RW_WRITER);
+
+       /*
+        * First see if table needs to be created?
+        */
+       if (zsb->z_fuid_obj == 0) {
+               zsb->z_fuid_obj = dmu_object_alloc(zsb->z_os,
+                   DMU_OT_FUID, 1 << 14, DMU_OT_FUID_SIZE,
+                   sizeof (uint64_t), tx);
+               VERIFY(zap_add(zsb->z_os, MASTER_NODE_OBJ,
+                   ZFS_FUID_TABLES, sizeof (uint64_t), 1,
+                   &zsb->z_fuid_obj, tx) == 0);
+       }
+
+       VERIFY(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       numnodes = avl_numnodes(&zsb->z_fuid_idx);
+       fuids = kmem_alloc(numnodes * sizeof (void *), KM_SLEEP);
+       for (i = 0, domnode = avl_first(&zsb->z_fuid_domain); domnode; i++,
+           domnode = AVL_NEXT(&zsb->z_fuid_domain, domnode)) {
+               VERIFY(nvlist_alloc(&fuids[i], NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               VERIFY(nvlist_add_uint64(fuids[i], FUID_IDX,
+                   domnode->f_idx) == 0);
+               VERIFY(nvlist_add_uint64(fuids[i], FUID_OFFSET, 0) == 0);
+               VERIFY(nvlist_add_string(fuids[i], FUID_DOMAIN,
+                   domnode->f_ksid->kd_name) == 0);
+       }
+       VERIFY(nvlist_add_nvlist_array(nvp, FUID_NVP_ARRAY,
+           fuids, numnodes) == 0);
+       for (i = 0; i != numnodes; i++)
+               nvlist_free(fuids[i]);
+       kmem_free(fuids, numnodes * sizeof (void *));
+       VERIFY(nvlist_size(nvp, &nvsize, NV_ENCODE_XDR) == 0);
+       packed = kmem_alloc(nvsize, KM_SLEEP);
+       VERIFY(nvlist_pack(nvp, &packed, &nvsize,
+           NV_ENCODE_XDR, KM_SLEEP) == 0);
+       nvlist_free(nvp);
+       zsb->z_fuid_size = nvsize;
+       dmu_write(zsb->z_os, zsb->z_fuid_obj, 0, zsb->z_fuid_size, packed, tx);
+       kmem_free(packed, zsb->z_fuid_size);
+       VERIFY(0 == dmu_bonus_hold(zsb->z_os, zsb->z_fuid_obj,
+           FTAG, &db));
+       dmu_buf_will_dirty(db, tx);
+       *(uint64_t *)db->db_data = zsb->z_fuid_size;
+       dmu_buf_rele(db, FTAG);
+
+       zsb->z_fuid_dirty = B_FALSE;
+       rw_exit(&zsb->z_fuid_lock);
+}
+
+/*
+ * Query domain table for a given domain.
+ *
+ * If domain isn't found and addok is set, it is added to AVL trees and
+ * the zsb->z_fuid_dirty flag will be set to TRUE.  It will then be
+ * necessary for the caller or another thread to detect the dirty table
+ * and sync out the changes.
+ */
+int
+zfs_fuid_find_by_domain(zfs_sb_t *zsb, const char *domain,
+    char **retdomain, boolean_t addok)
+{
+       fuid_domain_t searchnode, *findnode;
+       avl_index_t loc;
+       krw_t rw = RW_READER;
+
+       /*
+        * If the dummy "nobody" domain then return an index of 0
+        * to cause the created FUID to be a standard POSIX id
+        * for the user nobody.
+        */
+       if (domain[0] == '\0') {
+               if (retdomain)
+                       *retdomain = nulldomain;
+               return (0);
+       }
+
+       searchnode.f_ksid = ksid_lookupdomain(domain);
+       if (retdomain)
+               *retdomain = searchnode.f_ksid->kd_name;
+       if (!zsb->z_fuid_loaded)
+               zfs_fuid_init(zsb);
+
+retry:
+       rw_enter(&zsb->z_fuid_lock, rw);
+       findnode = avl_find(&zsb->z_fuid_domain, &searchnode, &loc);
+
+       if (findnode) {
+               rw_exit(&zsb->z_fuid_lock);
+               ksiddomain_rele(searchnode.f_ksid);
+               return (findnode->f_idx);
+       } else if (addok) {
+               fuid_domain_t *domnode;
+               uint64_t retidx;
+
+               if (rw == RW_READER && !rw_tryupgrade(&zsb->z_fuid_lock)) {
+                       rw_exit(&zsb->z_fuid_lock);
+                       rw = RW_WRITER;
+                       goto retry;
+               }
+
+               domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+               domnode->f_ksid = searchnode.f_ksid;
+
+               retidx = domnode->f_idx = avl_numnodes(&zsb->z_fuid_idx) + 1;
+
+               avl_add(&zsb->z_fuid_domain, domnode);
+               avl_add(&zsb->z_fuid_idx, domnode);
+               zsb->z_fuid_dirty = B_TRUE;
+               rw_exit(&zsb->z_fuid_lock);
+               return (retidx);
+       } else {
+               rw_exit(&zsb->z_fuid_lock);
+               return (-1);
+       }
+}
+
+/*
+ * Query domain table by index, returning domain string
+ *
+ * Returns a pointer from an avl node of the domain string.
+ *
+ */
+const char *
+zfs_fuid_find_by_idx(zfs_sb_t *zsb, uint32_t idx)
+{
+       char *domain;
+
+       if (idx == 0 || !zsb->z_use_fuids)
+               return (NULL);
+
+       if (!zsb->z_fuid_loaded)
+               zfs_fuid_init(zsb);
+
+       rw_enter(&zsb->z_fuid_lock, RW_READER);
+
+       if (zsb->z_fuid_obj || zsb->z_fuid_dirty)
+               domain = zfs_fuid_idx_domain(&zsb->z_fuid_idx, idx);
+       else
+               domain = nulldomain;
+       rw_exit(&zsb->z_fuid_lock);
+
+       ASSERT(domain);
+       return (domain);
+}
+
+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);
+}
+
+uid_t
+zfs_fuid_map_id(zfs_sb_t *zsb, uint64_t fuid,
+    cred_t *cr, zfs_fuid_type_t type)
+{
+#ifdef HAVE_KSID
+       uint32_t index = FUID_INDEX(fuid);
+       const char *domain;
+       uid_t id;
+
+       if (index == 0)
+               return (fuid);
+
+       domain = zfs_fuid_find_by_idx(zsb, index);
+       ASSERT(domain != NULL);
+
+       if (type == ZFS_OWNER || type == ZFS_ACE_USER) {
+               (void) kidmap_getuidbysid(crgetzone(cr), domain,
+                   FUID_RID(fuid), &id);
+       } else {
+               (void) kidmap_getgidbysid(crgetzone(cr), domain,
+                   FUID_RID(fuid), &id);
+       }
+       return (id);
+#else
+       /*
+        * The Linux port only supports POSIX IDs, use the passed id.
+        */
+       return (fuid);
+#endif /* HAVE_KSID */
+}
+
+/*
+ * Add a FUID node to the list of fuid's being created for this
+ * ACL
+ *
+ * If ACL has multiple domains, then keep only one copy of each unique
+ * domain.
+ */
+void
+zfs_fuid_node_add(zfs_fuid_info_t **fuidpp, const char *domain, uint32_t rid,
+    uint64_t idx, uint64_t id, zfs_fuid_type_t type)
+{
+       zfs_fuid_t *fuid;
+       zfs_fuid_domain_t *fuid_domain;
+       zfs_fuid_info_t *fuidp;
+       uint64_t fuididx;
+       boolean_t found = B_FALSE;
+
+       if (*fuidpp == NULL)
+               *fuidpp = zfs_fuid_info_alloc();
+
+       fuidp = *fuidpp;
+       /*
+        * First find fuid domain index in linked list
+        *
+        * If one isn't found then create an entry.
+        */
+
+       for (fuididx = 1, fuid_domain = list_head(&fuidp->z_domains);
+           fuid_domain; fuid_domain = list_next(&fuidp->z_domains,
+           fuid_domain), fuididx++) {
+               if (idx == fuid_domain->z_domidx) {
+                       found = B_TRUE;
+                       break;
+               }
+       }
+
+       if (!found) {
+               fuid_domain = kmem_alloc(sizeof (zfs_fuid_domain_t), KM_SLEEP);
+               fuid_domain->z_domain = domain;
+               fuid_domain->z_domidx = idx;
+               list_insert_tail(&fuidp->z_domains, fuid_domain);
+               fuidp->z_domain_str_sz += strlen(domain) + 1;
+               fuidp->z_domain_cnt++;
+       }
+
+       if (type == ZFS_ACE_USER || type == ZFS_ACE_GROUP) {
+
+               /*
+                * Now allocate fuid entry and add it on the end of the list
+                */
+
+               fuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP);
+               fuid->z_id = id;
+               fuid->z_domidx = idx;
+               fuid->z_logfuid = FUID_ENCODE(fuididx, rid);
+
+               list_insert_tail(&fuidp->z_fuids, fuid);
+               fuidp->z_fuid_cnt++;
+       } else {
+               if (type == ZFS_OWNER)
+                       fuidp->z_fuid_owner = FUID_ENCODE(fuididx, rid);
+               else
+                       fuidp->z_fuid_group = FUID_ENCODE(fuididx, rid);
+       }
+}
+
+#ifdef HAVE_KSID
+/*
+ * Create a file system FUID, based on information in the users cred
+ *
+ * If cred contains KSID_OWNER then it should be used to determine
+ * the uid otherwise cred's uid will be used. By default cred's gid
+ * is used unless it's an ephemeral ID in which case KSID_GROUP will
+ * be used if it exists.
+ */
+uint64_t
+zfs_fuid_create_cred(zfs_sb_t *zsb, zfs_fuid_type_t type,
+    cred_t *cr, zfs_fuid_info_t **fuidp)
+{
+       uint64_t        idx;
+       ksid_t          *ksid;
+       uint32_t        rid;
+       char            *kdomain;
+       const char      *domain;
+       uid_t           id;
+
+       VERIFY(type == ZFS_OWNER || type == ZFS_GROUP);
+
+       ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP);
+
+       if (!zsb->z_use_fuids || (ksid == NULL)) {
+               id = (type == ZFS_OWNER) ? crgetuid(cr) : crgetgid(cr);
+
+               if (IS_EPHEMERAL(id))
+                       return ((type == ZFS_OWNER) ? UID_NOBODY : GID_NOBODY);
+
+               return ((uint64_t)id);
+       }
+
+       /*
+        * ksid is present and FUID is supported
+        */
+       id = (type == ZFS_OWNER) ? ksid_getid(ksid) : crgetgid(cr);
+
+       if (!IS_EPHEMERAL(id))
+               return ((uint64_t)id);
+
+       if (type == ZFS_GROUP)
+               id = ksid_getid(ksid);
+
+       rid = ksid_getrid(ksid);
+       domain = ksid_getdomain(ksid);
+
+       idx = zfs_fuid_find_by_domain(zsb, domain, &kdomain, B_TRUE);
+
+       zfs_fuid_node_add(fuidp, kdomain, rid, idx, id, type);
+
+       return (FUID_ENCODE(idx, rid));
+}
+#endif /* HAVE_KSID */
+
+/*
+ * Create a file system FUID for an ACL ace
+ * or a chown/chgrp of the file.
+ * This is similar to zfs_fuid_create_cred, except that
+ * we can't find the domain + rid information in the
+ * cred.  Instead we have to query Winchester for the
+ * domain and rid.
+ *
+ * During replay operations the domain+rid information is
+ * found in the zfs_fuid_info_t that the replay code has
+ * attached to the zsb of the file system.
+ */
+uint64_t
+zfs_fuid_create(zfs_sb_t *zsb, uint64_t id, cred_t *cr,
+    zfs_fuid_type_t type, zfs_fuid_info_t **fuidpp)
+{
+#ifdef HAVE_KSID
+       const char *domain;
+       char *kdomain;
+       uint32_t fuid_idx = FUID_INDEX(id);
+       uint32_t rid;
+       idmap_stat status;
+       uint64_t idx = 0;
+       zfs_fuid_t *zfuid = NULL;
+       zfs_fuid_info_t *fuidp = NULL;
+
+       /*
+        * If POSIX ID, or entry is already a FUID then
+        * just return the id
+        *
+        * We may also be handed an already FUID'ized id via
+        * chmod.
+        */
+
+       if (!zsb->z_use_fuids || !IS_EPHEMERAL(id) || fuid_idx != 0)
+               return (id);
+
+       if (zsb->z_replay) {
+               fuidp = zsb->z_fuid_replay;
+
+               /*
+                * If we are passed an ephemeral id, but no
+                * fuid_info was logged then return NOBODY.
+                * This is most likely a result of idmap service
+                * not being available.
+                */
+               if (fuidp == NULL)
+                       return (UID_NOBODY);
+
+               VERIFY3U(type, >=, ZFS_OWNER);
+               VERIFY3U(type, <=, ZFS_ACE_GROUP);
+
+               switch (type) {
+               case ZFS_ACE_USER:
+               case ZFS_ACE_GROUP:
+                       zfuid = list_head(&fuidp->z_fuids);
+                       rid = FUID_RID(zfuid->z_logfuid);
+                       idx = FUID_INDEX(zfuid->z_logfuid);
+                       break;
+               case ZFS_OWNER:
+                       rid = FUID_RID(fuidp->z_fuid_owner);
+                       idx = FUID_INDEX(fuidp->z_fuid_owner);
+                       break;
+               case ZFS_GROUP:
+                       rid = FUID_RID(fuidp->z_fuid_group);
+                       idx = FUID_INDEX(fuidp->z_fuid_group);
+                       break;
+               };
+               domain = fuidp->z_domain_table[idx - 1];
+       } else {
+               if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+                       status = kidmap_getsidbyuid(crgetzone(cr), id,
+                           &domain, &rid);
+               else
+                       status = kidmap_getsidbygid(crgetzone(cr), id,
+                           &domain, &rid);
+
+               if (status != 0) {
+                       /*
+                        * When returning nobody we will need to
+                        * make a dummy fuid table entry for logging
+                        * purposes.
+                        */
+                       rid = UID_NOBODY;
+                       domain = nulldomain;
+               }
+       }
+
+       idx = zfs_fuid_find_by_domain(zsb, domain, &kdomain, B_TRUE);
+
+       if (!zsb->z_replay)
+               zfs_fuid_node_add(fuidpp, kdomain,
+                   rid, idx, id, type);
+       else if (zfuid != NULL) {
+               list_remove(&fuidp->z_fuids, zfuid);
+               kmem_free(zfuid, sizeof (zfs_fuid_t));
+       }
+       return (FUID_ENCODE(idx, rid));
+#else
+       /*
+        * The Linux port only supports POSIX IDs, use the passed id.
+        */
+       return (id);
+#endif
+}
+
+void
+zfs_fuid_destroy(zfs_sb_t *zsb)
+{
+       rw_enter(&zsb->z_fuid_lock, RW_WRITER);
+       if (!zsb->z_fuid_loaded) {
+               rw_exit(&zsb->z_fuid_lock);
+               return;
+       }
+       zfs_fuid_table_destroy(&zsb->z_fuid_idx, &zsb->z_fuid_domain);
+       rw_exit(&zsb->z_fuid_lock);
+}
+
+/*
+ * Allocate zfs_fuid_info for tracking FUIDs created during
+ * zfs_mknode, VOP_SETATTR() or VOP_SETSECATTR()
+ */
+zfs_fuid_info_t *
+zfs_fuid_info_alloc(void)
+{
+       zfs_fuid_info_t *fuidp;
+
+       fuidp = kmem_zalloc(sizeof (zfs_fuid_info_t), KM_SLEEP);
+       list_create(&fuidp->z_domains, sizeof (zfs_fuid_domain_t),
+           offsetof(zfs_fuid_domain_t, z_next));
+       list_create(&fuidp->z_fuids, sizeof (zfs_fuid_t),
+           offsetof(zfs_fuid_t, z_next));
+       return (fuidp);
+}
+
+/*
+ * Release all memory associated with zfs_fuid_info_t
+ */
+void
+zfs_fuid_info_free(zfs_fuid_info_t *fuidp)
+{
+       zfs_fuid_t *zfuid;
+       zfs_fuid_domain_t *zdomain;
+
+       while ((zfuid = list_head(&fuidp->z_fuids)) != NULL) {
+               list_remove(&fuidp->z_fuids, zfuid);
+               kmem_free(zfuid, sizeof (zfs_fuid_t));
+       }
+
+       if (fuidp->z_domain_table != NULL)
+               kmem_free(fuidp->z_domain_table,
+                   (sizeof (char **)) * fuidp->z_domain_cnt);
+
+       while ((zdomain = list_head(&fuidp->z_domains)) != NULL) {
+               list_remove(&fuidp->z_domains, zdomain);
+               kmem_free(zdomain, sizeof (zfs_fuid_domain_t));
+       }
+
+       kmem_free(fuidp, sizeof (zfs_fuid_info_t));
+}
+
+/*
+ * Check to see if id is a groupmember.  If cred
+ * has ksid info then sidlist is checked first
+ * and if still not found then POSIX groups are checked
+ *
+ * Will use a straight FUID compare when possible.
+ */
+boolean_t
+zfs_groupmember(zfs_sb_t *zsb, uint64_t id, cred_t *cr)
+{
+#ifdef HAVE_KSID
+       ksid_t          *ksid = crgetsid(cr, KSID_GROUP);
+       ksidlist_t      *ksidlist = crgetsidlist(cr);
+       uid_t           gid;
+
+       if (ksid && ksidlist) {
+               int             i;
+               ksid_t          *ksid_groups;
+               uint32_t        idx = FUID_INDEX(id);
+               uint32_t        rid = FUID_RID(id);
+
+               ksid_groups = ksidlist->ksl_sids;
+
+               for (i = 0; i != ksidlist->ksl_nsid; i++) {
+                       if (idx == 0) {
+                               if (id != IDMAP_WK_CREATOR_GROUP_GID &&
+                                   id == ksid_groups[i].ks_id) {
+                                       return (B_TRUE);
+                               }
+                       } else {
+                               const char *domain;
+
+                               domain = zfs_fuid_find_by_idx(zsb, idx);
+                               ASSERT(domain != NULL);
+
+                               if (strcmp(domain,
+                                   IDMAP_WK_CREATOR_SID_AUTHORITY) == 0)
+                                       return (B_FALSE);
+
+                               if ((strcmp(domain,
+                                   ksid_groups[i].ks_domain->kd_name) == 0) &&
+                                   rid == ksid_groups[i].ks_rid)
+                                       return (B_TRUE);
+                       }
+               }
+       }
+
+       /*
+        * Not found in ksidlist, check posix groups
+        */
+       gid = zfs_fuid_map_id(zsb, id, cr, ZFS_GROUP);
+       return (groupmember(gid, cr));
+#else
+       return (B_TRUE);
+#endif
+}
+
+void
+zfs_fuid_txhold(zfs_sb_t *zsb, dmu_tx_t *tx)
+{
+       if (zsb->z_fuid_obj == 0) {
+               dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+               dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+                   FUID_SIZE_ESTIMATE(zsb));
+               dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+       } else {
+               dmu_tx_hold_bonus(tx, zsb->z_fuid_obj);
+               dmu_tx_hold_write(tx, zsb->z_fuid_obj, 0,
+                   FUID_SIZE_ESTIMATE(zsb));
+       }
+}
+#endif
diff --git a/zfs/module/zfs/zfs_ioctl.c b/zfs/module/zfs/zfs_ioctl.c
new file mode 100644 (file)
index 0000000..3ebe28d
--- /dev/null
@@ -0,0 +1,6059 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ * Portions Copyright 2011 Martin Matuska
+ * 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 (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2014 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.
+ */
+
+/*
+ * ZFS ioctls.
+ *
+ * This file handles the ioctls to /dev/zfs, used for configuring ZFS storage
+ * pools and filesystems, e.g. with /sbin/zfs and /sbin/zpool.
+ *
+ * There are two ways that we handle ioctls: the legacy way where almost
+ * all of the logic is in the ioctl callback, and the new way where most
+ * of the marshalling is handled in the common entry point, zfsdev_ioctl().
+ *
+ * Non-legacy ioctls should be registered by calling
+ * zfs_ioctl_register() from zfs_ioctl_init().  The ioctl is invoked
+ * from userland by lzc_ioctl().
+ *
+ * The registration arguments are as follows:
+ *
+ * const char *name
+ *   The name of the ioctl.  This is used for history logging.  If the
+ *   ioctl returns successfully (the callback returns 0), and allow_log
+ *   is true, then a history log entry will be recorded with the input &
+ *   output nvlists.  The log entry can be printed with "zpool history -i".
+ *
+ * zfs_ioc_t ioc
+ *   The ioctl request number, which userland will pass to ioctl(2).
+ *   The ioctl numbers can change from release to release, because
+ *   the caller (libzfs) must be matched to the kernel.
+ *
+ * zfs_secpolicy_func_t *secpolicy
+ *   This function will be called before the zfs_ioc_func_t, to
+ *   determine if this operation is permitted.  It should return EPERM
+ *   on failure, and 0 on success.  Checks include determining if the
+ *   dataset is visible in this zone, and if the user has either all
+ *   zfs privileges in the zone (SYS_MOUNT), or has been granted permission
+ *   to do this operation on this dataset with "zfs allow".
+ *
+ * zfs_ioc_namecheck_t namecheck
+ *   This specifies what to expect in the zfs_cmd_t:zc_name -- a pool
+ *   name, a dataset name, or nothing.  If the name is not well-formed,
+ *   the ioctl will fail and the callback will not be called.
+ *   Therefore, the callback can assume that the name is well-formed
+ *   (e.g. is null-terminated, doesn't have more than one '@' character,
+ *   doesn't have invalid characters).
+ *
+ * zfs_ioc_poolcheck_t pool_check
+ *   This specifies requirements on the pool state.  If the pool does
+ *   not meet them (is suspended or is readonly), the ioctl will fail
+ *   and the callback will not be called.  If any checks are specified
+ *   (i.e. it is not POOL_CHECK_NONE), namecheck must not be NO_NAME.
+ *   Multiple checks can be or-ed together (e.g. POOL_CHECK_SUSPENDED |
+ *   POOL_CHECK_READONLY).
+ *
+ * boolean_t smush_outnvlist
+ *   If smush_outnvlist is true, then the output is presumed to be a
+ *   list of errors, and it will be "smushed" down to fit into the
+ *   caller's buffer, by removing some entries and replacing them with a
+ *   single "N_MORE_ERRORS" entry indicating how many were removed.  See
+ *   nvlist_smush() for details.  If smush_outnvlist is false, and the
+ *   outnvlist does not fit into the userland-provided buffer, then the
+ *   ioctl will fail with ENOMEM.
+ *
+ * zfs_ioc_func_t *func
+ *   The callback function that will perform the operation.
+ *
+ *   The callback should return 0 on success, or an error number on
+ *   failure.  If the function fails, the userland ioctl will return -1,
+ *   and errno will be set to the callback's return value.  The callback
+ *   will be called with the following arguments:
+ *
+ *   const char *name
+ *     The name of the pool or dataset to operate on, from
+ *     zfs_cmd_t:zc_name.  The 'namecheck' argument specifies the
+ *     expected type (pool, dataset, or none).
+ *
+ *   nvlist_t *innvl
+ *     The input nvlist, deserialized from zfs_cmd_t:zc_nvlist_src.  Or
+ *     NULL if no input nvlist was provided.  Changes to this nvlist are
+ *     ignored.  If the input nvlist could not be deserialized, the
+ *     ioctl will fail and the callback will not be called.
+ *
+ *   nvlist_t *outnvl
+ *     The output nvlist, initially empty.  The callback can fill it in,
+ *     and it will be returned to userland by serializing it into
+ *     zfs_cmd_t:zc_nvlist_dst.  If it is non-empty, and serialization
+ *     fails (e.g. because the caller didn't supply a large enough
+ *     buffer), then the overall ioctl will fail.  See the
+ *     'smush_nvlist' argument above for additional behaviors.
+ *
+ *     There are two typical uses of the output nvlist:
+ *       - To return state, e.g. property values.  In this case,
+ *         smush_outnvlist should be false.  If the buffer was not large
+ *         enough, the caller will reallocate a larger buffer and try
+ *         the ioctl again.
+ *
+ *       - To return multiple errors from an ioctl which makes on-disk
+ *         changes.  In this case, smush_outnvlist should be true.
+ *         Ioctls which make on-disk modifications should generally not
+ *         use the outnvl if they succeed, because the caller can not
+ *         distinguish between the operation failing, and
+ *         deserialization failing.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/modctl.h>
+#include <sys/open.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zap.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/vdev.h>
+#include <sys/priv_impl.h>
+#include <sys/dmu.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_deleg.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunldi.h>
+#include <sys/policy.h>
+#include <sys/zone.h>
+#include <sys/nvpair.h>
+#include <sys/pathname.h>
+#include <sys/mount.h>
+#include <sys/sdt.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_dir.h>
+#include <sys/zfs_onexit.h>
+#include <sys/zvol.h>
+#include <sys/dsl_scan.h>
+#include <sharefs/share.h>
+#include <sys/fm/util.h>
+
+#include <sys/dmu_send.h>
+#include <sys/dsl_destroy.h>
+#include <sys/dsl_bookmark.h>
+#include <sys/dsl_userhold.h>
+#include <sys/zfeature.h>
+
+#include <linux/miscdevice.h>
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "zfs_deleg.h"
+#include "zfs_comutil.h"
+
+kmutex_t zfsdev_state_lock;
+zfsdev_state_t *zfsdev_state_list;
+
+extern void zfs_init(void);
+extern void zfs_fini(void);
+
+uint_t zfs_fsyncer_key;
+extern uint_t rrw_tsd_key;
+static uint_t zfs_allow_log_key;
+
+typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
+typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
+typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
+
+typedef enum {
+       NO_NAME,
+       POOL_NAME,
+       DATASET_NAME
+} zfs_ioc_namecheck_t;
+
+typedef enum {
+       POOL_CHECK_NONE         = 1 << 0,
+       POOL_CHECK_SUSPENDED    = 1 << 1,
+       POOL_CHECK_READONLY     = 1 << 2,
+} zfs_ioc_poolcheck_t;
+
+typedef struct zfs_ioc_vec {
+       zfs_ioc_legacy_func_t   *zvec_legacy_func;
+       zfs_ioc_func_t          *zvec_func;
+       zfs_secpolicy_func_t    *zvec_secpolicy;
+       zfs_ioc_namecheck_t     zvec_namecheck;
+       boolean_t               zvec_allow_log;
+       zfs_ioc_poolcheck_t     zvec_pool_check;
+       boolean_t               zvec_smush_outnvlist;
+       const char              *zvec_name;
+} zfs_ioc_vec_t;
+
+/* This array is indexed by zfs_userquota_prop_t */
+static const char *userquota_perms[] = {
+       ZFS_DELEG_PERM_USERUSED,
+       ZFS_DELEG_PERM_USERQUOTA,
+       ZFS_DELEG_PERM_GROUPUSED,
+       ZFS_DELEG_PERM_GROUPQUOTA,
+};
+
+static int zfs_ioc_userspace_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,
+    nvlist_t **errors);
+static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *,
+    boolean_t *);
+int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *);
+static int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp);
+
+static void
+history_str_free(char *buf)
+{
+       kmem_free(buf, HIS_MAX_RECORD_LEN);
+}
+
+static char *
+history_str_get(zfs_cmd_t *zc)
+{
+       char *buf;
+
+       if (zc->zc_history == 0)
+               return (NULL);
+
+       buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
+       if (copyinstr((void *)(uintptr_t)zc->zc_history,
+           buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
+               history_str_free(buf);
+               return (NULL);
+       }
+
+       buf[HIS_MAX_RECORD_LEN -1] = '\0';
+
+       return (buf);
+}
+
+/*
+ * Check to see if the named dataset is currently defined as bootable
+ */
+static boolean_t
+zfs_is_bootfs(const char *name)
+{
+       objset_t *os;
+
+       if (dmu_objset_hold(name, FTAG, &os) == 0) {
+               boolean_t ret;
+               ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os)));
+               dmu_objset_rele(os, FTAG);
+               return (ret);
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Return non-zero if the spa version is less than requested version.
+ */
+static int
+zfs_earlier_version(const char *name, int version)
+{
+       spa_t *spa;
+
+       if (spa_open(name, &spa, FTAG) == 0) {
+               if (spa_version(spa) < version) {
+                       spa_close(spa, FTAG);
+                       return (1);
+               }
+               spa_close(spa, FTAG);
+       }
+       return (0);
+}
+
+/*
+ * Return TRUE if the ZPL version is less than requested version.
+ */
+static boolean_t
+zpl_earlier_version(const char *name, int version)
+{
+       objset_t *os;
+       boolean_t rc = B_TRUE;
+
+       if (dmu_objset_hold(name, FTAG, &os) == 0) {
+               uint64_t zplversion;
+
+               if (dmu_objset_type(os) != DMU_OST_ZFS) {
+                       dmu_objset_rele(os, FTAG);
+                       return (B_TRUE);
+               }
+               /* XXX reading from non-owned objset */
+               if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0)
+                       rc = zplversion < version;
+               dmu_objset_rele(os, FTAG);
+       }
+       return (rc);
+}
+
+static void
+zfs_log_history(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       char *buf;
+
+       if ((buf = history_str_get(zc)) == NULL)
+               return;
+
+       if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
+               if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
+                       (void) spa_history_log(spa, buf);
+               spa_close(spa, FTAG);
+       }
+       history_str_free(buf);
+}
+
+/*
+ * Policy for top-level read operations (list pools).  Requires no privileges,
+ * and can be used in the local zone, as there is no associated dataset.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (0);
+}
+
+/*
+ * Policy for dataset read operations (list children, get statistics).  Requires
+ * no privileges, but must be visible in the local zone.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       if (INGLOBALZONE(curproc) ||
+           zone_dataset_visible(zc->zc_name, NULL))
+               return (0);
+
+       return (SET_ERROR(ENOENT));
+}
+
+static int
+zfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr)
+{
+       int writable = 1;
+
+       /*
+        * The dataset must be visible by this zone -- check this first
+        * so they don't see EPERM on something they shouldn't know about.
+        */
+       if (!INGLOBALZONE(curproc) &&
+           !zone_dataset_visible(dataset, &writable))
+               return (SET_ERROR(ENOENT));
+
+       if (INGLOBALZONE(curproc)) {
+               /*
+                * If the fs is zoned, only root can access it from the
+                * global zone.
+                */
+               if (secpolicy_zfs(cr) && zoned)
+                       return (SET_ERROR(EPERM));
+       } else {
+               /*
+                * If we are in a local zone, the 'zoned' property must be set.
+                */
+               if (!zoned)
+                       return (SET_ERROR(EPERM));
+
+               /* must be writable by this zone */
+               if (!writable)
+                       return (SET_ERROR(EPERM));
+       }
+       return (0);
+}
+
+static int
+zfs_dozonecheck(const char *dataset, cred_t *cr)
+{
+       uint64_t zoned;
+
+       if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
+               return (SET_ERROR(ENOENT));
+
+       return (zfs_dozonecheck_impl(dataset, zoned, cr));
+}
+
+static int
+zfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr)
+{
+       uint64_t zoned;
+
+       if (dsl_prop_get_int_ds(ds, "zoned", &zoned))
+               return (SET_ERROR(ENOENT));
+
+       return (zfs_dozonecheck_impl(dataset, zoned, cr));
+}
+
+static int
+zfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds,
+    const char *perm, cred_t *cr)
+{
+       int error;
+
+       error = zfs_dozonecheck_ds(name, ds, cr);
+       if (error == 0) {
+               error = secpolicy_zfs(cr);
+               if (error != 0)
+                       error = dsl_deleg_access_impl(ds, perm, cr);
+       }
+       return (error);
+}
+
+static int
+zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
+{
+       int error;
+       dsl_dataset_t *ds;
+       dsl_pool_t *dp;
+
+       error = dsl_pool_hold(name, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold(dp, name, FTAG, &ds);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       error = zfs_secpolicy_write_perms_ds(name, ds, perm, cr);
+
+       dsl_dataset_rele(ds, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (error);
+}
+
+/*
+ * Policy for setting the security label property.
+ *
+ * Returns 0 for success, non-zero for access and other errors.
+ */
+static int
+zfs_set_slabel_policy(const char *name, char *strval, cred_t *cr)
+{
+#ifdef HAVE_MLSLABEL
+       char            ds_hexsl[MAXNAMELEN];
+       bslabel_t       ds_sl, new_sl;
+       boolean_t       new_default = FALSE;
+       uint64_t        zoned;
+       int             needed_priv = -1;
+       int             error;
+
+       /* First get the existing dataset label. */
+       error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL),
+           1, sizeof (ds_hexsl), &ds_hexsl, NULL);
+       if (error != 0)
+               return (SET_ERROR(EPERM));
+
+       if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
+               new_default = TRUE;
+
+       /* The label must be translatable */
+       if (!new_default && (hexstr_to_label(strval, &new_sl) != 0))
+               return (SET_ERROR(EINVAL));
+
+       /*
+        * In a non-global zone, disallow attempts to set a label that
+        * doesn't match that of the zone; otherwise no other checks
+        * are needed.
+        */
+       if (!INGLOBALZONE(curproc)) {
+               if (new_default || !blequal(&new_sl, CR_SL(CRED())))
+                       return (SET_ERROR(EPERM));
+               return (0);
+       }
+
+       /*
+        * For global-zone datasets (i.e., those whose zoned property is
+        * "off", verify that the specified new label is valid for the
+        * global zone.
+        */
+       if (dsl_prop_get_integer(name,
+           zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL))
+               return (SET_ERROR(EPERM));
+       if (!zoned) {
+               if (zfs_check_global_label(name, strval) != 0)
+                       return (SET_ERROR(EPERM));
+       }
+
+       /*
+        * If the existing dataset label is nondefault, check if the
+        * dataset is mounted (label cannot be changed while mounted).
+        * Get the zfs_sb_t; if there isn't one, then the dataset isn't
+        * mounted (or isn't a dataset, doesn't exist, ...).
+        */
+       if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) {
+               objset_t *os;
+               static char *setsl_tag = "setsl_tag";
+
+               /*
+                * Try to own the dataset; abort if there is any error,
+                * (e.g., already mounted, in use, or other error).
+                */
+               error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE,
+                   setsl_tag, &os);
+               if (error != 0)
+                       return (SET_ERROR(EPERM));
+
+               dmu_objset_disown(os, setsl_tag);
+
+               if (new_default) {
+                       needed_priv = PRIV_FILE_DOWNGRADE_SL;
+                       goto out_check;
+               }
+
+               if (hexstr_to_label(strval, &new_sl) != 0)
+                       return (SET_ERROR(EPERM));
+
+               if (blstrictdom(&ds_sl, &new_sl))
+                       needed_priv = PRIV_FILE_DOWNGRADE_SL;
+               else if (blstrictdom(&new_sl, &ds_sl))
+                       needed_priv = PRIV_FILE_UPGRADE_SL;
+       } else {
+               /* dataset currently has a default label */
+               if (!new_default)
+                       needed_priv = PRIV_FILE_UPGRADE_SL;
+       }
+
+out_check:
+       if (needed_priv != -1)
+               return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL));
+       return (0);
+#else
+       return (ENOTSUP);
+#endif /* HAVE_MLSLABEL */
+}
+
+static int
+zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
+    cred_t *cr)
+{
+       char *strval;
+
+       /*
+        * Check permissions for special properties.
+        */
+       switch (prop) {
+       default:
+               break;
+       case ZFS_PROP_ZONED:
+               /*
+                * Disallow setting of 'zoned' from within a local zone.
+                */
+               if (!INGLOBALZONE(curproc))
+                       return (SET_ERROR(EPERM));
+               break;
+
+       case ZFS_PROP_QUOTA:
+       case ZFS_PROP_FILESYSTEM_LIMIT:
+       case ZFS_PROP_SNAPSHOT_LIMIT:
+               if (!INGLOBALZONE(curproc)) {
+                       uint64_t zoned;
+                       char setpoint[MAXNAMELEN];
+                       /*
+                        * Unprivileged users are allowed to modify the
+                        * limit on things *under* (ie. contained by)
+                        * the thing they own.
+                        */
+                       if (dsl_prop_get_integer(dsname, "zoned", &zoned,
+                           setpoint))
+                               return (SET_ERROR(EPERM));
+                       if (!zoned || strlen(dsname) <= strlen(setpoint))
+                               return (SET_ERROR(EPERM));
+               }
+               break;
+
+       case ZFS_PROP_MLSLABEL:
+               if (!is_system_labeled())
+                       return (SET_ERROR(EPERM));
+
+               if (nvpair_value_string(propval, &strval) == 0) {
+                       int err;
+
+                       err = zfs_set_slabel_policy(dsname, strval, CRED());
+                       if (err != 0)
+                               return (err);
+               }
+               break;
+       }
+
+       return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       int error;
+
+       error = zfs_dozonecheck(zc->zc_name, cr);
+       if (error != 0)
+               return (error);
+
+       /*
+        * permission to set permissions will be evaluated later in
+        * dsl_deleg_can_allow()
+        */
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_ROLLBACK, cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       char *cp;
+       int error;
+
+       /*
+        * Generate the current snapshot name from the given objsetid, then
+        * use that name for the secpolicy/zone checks.
+        */
+       cp = strchr(zc->zc_name, '@');
+       if (cp == NULL)
+               return (SET_ERROR(EINVAL));
+       error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       dsl_dataset_name(ds, zc->zc_name);
+
+       error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds,
+           ZFS_DELEG_PERM_SEND, cr);
+       dsl_dataset_rele(ds, FTAG);
+       dsl_pool_rele(dp, FTAG);
+
+       return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_SEND, cr));
+}
+
+#ifdef HAVE_SMB_SHARE
+/* ARGSUSED */
+static int
+zfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       vnode_t *vp;
+       int error;
+
+       if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
+           NO_FOLLOW, NULL, &vp)) != 0)
+               return (error);
+
+       /* Now make sure mntpnt and dataset are ZFS */
+
+       if (vp->v_vfsp->vfs_fstype != zfsfstype ||
+           (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
+           zc->zc_name) != 0)) {
+               VN_RELE(vp);
+               return (SET_ERROR(EPERM));
+       }
+
+       VN_RELE(vp);
+       return (dsl_deleg_access(zc->zc_name,
+           ZFS_DELEG_PERM_SHARE, cr));
+}
+#endif /* HAVE_SMB_SHARE */
+
+int
+zfs_secpolicy_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+#ifdef HAVE_SMB_SHARE
+       if (!INGLOBALZONE(curproc))
+               return (SET_ERROR(EPERM));
+
+       if (secpolicy_nfs(cr) == 0) {
+               return (0);
+       } else {
+               return (zfs_secpolicy_deleg_share(zc, innvl, cr));
+       }
+#else
+       return (SET_ERROR(ENOTSUP));
+#endif /* HAVE_SMB_SHARE */
+}
+
+int
+zfs_secpolicy_smb_acl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+#ifdef HAVE_SMB_SHARE
+       if (!INGLOBALZONE(curproc))
+               return (SET_ERROR(EPERM));
+
+       if (secpolicy_smb(cr) == 0) {
+               return (0);
+       } else {
+               return (zfs_secpolicy_deleg_share(zc, innvl, cr));
+       }
+#else
+       return (SET_ERROR(ENOTSUP));
+#endif /* HAVE_SMB_SHARE */
+}
+
+static int
+zfs_get_parent(const char *datasetname, char *parent, int parentsize)
+{
+       char *cp;
+
+       /*
+        * Remove the @bla or /bla from the end of the name to get the parent.
+        */
+       (void) strncpy(parent, datasetname, parentsize);
+       cp = strrchr(parent, '@');
+       if (cp != NULL) {
+               cp[0] = '\0';
+       } else {
+               cp = strrchr(parent, '/');
+               if (cp == NULL)
+                       return (SET_ERROR(ENOENT));
+               cp[0] = '\0';
+       }
+
+       return (0);
+}
+
+int
+zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
+{
+       int error;
+
+       if ((error = zfs_secpolicy_write_perms(name,
+           ZFS_DELEG_PERM_MOUNT, cr)) != 0)
+               return (error);
+
+       return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_destroy(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
+}
+
+/*
+ * Destroying snapshots with delegated permissions requires
+ * descendant mount and destroy permissions.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       nvlist_t *snaps;
+       nvpair_t *pair, *nextpair;
+       int error = 0;
+
+       if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
+               return (SET_ERROR(EINVAL));
+       for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
+           pair = nextpair) {
+               nextpair = nvlist_next_nvpair(snaps, pair);
+               error = zfs_secpolicy_destroy_perms(nvpair_name(pair), cr);
+               if (error == ENOENT) {
+                       /*
+                        * Ignore any snapshots that don't exist (we consider
+                        * them "already destroyed").  Remove the name from the
+                        * nvl here in case the snapshot is created between
+                        * now and when we try to destroy it (in which case
+                        * we don't want to destroy it since we haven't
+                        * checked for permission).
+                        */
+                       fnvlist_remove_nvpair(snaps, pair);
+                       error = 0;
+               }
+               if (error != 0)
+                       break;
+       }
+
+       return (error);
+}
+
+int
+zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
+{
+       char    parentname[MAXNAMELEN];
+       int     error;
+
+       if ((error = zfs_secpolicy_write_perms(from,
+           ZFS_DELEG_PERM_RENAME, cr)) != 0)
+               return (error);
+
+       if ((error = zfs_secpolicy_write_perms(from,
+           ZFS_DELEG_PERM_MOUNT, cr)) != 0)
+               return (error);
+
+       if ((error = zfs_get_parent(to, parentname,
+           sizeof (parentname))) != 0)
+               return (error);
+
+       if ((error = zfs_secpolicy_write_perms(parentname,
+           ZFS_DELEG_PERM_CREATE, cr)) != 0)
+               return (error);
+
+       if ((error = zfs_secpolicy_write_perms(parentname,
+           ZFS_DELEG_PERM_MOUNT, cr)) != 0)
+               return (error);
+
+       return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *clone;
+       int error;
+
+       error = zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_PROMOTE, cr);
+       if (error != 0)
+               return (error);
+
+       error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &clone);
+
+       if (error == 0) {
+               char parentname[MAXNAMELEN];
+               dsl_dataset_t *origin = NULL;
+               dsl_dir_t *dd;
+               dd = clone->ds_dir;
+
+               error = dsl_dataset_hold_obj(dd->dd_pool,
+                   dsl_dir_phys(dd)->dd_origin_obj, FTAG, &origin);
+               if (error != 0) {
+                       dsl_dataset_rele(clone, FTAG);
+                       dsl_pool_rele(dp, FTAG);
+                       return (error);
+               }
+
+               error = zfs_secpolicy_write_perms_ds(zc->zc_name, clone,
+                   ZFS_DELEG_PERM_MOUNT, cr);
+
+               dsl_dataset_name(origin, parentname);
+               if (error == 0) {
+                       error = zfs_secpolicy_write_perms_ds(parentname, origin,
+                           ZFS_DELEG_PERM_PROMOTE, cr);
+               }
+               dsl_dataset_rele(clone, FTAG);
+               dsl_dataset_rele(origin, FTAG);
+       }
+       dsl_pool_rele(dp, FTAG);
+       return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       int error;
+
+       if ((error = zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
+               return (error);
+
+       if ((error = zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_MOUNT, cr)) != 0)
+               return (error);
+
+       return (zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_CREATE, cr));
+}
+
+int
+zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
+{
+       return (zfs_secpolicy_write_perms(name,
+           ZFS_DELEG_PERM_SNAPSHOT, cr));
+}
+
+/*
+ * Check for permission to create each snapshot in the nvlist.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       nvlist_t *snaps;
+       int error = 0;
+       nvpair_t *pair;
+
+       if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
+               return (SET_ERROR(EINVAL));
+       for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(snaps, pair)) {
+               char *name = nvpair_name(pair);
+               char *atp = strchr(name, '@');
+
+               if (atp == NULL) {
+                       error = SET_ERROR(EINVAL);
+                       break;
+               }
+               *atp = '\0';
+               error = zfs_secpolicy_snapshot_perms(name, cr);
+               *atp = '@';
+               if (error != 0)
+                       break;
+       }
+       return (error);
+}
+
+/*
+ * Check for permission to create each snapshot in the nvlist.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       int error = 0;
+       nvpair_t *pair;
+
+       for (pair = nvlist_next_nvpair(innvl, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
+               char *name = nvpair_name(pair);
+               char *hashp = strchr(name, '#');
+
+               if (hashp == NULL) {
+                       error = SET_ERROR(EINVAL);
+                       break;
+               }
+               *hashp = '\0';
+               error = zfs_secpolicy_write_perms(name,
+                   ZFS_DELEG_PERM_BOOKMARK, cr);
+               *hashp = '#';
+               if (error != 0)
+                       break;
+       }
+       return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       nvpair_t *pair, *nextpair;
+       int error = 0;
+
+       for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL;
+           pair = nextpair) {
+               char *name = nvpair_name(pair);
+               char *hashp = strchr(name, '#');
+               nextpair = nvlist_next_nvpair(innvl, pair);
+
+               if (hashp == NULL) {
+                       error = SET_ERROR(EINVAL);
+                       break;
+               }
+
+               *hashp = '\0';
+               error = zfs_secpolicy_write_perms(name,
+                   ZFS_DELEG_PERM_DESTROY, cr);
+               *hashp = '#';
+               if (error == ENOENT) {
+                       /*
+                        * Ignore any filesystems that don't exist (we consider
+                        * their bookmarks "already destroyed").  Remove
+                        * the name from the nvl here in case the filesystem
+                        * is created between now and when we try to destroy
+                        * the bookmark (in which case we don't want to
+                        * destroy it since we haven't checked for permission).
+                        */
+                       fnvlist_remove_nvpair(innvl, pair);
+                       error = 0;
+               }
+               if (error != 0)
+                       break;
+       }
+
+       return (error);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       /*
+        * Even root must have a proper TSD so that we know what pool
+        * to log to.
+        */
+       if (tsd_get(zfs_allow_log_key) == NULL)
+               return (SET_ERROR(EPERM));
+       return (0);
+}
+
+static int
+zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       char    parentname[MAXNAMELEN];
+       int     error;
+       char    *origin;
+
+       if ((error = zfs_get_parent(zc->zc_name, parentname,
+           sizeof (parentname))) != 0)
+               return (error);
+
+       if (nvlist_lookup_string(innvl, "origin", &origin) == 0 &&
+           (error = zfs_secpolicy_write_perms(origin,
+           ZFS_DELEG_PERM_CLONE, cr)) != 0)
+               return (error);
+
+       if ((error = zfs_secpolicy_write_perms(parentname,
+           ZFS_DELEG_PERM_CREATE, cr)) != 0)
+               return (error);
+
+       return (zfs_secpolicy_write_perms(parentname,
+           ZFS_DELEG_PERM_MOUNT, cr));
+}
+
+/*
+ * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
+ * SYS_CONFIG privilege, which is not available in a local zone.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       if (secpolicy_sys_config(cr, B_FALSE) != 0)
+               return (SET_ERROR(EPERM));
+
+       return (0);
+}
+
+/*
+ * Policy for object to name lookups.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_diff(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       int error;
+
+       if ((error = secpolicy_sys_config(cr, B_FALSE)) == 0)
+               return (0);
+
+       error = zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_DIFF, cr);
+       return (error);
+}
+
+/*
+ * Policy for fault injection.  Requires all privileges.
+ */
+/* ARGSUSED */
+static int
+zfs_secpolicy_inject(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (secpolicy_zinject(cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_inherit_prop(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       zfs_prop_t prop = zfs_name_to_prop(zc->zc_value);
+
+       if (prop == ZPROP_INVAL) {
+               if (!zfs_prop_user(zc->zc_value))
+                       return (SET_ERROR(EINVAL));
+               return (zfs_secpolicy_write_perms(zc->zc_name,
+                   ZFS_DELEG_PERM_USERPROP, cr));
+       } else {
+               return (zfs_secpolicy_setprop(zc->zc_name, prop,
+                   NULL, cr));
+       }
+}
+
+static int
+zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       int err = zfs_secpolicy_read(zc, innvl, cr);
+       if (err)
+               return (err);
+
+       if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS)
+               return (SET_ERROR(EINVAL));
+
+       if (zc->zc_value[0] == 0) {
+               /*
+                * They are asking about a posix uid/gid.  If it's
+                * themself, allow it.
+                */
+               if (zc->zc_objset_type == ZFS_PROP_USERUSED ||
+                   zc->zc_objset_type == ZFS_PROP_USERQUOTA) {
+                       if (zc->zc_guid == crgetuid(cr))
+                               return (0);
+               } else {
+                       if (groupmember(zc->zc_guid, cr))
+                               return (0);
+               }
+       }
+
+       return (zfs_secpolicy_write_perms(zc->zc_name,
+           userquota_perms[zc->zc_objset_type], cr));
+}
+
+static int
+zfs_secpolicy_userspace_many(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       int err = zfs_secpolicy_read(zc, innvl, cr);
+       if (err)
+               return (err);
+
+       if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS)
+               return (SET_ERROR(EINVAL));
+
+       return (zfs_secpolicy_write_perms(zc->zc_name,
+           userquota_perms[zc->zc_objset_type], cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_userspace_upgrade(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (zfs_secpolicy_setprop(zc->zc_name, ZFS_PROP_VERSION,
+           NULL, cr));
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       nvpair_t *pair;
+       nvlist_t *holds;
+       int error;
+
+       error = nvlist_lookup_nvlist(innvl, "holds", &holds);
+       if (error != 0)
+               return (SET_ERROR(EINVAL));
+
+       for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(holds, pair)) {
+               char fsname[MAXNAMELEN];
+               error = dmu_fsname(nvpair_name(pair), fsname);
+               if (error != 0)
+                       return (error);
+               error = zfs_secpolicy_write_perms(fsname,
+                   ZFS_DELEG_PERM_HOLD, cr);
+               if (error != 0)
+                       return (error);
+       }
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       nvpair_t *pair;
+       int error;
+
+       for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(innvl, pair)) {
+               char fsname[MAXNAMELEN];
+               error = dmu_fsname(nvpair_name(pair), fsname);
+               if (error != 0)
+                       return (error);
+               error = zfs_secpolicy_write_perms(fsname,
+                   ZFS_DELEG_PERM_RELEASE, cr);
+               if (error != 0)
+                       return (error);
+       }
+       return (0);
+}
+
+/*
+ * Policy for allowing temporary snapshots to be taken or released
+ */
+static int
+zfs_secpolicy_tmp_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       /*
+        * A temporary snapshot is the same as a snapshot,
+        * hold, destroy and release all rolled into one.
+        * Delegated diff alone is sufficient that we allow this.
+        */
+       int error;
+
+       if ((error = zfs_secpolicy_write_perms(zc->zc_name,
+           ZFS_DELEG_PERM_DIFF, cr)) == 0)
+               return (0);
+
+       error = zfs_secpolicy_snapshot_perms(zc->zc_name, cr);
+       if (error == 0)
+               error = zfs_secpolicy_hold(zc, innvl, cr);
+       if (error == 0)
+               error = zfs_secpolicy_release(zc, innvl, cr);
+       if (error == 0)
+               error = zfs_secpolicy_destroy(zc, innvl, cr);
+       return (error);
+}
+
+/*
+ * Returns the nvlist as specified by the user in the zfs_cmd_t.
+ */
+static int
+get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp)
+{
+       char *packed;
+       int error;
+       nvlist_t *list = NULL;
+
+       /*
+        * Read in and unpack the user-supplied nvlist.
+        */
+       if (size == 0)
+               return (SET_ERROR(EINVAL));
+
+       packed = vmem_alloc(size, KM_SLEEP);
+
+       if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
+           iflag)) != 0) {
+               vmem_free(packed, size);
+               return (SET_ERROR(EFAULT));
+       }
+
+       if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) {
+               vmem_free(packed, size);
+               return (error);
+       }
+
+       vmem_free(packed, size);
+
+       *nvp = list;
+       return (0);
+}
+
+/*
+ * Reduce the size of this nvlist until it can be serialized in 'max' bytes.
+ * Entries will be removed from the end of the nvlist, and one int32 entry
+ * named "N_MORE_ERRORS" will be added indicating how many entries were
+ * removed.
+ */
+static int
+nvlist_smush(nvlist_t *errors, size_t max)
+{
+       size_t size;
+
+       size = fnvlist_size(errors);
+
+       if (size > max) {
+               nvpair_t *more_errors;
+               int n = 0;
+
+               if (max < 1024)
+                       return (SET_ERROR(ENOMEM));
+
+               fnvlist_add_int32(errors, ZPROP_N_MORE_ERRORS, 0);
+               more_errors = nvlist_prev_nvpair(errors, NULL);
+
+               do {
+                       nvpair_t *pair = nvlist_prev_nvpair(errors,
+                           more_errors);
+                       fnvlist_remove_nvpair(errors, pair);
+                       n++;
+                       size = fnvlist_size(errors);
+               } while (size > max);
+
+               fnvlist_remove_nvpair(errors, more_errors);
+               fnvlist_add_int32(errors, ZPROP_N_MORE_ERRORS, n);
+               ASSERT3U(fnvlist_size(errors), <=, max);
+       }
+
+       return (0);
+}
+
+static int
+put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
+{
+       char *packed = NULL;
+       int error = 0;
+       size_t size;
+
+       size = fnvlist_size(nvl);
+
+       if (size > zc->zc_nvlist_dst_size) {
+               error = SET_ERROR(ENOMEM);
+       } else {
+               packed = fnvlist_pack(nvl, &size);
+               if (ddi_copyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
+                   size, zc->zc_iflags) != 0)
+                       error = SET_ERROR(EFAULT);
+               fnvlist_pack_free(packed, size);
+       }
+
+       zc->zc_nvlist_dst_size = size;
+       zc->zc_nvlist_dst_filled = B_TRUE;
+       return (error);
+}
+
+static int
+get_zfs_sb(const char *dsname, zfs_sb_t **zsbp)
+{
+       objset_t *os;
+       int error;
+
+       error = dmu_objset_hold(dsname, FTAG, &os);
+       if (error != 0)
+               return (error);
+       if (dmu_objset_type(os) != DMU_OST_ZFS) {
+               dmu_objset_rele(os, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       mutex_enter(&os->os_user_ptr_lock);
+       *zsbp = dmu_objset_get_user(os);
+       /* bump s_active only when non-zero to prevent umount race */
+       if (*zsbp == NULL || (*zsbp)->z_sb == NULL ||
+           !atomic_inc_not_zero(&((*zsbp)->z_sb->s_active))) {
+               error = SET_ERROR(ESRCH);
+       }
+       mutex_exit(&os->os_user_ptr_lock);
+       dmu_objset_rele(os, FTAG);
+       return (error);
+}
+
+/*
+ * Find a zfs_sb_t for a mounted filesystem, or create our own, in which
+ * case its z_sb will be NULL, and it will be opened as the owner.
+ * If 'writer' is set, the z_teardown_lock will be held for RW_WRITER,
+ * which prevents all inode ops from running.
+ */
+static int
+zfs_sb_hold(const char *name, void *tag, zfs_sb_t **zsbp, boolean_t writer)
+{
+       int error = 0;
+
+       if (get_zfs_sb(name, zsbp) != 0)
+               error = zfs_sb_create(name, NULL, zsbp);
+       if (error == 0) {
+               rrm_enter(&(*zsbp)->z_teardown_lock, (writer) ? RW_WRITER :
+                   RW_READER, tag);
+               if ((*zsbp)->z_unmounted) {
+                       /*
+                        * XXX we could probably try again, since the unmounting
+                        * thread should be just about to disassociate the
+                        * objset from the zsb.
+                        */
+                       rrm_exit(&(*zsbp)->z_teardown_lock, tag);
+                       return (SET_ERROR(EBUSY));
+               }
+       }
+       return (error);
+}
+
+static void
+zfs_sb_rele(zfs_sb_t *zsb, void *tag)
+{
+       rrm_exit(&zsb->z_teardown_lock, tag);
+
+       if (zsb->z_sb) {
+               deactivate_super(zsb->z_sb);
+       } else {
+               dmu_objset_disown(zsb->z_os, zsb);
+               zfs_sb_free(zsb);
+       }
+}
+
+static int
+zfs_ioc_pool_create(zfs_cmd_t *zc)
+{
+       int error;
+       nvlist_t *config, *props = NULL;
+       nvlist_t *rootprops = NULL;
+       nvlist_t *zplprops = NULL;
+
+       if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
+           zc->zc_iflags, &config)))
+               return (error);
+
+       if (zc->zc_nvlist_src_size != 0 && (error =
+           get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &props))) {
+               nvlist_free(config);
+               return (error);
+       }
+
+       if (props) {
+               nvlist_t *nvl = NULL;
+               uint64_t version = SPA_VERSION;
+
+               (void) nvlist_lookup_uint64(props,
+                   zpool_prop_to_name(ZPOOL_PROP_VERSION), &version);
+               if (!SPA_VERSION_IS_SUPPORTED(version)) {
+                       error = SET_ERROR(EINVAL);
+                       goto pool_props_bad;
+               }
+               (void) nvlist_lookup_nvlist(props, ZPOOL_ROOTFS_PROPS, &nvl);
+               if (nvl) {
+                       error = nvlist_dup(nvl, &rootprops, KM_SLEEP);
+                       if (error != 0) {
+                               nvlist_free(config);
+                               nvlist_free(props);
+                               return (error);
+                       }
+                       (void) nvlist_remove_all(props, ZPOOL_ROOTFS_PROPS);
+               }
+               VERIFY(nvlist_alloc(&zplprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               error = zfs_fill_zplprops_root(version, rootprops,
+                   zplprops, NULL);
+               if (error != 0)
+                       goto pool_props_bad;
+       }
+
+       error = spa_create(zc->zc_name, config, props, zplprops);
+
+       /*
+        * Set the remaining root properties
+        */
+       if (!error && (error = zfs_set_prop_nvlist(zc->zc_name,
+           ZPROP_SRC_LOCAL, rootprops, NULL)) != 0)
+               (void) spa_destroy(zc->zc_name);
+
+pool_props_bad:
+       nvlist_free(rootprops);
+       nvlist_free(zplprops);
+       nvlist_free(config);
+       nvlist_free(props);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_destroy(zfs_cmd_t *zc)
+{
+       int error;
+       zfs_log_history(zc);
+       error = spa_destroy(zc->zc_name);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_import(zfs_cmd_t *zc)
+{
+       nvlist_t *config, *props = NULL;
+       uint64_t guid;
+       int error;
+
+       if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
+           zc->zc_iflags, &config)) != 0)
+               return (error);
+
+       if (zc->zc_nvlist_src_size != 0 && (error =
+           get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &props))) {
+               nvlist_free(config);
+               return (error);
+       }
+
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
+           guid != zc->zc_guid)
+               error = SET_ERROR(EINVAL);
+       else
+               error = spa_import(zc->zc_name, config, props, zc->zc_cookie);
+
+       if (zc->zc_nvlist_dst != 0) {
+               int err;
+
+               if ((err = put_nvlist(zc, config)) != 0)
+                       error = err;
+       }
+
+       nvlist_free(config);
+
+       if (props)
+               nvlist_free(props);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_export(zfs_cmd_t *zc)
+{
+       int error;
+       boolean_t force = (boolean_t)zc->zc_cookie;
+       boolean_t hardforce = (boolean_t)zc->zc_guid;
+
+       zfs_log_history(zc);
+       error = spa_export(zc->zc_name, NULL, force, hardforce);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_configs(zfs_cmd_t *zc)
+{
+       nvlist_t *configs;
+       int error;
+
+       if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
+               return (SET_ERROR(EEXIST));
+
+       error = put_nvlist(zc, configs);
+
+       nvlist_free(configs);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of the pool
+ *
+ * outputs:
+ * zc_cookie           real errno
+ * zc_nvlist_dst       config nvlist
+ * zc_nvlist_dst_size  size of config nvlist
+ */
+static int
+zfs_ioc_pool_stats(zfs_cmd_t *zc)
+{
+       nvlist_t *config;
+       int error;
+       int ret = 0;
+
+       error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
+           sizeof (zc->zc_value));
+
+       if (config != NULL) {
+               ret = put_nvlist(zc, config);
+               nvlist_free(config);
+
+               /*
+                * The config may be present even if 'error' is non-zero.
+                * In this case we return success, and preserve the real errno
+                * in 'zc_cookie'.
+                */
+               zc->zc_cookie = error;
+       } else {
+               ret = error;
+       }
+
+       return (ret);
+}
+
+/*
+ * Try to import the given pool, returning pool stats as appropriate so that
+ * user land knows which devices are available and overall pool health.
+ */
+static int
+zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
+{
+       nvlist_t *tryconfig, *config;
+       int error;
+
+       if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
+           zc->zc_iflags, &tryconfig)) != 0)
+               return (error);
+
+       config = spa_tryimport(tryconfig);
+
+       nvlist_free(tryconfig);
+
+       if (config == NULL)
+               return (SET_ERROR(EINVAL));
+
+       error = put_nvlist(zc, config);
+       nvlist_free(config);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name              name of the pool
+ * zc_cookie            scan func (pool_scan_func_t)
+ */
+static int
+zfs_ioc_pool_scan(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       if (zc->zc_cookie == POOL_SCAN_NONE)
+               error = spa_scan_stop(spa);
+       else
+               error = spa_scan(spa, zc->zc_cookie);
+
+       spa_close(spa, FTAG);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_freeze(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error == 0) {
+               spa_freeze(spa);
+               spa_close(spa, FTAG);
+       }
+       return (error);
+}
+
+static int
+zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       if (zc->zc_cookie < spa_version(spa) ||
+           !SPA_VERSION_IS_SUPPORTED(zc->zc_cookie)) {
+               spa_close(spa, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       spa_upgrade(spa, zc->zc_cookie);
+       spa_close(spa, FTAG);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_get_history(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       char *hist_buf;
+       uint64_t size;
+       int error;
+
+       if ((size = zc->zc_history_len) == 0)
+               return (SET_ERROR(EINVAL));
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
+               spa_close(spa, FTAG);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       hist_buf = vmem_alloc(size, KM_SLEEP);
+       if ((error = spa_history_get(spa, &zc->zc_history_offset,
+           &zc->zc_history_len, hist_buf)) == 0) {
+               error = ddi_copyout(hist_buf,
+                   (void *)(uintptr_t)zc->zc_history,
+                   zc->zc_history_len, zc->zc_iflags);
+       }
+
+       spa_close(spa, FTAG);
+       vmem_free(hist_buf, size);
+       return (error);
+}
+
+static int
+zfs_ioc_pool_reguid(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error == 0) {
+               error = spa_change_guid(spa);
+               spa_close(spa, FTAG);
+       }
+       return (error);
+}
+
+static int
+zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
+{
+       return (dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value));
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_obj              object to find
+ *
+ * outputs:
+ * zc_value            name of object
+ */
+static int
+zfs_ioc_obj_to_path(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error;
+
+       /* XXX reading from objset not owned */
+       if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0)
+               return (error);
+       if (dmu_objset_type(os) != DMU_OST_ZFS) {
+               dmu_objset_rele(os, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+       error = zfs_obj_to_path(os, zc->zc_obj, zc->zc_value,
+           sizeof (zc->zc_value));
+       dmu_objset_rele(os, FTAG);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_obj              object to find
+ *
+ * outputs:
+ * zc_stat             stats on object
+ * zc_value            path to object
+ */
+static int
+zfs_ioc_obj_to_stats(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error;
+
+       /* XXX reading from objset not owned */
+       if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os)) != 0)
+               return (error);
+       if (dmu_objset_type(os) != DMU_OST_ZFS) {
+               dmu_objset_rele(os, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+       error = zfs_obj_to_stats(os, zc->zc_obj, &zc->zc_stat, zc->zc_value,
+           sizeof (zc->zc_value));
+       dmu_objset_rele(os, FTAG);
+
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_add(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+       nvlist_t *config;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
+           zc->zc_iflags, &config);
+       if (error == 0) {
+               error = spa_vdev_add(spa, config);
+               nvlist_free(config);
+       }
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of the pool
+ * zc_nvlist_conf      nvlist of devices to remove
+ * zc_cookie           to stop the remove?
+ */
+static int
+zfs_ioc_vdev_remove(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+       error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+       vdev_state_t newstate = VDEV_STATE_UNKNOWN;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+       switch (zc->zc_cookie) {
+       case VDEV_STATE_ONLINE:
+               error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate);
+               break;
+
+       case VDEV_STATE_OFFLINE:
+               error = vdev_offline(spa, zc->zc_guid, zc->zc_obj);
+               break;
+
+       case VDEV_STATE_FAULTED:
+               if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED &&
+                   zc->zc_obj != VDEV_AUX_EXTERNAL)
+                       zc->zc_obj = VDEV_AUX_ERR_EXCEEDED;
+
+               error = vdev_fault(spa, zc->zc_guid, zc->zc_obj);
+               break;
+
+       case VDEV_STATE_DEGRADED:
+               if (zc->zc_obj != VDEV_AUX_ERR_EXCEEDED &&
+                   zc->zc_obj != VDEV_AUX_EXTERNAL)
+                       zc->zc_obj = VDEV_AUX_ERR_EXCEEDED;
+
+               error = vdev_degrade(spa, zc->zc_guid, zc->zc_obj);
+               break;
+
+       default:
+               error = SET_ERROR(EINVAL);
+       }
+       zc->zc_cookie = newstate;
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_attach(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int replacing = zc->zc_cookie;
+       nvlist_t *config;
+       int error;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
+           zc->zc_iflags, &config)) == 0) {
+               error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
+               nvlist_free(config);
+       }
+
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_detach(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE);
+
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_split(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       nvlist_t *config, *props = NULL;
+       int error;
+       boolean_t exp = !!(zc->zc_cookie & ZPOOL_EXPORT_AFTER_SPLIT);
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
+           zc->zc_iflags, &config))) {
+               spa_close(spa, FTAG);
+               return (error);
+       }
+
+       if (zc->zc_nvlist_src_size != 0 && (error =
+           get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &props))) {
+               spa_close(spa, FTAG);
+               nvlist_free(config);
+               return (error);
+       }
+
+       error = spa_vdev_split_mirror(spa, zc->zc_string, config, props, exp);
+
+       spa_close(spa, FTAG);
+
+       nvlist_free(config);
+       nvlist_free(props);
+
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       char *path = zc->zc_value;
+       uint64_t guid = zc->zc_guid;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = spa_vdev_setpath(spa, guid, path);
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_vdev_setfru(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       char *fru = zc->zc_value;
+       uint64_t guid = zc->zc_guid;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = spa_vdev_setfru(spa, guid, fru);
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os)
+{
+       int error = 0;
+       nvlist_t *nv;
+
+       dmu_objset_fast_stat(os, &zc->zc_objset_stats);
+
+       if (zc->zc_nvlist_dst != 0 &&
+           (error = dsl_prop_get_all(os, &nv)) == 0) {
+               dmu_objset_stats(os, nv);
+               /*
+                * NB: zvol_get_stats() will read the objset contents,
+                * which we aren't supposed to do with a
+                * DS_MODE_USER hold, because it could be
+                * inconsistent.  So this is a bit of a workaround...
+                * XXX reading with out owning
+                */
+               if (!zc->zc_objset_stats.dds_inconsistent &&
+                   dmu_objset_type(os) == DMU_OST_ZVOL) {
+                       error = zvol_get_stats(os, nv);
+                       if (error == EIO)
+                               return (error);
+                       VERIFY0(error);
+               }
+               if (error == 0)
+                       error = put_nvlist(zc, nv);
+               nvlist_free(nv);
+       }
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_nvlist_dst_size  size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_objset_stats     stats
+ * zc_nvlist_dst       property nvlist
+ * zc_nvlist_dst_size  size of property nvlist
+ */
+static int
+zfs_ioc_objset_stats(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error;
+
+       error = dmu_objset_hold(zc->zc_name, FTAG, &os);
+       if (error == 0) {
+               error = zfs_ioc_objset_stats_impl(zc, os);
+               dmu_objset_rele(os, FTAG);
+       }
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_nvlist_dst_size  size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_nvlist_dst       received property nvlist
+ * zc_nvlist_dst_size  size of received property nvlist
+ *
+ * Gets received properties (distinct from local properties on or after
+ * SPA_VERSION_RECVD_PROPS) for callers who want to differentiate received from
+ * local property values.
+ */
+static int
+zfs_ioc_objset_recvd_props(zfs_cmd_t *zc)
+{
+       int error = 0;
+       nvlist_t *nv;
+
+       /*
+        * Without this check, we would return local property values if the
+        * caller has not already received properties on or after
+        * SPA_VERSION_RECVD_PROPS.
+        */
+       if (!dsl_prop_get_hasrecvd(zc->zc_name))
+               return (SET_ERROR(ENOTSUP));
+
+       if (zc->zc_nvlist_dst != 0 &&
+           (error = dsl_prop_get_received(zc->zc_name, &nv)) == 0) {
+               error = put_nvlist(zc, nv);
+               nvlist_free(nv);
+       }
+
+       return (error);
+}
+
+static int
+nvl_add_zplprop(objset_t *os, nvlist_t *props, zfs_prop_t prop)
+{
+       uint64_t value;
+       int error;
+
+       /*
+        * zfs_get_zplprop() will either find a value or give us
+        * the default value (if there is one).
+        */
+       if ((error = zfs_get_zplprop(os, prop, &value)) != 0)
+               return (error);
+       VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(prop), value) == 0);
+       return (0);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_nvlist_dst_size  size of buffer for zpl property nvlist
+ *
+ * outputs:
+ * zc_nvlist_dst       zpl property nvlist
+ * zc_nvlist_dst_size  size of zpl property nvlist
+ */
+static int
+zfs_ioc_objset_zplprops(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int err;
+
+       /* XXX reading without owning */
+       if ((err = dmu_objset_hold(zc->zc_name, FTAG, &os)))
+               return (err);
+
+       dmu_objset_fast_stat(os, &zc->zc_objset_stats);
+
+       /*
+        * NB: nvl_add_zplprop() will read the objset contents,
+        * which we aren't supposed to do with a DS_MODE_USER
+        * hold, because it could be inconsistent.
+        */
+       if (zc->zc_nvlist_dst != 0 &&
+           !zc->zc_objset_stats.dds_inconsistent &&
+           dmu_objset_type(os) == DMU_OST_ZFS) {
+               nvlist_t *nv;
+
+               VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 &&
+                   (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 &&
+                   (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 &&
+                   (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0)
+                       err = put_nvlist(zc, nv);
+               nvlist_free(nv);
+       } else {
+               err = SET_ERROR(ENOENT);
+       }
+       dmu_objset_rele(os, FTAG);
+       return (err);
+}
+
+boolean_t
+dataset_name_hidden(const char *name)
+{
+       /*
+        * Skip over datasets that are not visible in this zone,
+        * internal datasets (which have a $ in their name), and
+        * temporary datasets (which have a % in their name).
+        */
+       if (strchr(name, '$') != NULL)
+               return (B_TRUE);
+       if (strchr(name, '%') != NULL)
+               return (B_TRUE);
+       if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL))
+               return (B_TRUE);
+       return (B_FALSE);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_cookie           zap cursor
+ * zc_nvlist_dst_size  size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_name             name of next filesystem
+ * zc_cookie           zap cursor
+ * zc_objset_stats     stats
+ * zc_nvlist_dst       property nvlist
+ * zc_nvlist_dst_size  size of property nvlist
+ */
+static int
+zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error;
+       char *p;
+       size_t orig_len = strlen(zc->zc_name);
+
+top:
+       if ((error = dmu_objset_hold(zc->zc_name, FTAG, &os))) {
+               if (error == ENOENT)
+                       error = SET_ERROR(ESRCH);
+               return (error);
+       }
+
+       p = strrchr(zc->zc_name, '/');
+       if (p == NULL || p[1] != '\0')
+               (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
+       p = zc->zc_name + strlen(zc->zc_name);
+
+       do {
+               error = dmu_dir_list_next(os,
+                   sizeof (zc->zc_name) - (p - zc->zc_name), p,
+                   NULL, &zc->zc_cookie);
+               if (error == ENOENT)
+                       error = SET_ERROR(ESRCH);
+       } while (error == 0 && dataset_name_hidden(zc->zc_name));
+       dmu_objset_rele(os, FTAG);
+
+       /*
+        * If it's an internal dataset (ie. with a '$' in its name),
+        * don't try to get stats for it, otherwise we'll return ENOENT.
+        */
+       if (error == 0 && strchr(zc->zc_name, '$') == NULL) {
+               error = zfs_ioc_objset_stats(zc); /* fill in the stats */
+               if (error == ENOENT) {
+                       /* We lost a race with destroy, get the next one. */
+                       zc->zc_name[orig_len] = '\0';
+                       goto top;
+               }
+       }
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_cookie           zap cursor
+ * zc_nvlist_dst_size  size of buffer for property nvlist
+ *
+ * outputs:
+ * zc_name             name of next snapshot
+ * zc_objset_stats     stats
+ * zc_nvlist_dst       property nvlist
+ * zc_nvlist_dst_size  size of property nvlist
+ */
+static int
+zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error;
+
+       error = dmu_objset_hold(zc->zc_name, FTAG, &os);
+       if (error != 0) {
+               return (error == ENOENT ? ESRCH : error);
+       }
+
+       /*
+        * A dataset name of maximum length cannot have any snapshots,
+        * so exit immediately.
+        */
+       if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
+               dmu_objset_rele(os, FTAG);
+               return (SET_ERROR(ESRCH));
+       }
+
+       error = dmu_snapshot_list_next(os,
+           sizeof (zc->zc_name) - strlen(zc->zc_name),
+           zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie,
+           NULL);
+
+       if (error == 0 && !zc->zc_simple) {
+               dsl_dataset_t *ds;
+               dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool;
+
+               error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds);
+               if (error == 0) {
+                       objset_t *ossnap;
+
+                       error = dmu_objset_from_ds(ds, &ossnap);
+                       if (error == 0)
+                               error = zfs_ioc_objset_stats_impl(zc, ossnap);
+                       dsl_dataset_rele(ds, FTAG);
+               }
+       } else if (error == ENOENT) {
+               error = SET_ERROR(ESRCH);
+       }
+
+       dmu_objset_rele(os, FTAG);
+       /* if we failed, undo the @ that we tacked on to zc_name */
+       if (error != 0)
+               *strchr(zc->zc_name, '@') = '\0';
+       return (error);
+}
+
+static int
+zfs_prop_set_userquota(const char *dsname, nvpair_t *pair)
+{
+       const char *propname = nvpair_name(pair);
+       uint64_t *valary;
+       unsigned int vallen;
+       const char *domain;
+       char *dash;
+       zfs_userquota_prop_t type;
+       uint64_t rid;
+       uint64_t quota;
+       zfs_sb_t *zsb;
+       int err;
+
+       if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+               nvlist_t *attrs;
+               VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
+               if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
+                   &pair) != 0)
+                       return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * A correctly constructed propname is encoded as
+        * userquota@<rid>-<domain>.
+        */
+       if ((dash = strchr(propname, '-')) == NULL ||
+           nvpair_value_uint64_array(pair, &valary, &vallen) != 0 ||
+           vallen != 3)
+               return (SET_ERROR(EINVAL));
+
+       domain = dash + 1;
+       type = valary[0];
+       rid = valary[1];
+       quota = valary[2];
+
+       err = zfs_sb_hold(dsname, FTAG, &zsb, B_FALSE);
+       if (err == 0) {
+               err = zfs_set_userquota(zsb, type, domain, rid, quota);
+               zfs_sb_rele(zsb, FTAG);
+       }
+
+       return (err);
+}
+
+/*
+ * If the named property is one that has a special function to set its value,
+ * return 0 on success and a positive error code on failure; otherwise if it is
+ * not one of the special properties handled by this function, return -1.
+ *
+ * XXX: It would be better for callers of the property interface if we handled
+ * these special cases in dsl_prop.c (in the dsl layer).
+ */
+static int
+zfs_prop_set_special(const char *dsname, zprop_source_t source,
+    nvpair_t *pair)
+{
+       const char *propname = nvpair_name(pair);
+       zfs_prop_t prop = zfs_name_to_prop(propname);
+       uint64_t intval;
+       int err = -1;
+
+       if (prop == ZPROP_INVAL) {
+               if (zfs_prop_userquota(propname))
+                       return (zfs_prop_set_userquota(dsname, pair));
+               return (-1);
+       }
+
+       if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+               nvlist_t *attrs;
+               VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
+               VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
+                   &pair) == 0);
+       }
+
+       if (zfs_prop_get_type(prop) == PROP_TYPE_STRING)
+               return (-1);
+
+       VERIFY(0 == nvpair_value_uint64(pair, &intval));
+
+       switch (prop) {
+       case ZFS_PROP_QUOTA:
+               err = dsl_dir_set_quota(dsname, source, intval);
+               break;
+       case ZFS_PROP_REFQUOTA:
+               err = dsl_dataset_set_refquota(dsname, source, intval);
+               break;
+       case ZFS_PROP_FILESYSTEM_LIMIT:
+       case ZFS_PROP_SNAPSHOT_LIMIT:
+               if (intval == UINT64_MAX) {
+                       /* clearing the limit, just do it */
+                       err = 0;
+               } else {
+                       err = dsl_dir_activate_fs_ss_limit(dsname);
+               }
+               /*
+                * Set err to -1 to force the zfs_set_prop_nvlist code down the
+                * default path to set the value in the nvlist.
+                */
+               if (err == 0)
+                       err = -1;
+               break;
+       case ZFS_PROP_RESERVATION:
+               err = dsl_dir_set_reservation(dsname, source, intval);
+               break;
+       case ZFS_PROP_REFRESERVATION:
+               err = dsl_dataset_set_refreservation(dsname, source, intval);
+               break;
+       case ZFS_PROP_VOLSIZE:
+               err = zvol_set_volsize(dsname, intval);
+               break;
+       case ZFS_PROP_SNAPDEV:
+               err = zvol_set_snapdev(dsname, source, intval);
+               break;
+       case ZFS_PROP_VERSION:
+       {
+               zfs_sb_t *zsb;
+
+               if ((err = zfs_sb_hold(dsname, FTAG, &zsb, B_TRUE)) != 0)
+                       break;
+
+               err = zfs_set_version(zsb, intval);
+               zfs_sb_rele(zsb, FTAG);
+
+               if (err == 0 && intval >= ZPL_VERSION_USERSPACE) {
+                       zfs_cmd_t *zc;
+
+                       zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
+                       (void) strcpy(zc->zc_name, dsname);
+                       (void) zfs_ioc_userspace_upgrade(zc);
+                       kmem_free(zc, sizeof (zfs_cmd_t));
+               }
+               break;
+       }
+       default:
+               err = -1;
+       }
+
+       return (err);
+}
+
+/*
+ * This function is best effort. If it fails to set any of the given properties,
+ * it continues to set as many as it can and returns the last error
+ * encountered. If the caller provides a non-NULL errlist, it will be filled in
+ * with the list of names of all the properties that failed along with the
+ * corresponding error numbers.
+ *
+ * If every property is set successfully, zero is returned and errlist is not
+ * modified.
+ */
+int
+zfs_set_prop_nvlist(const char *dsname, zprop_source_t source, nvlist_t *nvl,
+    nvlist_t *errlist)
+{
+       nvpair_t *pair;
+       nvpair_t *propval;
+       int rv = 0;
+       uint64_t intval;
+       char *strval;
+
+       nvlist_t *genericnvl = fnvlist_alloc();
+       nvlist_t *retrynvl = fnvlist_alloc();
+retry:
+       pair = NULL;
+       while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) {
+               const char *propname = nvpair_name(pair);
+               zfs_prop_t prop = zfs_name_to_prop(propname);
+               int err = 0;
+
+               /* decode the property value */
+               propval = pair;
+               if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+                       nvlist_t *attrs;
+                       attrs = fnvpair_value_nvlist(pair);
+                       if (nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
+                           &propval) != 0)
+                               err = SET_ERROR(EINVAL);
+               }
+
+               /* Validate value type */
+               if (err == 0 && prop == ZPROP_INVAL) {
+                       if (zfs_prop_user(propname)) {
+                               if (nvpair_type(propval) != DATA_TYPE_STRING)
+                                       err = SET_ERROR(EINVAL);
+                       } else if (zfs_prop_userquota(propname)) {
+                               if (nvpair_type(propval) !=
+                                   DATA_TYPE_UINT64_ARRAY)
+                                       err = SET_ERROR(EINVAL);
+                       } else {
+                               err = SET_ERROR(EINVAL);
+                       }
+               } else if (err == 0) {
+                       if (nvpair_type(propval) == DATA_TYPE_STRING) {
+                               if (zfs_prop_get_type(prop) != PROP_TYPE_STRING)
+                                       err = SET_ERROR(EINVAL);
+                       } else if (nvpair_type(propval) == DATA_TYPE_UINT64) {
+                               const char *unused;
+
+                               intval = fnvpair_value_uint64(propval);
+
+                               switch (zfs_prop_get_type(prop)) {
+                               case PROP_TYPE_NUMBER:
+                                       break;
+                               case PROP_TYPE_STRING:
+                                       err = SET_ERROR(EINVAL);
+                                       break;
+                               case PROP_TYPE_INDEX:
+                                       if (zfs_prop_index_to_string(prop,
+                                           intval, &unused) != 0)
+                                               err = SET_ERROR(EINVAL);
+                                       break;
+                               default:
+                                       cmn_err(CE_PANIC,
+                                           "unknown property type");
+                               }
+                       } else {
+                               err = SET_ERROR(EINVAL);
+                       }
+               }
+
+               /* Validate permissions */
+               if (err == 0)
+                       err = zfs_check_settable(dsname, pair, CRED());
+
+               if (err == 0) {
+                       err = zfs_prop_set_special(dsname, source, pair);
+                       if (err == -1) {
+                               /*
+                                * For better performance we build up a list of
+                                * properties to set in a single transaction.
+                                */
+                               err = nvlist_add_nvpair(genericnvl, pair);
+                       } else if (err != 0 && nvl != retrynvl) {
+                               /*
+                                * This may be a spurious error caused by
+                                * receiving quota and reservation out of order.
+                                * Try again in a second pass.
+                                */
+                               err = nvlist_add_nvpair(retrynvl, pair);
+                       }
+               }
+
+               if (err != 0) {
+                       if (errlist != NULL)
+                               fnvlist_add_int32(errlist, propname, err);
+                       rv = err;
+               }
+       }
+
+       if (nvl != retrynvl && !nvlist_empty(retrynvl)) {
+               nvl = retrynvl;
+               goto retry;
+       }
+
+       if (!nvlist_empty(genericnvl) &&
+           dsl_props_set(dsname, source, genericnvl) != 0) {
+               /*
+                * If this fails, we still want to set as many properties as we
+                * can, so try setting them individually.
+                */
+               pair = NULL;
+               while ((pair = nvlist_next_nvpair(genericnvl, pair)) != NULL) {
+                       const char *propname = nvpair_name(pair);
+                       int err = 0;
+
+                       propval = pair;
+                       if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+                               nvlist_t *attrs;
+                               attrs = fnvpair_value_nvlist(pair);
+                               propval = fnvlist_lookup_nvpair(attrs,
+                                   ZPROP_VALUE);
+                       }
+
+                       if (nvpair_type(propval) == DATA_TYPE_STRING) {
+                               strval = fnvpair_value_string(propval);
+                               err = dsl_prop_set_string(dsname, propname,
+                                   source, strval);
+                       } else {
+                               intval = fnvpair_value_uint64(propval);
+                               err = dsl_prop_set_int(dsname, propname, source,
+                                   intval);
+                       }
+
+                       if (err != 0) {
+                               if (errlist != NULL) {
+                                       fnvlist_add_int32(errlist, propname,
+                                           err);
+                               }
+                               rv = err;
+                       }
+               }
+       }
+       nvlist_free(genericnvl);
+       nvlist_free(retrynvl);
+
+       return (rv);
+}
+
+/*
+ * Check that all the properties are valid user properties.
+ */
+static int
+zfs_check_userprops(const char *fsname, nvlist_t *nvl)
+{
+       nvpair_t *pair = NULL;
+       int error = 0;
+
+       while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) {
+               const char *propname = nvpair_name(pair);
+
+               if (!zfs_prop_user(propname) ||
+                   nvpair_type(pair) != DATA_TYPE_STRING)
+                       return (SET_ERROR(EINVAL));
+
+               if ((error = zfs_secpolicy_write_perms(fsname,
+                   ZFS_DELEG_PERM_USERPROP, CRED())))
+                       return (error);
+
+               if (strlen(propname) >= ZAP_MAXNAMELEN)
+                       return (SET_ERROR(ENAMETOOLONG));
+
+               if (strlen(fnvpair_value_string(pair)) >= ZAP_MAXVALUELEN)
+                       return (SET_ERROR(E2BIG));
+       }
+       return (0);
+}
+
+static void
+props_skip(nvlist_t *props, nvlist_t *skipped, nvlist_t **newprops)
+{
+       nvpair_t *pair;
+
+       VERIFY(nvlist_alloc(newprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       pair = NULL;
+       while ((pair = nvlist_next_nvpair(props, pair)) != NULL) {
+               if (nvlist_exists(skipped, nvpair_name(pair)))
+                       continue;
+
+               VERIFY(nvlist_add_nvpair(*newprops, pair) == 0);
+       }
+}
+
+static int
+clear_received_props(const char *dsname, nvlist_t *props,
+    nvlist_t *skipped)
+{
+       int err = 0;
+       nvlist_t *cleared_props = NULL;
+       props_skip(props, skipped, &cleared_props);
+       if (!nvlist_empty(cleared_props)) {
+               /*
+                * Acts on local properties until the dataset has received
+                * properties at least once on or after SPA_VERSION_RECVD_PROPS.
+                */
+               zprop_source_t flags = (ZPROP_SRC_NONE |
+                   (dsl_prop_get_hasrecvd(dsname) ? ZPROP_SRC_RECEIVED : 0));
+               err = zfs_set_prop_nvlist(dsname, flags, cleared_props, NULL);
+       }
+       nvlist_free(cleared_props);
+       return (err);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_value            name of property to set
+ * zc_nvlist_src{_size}        nvlist of properties to apply
+ * zc_cookie           received properties flag
+ *
+ * outputs:
+ * zc_nvlist_dst{_size} error for each unapplied received property
+ */
+static int
+zfs_ioc_set_prop(zfs_cmd_t *zc)
+{
+       nvlist_t *nvl;
+       boolean_t received = zc->zc_cookie;
+       zprop_source_t source = (received ? ZPROP_SRC_RECEIVED :
+           ZPROP_SRC_LOCAL);
+       nvlist_t *errors;
+       int error;
+
+       if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &nvl)) != 0)
+               return (error);
+
+       if (received) {
+               nvlist_t *origprops;
+
+               if (dsl_prop_get_received(zc->zc_name, &origprops) == 0) {
+                       (void) clear_received_props(zc->zc_name,
+                           origprops, nvl);
+                       nvlist_free(origprops);
+               }
+
+               error = dsl_prop_set_hasrecvd(zc->zc_name);
+       }
+
+       errors = fnvlist_alloc();
+       if (error == 0)
+               error = zfs_set_prop_nvlist(zc->zc_name, source, nvl, errors);
+
+       if (zc->zc_nvlist_dst != 0 && errors != NULL) {
+               (void) put_nvlist(zc, errors);
+       }
+
+       nvlist_free(errors);
+       nvlist_free(nvl);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_value            name of property to inherit
+ * zc_cookie           revert to received value if TRUE
+ *
+ * outputs:            none
+ */
+static int
+zfs_ioc_inherit_prop(zfs_cmd_t *zc)
+{
+       const char *propname = zc->zc_value;
+       zfs_prop_t prop = zfs_name_to_prop(propname);
+       boolean_t received = zc->zc_cookie;
+       zprop_source_t source = (received
+           ? ZPROP_SRC_NONE            /* revert to received value, if any */
+           : ZPROP_SRC_INHERITED);     /* explicitly inherit */
+
+       if (received) {
+               nvlist_t *dummy;
+               nvpair_t *pair;
+               zprop_type_t type;
+               int err;
+
+               /*
+                * zfs_prop_set_special() expects properties in the form of an
+                * nvpair with type info.
+                */
+               if (prop == ZPROP_INVAL) {
+                       if (!zfs_prop_user(propname))
+                               return (SET_ERROR(EINVAL));
+
+                       type = PROP_TYPE_STRING;
+               } else if (prop == ZFS_PROP_VOLSIZE ||
+                   prop == ZFS_PROP_VERSION) {
+                       return (SET_ERROR(EINVAL));
+               } else {
+                       type = zfs_prop_get_type(prop);
+               }
+
+               VERIFY(nvlist_alloc(&dummy, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+               switch (type) {
+               case PROP_TYPE_STRING:
+                       VERIFY(0 == nvlist_add_string(dummy, propname, ""));
+                       break;
+               case PROP_TYPE_NUMBER:
+               case PROP_TYPE_INDEX:
+                       VERIFY(0 == nvlist_add_uint64(dummy, propname, 0));
+                       break;
+               default:
+                       nvlist_free(dummy);
+                       return (SET_ERROR(EINVAL));
+               }
+
+               pair = nvlist_next_nvpair(dummy, NULL);
+               err = zfs_prop_set_special(zc->zc_name, source, pair);
+               nvlist_free(dummy);
+               if (err != -1)
+                       return (err); /* special property already handled */
+       } else {
+               /*
+                * Only check this in the non-received case. We want to allow
+                * 'inherit -S' to revert non-inheritable properties like quota
+                * and reservation to the received or default values even though
+                * they are not considered inheritable.
+                */
+               if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop))
+                       return (SET_ERROR(EINVAL));
+       }
+
+       /* property name has been validated by zfs_secpolicy_inherit_prop() */
+       return (dsl_prop_inherit(zc->zc_name, zc->zc_value, source));
+}
+
+static int
+zfs_ioc_pool_set_props(zfs_cmd_t *zc)
+{
+       nvlist_t *props;
+       spa_t *spa;
+       int error;
+       nvpair_t *pair;
+
+       if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &props)))
+               return (error);
+
+       /*
+        * If the only property is the configfile, then just do a spa_lookup()
+        * to handle the faulted case.
+        */
+       pair = nvlist_next_nvpair(props, NULL);
+       if (pair != NULL && strcmp(nvpair_name(pair),
+           zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 &&
+           nvlist_next_nvpair(props, pair) == NULL) {
+               mutex_enter(&spa_namespace_lock);
+               if ((spa = spa_lookup(zc->zc_name)) != NULL) {
+                       spa_configfile_set(spa, props, B_FALSE);
+                       spa_config_sync(spa, B_FALSE, B_TRUE);
+               }
+               mutex_exit(&spa_namespace_lock);
+               if (spa != NULL) {
+                       nvlist_free(props);
+                       return (0);
+               }
+       }
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
+               nvlist_free(props);
+               return (error);
+       }
+
+       error = spa_prop_set(spa, props);
+
+       nvlist_free(props);
+       spa_close(spa, FTAG);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_get_props(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+       nvlist_t *nvp = NULL;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
+               /*
+                * If the pool is faulted, there may be properties we can still
+                * get (such as altroot and cachefile), so attempt to get them
+                * anyway.
+                */
+               mutex_enter(&spa_namespace_lock);
+               if ((spa = spa_lookup(zc->zc_name)) != NULL)
+                       error = spa_prop_get(spa, &nvp);
+               mutex_exit(&spa_namespace_lock);
+       } else {
+               error = spa_prop_get(spa, &nvp);
+               spa_close(spa, FTAG);
+       }
+
+       if (error == 0 && zc->zc_nvlist_dst != 0)
+               error = put_nvlist(zc, nvp);
+       else
+               error = SET_ERROR(EFAULT);
+
+       nvlist_free(nvp);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_nvlist_src{_size}        nvlist of delegated permissions
+ * zc_perm_action      allow/unallow flag
+ *
+ * outputs:            none
+ */
+static int
+zfs_ioc_set_fsacl(zfs_cmd_t *zc)
+{
+       int error;
+       nvlist_t *fsaclnv = NULL;
+
+       if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &fsaclnv)) != 0)
+               return (error);
+
+       /*
+        * Verify nvlist is constructed correctly
+        */
+       if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) {
+               nvlist_free(fsaclnv);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * If we don't have PRIV_SYS_MOUNT, then validate
+        * that user is allowed to hand out each permission in
+        * the nvlist(s)
+        */
+
+       error = secpolicy_zfs(CRED());
+       if (error != 0) {
+               if (zc->zc_perm_action == B_FALSE) {
+                       error = dsl_deleg_can_allow(zc->zc_name,
+                           fsaclnv, CRED());
+               } else {
+                       error = dsl_deleg_can_unallow(zc->zc_name,
+                           fsaclnv, CRED());
+               }
+       }
+
+       if (error == 0)
+               error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action);
+
+       nvlist_free(fsaclnv);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ *
+ * outputs:
+ * zc_nvlist_src{_size}        nvlist of delegated permissions
+ */
+static int
+zfs_ioc_get_fsacl(zfs_cmd_t *zc)
+{
+       nvlist_t *nvp;
+       int error;
+
+       if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) {
+               error = put_nvlist(zc, nvp);
+               nvlist_free(nvp);
+       }
+
+       return (error);
+}
+
+/* ARGSUSED */
+static void
+zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
+{
+       zfs_creat_t *zct = arg;
+
+       zfs_create_fs(os, cr, zct->zct_zplprops, tx);
+}
+
+#define        ZFS_PROP_UNDEFINED      ((uint64_t)-1)
+
+/*
+ * inputs:
+ * os                  parent objset pointer (NULL if root fs)
+ * fuids_ok            fuids allowed in this version of the spa?
+ * sa_ok               SAs allowed in this version of the spa?
+ * createprops         list of properties requested by creator
+ *
+ * outputs:
+ * zplprops    values for the zplprops we attach to the master node object
+ * is_ci       true if requested file system will be purely case-insensitive
+ *
+ * Determine the settings for utf8only, normalization and
+ * casesensitivity.  Specific values may have been requested by the
+ * creator and/or we can inherit values from the parent dataset.  If
+ * the file system is of too early a vintage, a creator can not
+ * request settings for these properties, even if the requested
+ * setting is the default value.  We don't actually want to create dsl
+ * properties for these, so remove them from the source nvlist after
+ * processing.
+ */
+static int
+zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver,
+    boolean_t fuids_ok, boolean_t sa_ok, nvlist_t *createprops,
+    nvlist_t *zplprops, boolean_t *is_ci)
+{
+       uint64_t sense = ZFS_PROP_UNDEFINED;
+       uint64_t norm = ZFS_PROP_UNDEFINED;
+       uint64_t u8 = ZFS_PROP_UNDEFINED;
+       int error;
+
+       ASSERT(zplprops != NULL);
+
+       /*
+        * Pull out creator prop choices, if any.
+        */
+       if (createprops) {
+               (void) nvlist_lookup_uint64(createprops,
+                   zfs_prop_to_name(ZFS_PROP_VERSION), &zplver);
+               (void) nvlist_lookup_uint64(createprops,
+                   zfs_prop_to_name(ZFS_PROP_NORMALIZE), &norm);
+               (void) nvlist_remove_all(createprops,
+                   zfs_prop_to_name(ZFS_PROP_NORMALIZE));
+               (void) nvlist_lookup_uint64(createprops,
+                   zfs_prop_to_name(ZFS_PROP_UTF8ONLY), &u8);
+               (void) nvlist_remove_all(createprops,
+                   zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
+               (void) nvlist_lookup_uint64(createprops,
+                   zfs_prop_to_name(ZFS_PROP_CASE), &sense);
+               (void) nvlist_remove_all(createprops,
+                   zfs_prop_to_name(ZFS_PROP_CASE));
+       }
+
+       /*
+        * If the zpl version requested is whacky or the file system
+        * or pool is version is too "young" to support normalization
+        * and the creator tried to set a value for one of the props,
+        * error out.
+        */
+       if ((zplver < ZPL_VERSION_INITIAL || zplver > ZPL_VERSION) ||
+           (zplver >= ZPL_VERSION_FUID && !fuids_ok) ||
+           (zplver >= ZPL_VERSION_SA && !sa_ok) ||
+           (zplver < ZPL_VERSION_NORMALIZATION &&
+           (norm != ZFS_PROP_UNDEFINED || u8 != ZFS_PROP_UNDEFINED ||
+           sense != ZFS_PROP_UNDEFINED)))
+               return (SET_ERROR(ENOTSUP));
+
+       /*
+        * Put the version in the zplprops
+        */
+       VERIFY(nvlist_add_uint64(zplprops,
+           zfs_prop_to_name(ZFS_PROP_VERSION), zplver) == 0);
+
+       if (norm == ZFS_PROP_UNDEFINED &&
+           (error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &norm)) != 0)
+               return (error);
+       VERIFY(nvlist_add_uint64(zplprops,
+           zfs_prop_to_name(ZFS_PROP_NORMALIZE), norm) == 0);
+
+       /*
+        * If we're normalizing, names must always be valid UTF-8 strings.
+        */
+       if (norm)
+               u8 = 1;
+       if (u8 == ZFS_PROP_UNDEFINED &&
+           (error = zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &u8)) != 0)
+               return (error);
+       VERIFY(nvlist_add_uint64(zplprops,
+           zfs_prop_to_name(ZFS_PROP_UTF8ONLY), u8) == 0);
+
+       if (sense == ZFS_PROP_UNDEFINED &&
+           (error = zfs_get_zplprop(os, ZFS_PROP_CASE, &sense)) != 0)
+               return (error);
+       VERIFY(nvlist_add_uint64(zplprops,
+           zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0);
+
+       if (is_ci)
+               *is_ci = (sense == ZFS_CASE_INSENSITIVE);
+
+       return (0);
+}
+
+static int
+zfs_fill_zplprops(const char *dataset, nvlist_t *createprops,
+    nvlist_t *zplprops, boolean_t *is_ci)
+{
+       boolean_t fuids_ok, sa_ok;
+       uint64_t zplver = ZPL_VERSION;
+       objset_t *os = NULL;
+       char parentname[MAXNAMELEN];
+       char *cp;
+       spa_t *spa;
+       uint64_t spa_vers;
+       int error;
+
+       (void) strlcpy(parentname, dataset, sizeof (parentname));
+       cp = strrchr(parentname, '/');
+       ASSERT(cp != NULL);
+       cp[0] = '\0';
+
+       if ((error = spa_open(dataset, &spa, FTAG)) != 0)
+               return (error);
+
+       spa_vers = spa_version(spa);
+       spa_close(spa, FTAG);
+
+       zplver = zfs_zpl_version_map(spa_vers);
+       fuids_ok = (zplver >= ZPL_VERSION_FUID);
+       sa_ok = (zplver >= ZPL_VERSION_SA);
+
+       /*
+        * Open parent object set so we can inherit zplprop values.
+        */
+       if ((error = dmu_objset_hold(parentname, FTAG, &os)) != 0)
+               return (error);
+
+       error = zfs_fill_zplprops_impl(os, zplver, fuids_ok, sa_ok, createprops,
+           zplprops, is_ci);
+       dmu_objset_rele(os, FTAG);
+       return (error);
+}
+
+static int
+zfs_fill_zplprops_root(uint64_t spa_vers, nvlist_t *createprops,
+    nvlist_t *zplprops, boolean_t *is_ci)
+{
+       boolean_t fuids_ok;
+       boolean_t sa_ok;
+       uint64_t zplver = ZPL_VERSION;
+       int error;
+
+       zplver = zfs_zpl_version_map(spa_vers);
+       fuids_ok = (zplver >= ZPL_VERSION_FUID);
+       sa_ok = (zplver >= ZPL_VERSION_SA);
+
+       error = zfs_fill_zplprops_impl(NULL, zplver, fuids_ok, sa_ok,
+           createprops, zplprops, is_ci);
+       return (error);
+}
+
+/*
+ * innvl: {
+ *     "type" -> dmu_objset_type_t (int32)
+ *     (optional) "props" -> { prop -> value }
+ * }
+ *
+ * outnvl: propname -> error code (int32)
+ */
+static int
+zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       int error = 0;
+       zfs_creat_t zct = { 0 };
+       nvlist_t *nvprops = NULL;
+       void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
+       int32_t type32;
+       dmu_objset_type_t type;
+       boolean_t is_insensitive = B_FALSE;
+
+       if (nvlist_lookup_int32(innvl, "type", &type32) != 0)
+               return (SET_ERROR(EINVAL));
+       type = type32;
+       (void) nvlist_lookup_nvlist(innvl, "props", &nvprops);
+
+       switch (type) {
+       case DMU_OST_ZFS:
+               cbfunc = zfs_create_cb;
+               break;
+
+       case DMU_OST_ZVOL:
+               cbfunc = zvol_create_cb;
+               break;
+
+       default:
+               cbfunc = NULL;
+               break;
+       }
+       if (strchr(fsname, '@') ||
+           strchr(fsname, '%'))
+               return (SET_ERROR(EINVAL));
+
+       zct.zct_props = nvprops;
+
+       if (cbfunc == NULL)
+               return (SET_ERROR(EINVAL));
+
+       if (type == DMU_OST_ZVOL) {
+               uint64_t volsize, volblocksize;
+
+               if (nvprops == NULL)
+                       return (SET_ERROR(EINVAL));
+               if (nvlist_lookup_uint64(nvprops,
+                   zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) != 0)
+                       return (SET_ERROR(EINVAL));
+
+               if ((error = nvlist_lookup_uint64(nvprops,
+                   zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+                   &volblocksize)) != 0 && error != ENOENT)
+                       return (SET_ERROR(EINVAL));
+
+               if (error != 0)
+                       volblocksize = zfs_prop_default_numeric(
+                           ZFS_PROP_VOLBLOCKSIZE);
+
+               if ((error = zvol_check_volblocksize(fsname,
+                   volblocksize)) != 0 ||
+                   (error = zvol_check_volsize(volsize,
+                   volblocksize)) != 0)
+                       return (error);
+       } else if (type == DMU_OST_ZFS) {
+               int error;
+
+               /*
+                * We have to have normalization and
+                * case-folding flags correct when we do the
+                * file system creation, so go figure them out
+                * now.
+                */
+               VERIFY(nvlist_alloc(&zct.zct_zplprops,
+                   NV_UNIQUE_NAME, KM_SLEEP) == 0);
+               error = zfs_fill_zplprops(fsname, nvprops,
+                   zct.zct_zplprops, &is_insensitive);
+               if (error != 0) {
+                       nvlist_free(zct.zct_zplprops);
+                       return (error);
+               }
+       }
+
+       error = dmu_objset_create(fsname, type,
+           is_insensitive ? DS_FLAG_CI_DATASET : 0, cbfunc, &zct);
+       nvlist_free(zct.zct_zplprops);
+
+       /*
+        * It would be nice to do this atomically.
+        */
+       if (error == 0) {
+               error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL,
+                   nvprops, outnvl);
+               if (error != 0)
+                       (void) dsl_destroy_head(fsname);
+       }
+       return (error);
+}
+
+/*
+ * innvl: {
+ *     "origin" -> name of origin snapshot
+ *     (optional) "props" -> { prop -> value }
+ * }
+ *
+ * outputs:
+ * outnvl: propname -> error code (int32)
+ */
+static int
+zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       int error = 0;
+       nvlist_t *nvprops = NULL;
+       char *origin_name;
+
+       if (nvlist_lookup_string(innvl, "origin", &origin_name) != 0)
+               return (SET_ERROR(EINVAL));
+       (void) nvlist_lookup_nvlist(innvl, "props", &nvprops);
+
+       if (strchr(fsname, '@') ||
+           strchr(fsname, '%'))
+               return (SET_ERROR(EINVAL));
+
+       if (dataset_namecheck(origin_name, NULL, NULL) != 0)
+               return (SET_ERROR(EINVAL));
+       error = dmu_objset_clone(fsname, origin_name);
+       if (error != 0)
+               return (error);
+
+       /*
+        * It would be nice to do this atomically.
+        */
+       if (error == 0) {
+               error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL,
+                   nvprops, outnvl);
+               if (error != 0)
+                       (void) dsl_destroy_head(fsname);
+       }
+       return (error);
+}
+
+/*
+ * innvl: {
+ *     "snaps" -> { snapshot1, snapshot2 }
+ *     (optional) "props" -> { prop -> value (string) }
+ * }
+ *
+ * outnvl: snapshot -> error code (int32)
+ */
+static int
+zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       nvlist_t *snaps;
+       nvlist_t *props = NULL;
+       int error, poollen;
+       nvpair_t *pair, *pair2;
+
+       (void) nvlist_lookup_nvlist(innvl, "props", &props);
+       if ((error = zfs_check_userprops(poolname, props)) != 0)
+               return (error);
+
+       if (!nvlist_empty(props) &&
+           zfs_earlier_version(poolname, SPA_VERSION_SNAP_PROPS))
+               return (SET_ERROR(ENOTSUP));
+
+       if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
+               return (SET_ERROR(EINVAL));
+       poollen = strlen(poolname);
+       for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(snaps, pair)) {
+               const char *name = nvpair_name(pair);
+               const char *cp = strchr(name, '@');
+
+               /*
+                * The snap name must contain an @, and the part after it must
+                * contain only valid characters.
+                */
+               if (cp == NULL ||
+                   zfs_component_namecheck(cp + 1, NULL, NULL) != 0)
+                       return (SET_ERROR(EINVAL));
+
+               /*
+                * The snap must be in the specified pool.
+                */
+               if (strncmp(name, poolname, poollen) != 0 ||
+                   (name[poollen] != '/' && name[poollen] != '@'))
+                       return (SET_ERROR(EXDEV));
+
+               /* This must be the only snap of this fs. */
+               for (pair2 = nvlist_next_nvpair(snaps, pair);
+                   pair2 != NULL; pair2 = nvlist_next_nvpair(snaps, pair2)) {
+                       if (strncmp(name, nvpair_name(pair2), cp - name + 1)
+                           == 0) {
+                               return (SET_ERROR(EXDEV));
+                       }
+               }
+       }
+
+       error = dsl_dataset_snapshot(snaps, props, outnvl);
+
+       return (error);
+}
+
+/*
+ * innvl: "message" -> string
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_log_history(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       char *message;
+       spa_t *spa;
+       int error;
+       char *poolname;
+
+       /*
+        * The poolname in the ioctl is not set, we get it from the TSD,
+        * which was set at the end of the last successful ioctl that allows
+        * logging.  The secpolicy func already checked that it is set.
+        * Only one log ioctl is allowed after each successful ioctl, so
+        * we clear the TSD here.
+        */
+       poolname = tsd_get(zfs_allow_log_key);
+       (void) tsd_set(zfs_allow_log_key, NULL);
+       error = spa_open(poolname, &spa, FTAG);
+       strfree(poolname);
+       if (error != 0)
+               return (error);
+
+       if (nvlist_lookup_string(innvl, "message", &message) != 0)  {
+               spa_close(spa, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
+               spa_close(spa, FTAG);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       error = spa_history_log(spa, message);
+       spa_close(spa, FTAG);
+       return (error);
+}
+
+/*
+ * The dp_config_rwlock must not be held when calling this, because the
+ * unmount may need to write out data.
+ *
+ * This function is best-effort.  Callers must deal gracefully if it
+ * remains mounted (or is remounted after this call).
+ *
+ * Returns 0 if the argument is not a snapshot, or it is not currently a
+ * filesystem, or we were able to unmount it.  Returns error code otherwise.
+ */
+int
+zfs_unmount_snap(const char *snapname)
+{
+       int err;
+
+       if (strchr(snapname, '@') == NULL)
+               return (0);
+
+       err = zfsctl_snapshot_unmount((char *)snapname, MNT_FORCE);
+       if (err != 0 && err != ENOENT)
+               return (SET_ERROR(err));
+
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+zfs_unmount_snap_cb(const char *snapname, void *arg)
+{
+       return (zfs_unmount_snap(snapname));
+}
+
+/*
+ * When a clone is destroyed, its origin may also need to be destroyed,
+ * in which case it must be unmounted.  This routine will do that unmount
+ * if necessary.
+ */
+void
+zfs_destroy_unmount_origin(const char *fsname)
+{
+       int error;
+       objset_t *os;
+       dsl_dataset_t *ds;
+
+       error = dmu_objset_hold(fsname, FTAG, &os);
+       if (error != 0)
+               return;
+       ds = dmu_objset_ds(os);
+       if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) {
+               char originname[MAXNAMELEN];
+               dsl_dataset_name(ds->ds_prev, originname);
+               dmu_objset_rele(os, FTAG);
+               (void) zfs_unmount_snap(originname);
+       } else {
+               dmu_objset_rele(os, FTAG);
+       }
+}
+
+/*
+ * innvl: {
+ *     "snaps" -> { snapshot1, snapshot2 }
+ *     (optional boolean) "defer"
+ * }
+ *
+ * outnvl: snapshot -> error code (int32)
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       nvlist_t *snaps;
+       nvpair_t *pair;
+       boolean_t defer;
+
+       if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
+               return (SET_ERROR(EINVAL));
+       defer = nvlist_exists(innvl, "defer");
+
+       for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(snaps, pair)) {
+               (void) zfs_unmount_snap(nvpair_name(pair));
+       }
+
+       return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
+}
+
+/*
+ * Create bookmarks.  Bookmark names are of the form <fs>#<bmark>.
+ * All bookmarks must be in the same pool.
+ *
+ * innvl: {
+ *     bookmark1 -> snapshot1, bookmark2 -> snapshot2
+ * }
+ *
+ * outnvl: bookmark -> error code (int32)
+ *
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_bookmark(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       nvpair_t *pair, *pair2;
+
+       for (pair = nvlist_next_nvpair(innvl, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
+               char *snap_name;
+
+               /*
+                * Verify the snapshot argument.
+                */
+               if (nvpair_value_string(pair, &snap_name) != 0)
+                       return (SET_ERROR(EINVAL));
+
+
+               /* Verify that the keys (bookmarks) are unique */
+               for (pair2 = nvlist_next_nvpair(innvl, pair);
+                   pair2 != NULL; pair2 = nvlist_next_nvpair(innvl, pair2)) {
+                       if (strcmp(nvpair_name(pair), nvpair_name(pair2)) == 0)
+                               return (SET_ERROR(EINVAL));
+               }
+       }
+
+       return (dsl_bookmark_create(innvl, outnvl));
+}
+
+/*
+ * innvl: {
+ *     property 1, property 2, ...
+ * }
+ *
+ * outnvl: {
+ *     bookmark name 1 -> { property 1, property 2, ... },
+ *     bookmark name 2 -> { property 1, property 2, ... }
+ * }
+ *
+ */
+static int
+zfs_ioc_get_bookmarks(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       return (dsl_get_bookmarks(fsname, innvl, outnvl));
+}
+
+/*
+ * innvl: {
+ *     bookmark name 1, bookmark name 2
+ * }
+ *
+ * outnvl: bookmark -> error code (int32)
+ *
+ */
+static int
+zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl,
+    nvlist_t *outnvl)
+{
+       int error, poollen;
+       nvpair_t *pair;
+
+       poollen = strlen(poolname);
+       for (pair = nvlist_next_nvpair(innvl, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
+               const char *name = nvpair_name(pair);
+               const char *cp = strchr(name, '#');
+
+               /*
+                * The bookmark name must contain an #, and the part after it
+                * must contain only valid characters.
+                */
+               if (cp == NULL ||
+                   zfs_component_namecheck(cp + 1, NULL, NULL) != 0)
+                       return (SET_ERROR(EINVAL));
+
+               /*
+                * The bookmark must be in the specified pool.
+                */
+               if (strncmp(name, poolname, poollen) != 0 ||
+                   (name[poollen] != '/' && name[poollen] != '#'))
+                       return (SET_ERROR(EXDEV));
+       }
+
+       error = dsl_bookmark_destroy(innvl, outnvl);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of dataset to destroy
+ * zc_objset_type      type of objset
+ * zc_defer_destroy    mark for deferred destroy
+ *
+ * outputs:            none
+ */
+static int
+zfs_ioc_destroy(zfs_cmd_t *zc)
+{
+       int err;
+
+       if (zc->zc_objset_type == DMU_OST_ZFS) {
+               err = zfs_unmount_snap(zc->zc_name);
+               if (err != 0)
+                       return (err);
+       }
+
+       if (strchr(zc->zc_name, '@'))
+               err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
+       else
+               err = dsl_destroy_head(zc->zc_name);
+
+       return (err);
+}
+
+/*
+ * fsname is name of dataset to rollback (to most recent snapshot)
+ *
+ * innvl is not used.
+ *
+ * outnvl: "target" -> name of most recent snapshot
+ * }
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl)
+{
+       zfs_sb_t *zsb;
+       int error;
+
+       if (get_zfs_sb(fsname, &zsb) == 0) {
+               error = zfs_suspend_fs(zsb);
+               if (error == 0) {
+                       int resume_err;
+
+                       error = dsl_dataset_rollback(fsname, zsb, outnvl);
+                       resume_err = zfs_resume_fs(zsb, fsname);
+                       error = error ? error : resume_err;
+               }
+               deactivate_super(zsb->z_sb);
+       } else {
+               error = dsl_dataset_rollback(fsname, NULL, outnvl);
+       }
+       return (error);
+}
+
+static int
+recursive_unmount(const char *fsname, void *arg)
+{
+       const char *snapname = arg;
+       char *fullname;
+       int error;
+
+       fullname = kmem_asprintf("%s@%s", fsname, snapname);
+       error = zfs_unmount_snap(fullname);
+       strfree(fullname);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name     old name of dataset
+ * zc_value    new name of dataset
+ * zc_cookie   recursive flag (only valid for snapshots)
+ *
+ * outputs:    none
+ */
+static int
+zfs_ioc_rename(zfs_cmd_t *zc)
+{
+       boolean_t recursive = zc->zc_cookie & 1;
+       char *at;
+
+       zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
+       if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
+           strchr(zc->zc_value, '%'))
+               return (SET_ERROR(EINVAL));
+
+       at = strchr(zc->zc_name, '@');
+       if (at != NULL) {
+               /* snaps must be in same fs */
+               int error;
+
+               if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1))
+                       return (SET_ERROR(EXDEV));
+               *at = '\0';
+               if (zc->zc_objset_type == DMU_OST_ZFS) {
+                       error = dmu_objset_find(zc->zc_name,
+                           recursive_unmount, at + 1,
+                           recursive ? DS_FIND_CHILDREN : 0);
+                       if (error != 0) {
+                               *at = '@';
+                               return (error);
+                       }
+               }
+               error = dsl_dataset_rename_snapshot(zc->zc_name,
+                   at + 1, strchr(zc->zc_value, '@') + 1, recursive);
+               *at = '@';
+
+               return (error);
+       } else {
+               return (dsl_dir_rename(zc->zc_name, zc->zc_value));
+       }
+}
+
+static int
+zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
+{
+       const char *propname = nvpair_name(pair);
+       boolean_t issnap = (strchr(dsname, '@') != NULL);
+       zfs_prop_t prop = zfs_name_to_prop(propname);
+       uint64_t intval;
+       int err;
+
+       if (prop == ZPROP_INVAL) {
+               if (zfs_prop_user(propname)) {
+                       if ((err = zfs_secpolicy_write_perms(dsname,
+                           ZFS_DELEG_PERM_USERPROP, cr)))
+                               return (err);
+                       return (0);
+               }
+
+               if (!issnap && zfs_prop_userquota(propname)) {
+                       const char *perm = NULL;
+                       const char *uq_prefix =
+                           zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA];
+                       const char *gq_prefix =
+                           zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA];
+
+                       if (strncmp(propname, uq_prefix,
+                           strlen(uq_prefix)) == 0) {
+                               perm = ZFS_DELEG_PERM_USERQUOTA;
+                       } else if (strncmp(propname, gq_prefix,
+                           strlen(gq_prefix)) == 0) {
+                               perm = ZFS_DELEG_PERM_GROUPQUOTA;
+                       } else {
+                               /* USERUSED and GROUPUSED are read-only */
+                               return (SET_ERROR(EINVAL));
+                       }
+
+                       if ((err = zfs_secpolicy_write_perms(dsname, perm, cr)))
+                               return (err);
+                       return (0);
+               }
+
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (issnap)
+               return (SET_ERROR(EINVAL));
+
+       if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+               /*
+                * dsl_prop_get_all_impl() returns properties in this
+                * format.
+                */
+               nvlist_t *attrs;
+               VERIFY(nvpair_value_nvlist(pair, &attrs) == 0);
+               VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
+                   &pair) == 0);
+       }
+
+       /*
+        * Check that this value is valid for this pool version
+        */
+       switch (prop) {
+       case ZFS_PROP_COMPRESSION:
+               /*
+                * If the user specified gzip compression, make sure
+                * the SPA supports it. We ignore any errors here since
+                * we'll catch them later.
+                */
+               if (nvpair_value_uint64(pair, &intval) == 0) {
+                       if (intval >= ZIO_COMPRESS_GZIP_1 &&
+                           intval <= ZIO_COMPRESS_GZIP_9 &&
+                           zfs_earlier_version(dsname,
+                           SPA_VERSION_GZIP_COMPRESSION)) {
+                               return (SET_ERROR(ENOTSUP));
+                       }
+
+                       if (intval == ZIO_COMPRESS_ZLE &&
+                           zfs_earlier_version(dsname,
+                           SPA_VERSION_ZLE_COMPRESSION))
+                               return (SET_ERROR(ENOTSUP));
+
+                       if (intval == ZIO_COMPRESS_LZ4) {
+                               spa_t *spa;
+
+                               if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                                       return (err);
+
+                               if (!spa_feature_is_enabled(spa,
+                                   SPA_FEATURE_LZ4_COMPRESS)) {
+                                       spa_close(spa, FTAG);
+                                       return (SET_ERROR(ENOTSUP));
+                               }
+                               spa_close(spa, FTAG);
+                       }
+
+                       /*
+                        * If this is a bootable dataset then
+                        * verify that the compression algorithm
+                        * is supported for booting. We must return
+                        * something other than ENOTSUP since it
+                        * implies a downrev pool version.
+                        */
+                       if (zfs_is_bootfs(dsname) &&
+                           !BOOTFS_COMPRESS_VALID(intval)) {
+                               return (SET_ERROR(ERANGE));
+                       }
+               }
+               break;
+
+       case ZFS_PROP_COPIES:
+               if (zfs_earlier_version(dsname, SPA_VERSION_DITTO_BLOCKS))
+                       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 */
+               if (nvpair_value_uint64(pair, &intval) == 0 &&
+                   intval > SPA_OLD_MAXBLOCKSIZE) {
+                       spa_t *spa;
+
+                       /*
+                        * If this is a bootable dataset then
+                        * the 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));
+                       }
+
+                       /*
+                        * We don't allow setting the property above 1MB,
+                        * unless the tunable has been changed.
+                        */
+                       if (intval > zfs_max_recordsize ||
+                           intval > SPA_MAXBLOCKSIZE)
+                               return (SET_ERROR(EDOM));
+
+                       if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                               return (err);
+
+                       if (!spa_feature_is_enabled(spa,
+                           SPA_FEATURE_LARGE_BLOCKS)) {
+                               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));
+               break;
+
+       case ZFS_PROP_ACLINHERIT:
+               if (nvpair_type(pair) == DATA_TYPE_UINT64 &&
+                   nvpair_value_uint64(pair, &intval) == 0) {
+                       if (intval == ZFS_ACL_PASSTHROUGH_X &&
+                           zfs_earlier_version(dsname,
+                           SPA_VERSION_PASSTHROUGH_X))
+                               return (SET_ERROR(ENOTSUP));
+               }
+               break;
+       default:
+               break;
+       }
+
+       return (zfs_secpolicy_setprop(dsname, prop, pair, CRED()));
+}
+
+/*
+ * Removes properties from the given props list that fail permission checks
+ * needed to clear them and to restore them in case of a receive error. For each
+ * property, make sure we have both set and inherit permissions.
+ *
+ * Returns the first error encountered if any permission checks fail. If the
+ * caller provides a non-NULL errlist, it also gives the complete list of names
+ * of all the properties that failed a permission check along with the
+ * corresponding error numbers. The caller is responsible for freeing the
+ * returned errlist.
+ *
+ * If every property checks out successfully, zero is returned and the list
+ * pointed at by errlist is NULL.
+ */
+static int
+zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist)
+{
+       zfs_cmd_t *zc;
+       nvpair_t *pair, *next_pair;
+       nvlist_t *errors;
+       int err, rv = 0;
+
+       if (props == NULL)
+               return (0);
+
+       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);
+       pair = nvlist_next_nvpair(props, NULL);
+       while (pair != NULL) {
+               next_pair = nvlist_next_nvpair(props, pair);
+
+               (void) strcpy(zc->zc_value, nvpair_name(pair));
+               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);
+                       VERIFY(nvlist_add_int32(errors,
+                           zc->zc_value, err) == 0);
+               }
+               pair = next_pair;
+       }
+       kmem_free(zc, sizeof (zfs_cmd_t));
+
+       if ((pair = nvlist_next_nvpair(errors, NULL)) == NULL) {
+               nvlist_free(errors);
+               errors = NULL;
+       } else {
+               VERIFY(nvpair_value_int32(pair, &rv) == 0);
+       }
+
+       if (errlist == NULL)
+               nvlist_free(errors);
+       else
+               *errlist = errors;
+
+       return (rv);
+}
+
+static boolean_t
+propval_equals(nvpair_t *p1, nvpair_t *p2)
+{
+       if (nvpair_type(p1) == DATA_TYPE_NVLIST) {
+               /* dsl_prop_get_all_impl() format */
+               nvlist_t *attrs;
+               VERIFY(nvpair_value_nvlist(p1, &attrs) == 0);
+               VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
+                   &p1) == 0);
+       }
+
+       if (nvpair_type(p2) == DATA_TYPE_NVLIST) {
+               nvlist_t *attrs;
+               VERIFY(nvpair_value_nvlist(p2, &attrs) == 0);
+               VERIFY(nvlist_lookup_nvpair(attrs, ZPROP_VALUE,
+                   &p2) == 0);
+       }
+
+       if (nvpair_type(p1) != nvpair_type(p2))
+               return (B_FALSE);
+
+       if (nvpair_type(p1) == DATA_TYPE_STRING) {
+               char *valstr1, *valstr2;
+
+               VERIFY(nvpair_value_string(p1, (char **)&valstr1) == 0);
+               VERIFY(nvpair_value_string(p2, (char **)&valstr2) == 0);
+               return (strcmp(valstr1, valstr2) == 0);
+       } else {
+               uint64_t intval1, intval2;
+
+               VERIFY(nvpair_value_uint64(p1, &intval1) == 0);
+               VERIFY(nvpair_value_uint64(p2, &intval2) == 0);
+               return (intval1 == intval2);
+       }
+}
+
+/*
+ * Remove properties from props if they are not going to change (as determined
+ * by comparison with origprops). Remove them from origprops as well, since we
+ * do not need to clear or restore properties that won't change.
+ */
+static void
+props_reduce(nvlist_t *props, nvlist_t *origprops)
+{
+       nvpair_t *pair, *next_pair;
+
+       if (origprops == NULL)
+               return; /* all props need to be received */
+
+       pair = nvlist_next_nvpair(props, NULL);
+       while (pair != NULL) {
+               const char *propname = nvpair_name(pair);
+               nvpair_t *match;
+
+               next_pair = nvlist_next_nvpair(props, pair);
+
+               if ((nvlist_lookup_nvpair(origprops, propname,
+                   &match) != 0) || !propval_equals(pair, match))
+                       goto next; /* need to set received value */
+
+               /* don't clear the existing received value */
+               (void) nvlist_remove_nvpair(origprops, match);
+               /* don't bother receiving the property */
+               (void) nvlist_remove_nvpair(props, pair);
+next:
+               pair = next_pair;
+       }
+}
+
+#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
+ */
+static int
+zfs_ioc_recv(zfs_cmd_t *zc)
+{
+       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 *origprops = NULL; /* existing properties */
+       char *origin = NULL;
+       char *tosnap;
+       char tofs[ZFS_MAXNAMELEN];
+       boolean_t first_recvd_props = B_FALSE;
+
+       if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
+           strchr(zc->zc_value, '@') == NULL ||
+           strchr(zc->zc_value, '%'))
+               return (SET_ERROR(EINVAL));
+
+       (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);
+               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);
+       if (error != 0)
+               goto out;
+
+       /*
+        * Set properties before we receive the stream so that they are applied
+        * to the new data. Note that we must call dmu_recv_stream() if
+        * dmu_recv_begin() succeeds.
+        */
+       if (props != NULL && !drc.drc_newfs) {
+               if (spa_version(dsl_dataset_get_spa(drc.drc_ds)) >=
+                   SPA_VERSION_RECVD_PROPS &&
+                   !dsl_prop_get_hasrecvd(tofs))
+                       first_recvd_props = B_TRUE;
+
+               /*
+                * If new received properties are supplied, they are to
+                * completely replace the existing received properties, so stash
+                * away the existing ones.
+                */
+               if (dsl_prop_get_received(tofs, &origprops) == 0) {
+                       nvlist_t *errlist = NULL;
+                       /*
+                        * Don't bother writing a property if its value won't
+                        * change (and avoid the unnecessary security checks).
+                        *
+                        * The first receive after SPA_VERSION_RECVD_PROPS is a
+                        * special case where we blow away all local properties
+                        * regardless.
+                        */
+                       if (!first_recvd_props)
+                               props_reduce(props, origprops);
+                       if (zfs_check_clearable(tofs, origprops, &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;
+               } else {
+                       zc->zc_obj |= ZPROP_ERR_NOCLEAR;
+               }
+       }
+
+       if (props != NULL) {
+               props_error = dsl_prop_set_hasrecvd(tofs);
+
+               if (props_error == 0) {
+                       (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
+                           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);
+
+       if (error == 0) {
+               zfs_sb_t *zsb = NULL;
+
+               if (get_zfs_sb(tofs, &zsb) == 0) {
+                       /* online recv */
+                       int end_err;
+
+                       error = zfs_suspend_fs(zsb);
+                       /*
+                        * If the suspend fails, then the recv_end will
+                        * likely also fail, and clean up after itself.
+                        */
+                       end_err = dmu_recv_end(&drc, zsb);
+                       if (error == 0)
+                               error = zfs_resume_fs(zsb, tofs);
+                       error = error ? error : end_err;
+                       deactivate_super(zsb->z_sb);
+               } else {
+                       error = dmu_recv_end(&drc, NULL);
+               }
+       }
+
+       zc->zc_cookie = off - fp->f_offset;
+       if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+               fp->f_offset = off;
+
+#ifdef DEBUG
+       if (zfs_ioc_recv_inject_err) {
+               zfs_ioc_recv_inject_err = B_FALSE;
+               error = 1;
+       }
+#endif
+
+       /*
+        * On error, restore the original props.
+        */
+       if (error != 0 && props != NULL && !drc.drc_newfs) {
+               if (clear_received_props(tofs, props, NULL) != 0) {
+                       /*
+                        * We failed to clear the received properties.
+                        * Since we may have left a $recvd value on the
+                        * system, we can't clear the $hasrecvd flag.
+                        */
+                       zc->zc_obj |= 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;
+               }
+
+               /*
+                * dsl_props_set() will not convert RECEIVED to LOCAL on or
+                * after SPA_VERSION_RECVD_PROPS, so we need to specify LOCAL
+                * explictly if we're restoring local properties cleared in the
+                * first new-style receive.
+                */
+               if (origprops != NULL &&
+                   zfs_set_prop_nvlist(tofs, (first_recvd_props ?
+                   ZPROP_SRC_LOCAL : ZPROP_SRC_RECEIVED),
+                   origprops, NULL) != 0) {
+                       /*
+                        * We stashed the original properties but failed to
+                        * restore them.
+                        */
+                       zc->zc_obj |= ZPROP_ERR_NORESTORE;
+               }
+       }
+out:
+       nvlist_free(props);
+       nvlist_free(origprops);
+       nvlist_free(errors);
+       releasef(fd);
+
+       if (error == 0)
+               error = props_error;
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name     name of snapshot to send
+ * zc_cookie   file descriptor to send stream to
+ * zc_obj      fromorigin flag (mutually exclusive with zc_fromobj)
+ * zc_sendobj  objsetid of snapshot to send
+ * zc_fromobj  objsetid of incremental fromsnap (may be zero)
+ * zc_guid     if set, estimate size of stream only.  zc_cookie is ignored.
+ *             output size in zc_objset_type.
+ * zc_flags    lzc_send_flags
+ *
+ * outputs:
+ * zc_objset_type      estimated size, if zc_guid is set
+ */
+static int
+zfs_ioc_send(zfs_cmd_t *zc)
+{
+       int error;
+       offset_t off;
+       boolean_t estimate = (zc->zc_guid != 0);
+       boolean_t embedok = (zc->zc_flags & 0x1);
+       boolean_t large_block_ok = (zc->zc_flags & 0x2);
+
+       if (zc->zc_obj != 0) {
+               dsl_pool_t *dp;
+               dsl_dataset_t *tosnap;
+
+               error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
+               if (error != 0)
+                       return (error);
+
+               error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &tosnap);
+               if (error != 0) {
+                       dsl_pool_rele(dp, FTAG);
+                       return (error);
+               }
+
+               if (dsl_dir_is_clone(tosnap->ds_dir))
+                       zc->zc_fromobj =
+                           dsl_dir_phys(tosnap->ds_dir)->dd_origin_obj;
+               dsl_dataset_rele(tosnap, FTAG);
+               dsl_pool_rele(dp, FTAG);
+       }
+
+       if (estimate) {
+               dsl_pool_t *dp;
+               dsl_dataset_t *tosnap;
+               dsl_dataset_t *fromsnap = NULL;
+
+               error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
+               if (error != 0)
+                       return (error);
+
+               error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &tosnap);
+               if (error != 0) {
+                       dsl_pool_rele(dp, FTAG);
+                       return (error);
+               }
+
+               if (zc->zc_fromobj != 0) {
+                       error = dsl_dataset_hold_obj(dp, zc->zc_fromobj,
+                           FTAG, &fromsnap);
+                       if (error != 0) {
+                               dsl_dataset_rele(tosnap, FTAG);
+                               dsl_pool_rele(dp, FTAG);
+                               return (error);
+                       }
+               }
+
+               error = dmu_send_estimate(tosnap, fromsnap,
+                   &zc->zc_objset_type);
+
+               if (fromsnap != NULL)
+                       dsl_dataset_rele(fromsnap, FTAG);
+               dsl_dataset_rele(tosnap, FTAG);
+               dsl_pool_rele(dp, FTAG);
+       } else {
+               file_t *fp = getf(zc->zc_cookie);
+               if (fp == NULL)
+                       return (SET_ERROR(EBADF));
+
+               off = fp->f_offset;
+               error = dmu_send_obj(zc->zc_name, zc->zc_sendobj,
+                   zc->zc_fromobj, embedok, large_block_ok,
+                   zc->zc_cookie, fp->f_vnode, &off);
+
+               if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+                       fp->f_offset = off;
+               releasef(zc->zc_cookie);
+       }
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name     name of snapshot on which to report progress
+ * zc_cookie   file descriptor of send stream
+ *
+ * outputs:
+ * zc_cookie   number of bytes written in send stream thus far
+ */
+static int
+zfs_ioc_send_progress(zfs_cmd_t *zc)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *ds;
+       dmu_sendarg_t *dsp = NULL;
+       int error;
+
+       error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &ds);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       mutex_enter(&ds->ds_sendstream_lock);
+
+       /*
+        * Iterate over all the send streams currently active on this dataset.
+        * If there's one which matches the specified file descriptor _and_ the
+        * stream was started by the current process, return the progress of
+        * that stream.
+        */
+
+       for (dsp = list_head(&ds->ds_sendstreams); dsp != NULL;
+           dsp = list_next(&ds->ds_sendstreams, dsp)) {
+               if (dsp->dsa_outfd == zc->zc_cookie &&
+                   dsp->dsa_proc->group_leader == curproc->group_leader)
+                       break;
+       }
+
+       if (dsp != NULL)
+               zc->zc_cookie = *(dsp->dsa_off);
+       else
+               error = SET_ERROR(ENOENT);
+
+       mutex_exit(&ds->ds_sendstream_lock);
+       dsl_dataset_rele(ds, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (error);
+}
+
+static int
+zfs_ioc_inject_fault(zfs_cmd_t *zc)
+{
+       int id, error;
+
+       error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
+           &zc->zc_inject_record);
+
+       if (error == 0)
+               zc->zc_guid = (uint64_t)id;
+
+       return (error);
+}
+
+static int
+zfs_ioc_clear_fault(zfs_cmd_t *zc)
+{
+       return (zio_clear_fault((int)zc->zc_guid));
+}
+
+static int
+zfs_ioc_inject_list_next(zfs_cmd_t *zc)
+{
+       int id = (int)zc->zc_guid;
+       int error;
+
+       error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
+           &zc->zc_inject_record);
+
+       zc->zc_guid = id;
+
+       return (error);
+}
+
+static int
+zfs_ioc_error_log(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+       size_t count = (size_t)zc->zc_nvlist_dst_size;
+
+       if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
+               return (error);
+
+       error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
+           &count);
+       if (error == 0)
+               zc->zc_nvlist_dst_size = count;
+       else
+               zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
+
+       spa_close(spa, FTAG);
+
+       return (error);
+}
+
+static int
+zfs_ioc_clear(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       vdev_t *vd;
+       int error;
+
+       /*
+        * On zpool clear we also fix up missing slogs
+        */
+       mutex_enter(&spa_namespace_lock);
+       spa = spa_lookup(zc->zc_name);
+       if (spa == NULL) {
+               mutex_exit(&spa_namespace_lock);
+               return (SET_ERROR(EIO));
+       }
+       if (spa_get_log_state(spa) == SPA_LOG_MISSING) {
+               /* we need to let spa_open/spa_load clear the chains */
+               spa_set_log_state(spa, SPA_LOG_CLEAR);
+       }
+       spa->spa_last_open_failed = 0;
+       mutex_exit(&spa_namespace_lock);
+
+       if (zc->zc_cookie & ZPOOL_NO_REWIND) {
+               error = spa_open(zc->zc_name, &spa, FTAG);
+       } else {
+               nvlist_t *policy;
+               nvlist_t *config = NULL;
+
+               if (zc->zc_nvlist_src == 0)
+                       return (SET_ERROR(EINVAL));
+
+               if ((error = get_nvlist(zc->zc_nvlist_src,
+                   zc->zc_nvlist_src_size, zc->zc_iflags, &policy)) == 0) {
+                       error = spa_open_rewind(zc->zc_name, &spa, FTAG,
+                           policy, &config);
+                       if (config != NULL) {
+                               int err;
+
+                               if ((err = put_nvlist(zc, config)) != 0)
+                                       error = err;
+                               nvlist_free(config);
+                       }
+                       nvlist_free(policy);
+               }
+       }
+
+       if (error != 0)
+               return (error);
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+
+       if (zc->zc_guid == 0) {
+               vd = NULL;
+       } else {
+               vd = spa_lookup_by_guid(spa, zc->zc_guid, B_TRUE);
+               if (vd == NULL) {
+                       (void) spa_vdev_state_exit(spa, NULL, ENODEV);
+                       spa_close(spa, FTAG);
+                       return (SET_ERROR(ENODEV));
+               }
+       }
+
+       vdev_clear(spa, vd);
+
+       (void) spa_vdev_state_exit(spa, NULL, 0);
+
+       /*
+        * Resume any suspended I/Os.
+        */
+       if (zio_resume(spa) != 0)
+               error = SET_ERROR(EIO);
+
+       spa_close(spa, FTAG);
+
+       return (error);
+}
+
+static int
+zfs_ioc_pool_reopen(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error != 0)
+               return (error);
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+
+       /*
+        * If a resilver is already in progress then set the
+        * spa_scrub_reopen flag to B_TRUE so that we don't restart
+        * the scan as a side effect of the reopen. Otherwise, let
+        * vdev_open() decided if a resilver is required.
+        */
+       spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool);
+       vdev_reopen(spa->spa_root_vdev);
+       spa->spa_scrub_reopen = B_FALSE;
+
+       (void) spa_vdev_state_exit(spa, NULL, 0);
+       spa_close(spa, FTAG);
+       return (0);
+}
+/*
+ * inputs:
+ * zc_name     name of filesystem
+ * zc_value    name of origin snapshot
+ *
+ * outputs:
+ * zc_string   name of conflicting snapshot, if there is one
+ */
+static int
+zfs_ioc_promote(zfs_cmd_t *zc)
+{
+       char *cp;
+
+       /*
+        * We don't need to unmount *all* the origin fs's snapshots, but
+        * it's easier.
+        */
+       cp = strchr(zc->zc_value, '@');
+       if (cp)
+               *cp = '\0';
+       (void) dmu_objset_find(zc->zc_value,
+           zfs_unmount_snap_cb, NULL, DS_FIND_SNAPSHOTS);
+       return (dsl_dataset_promote(zc->zc_name, zc->zc_string));
+}
+
+/*
+ * Retrieve a single {user|group}{used|quota}@... property.
+ *
+ * inputs:
+ * zc_name     name of filesystem
+ * zc_objset_type zfs_userquota_prop_t
+ * zc_value    domain name (eg. "S-1-234-567-89")
+ * zc_guid     RID/UID/GID
+ *
+ * outputs:
+ * zc_cookie   property value
+ */
+static int
+zfs_ioc_userspace_one(zfs_cmd_t *zc)
+{
+       zfs_sb_t *zsb;
+       int error;
+
+       if (zc->zc_objset_type >= ZFS_NUM_USERQUOTA_PROPS)
+               return (SET_ERROR(EINVAL));
+
+       error = zfs_sb_hold(zc->zc_name, FTAG, &zsb, B_FALSE);
+       if (error != 0)
+               return (error);
+
+       error = zfs_userspace_one(zsb,
+           zc->zc_objset_type, zc->zc_value, zc->zc_guid, &zc->zc_cookie);
+       zfs_sb_rele(zsb, FTAG);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_cookie           zap cursor
+ * zc_objset_type      zfs_userquota_prop_t
+ * zc_nvlist_dst[_size] buffer to fill (not really an nvlist)
+ *
+ * outputs:
+ * zc_nvlist_dst[_size]        data buffer (array of zfs_useracct_t)
+ * zc_cookie   zap cursor
+ */
+static int
+zfs_ioc_userspace_many(zfs_cmd_t *zc)
+{
+       zfs_sb_t *zsb;
+       int bufsize = zc->zc_nvlist_dst_size;
+       int error;
+       void *buf;
+
+       if (bufsize <= 0)
+               return (SET_ERROR(ENOMEM));
+
+       error = zfs_sb_hold(zc->zc_name, FTAG, &zsb, B_FALSE);
+       if (error != 0)
+               return (error);
+
+       buf = vmem_alloc(bufsize, KM_SLEEP);
+
+       error = zfs_userspace_many(zsb, zc->zc_objset_type, &zc->zc_cookie,
+           buf, &zc->zc_nvlist_dst_size);
+
+       if (error == 0) {
+               error = xcopyout(buf,
+                   (void *)(uintptr_t)zc->zc_nvlist_dst,
+                   zc->zc_nvlist_dst_size);
+       }
+       vmem_free(buf, bufsize);
+       zfs_sb_rele(zsb, FTAG);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ *
+ * outputs:
+ * none
+ */
+static int
+zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error = 0;
+       zfs_sb_t *zsb;
+
+       if (get_zfs_sb(zc->zc_name, &zsb) == 0) {
+               if (!dmu_objset_userused_enabled(zsb->z_os)) {
+                       /*
+                        * If userused is not enabled, it may be because the
+                        * objset needs to be closed & reopened (to grow the
+                        * objset_phys_t).  Suspend/resume the fs will do that.
+                        */
+                       error = zfs_suspend_fs(zsb);
+                       if (error == 0) {
+                               dmu_objset_refresh_ownership(zsb->z_os,
+                                   zsb);
+                               error = zfs_resume_fs(zsb, zc->zc_name);
+                       }
+               }
+               if (error == 0)
+                       error = dmu_objset_userspace_upgrade(zsb->z_os);
+               deactivate_super(zsb->z_sb);
+       } else {
+               /* XXX kind of reading contents without owning */
+               error = dmu_objset_hold(zc->zc_name, FTAG, &os);
+               if (error != 0)
+                       return (error);
+
+               error = dmu_objset_userspace_upgrade(os);
+               dmu_objset_rele(os, FTAG);
+       }
+
+       return (error);
+}
+
+static int
+zfs_ioc_share(zfs_cmd_t *zc)
+{
+       return (SET_ERROR(ENOSYS));
+}
+
+ace_t full_access[] = {
+       {(uid_t)-1, ACE_ALL_PERMS, ACE_EVERYONE, 0}
+};
+
+/*
+ * inputs:
+ * zc_name             name of containing filesystem
+ * zc_obj              object # beyond which we want next in-use object #
+ *
+ * outputs:
+ * zc_obj              next in-use object #
+ */
+static int
+zfs_ioc_next_obj(zfs_cmd_t *zc)
+{
+       objset_t *os = NULL;
+       int error;
+
+       error = dmu_objset_hold(zc->zc_name, FTAG, &os);
+       if (error != 0)
+               return (error);
+
+       error = dmu_object_next(os, &zc->zc_obj, B_FALSE, 0);
+
+       dmu_objset_rele(os, FTAG);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ * zc_value            prefix name for snapshot
+ * zc_cleanup_fd       cleanup-on-exit file descriptor for calling process
+ *
+ * outputs:
+ * zc_value            short name of new snapshot
+ */
+static int
+zfs_ioc_tmp_snapshot(zfs_cmd_t *zc)
+{
+       char *snap_name;
+       char *hold_name;
+       int error;
+       minor_t minor;
+
+       error = zfs_onexit_fd_hold(zc->zc_cleanup_fd, &minor);
+       if (error != 0)
+               return (error);
+
+       snap_name = kmem_asprintf("%s-%016llx", zc->zc_value,
+           (u_longlong_t)ddi_get_lbolt64());
+       hold_name = kmem_asprintf("%%%s", zc->zc_value);
+
+       error = dsl_dataset_snapshot_tmp(zc->zc_name, snap_name, minor,
+           hold_name);
+       if (error == 0)
+               (void) strcpy(zc->zc_value, snap_name);
+       strfree(snap_name);
+       strfree(hold_name);
+       zfs_onexit_fd_rele(zc->zc_cleanup_fd);
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of "to" snapshot
+ * zc_value            name of "from" snapshot
+ * zc_cookie           file descriptor to write diff data on
+ *
+ * outputs:
+ * dmu_diff_record_t's to the file descriptor
+ */
+static int
+zfs_ioc_diff(zfs_cmd_t *zc)
+{
+       file_t *fp;
+       offset_t off;
+       int error;
+
+       fp = getf(zc->zc_cookie);
+       if (fp == NULL)
+               return (SET_ERROR(EBADF));
+
+       off = fp->f_offset;
+
+       error = dmu_diff(zc->zc_name, zc->zc_value, fp->f_vnode, &off);
+
+       if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+               fp->f_offset = off;
+       releasef(zc->zc_cookie);
+
+       return (error);
+}
+
+/*
+ * Remove all ACL files in shares dir
+ */
+#ifdef HAVE_SMB_SHARE
+static int
+zfs_smb_acl_purge(znode_t *dzp)
+{
+       zap_cursor_t    zc;
+       zap_attribute_t zap;
+       zfs_sb_t *zsb = ZTOZSB(dzp);
+       int error;
+
+       for (zap_cursor_init(&zc, zsb->z_os, dzp->z_id);
+           (error = zap_cursor_retrieve(&zc, &zap)) == 0;
+           zap_cursor_advance(&zc)) {
+               if ((error = VOP_REMOVE(ZTOV(dzp), zap.za_name, kcred,
+                   NULL, 0)) != 0)
+                       break;
+       }
+       zap_cursor_fini(&zc);
+       return (error);
+}
+#endif /* HAVE_SMB_SHARE */
+
+static int
+zfs_ioc_smb_acl(zfs_cmd_t *zc)
+{
+#ifdef HAVE_SMB_SHARE
+       vnode_t *vp;
+       znode_t *dzp;
+       vnode_t *resourcevp = NULL;
+       znode_t *sharedir;
+       zfs_sb_t *zsb;
+       nvlist_t *nvlist;
+       char *src, *target;
+       vattr_t vattr;
+       vsecattr_t vsec;
+       int error = 0;
+
+       if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
+           NO_FOLLOW, NULL, &vp)) != 0)
+               return (error);
+
+       /* Now make sure mntpnt and dataset are ZFS */
+
+       if (vp->v_vfsp->vfs_fstype != zfsfstype ||
+           (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
+           zc->zc_name) != 0)) {
+               VN_RELE(vp);
+               return (SET_ERROR(EINVAL));
+       }
+
+       dzp = VTOZ(vp);
+       zsb = ZTOZSB(dzp);
+       ZFS_ENTER(zsb);
+
+       /*
+        * Create share dir if its missing.
+        */
+       mutex_enter(&zsb->z_lock);
+       if (zsb->z_shares_dir == 0) {
+               dmu_tx_t *tx;
+
+               tx = dmu_tx_create(zsb->z_os);
+               dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, TRUE,
+                   ZFS_SHARES_DIR);
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
+               error = dmu_tx_assign(tx, TXG_WAIT);
+               if (error != 0) {
+                       dmu_tx_abort(tx);
+               } else {
+                       error = zfs_create_share_dir(zsb, tx);
+                       dmu_tx_commit(tx);
+               }
+               if (error != 0) {
+                       mutex_exit(&zsb->z_lock);
+                       VN_RELE(vp);
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+       }
+       mutex_exit(&zsb->z_lock);
+
+       ASSERT(zsb->z_shares_dir);
+       if ((error = zfs_zget(zsb, zsb->z_shares_dir, &sharedir)) != 0) {
+               VN_RELE(vp);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       switch (zc->zc_cookie) {
+       case ZFS_SMB_ACL_ADD:
+               vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE;
+               vattr.va_mode = S_IFREG|0777;
+               vattr.va_uid = 0;
+               vattr.va_gid = 0;
+
+               vsec.vsa_mask = VSA_ACE;
+               vsec.vsa_aclentp = &full_access;
+               vsec.vsa_aclentsz = sizeof (full_access);
+               vsec.vsa_aclcnt = 1;
+
+               error = VOP_CREATE(ZTOV(sharedir), zc->zc_string,
+                   &vattr, EXCL, 0, &resourcevp, kcred, 0, NULL, &vsec);
+               if (resourcevp)
+                       VN_RELE(resourcevp);
+               break;
+
+       case ZFS_SMB_ACL_REMOVE:
+               error = VOP_REMOVE(ZTOV(sharedir), zc->zc_string, kcred,
+                   NULL, 0);
+               break;
+
+       case ZFS_SMB_ACL_RENAME:
+               if ((error = get_nvlist(zc->zc_nvlist_src,
+                   zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) {
+                       VN_RELE(vp);
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+               if (nvlist_lookup_string(nvlist, ZFS_SMB_ACL_SRC, &src) ||
+                   nvlist_lookup_string(nvlist, ZFS_SMB_ACL_TARGET,
+                   &target)) {
+                       VN_RELE(vp);
+                       VN_RELE(ZTOV(sharedir));
+                       ZFS_EXIT(zsb);
+                       nvlist_free(nvlist);
+                       return (error);
+               }
+               error = VOP_RENAME(ZTOV(sharedir), src, ZTOV(sharedir), target,
+                   kcred, NULL, 0);
+               nvlist_free(nvlist);
+               break;
+
+       case ZFS_SMB_ACL_PURGE:
+               error = zfs_smb_acl_purge(sharedir);
+               break;
+
+       default:
+               error = SET_ERROR(EINVAL);
+               break;
+       }
+
+       VN_RELE(vp);
+       VN_RELE(ZTOV(sharedir));
+
+       ZFS_EXIT(zsb);
+
+       return (error);
+#else
+       return (SET_ERROR(ENOTSUP));
+#endif /* HAVE_SMB_SHARE */
+}
+
+/*
+ * innvl: {
+ *     "holds" -> { snapname -> holdname (string), ... }
+ *     (optional) "cleanup_fd" -> fd (int32)
+ * }
+ *
+ * outnvl: {
+ *     snapname -> error value (int32)
+ *     ...
+ * }
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
+{
+       nvlist_t *holds;
+       int cleanup_fd = -1;
+       int error;
+       minor_t minor = 0;
+
+       error = nvlist_lookup_nvlist(args, "holds", &holds);
+       if (error != 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)
+                       return (error);
+       }
+
+       error = dsl_dataset_user_hold(holds, minor, errlist);
+       if (minor != 0)
+               zfs_onexit_fd_rele(cleanup_fd);
+       return (error);
+}
+
+/*
+ * innvl is not used.
+ *
+ * outnvl: {
+ *    holdname -> time added (uint64 seconds since epoch)
+ *    ...
+ * }
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
+{
+       return (dsl_dataset_get_holds(snapname, outnvl));
+}
+
+/*
+ * innvl: {
+ *     snapname -> { holdname, ... }
+ *     ...
+ * }
+ *
+ * outnvl: {
+ *     snapname -> error value (int32)
+ *     ...
+ * }
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
+{
+       return (dsl_dataset_user_release(holds, errlist));
+}
+
+/*
+ * inputs:
+ * zc_guid             flags (ZEVENT_NONBLOCK)
+ * zc_cleanup_fd       zevent file descriptor
+ *
+ * outputs:
+ * zc_nvlist_dst       next nvlist event
+ * zc_cookie           dropped events since last get
+ */
+static int
+zfs_ioc_events_next(zfs_cmd_t *zc)
+{
+       zfs_zevent_t *ze;
+       nvlist_t *event = NULL;
+       minor_t minor;
+       uint64_t dropped = 0;
+       int error;
+
+       error = zfs_zevent_fd_hold(zc->zc_cleanup_fd, &minor, &ze);
+       if (error != 0)
+               return (error);
+
+       do {
+               error = zfs_zevent_next(ze, &event,
+                       &zc->zc_nvlist_dst_size, &dropped);
+               if (event != NULL) {
+                       zc->zc_cookie = dropped;
+                       error = put_nvlist(zc, event);
+                       nvlist_free(event);
+               }
+
+               if (zc->zc_guid & ZEVENT_NONBLOCK)
+                       break;
+
+               if ((error == 0) || (error != ENOENT))
+                       break;
+
+               error = zfs_zevent_wait(ze);
+               if (error != 0)
+                       break;
+       } while (1);
+
+       zfs_zevent_fd_rele(zc->zc_cleanup_fd);
+
+       return (error);
+}
+
+/*
+ * outputs:
+ * zc_cookie           cleared events count
+ */
+static int
+zfs_ioc_events_clear(zfs_cmd_t *zc)
+{
+       int count;
+
+       zfs_zevent_drain_all(&count);
+       zc->zc_cookie = count;
+
+       return (0);
+}
+
+/*
+ * inputs:
+ * zc_guid             eid | ZEVENT_SEEK_START | ZEVENT_SEEK_END
+ * zc_cleanup          zevent file descriptor
+ */
+static int
+zfs_ioc_events_seek(zfs_cmd_t *zc)
+{
+       zfs_zevent_t *ze;
+       minor_t minor;
+       int error;
+
+       error = zfs_zevent_fd_hold(zc->zc_cleanup_fd, &minor, &ze);
+       if (error != 0)
+               return (error);
+
+       error = zfs_zevent_seek(ze, zc->zc_guid);
+       zfs_zevent_fd_rele(zc->zc_cleanup_fd);
+
+       return (error);
+}
+
+/*
+ * inputs:
+ * zc_name             name of new filesystem or snapshot
+ * zc_value            full name of old snapshot
+ *
+ * outputs:
+ * zc_cookie           space in bytes
+ * zc_objset_type      compressed space in bytes
+ * zc_perm_action      uncompressed space in bytes
+ */
+static int
+zfs_ioc_space_written(zfs_cmd_t *zc)
+{
+       int error;
+       dsl_pool_t *dp;
+       dsl_dataset_t *new, *old;
+
+       error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
+       if (error != 0)
+               return (error);
+       error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &new);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+       error = dsl_dataset_hold(dp, zc->zc_value, FTAG, &old);
+       if (error != 0) {
+               dsl_dataset_rele(new, FTAG);
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       error = dsl_dataset_space_written(old, new, &zc->zc_cookie,
+           &zc->zc_objset_type, &zc->zc_perm_action);
+       dsl_dataset_rele(old, FTAG);
+       dsl_dataset_rele(new, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (error);
+}
+
+/*
+ * innvl: {
+ *     "firstsnap" -> snapshot name
+ * }
+ *
+ * outnvl: {
+ *     "used" -> space in bytes
+ *     "compressed" -> compressed space in bytes
+ *     "uncompressed" -> uncompressed space in bytes
+ * }
+ */
+static int
+zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       int error;
+       dsl_pool_t *dp;
+       dsl_dataset_t *new, *old;
+       char *firstsnap;
+       uint64_t used, comp, uncomp;
+
+       if (nvlist_lookup_string(innvl, "firstsnap", &firstsnap) != 0)
+               return (SET_ERROR(EINVAL));
+
+       error = dsl_pool_hold(lastsnap, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold(dp, lastsnap, FTAG, &new);
+       if (error == 0 && !new->ds_is_snapshot) {
+               dsl_dataset_rele(new, FTAG);
+               error = SET_ERROR(EINVAL);
+       }
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+       error = dsl_dataset_hold(dp, firstsnap, FTAG, &old);
+       if (error == 0 && !old->ds_is_snapshot) {
+               dsl_dataset_rele(old, FTAG);
+               error = SET_ERROR(EINVAL);
+       }
+       if (error != 0) {
+               dsl_dataset_rele(new, FTAG);
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       error = dsl_dataset_space_wouldfree(old, new, &used, &comp, &uncomp);
+       dsl_dataset_rele(old, FTAG);
+       dsl_dataset_rele(new, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       fnvlist_add_uint64(outnvl, "used", used);
+       fnvlist_add_uint64(outnvl, "compressed", comp);
+       fnvlist_add_uint64(outnvl, "uncompressed", uncomp);
+       return (error);
+}
+
+/*
+ * innvl: {
+ *     "fd" -> file descriptor to write stream to (int32)
+ *     (optional) "fromsnap" -> full snap 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
+ * }
+ *
+ * outnvl is unused
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       int error;
+       offset_t off;
+       char *fromname = NULL;
+       int fd;
+       file_t *fp;
+       boolean_t largeblockok;
+       boolean_t embedok;
+
+       error = nvlist_lookup_int32(innvl, "fd", &fd);
+       if (error != 0)
+               return (SET_ERROR(EINVAL));
+
+       (void) nvlist_lookup_string(innvl, "fromsnap", &fromname);
+
+       largeblockok = nvlist_exists(innvl, "largeblockok");
+       embedok = nvlist_exists(innvl, "embedok");
+
+       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);
+
+       if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+               fp->f_offset = off;
+
+       releasef(fd);
+       return (error);
+}
+
+/*
+ * Determine approximately how large a zfs send stream will be -- the number
+ * of bytes that will be written to the fd supplied to zfs_ioc_send_new().
+ *
+ * innvl: {
+ *     (optional) "from" -> full snap or bookmark name to send an incremental
+ *                          from
+ * }
+ *
+ * outnvl: {
+ *     "space" -> bytes of space (uint64)
+ * }
+ */
+static int
+zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       dsl_pool_t *dp;
+       dsl_dataset_t *tosnap;
+       int error;
+       char *fromname;
+       uint64_t space;
+
+       error = dsl_pool_hold(snapname, FTAG, &dp);
+       if (error != 0)
+               return (error);
+
+       error = dsl_dataset_hold(dp, snapname, FTAG, &tosnap);
+       if (error != 0) {
+               dsl_pool_rele(dp, FTAG);
+               return (error);
+       }
+
+       error = nvlist_lookup_string(innvl, "from", &fromname);
+       if (error == 0) {
+               if (strchr(fromname, '@') != NULL) {
+                       /*
+                        * If from is a snapshot, hold it and use the more
+                        * efficient dmu_send_estimate to estimate send space
+                        * size using deadlists.
+                        */
+                       dsl_dataset_t *fromsnap;
+                       error = dsl_dataset_hold(dp, fromname, FTAG, &fromsnap);
+                       if (error != 0)
+                               goto out;
+                       error = dmu_send_estimate(tosnap, fromsnap, &space);
+                       dsl_dataset_rele(fromsnap, FTAG);
+               } else if (strchr(fromname, '#') != NULL) {
+                       /*
+                        * If from is a bookmark, fetch the creation TXG of the
+                        * snapshot it was created from and use that to find
+                        * blocks that were born after it.
+                        */
+                       zfs_bookmark_phys_t frombm;
+
+                       error = dsl_bookmark_lookup(dp, fromname, tosnap,
+                           &frombm);
+                       if (error != 0)
+                               goto out;
+                       error = dmu_send_estimate_from_txg(tosnap,
+                           frombm.zbm_creation_txg, &space);
+               } else {
+                       /*
+                        * from is not properly formatted as a snapshot or
+                        * bookmark
+                        */
+                       error = SET_ERROR(EINVAL);
+                       goto out;
+               }
+       } else {
+               // If estimating the size of a full send, use dmu_send_estimate
+               error = dmu_send_estimate(tosnap, NULL, &space);
+       }
+
+       fnvlist_add_uint64(outnvl, "space", space);
+
+out:
+       dsl_dataset_rele(tosnap, FTAG);
+       dsl_pool_rele(dp, FTAG);
+       return (error);
+}
+
+static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST];
+
+static void
+zfs_ioctl_register_legacy(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
+    zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
+    boolean_t log_history, zfs_ioc_poolcheck_t pool_check)
+{
+       zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST];
+
+       ASSERT3U(ioc, >=, ZFS_IOC_FIRST);
+       ASSERT3U(ioc, <, ZFS_IOC_LAST);
+       ASSERT3P(vec->zvec_legacy_func, ==, NULL);
+       ASSERT3P(vec->zvec_func, ==, NULL);
+
+       vec->zvec_legacy_func = func;
+       vec->zvec_secpolicy = secpolicy;
+       vec->zvec_namecheck = namecheck;
+       vec->zvec_allow_log = log_history;
+       vec->zvec_pool_check = pool_check;
+}
+
+/*
+ * See the block comment at the beginning of this file for details on
+ * each argument to this function.
+ */
+static void
+zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func,
+    zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
+    zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist,
+    boolean_t allow_log)
+{
+       zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST];
+
+       ASSERT3U(ioc, >=, ZFS_IOC_FIRST);
+       ASSERT3U(ioc, <, ZFS_IOC_LAST);
+       ASSERT3P(vec->zvec_legacy_func, ==, NULL);
+       ASSERT3P(vec->zvec_func, ==, NULL);
+
+       /* if we are logging, the name must be valid */
+       ASSERT(!allow_log || namecheck != NO_NAME);
+
+       vec->zvec_name = name;
+       vec->zvec_func = func;
+       vec->zvec_secpolicy = secpolicy;
+       vec->zvec_namecheck = namecheck;
+       vec->zvec_pool_check = pool_check;
+       vec->zvec_smush_outnvlist = smush_outnvlist;
+       vec->zvec_allow_log = allow_log;
+}
+
+static void
+zfs_ioctl_register_pool(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
+    zfs_secpolicy_func_t *secpolicy, boolean_t log_history,
+    zfs_ioc_poolcheck_t pool_check)
+{
+       zfs_ioctl_register_legacy(ioc, func, secpolicy,
+           POOL_NAME, log_history, pool_check);
+}
+
+static void
+zfs_ioctl_register_dataset_nolog(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
+    zfs_secpolicy_func_t *secpolicy, zfs_ioc_poolcheck_t pool_check)
+{
+       zfs_ioctl_register_legacy(ioc, func, secpolicy,
+           DATASET_NAME, B_FALSE, pool_check);
+}
+
+static void
+zfs_ioctl_register_pool_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func)
+{
+       zfs_ioctl_register_legacy(ioc, func, zfs_secpolicy_config,
+           POOL_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+}
+
+static void
+zfs_ioctl_register_pool_meta(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
+    zfs_secpolicy_func_t *secpolicy)
+{
+       zfs_ioctl_register_legacy(ioc, func, secpolicy,
+           NO_NAME, B_FALSE, POOL_CHECK_NONE);
+}
+
+static void
+zfs_ioctl_register_dataset_read_secpolicy(zfs_ioc_t ioc,
+    zfs_ioc_legacy_func_t *func, zfs_secpolicy_func_t *secpolicy)
+{
+       zfs_ioctl_register_legacy(ioc, func, secpolicy,
+           DATASET_NAME, B_FALSE, POOL_CHECK_SUSPENDED);
+}
+
+static void
+zfs_ioctl_register_dataset_read(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func)
+{
+       zfs_ioctl_register_dataset_read_secpolicy(ioc, func,
+           zfs_secpolicy_read);
+}
+
+static void
+zfs_ioctl_register_dataset_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
+       zfs_secpolicy_func_t *secpolicy)
+{
+       zfs_ioctl_register_legacy(ioc, func, secpolicy,
+           DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+}
+
+static void
+zfs_ioctl_init(void)
+{
+       zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT,
+           zfs_ioc_snapshot, zfs_secpolicy_snapshot, POOL_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
+       zfs_ioctl_register("log_history", ZFS_IOC_LOG_HISTORY,
+           zfs_ioc_log_history, zfs_secpolicy_log_history, NO_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
+
+       zfs_ioctl_register("space_snaps", ZFS_IOC_SPACE_SNAPS,
+           zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME,
+           POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+
+       zfs_ioctl_register("send", ZFS_IOC_SEND_NEW,
+           zfs_ioc_send_new, zfs_secpolicy_send_new, DATASET_NAME,
+           POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+
+       zfs_ioctl_register("send_space", ZFS_IOC_SEND_SPACE,
+           zfs_ioc_send_space, zfs_secpolicy_read, DATASET_NAME,
+           POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+
+       zfs_ioctl_register("create", ZFS_IOC_CREATE,
+           zfs_ioc_create, zfs_secpolicy_create_clone, DATASET_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
+       zfs_ioctl_register("clone", ZFS_IOC_CLONE,
+           zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
+       zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS,
+           zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
+       zfs_ioctl_register("hold", ZFS_IOC_HOLD,
+           zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+       zfs_ioctl_register("release", ZFS_IOC_RELEASE,
+           zfs_ioc_release, zfs_secpolicy_release, POOL_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
+       zfs_ioctl_register("get_holds", ZFS_IOC_GET_HOLDS,
+           zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME,
+           POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+
+       zfs_ioctl_register("rollback", ZFS_IOC_ROLLBACK,
+           zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE);
+
+       zfs_ioctl_register("bookmark", ZFS_IOC_BOOKMARK,
+           zfs_ioc_bookmark, zfs_secpolicy_bookmark, POOL_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
+       zfs_ioctl_register("get_bookmarks", ZFS_IOC_GET_BOOKMARKS,
+           zfs_ioc_get_bookmarks, zfs_secpolicy_read, DATASET_NAME,
+           POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+
+       zfs_ioctl_register("destroy_bookmarks", ZFS_IOC_DESTROY_BOOKMARKS,
+           zfs_ioc_destroy_bookmarks, zfs_secpolicy_destroy_bookmarks,
+           POOL_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,
+           zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_READONLY);
+
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_CREATE, zfs_ioc_pool_create,
+           zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SCAN,
+           zfs_ioc_pool_scan);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_UPGRADE,
+           zfs_ioc_pool_upgrade);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ADD,
+           zfs_ioc_vdev_add);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_REMOVE,
+           zfs_ioc_vdev_remove);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SET_STATE,
+           zfs_ioc_vdev_set_state);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_ATTACH,
+           zfs_ioc_vdev_attach);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_DETACH,
+           zfs_ioc_vdev_detach);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETPATH,
+           zfs_ioc_vdev_setpath);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SETFRU,
+           zfs_ioc_vdev_setfru);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_SET_PROPS,
+           zfs_ioc_pool_set_props);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_VDEV_SPLIT,
+           zfs_ioc_vdev_split);
+       zfs_ioctl_register_pool_modify(ZFS_IOC_POOL_REGUID,
+           zfs_ioc_pool_reguid);
+
+       zfs_ioctl_register_pool_meta(ZFS_IOC_POOL_CONFIGS,
+           zfs_ioc_pool_configs, zfs_secpolicy_none);
+       zfs_ioctl_register_pool_meta(ZFS_IOC_POOL_TRYIMPORT,
+           zfs_ioc_pool_tryimport, zfs_secpolicy_config);
+       zfs_ioctl_register_pool_meta(ZFS_IOC_INJECT_FAULT,
+           zfs_ioc_inject_fault, zfs_secpolicy_inject);
+       zfs_ioctl_register_pool_meta(ZFS_IOC_CLEAR_FAULT,
+           zfs_ioc_clear_fault, zfs_secpolicy_inject);
+       zfs_ioctl_register_pool_meta(ZFS_IOC_INJECT_LIST_NEXT,
+           zfs_ioc_inject_list_next, zfs_secpolicy_inject);
+
+       /*
+        * pool destroy, and export don't log the history as part of
+        * zfsdev_ioctl, but rather zfs_ioc_pool_export
+        * does the logging of those commands.
+        */
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_DESTROY, zfs_ioc_pool_destroy,
+           zfs_secpolicy_config, B_FALSE, POOL_CHECK_SUSPENDED);
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_EXPORT, zfs_ioc_pool_export,
+           zfs_secpolicy_config, B_FALSE, POOL_CHECK_SUSPENDED);
+
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_STATS, zfs_ioc_pool_stats,
+           zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE);
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_PROPS, zfs_ioc_pool_get_props,
+           zfs_secpolicy_read, B_FALSE, POOL_CHECK_NONE);
+
+       zfs_ioctl_register_pool(ZFS_IOC_ERROR_LOG, zfs_ioc_error_log,
+           zfs_secpolicy_inject, B_FALSE, POOL_CHECK_SUSPENDED);
+       zfs_ioctl_register_pool(ZFS_IOC_DSOBJ_TO_DSNAME,
+           zfs_ioc_dsobj_to_dsname,
+           zfs_secpolicy_diff, B_FALSE, POOL_CHECK_SUSPENDED);
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_GET_HISTORY,
+           zfs_ioc_pool_get_history,
+           zfs_secpolicy_config, B_FALSE, POOL_CHECK_SUSPENDED);
+
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_IMPORT, zfs_ioc_pool_import,
+           zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE);
+
+       zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear,
+           zfs_secpolicy_config, B_TRUE, POOL_CHECK_NONE);
+       zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen,
+           zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED);
+
+       zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN,
+           zfs_ioc_space_written);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_RECVD_PROPS,
+           zfs_ioc_objset_recvd_props);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_NEXT_OBJ,
+           zfs_ioc_next_obj);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_GET_FSACL,
+           zfs_ioc_get_fsacl);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_STATS,
+           zfs_ioc_objset_stats);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_OBJSET_ZPLPROPS,
+           zfs_ioc_objset_zplprops);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_DATASET_LIST_NEXT,
+           zfs_ioc_dataset_list_next);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_SNAPSHOT_LIST_NEXT,
+           zfs_ioc_snapshot_list_next);
+       zfs_ioctl_register_dataset_read(ZFS_IOC_SEND_PROGRESS,
+           zfs_ioc_send_progress);
+
+       zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_DIFF,
+           zfs_ioc_diff, zfs_secpolicy_diff);
+       zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_STATS,
+           zfs_ioc_obj_to_stats, zfs_secpolicy_diff);
+       zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_OBJ_TO_PATH,
+           zfs_ioc_obj_to_path, zfs_secpolicy_diff);
+       zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_USERSPACE_ONE,
+           zfs_ioc_userspace_one, zfs_secpolicy_userspace_one);
+       zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_USERSPACE_MANY,
+           zfs_ioc_userspace_many, zfs_secpolicy_userspace_many);
+       zfs_ioctl_register_dataset_read_secpolicy(ZFS_IOC_SEND,
+           zfs_ioc_send, zfs_secpolicy_send);
+
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_PROP, zfs_ioc_set_prop,
+           zfs_secpolicy_none);
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy,
+           zfs_secpolicy_destroy);
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_RENAME, zfs_ioc_rename,
+           zfs_secpolicy_rename);
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_RECV, zfs_ioc_recv,
+           zfs_secpolicy_recv);
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_PROMOTE, zfs_ioc_promote,
+           zfs_secpolicy_promote);
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_INHERIT_PROP,
+           zfs_ioc_inherit_prop, zfs_secpolicy_inherit_prop);
+       zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_FSACL, zfs_ioc_set_fsacl,
+           zfs_secpolicy_set_fsacl);
+
+       zfs_ioctl_register_dataset_nolog(ZFS_IOC_SHARE, zfs_ioc_share,
+           zfs_secpolicy_share, POOL_CHECK_NONE);
+       zfs_ioctl_register_dataset_nolog(ZFS_IOC_SMB_ACL, zfs_ioc_smb_acl,
+           zfs_secpolicy_smb_acl, POOL_CHECK_NONE);
+       zfs_ioctl_register_dataset_nolog(ZFS_IOC_USERSPACE_UPGRADE,
+           zfs_ioc_userspace_upgrade, zfs_secpolicy_userspace_upgrade,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+       zfs_ioctl_register_dataset_nolog(ZFS_IOC_TMP_SNAPSHOT,
+           zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+
+       /*
+        * ZoL functions
+        */
+       zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_NEXT, zfs_ioc_events_next,
+           zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
+       zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
+           zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
+       zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_SEEK, zfs_ioc_events_seek,
+           zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
+}
+
+int
+pool_status_check(const char *name, zfs_ioc_namecheck_t type,
+    zfs_ioc_poolcheck_t check)
+{
+       spa_t *spa;
+       int error;
+
+       ASSERT(type == POOL_NAME || type == DATASET_NAME);
+
+       if (check & POOL_CHECK_NONE)
+               return (0);
+
+       error = spa_open(name, &spa, FTAG);
+       if (error == 0) {
+               if ((check & POOL_CHECK_SUSPENDED) && spa_suspended(spa))
+                       error = SET_ERROR(EAGAIN);
+               else if ((check & POOL_CHECK_READONLY) && !spa_writeable(spa))
+                       error = SET_ERROR(EROFS);
+               spa_close(spa, FTAG);
+       }
+       return (error);
+}
+
+static void *
+zfsdev_get_state_impl(minor_t minor, enum zfsdev_state_type which)
+{
+       zfsdev_state_t *zs;
+
+       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
+               if (zs->zs_minor == minor) {
+                       smp_rmb();
+                       switch (which) {
+                       case ZST_ONEXIT:
+                               return (zs->zs_onexit);
+                       case ZST_ZEVENT:
+                               return (zs->zs_zevent);
+                       case ZST_ALL:
+                               return (zs);
+                       }
+               }
+       }
+
+       return (NULL);
+}
+
+void *
+zfsdev_get_state(minor_t minor, enum zfsdev_state_type which)
+{
+       void *ptr;
+
+       ptr = zfsdev_get_state_impl(minor, which);
+
+       return (ptr);
+}
+
+int
+zfsdev_getminor(struct file *filp, minor_t *minorp)
+{
+       zfsdev_state_t *zs, *fpd;
+
+       ASSERT(filp != NULL);
+       ASSERT(!MUTEX_HELD(&zfsdev_state_lock));
+
+       fpd = filp->private_data;
+       if (fpd == NULL)
+               return (EBADF);
+
+       mutex_enter(&zfsdev_state_lock);
+
+       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
+
+               if (zs->zs_minor == -1)
+                       continue;
+
+               if (fpd == zs) {
+                       *minorp = fpd->zs_minor;
+                       mutex_exit(&zfsdev_state_lock);
+                       return (0);
+               }
+       }
+
+       mutex_exit(&zfsdev_state_lock);
+
+       return (EBADF);
+}
+
+/*
+ * Find a free minor number.  The zfsdev_state_list is expected to
+ * be short since it is only a list of currently open file handles.
+ */
+minor_t
+zfsdev_minor_alloc(void)
+{
+       static minor_t last_minor = 0;
+       minor_t m;
+
+       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+       for (m = last_minor + 1; m != last_minor; m++) {
+               if (m > ZFSDEV_MAX_MINOR)
+                       m = 1;
+               if (zfsdev_get_state_impl(m, ZST_ALL) == NULL) {
+                       last_minor = m;
+                       return (m);
+               }
+       }
+
+       return (0);
+}
+
+static int
+zfsdev_state_init(struct file *filp)
+{
+       zfsdev_state_t *zs, *zsprev = NULL;
+       minor_t minor;
+       boolean_t newzs = B_FALSE;
+
+       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+       minor = zfsdev_minor_alloc();
+       if (minor == 0)
+               return (SET_ERROR(ENXIO));
+
+       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
+               if (zs->zs_minor == -1)
+                       break;
+               zsprev = zs;
+       }
+
+       if (!zs) {
+               zs = kmem_zalloc(sizeof (zfsdev_state_t), KM_SLEEP);
+               newzs = B_TRUE;
+       }
+
+       zs->zs_file = filp;
+       filp->private_data = zs;
+
+       zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit);
+       zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent);
+
+
+       /*
+        * In order to provide for lock-free concurrent read access
+        * to the minor list in zfsdev_get_state_impl(), new entries
+        * must be completely written before linking them into the
+        * list whereas existing entries are already linked; the last
+        * operation must be updating zs_minor (from -1 to the new
+        * value).
+        */
+       if (newzs) {
+               zs->zs_minor = minor;
+               smp_wmb();
+               zsprev->zs_next = zs;
+       } else {
+               smp_wmb();
+               zs->zs_minor = minor;
+       }
+
+       return (0);
+}
+
+static int
+zfsdev_state_destroy(struct file *filp)
+{
+       zfsdev_state_t *zs;
+
+       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+       ASSERT(filp->private_data != NULL);
+
+       zs = filp->private_data;
+       zs->zs_minor = -1;
+       zfs_onexit_destroy(zs->zs_onexit);
+       zfs_zevent_destroy(zs->zs_zevent);
+
+       return (0);
+}
+
+static int
+zfsdev_open(struct inode *ino, struct file *filp)
+{
+       int error;
+
+       mutex_enter(&zfsdev_state_lock);
+       error = zfsdev_state_init(filp);
+       mutex_exit(&zfsdev_state_lock);
+
+       return (-error);
+}
+
+static int
+zfsdev_release(struct inode *ino, struct file *filp)
+{
+       int error;
+
+       mutex_enter(&zfsdev_state_lock);
+       error = zfsdev_state_destroy(filp);
+       mutex_exit(&zfsdev_state_lock);
+
+       return (-error);
+}
+
+static long
+zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+{
+       zfs_cmd_t *zc;
+       uint_t vecnum;
+       int error, rc, flag = 0;
+       const zfs_ioc_vec_t *vec;
+       char *saved_poolname = NULL;
+       nvlist_t *innvl = NULL;
+       fstrans_cookie_t cookie;
+
+       vecnum = cmd - ZFS_IOC_FIRST;
+       if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
+               return (-SET_ERROR(EINVAL));
+       vec = &zfs_ioc_vec[vecnum];
+
+       /*
+        * The registered ioctl list may be sparse, verify that either
+        * a normal or legacy handler are registered.
+        */
+       if (vec->zvec_func == NULL && vec->zvec_legacy_func == NULL)
+               return (-SET_ERROR(EINVAL));
+
+       zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
+
+       error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag);
+       if (error != 0) {
+               error = SET_ERROR(EFAULT);
+               goto out;
+       }
+
+       zc->zc_iflags = flag & FKIOCTL;
+       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)
+                       goto out;
+       }
+
+       /*
+        * Ensure that all pool/dataset names are valid before we pass down to
+        * the lower layers.
+        */
+       zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
+       switch (vec->zvec_namecheck) {
+       case POOL_NAME:
+               if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
+                       error = SET_ERROR(EINVAL);
+               else
+                       error = pool_status_check(zc->zc_name,
+                           vec->zvec_namecheck, vec->zvec_pool_check);
+               break;
+
+       case DATASET_NAME:
+               if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
+                       error = SET_ERROR(EINVAL);
+               else
+                       error = pool_status_check(zc->zc_name,
+                           vec->zvec_namecheck, vec->zvec_pool_check);
+               break;
+
+       case NO_NAME:
+               break;
+       }
+
+
+       if (error == 0 && !(flag & FKIOCTL)) {
+               cookie = spl_fstrans_mark();
+               error = vec->zvec_secpolicy(zc, innvl, CRED());
+               spl_fstrans_unmark(cookie);
+       }
+
+       if (error != 0)
+               goto out;
+
+       /* legacy ioctls can modify zc_name */
+       saved_poolname = strdup(zc->zc_name);
+       if (saved_poolname == NULL) {
+               error = SET_ERROR(ENOMEM);
+               goto out;
+       } else {
+               saved_poolname[strcspn(saved_poolname, "/@#")] = '\0';
+       }
+
+       if (vec->zvec_func != NULL) {
+               nvlist_t *outnvl;
+               int puterror = 0;
+               spa_t *spa;
+               nvlist_t *lognv = NULL;
+
+               ASSERT(vec->zvec_legacy_func == NULL);
+
+               /*
+                * Add the innvl to the lognv before calling the func,
+                * in case the func changes the innvl.
+                */
+               if (vec->zvec_allow_log) {
+                       lognv = fnvlist_alloc();
+                       fnvlist_add_string(lognv, ZPOOL_HIST_IOCTL,
+                           vec->zvec_name);
+                       if (!nvlist_empty(innvl)) {
+                               fnvlist_add_nvlist(lognv, ZPOOL_HIST_INPUT_NVL,
+                                   innvl);
+                       }
+               }
+
+               outnvl = fnvlist_alloc();
+               cookie = spl_fstrans_mark();
+               error = vec->zvec_func(zc->zc_name, innvl, outnvl);
+               spl_fstrans_unmark(cookie);
+
+               if (error == 0 && vec->zvec_allow_log &&
+                   spa_open(zc->zc_name, &spa, FTAG) == 0) {
+                       if (!nvlist_empty(outnvl)) {
+                               fnvlist_add_nvlist(lognv, ZPOOL_HIST_OUTPUT_NVL,
+                                   outnvl);
+                       }
+                       (void) spa_history_log_nvl(spa, lognv);
+                       spa_close(spa, FTAG);
+               }
+               fnvlist_free(lognv);
+
+               if (!nvlist_empty(outnvl) || zc->zc_nvlist_dst_size != 0) {
+                       int smusherror = 0;
+                       if (vec->zvec_smush_outnvlist) {
+                               smusherror = nvlist_smush(outnvl,
+                                   zc->zc_nvlist_dst_size);
+                       }
+                       if (smusherror == 0)
+                               puterror = put_nvlist(zc, outnvl);
+               }
+
+               if (puterror != 0)
+                       error = puterror;
+
+               nvlist_free(outnvl);
+       } else {
+               cookie = spl_fstrans_mark();
+               error = vec->zvec_legacy_func(zc);
+               spl_fstrans_unmark(cookie);
+       }
+
+out:
+       nvlist_free(innvl);
+       rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag);
+       if (error == 0 && rc != 0)
+               error = SET_ERROR(EFAULT);
+       if (error == 0 && vec->zvec_allow_log) {
+               char *s = tsd_get(zfs_allow_log_key);
+               if (s != NULL)
+                       strfree(s);
+               (void) tsd_set(zfs_allow_log_key, saved_poolname);
+       } else {
+               if (saved_poolname != NULL)
+                       strfree(saved_poolname);
+       }
+
+       kmem_free(zc, sizeof (zfs_cmd_t));
+       return (-error);
+}
+
+#ifdef CONFIG_COMPAT
+static long
+zfsdev_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+{
+       return (zfsdev_ioctl(filp, cmd, arg));
+}
+#else
+#define        zfsdev_compat_ioctl     NULL
+#endif
+
+static const struct file_operations zfsdev_fops = {
+       .open           = zfsdev_open,
+       .release        = zfsdev_release,
+       .unlocked_ioctl = zfsdev_ioctl,
+       .compat_ioctl   = zfsdev_compat_ioctl,
+       .owner          = THIS_MODULE,
+};
+
+static struct miscdevice zfs_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = ZFS_DRIVER,
+       .fops           = &zfsdev_fops,
+};
+
+static int
+zfs_attach(void)
+{
+       int error;
+
+       mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL);
+       zfsdev_state_list = kmem_zalloc(sizeof (zfsdev_state_t), KM_SLEEP);
+       zfsdev_state_list->zs_minor = -1;
+
+       error = misc_register(&zfs_misc);
+       if (error != 0) {
+               printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
+               return (error);
+       }
+
+       return (0);
+}
+
+static void
+zfs_detach(void)
+{
+       zfsdev_state_t *zs, *zsprev = NULL;
+
+       misc_deregister(&zfs_misc);
+       mutex_destroy(&zfsdev_state_lock);
+
+       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
+               if (zsprev)
+                       kmem_free(zsprev, sizeof (zfsdev_state_t));
+               zsprev = zs;
+       }
+       if (zsprev)
+               kmem_free(zsprev, sizeof (zfsdev_state_t));
+}
+
+static void
+zfs_allow_log_destroy(void *arg)
+{
+       char *poolname = arg;
+       strfree(poolname);
+}
+
+#ifdef DEBUG
+#define        ZFS_DEBUG_STR   " (DEBUG mode)"
+#else
+#define        ZFS_DEBUG_STR   ""
+#endif
+
+static int __init
+_init(void)
+{
+       int error;
+
+       error = -vn_set_pwd("/");
+       if (error) {
+               printk(KERN_NOTICE
+                   "ZFS: Warning unable to set pwd to '/': %d\n", error);
+               return (error);
+       }
+
+       if ((error = -zvol_init()) != 0)
+               return (error);
+
+       spa_init(FREAD | FWRITE);
+       zfs_init();
+
+       zfs_ioctl_init();
+
+       if ((error = zfs_attach()) != 0)
+               goto out;
+
+       tsd_create(&zfs_fsyncer_key, NULL);
+       tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
+       tsd_create(&zfs_allow_log_key, zfs_allow_log_destroy);
+
+       printk(KERN_NOTICE "ZFS: Loaded module v%s-%s%s, "
+           "ZFS pool version %s, ZFS filesystem version %s\n",
+           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR,
+           SPA_VERSION_STRING, ZPL_VERSION_STRING);
+#ifndef CONFIG_FS_POSIX_ACL
+       printk(KERN_NOTICE "ZFS: Posix ACLs disabled by kernel\n");
+#endif /* CONFIG_FS_POSIX_ACL */
+
+       return (0);
+
+out:
+       zfs_fini();
+       spa_fini();
+       (void) zvol_fini();
+       printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s-%s%s"
+           ", rc = %d\n", ZFS_META_VERSION, ZFS_META_RELEASE,
+           ZFS_DEBUG_STR, error);
+
+       return (error);
+}
+
+static void __exit
+_fini(void)
+{
+       zfs_detach();
+       zfs_fini();
+       spa_fini();
+       zvol_fini();
+
+       tsd_destroy(&zfs_fsyncer_key);
+       tsd_destroy(&rrw_tsd_key);
+       tsd_destroy(&zfs_allow_log_key);
+
+       printk(KERN_NOTICE "ZFS: Unloaded module v%s-%s%s\n",
+           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR);
+}
+
+#ifdef HAVE_SPL
+module_init(_init);
+module_exit(_fini);
+
+MODULE_DESCRIPTION("ZFS");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
+#endif /* HAVE_SPL */
diff --git a/zfs/module/zfs/zfs_log.c b/zfs/module/zfs/zfs_log.c
new file mode 100644 (file)
index 0000000..38d8de0
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/thread.h>
+#include <sys/file.h>
+#include <sys/vfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_dir.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/byteorder.h>
+#include <sys/policy.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/acl.h>
+#include <sys/dmu.h>
+#include <sys/spa.h>
+#include <sys/zfs_fuid.h>
+#include <sys/ddi.h>
+#include <sys/dsl_dataset.h>
+
+/*
+ * These zfs_log_* functions must be called within a dmu tx, in one
+ * of 2 contexts depending on zilog->z_replay:
+ *
+ * Non replay mode
+ * ---------------
+ * We need to record the transaction so that if it is committed to
+ * the Intent Log then it can be replayed.  An intent log transaction
+ * structure (itx_t) is allocated and all the information necessary to
+ * possibly replay the transaction is saved in it. The itx is then assigned
+ * a sequence number and inserted in the in-memory list anchored in the zilog.
+ *
+ * Replay mode
+ * -----------
+ * We need to mark the intent log record as replayed in the log header.
+ * This is done in the same transaction as the replay so that they
+ * commit atomically.
+ */
+
+int
+zfs_log_create_txtype(zil_create_t type, vsecattr_t *vsecp, vattr_t *vap)
+{
+       int isxvattr = (vap->va_mask & ATTR_XVATTR);
+       switch (type) {
+       case Z_FILE:
+               if (vsecp == NULL && !isxvattr)
+                       return (TX_CREATE);
+               if (vsecp && isxvattr)
+                       return (TX_CREATE_ACL_ATTR);
+               if (vsecp)
+                       return (TX_CREATE_ACL);
+               else
+                       return (TX_CREATE_ATTR);
+               /*NOTREACHED*/
+       case Z_DIR:
+               if (vsecp == NULL && !isxvattr)
+                       return (TX_MKDIR);
+               if (vsecp && isxvattr)
+                       return (TX_MKDIR_ACL_ATTR);
+               if (vsecp)
+                       return (TX_MKDIR_ACL);
+               else
+                       return (TX_MKDIR_ATTR);
+       case Z_XATTRDIR:
+               return (TX_MKXATTR);
+       }
+       ASSERT(0);
+       return (TX_MAX_TYPE);
+}
+
+/*
+ * build up the log data necessary for logging xvattr_t
+ * First lr_attr_t is initialized.  following the lr_attr_t
+ * is the mapsize and attribute bitmap copied from the xvattr_t.
+ * Following the bitmap and bitmapsize two 64 bit words are reserved
+ * for the create time which may be set.  Following the create time
+ * records a single 64 bit integer which has the bits to set on
+ * replay for the xvattr.
+ */
+static void
+zfs_log_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
+{
+       uint32_t        *bitmap;
+       uint64_t        *attrs;
+       uint64_t        *crtime;
+       xoptattr_t      *xoap;
+       void            *scanstamp;
+       int             i;
+
+       xoap = xva_getxoptattr(xvap);
+       ASSERT(xoap);
+
+       lrattr->lr_attr_masksize = xvap->xva_mapsize;
+       bitmap = &lrattr->lr_attr_bitmap;
+       for (i = 0; i != xvap->xva_mapsize; i++, bitmap++) {
+               *bitmap = xvap->xva_reqattrmap[i];
+       }
+
+       /* Now pack the attributes up in a single uint64_t */
+       attrs = (uint64_t *)bitmap;
+       crtime = attrs + 1;
+       scanstamp = (caddr_t)(crtime + 2);
+       *attrs = 0;
+       if (XVA_ISSET_REQ(xvap, XAT_READONLY))
+               *attrs |= (xoap->xoa_readonly == 0) ? 0 :
+                   XAT0_READONLY;
+       if (XVA_ISSET_REQ(xvap, XAT_HIDDEN))
+               *attrs |= (xoap->xoa_hidden == 0) ? 0 :
+                   XAT0_HIDDEN;
+       if (XVA_ISSET_REQ(xvap, XAT_SYSTEM))
+               *attrs |= (xoap->xoa_system == 0) ? 0 :
+                   XAT0_SYSTEM;
+       if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE))
+               *attrs |= (xoap->xoa_archive == 0) ? 0 :
+                   XAT0_ARCHIVE;
+       if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+               *attrs |= (xoap->xoa_immutable == 0) ? 0 :
+                   XAT0_IMMUTABLE;
+       if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+               *attrs |= (xoap->xoa_nounlink == 0) ? 0 :
+                   XAT0_NOUNLINK;
+       if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+               *attrs |= (xoap->xoa_appendonly == 0) ? 0 :
+                   XAT0_APPENDONLY;
+       if (XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+               *attrs |= (xoap->xoa_opaque == 0) ? 0 :
+                   XAT0_APPENDONLY;
+       if (XVA_ISSET_REQ(xvap, XAT_NODUMP))
+               *attrs |= (xoap->xoa_nodump == 0) ? 0 :
+                   XAT0_NODUMP;
+       if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED))
+               *attrs |= (xoap->xoa_av_quarantined == 0) ? 0 :
+                   XAT0_AV_QUARANTINED;
+       if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+               *attrs |= (xoap->xoa_av_modified == 0) ? 0 :
+                   XAT0_AV_MODIFIED;
+       if (XVA_ISSET_REQ(xvap, XAT_CREATETIME))
+               ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime);
+       if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+               bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ);
+       if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
+               *attrs |= (xoap->xoa_reparse == 0) ? 0 :
+                   XAT0_REPARSE;
+       if (XVA_ISSET_REQ(xvap, XAT_OFFLINE))
+               *attrs |= (xoap->xoa_offline == 0) ? 0 :
+                   XAT0_OFFLINE;
+       if (XVA_ISSET_REQ(xvap, XAT_SPARSE))
+               *attrs |= (xoap->xoa_sparse == 0) ? 0 :
+                   XAT0_SPARSE;
+}
+
+static void *
+zfs_log_fuid_ids(zfs_fuid_info_t *fuidp, void *start)
+{
+       zfs_fuid_t *zfuid;
+       uint64_t *fuidloc = start;
+
+       /* First copy in the ACE FUIDs */
+       for (zfuid = list_head(&fuidp->z_fuids); zfuid;
+           zfuid = list_next(&fuidp->z_fuids, zfuid)) {
+               *fuidloc++ = zfuid->z_logfuid;
+       }
+       return (fuidloc);
+}
+
+
+static void *
+zfs_log_fuid_domains(zfs_fuid_info_t *fuidp, void *start)
+{
+       zfs_fuid_domain_t *zdomain;
+
+       /* now copy in the domain info, if any */
+       if (fuidp->z_domain_str_sz != 0) {
+               for (zdomain = list_head(&fuidp->z_domains); zdomain;
+                   zdomain = list_next(&fuidp->z_domains, zdomain)) {
+                       bcopy((void *)zdomain->z_domain, start,
+                           strlen(zdomain->z_domain) + 1);
+                       start = (caddr_t)start +
+                           strlen(zdomain->z_domain) + 1;
+               }
+       }
+       return (start);
+}
+
+/*
+ * Handles TX_CREATE, TX_CREATE_ATTR, TX_MKDIR, TX_MKDIR_ATTR and
+ * TK_MKXATTR transactions.
+ *
+ * TX_CREATE and TX_MKDIR are standard creates, but they may have FUID
+ * domain information appended prior to the name.  In this case the
+ * uid/gid in the log record will be a log centric FUID.
+ *
+ * TX_CREATE_ACL_ATTR and TX_MKDIR_ACL_ATTR handle special creates that
+ * may contain attributes, ACL and optional fuid information.
+ *
+ * TX_CREATE_ACL and TX_MKDIR_ACL handle special creates that specify
+ * and ACL and normal users/groups in the ACEs.
+ *
+ * There may be an optional xvattr attribute information similar
+ * to zfs_log_setattr.
+ *
+ * Also, after the file name "domain" strings may be appended.
+ */
+void
+zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *dzp, znode_t *zp, char *name, vsecattr_t *vsecp,
+    zfs_fuid_info_t *fuidp, vattr_t *vap)
+{
+       itx_t *itx;
+       lr_create_t *lr;
+       lr_acl_create_t *lracl;
+       size_t aclsize = 0;
+       size_t xvatsize = 0;
+       size_t txsize;
+       xvattr_t *xvap = (xvattr_t *)vap;
+       void *end;
+       size_t lrsize;
+       size_t namesize = strlen(name) + 1;
+       size_t fuidsz = 0;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       /*
+        * If we have FUIDs present then add in space for
+        * domains and ACE fuid's if any.
+        */
+       if (fuidp) {
+               fuidsz += fuidp->z_domain_str_sz;
+               fuidsz += fuidp->z_fuid_cnt * sizeof (uint64_t);
+       }
+
+       if (vap->va_mask & ATTR_XVATTR)
+               xvatsize = ZIL_XVAT_SIZE(xvap->xva_mapsize);
+
+       if ((int)txtype == TX_CREATE_ATTR || (int)txtype == TX_MKDIR_ATTR ||
+           (int)txtype == TX_CREATE || (int)txtype == TX_MKDIR ||
+           (int)txtype == TX_MKXATTR) {
+               txsize = sizeof (*lr) + namesize + fuidsz + xvatsize;
+               lrsize = sizeof (*lr);
+       } else {
+               txsize =
+                   sizeof (lr_acl_create_t) + namesize + fuidsz +
+                   ZIL_ACE_LENGTH(aclsize) + xvatsize;
+               lrsize = sizeof (lr_acl_create_t);
+       }
+
+       itx = zil_itx_create(txtype, txsize);
+
+       lr = (lr_create_t *)&itx->itx_lr;
+       lr->lr_doid = dzp->z_id;
+       lr->lr_foid = zp->z_id;
+       lr->lr_mode = zp->z_mode;
+       if (!IS_EPHEMERAL(zp->z_uid)) {
+               lr->lr_uid = (uint64_t)zp->z_uid;
+       } else {
+               lr->lr_uid = fuidp->z_fuid_owner;
+       }
+       if (!IS_EPHEMERAL(zp->z_gid)) {
+               lr->lr_gid = (uint64_t)zp->z_gid;
+       } else {
+               lr->lr_gid = fuidp->z_fuid_group;
+       }
+       (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(ZTOZSB(zp)), &lr->lr_gen,
+           sizeof (uint64_t));
+       (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_CRTIME(ZTOZSB(zp)),
+           lr->lr_crtime, sizeof (uint64_t) * 2);
+
+       if (sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(ZTOZSB(zp)), &lr->lr_rdev,
+           sizeof (lr->lr_rdev)) != 0)
+               lr->lr_rdev = 0;
+
+       /*
+        * Fill in xvattr info if any
+        */
+       if (vap->va_mask & ATTR_XVATTR) {
+               zfs_log_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), xvap);
+               end = (caddr_t)lr + lrsize + xvatsize;
+       } else {
+               end = (caddr_t)lr + lrsize;
+       }
+
+       /* Now fill in any ACL info */
+
+       if (vsecp) {
+               lracl = (lr_acl_create_t *)&itx->itx_lr;
+               lracl->lr_aclcnt = vsecp->vsa_aclcnt;
+               lracl->lr_acl_bytes = aclsize;
+               lracl->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
+               lracl->lr_fuidcnt  = fuidp ? fuidp->z_fuid_cnt : 0;
+               if (vsecp->vsa_aclflags & VSA_ACE_ACLFLAGS)
+                       lracl->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
+               else
+                       lracl->lr_acl_flags = 0;
+
+               bcopy(vsecp->vsa_aclentp, end, aclsize);
+               end = (caddr_t)end + ZIL_ACE_LENGTH(aclsize);
+       }
+
+       /* drop in FUID info */
+       if (fuidp) {
+               end = zfs_log_fuid_ids(fuidp, end);
+               end = zfs_log_fuid_domains(fuidp, end);
+       }
+       /*
+        * Now place file name in log record
+        */
+       bcopy(name, end, namesize);
+
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * Handles both TX_REMOVE and TX_RMDIR transactions.
+ */
+void
+zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+       znode_t *dzp, char *name, uint64_t foid)
+{
+       itx_t *itx;
+       lr_remove_t *lr;
+       size_t namesize = strlen(name) + 1;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       itx = zil_itx_create(txtype, sizeof (*lr) + namesize);
+       lr = (lr_remove_t *)&itx->itx_lr;
+       lr->lr_doid = dzp->z_id;
+       bcopy(name, (char *)(lr + 1), namesize);
+
+       itx->itx_oid = foid;
+
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * Handles TX_LINK transactions.
+ */
+void
+zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+       znode_t *dzp, znode_t *zp, char *name)
+{
+       itx_t *itx;
+       lr_link_t *lr;
+       size_t namesize = strlen(name) + 1;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       itx = zil_itx_create(txtype, sizeof (*lr) + namesize);
+       lr = (lr_link_t *)&itx->itx_lr;
+       lr->lr_doid = dzp->z_id;
+       lr->lr_link_obj = zp->z_id;
+       bcopy(name, (char *)(lr + 1), namesize);
+
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * Handles TX_SYMLINK transactions.
+ */
+void
+zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+    znode_t *dzp, znode_t *zp, char *name, char *link)
+{
+       itx_t *itx;
+       lr_create_t *lr;
+       size_t namesize = strlen(name) + 1;
+       size_t linksize = strlen(link) + 1;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       itx = zil_itx_create(txtype, sizeof (*lr) + namesize + linksize);
+       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_mode = zp->z_mode;
+       (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(ZTOZSB(zp)), &lr->lr_gen,
+           sizeof (uint64_t));
+       (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_CRTIME(ZTOZSB(zp)),
+           lr->lr_crtime, sizeof (uint64_t) * 2);
+       bcopy(name, (char *)(lr + 1), namesize);
+       bcopy(link, (char *)(lr + 1) + namesize, linksize);
+
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * Handles TX_RENAME transactions.
+ */
+void
+zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+       znode_t *sdzp, char *sname, znode_t *tdzp, char *dname, znode_t *szp)
+{
+       itx_t *itx;
+       lr_rename_t *lr;
+       size_t snamesize = strlen(sname) + 1;
+       size_t dnamesize = strlen(dname) + 1;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       itx = zil_itx_create(txtype, sizeof (*lr) + snamesize + dnamesize);
+       lr = (lr_rename_t *)&itx->itx_lr;
+       lr->lr_sdoid = sdzp->z_id;
+       lr->lr_tdoid = tdzp->z_id;
+       bcopy(sname, (char *)(lr + 1), snamesize);
+       bcopy(dname, (char *)(lr + 1) + snamesize, dnamesize);
+       itx->itx_oid = szp->z_id;
+
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * zfs_log_write() handles TX_WRITE transactions. The specified callback is
+ * called as soon as the write is on stable storage (be it via a DMU sync or a
+ * ZIL commit).
+ */
+long zfs_immediate_write_sz = 32768;
+
+void
+zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+       znode_t *zp, offset_t off, ssize_t resid, int ioflag,
+       zil_callback_t callback, void *callback_data)
+{
+       itx_wr_state_t write_state;
+       boolean_t slogging;
+       uintptr_t fsync_cnt;
+       ssize_t immediate_write_sz;
+
+       if (zil_replaying(zilog, tx) || zp->z_unlinked) {
+               if (callback != NULL)
+                       callback(callback_data);
+               return;
+       }
+
+       immediate_write_sz = (zilog->zl_logbias == ZFS_LOGBIAS_THROUGHPUT)
+           ? 0 : (ssize_t)zfs_immediate_write_sz;
+
+       slogging = spa_has_slogs(zilog->zl_spa) &&
+           (zilog->zl_logbias == ZFS_LOGBIAS_LATENCY);
+       if (resid > immediate_write_sz && !slogging && resid <= zp->z_blksz)
+               write_state = WR_INDIRECT;
+       else if (ioflag & (FSYNC | FDSYNC))
+               write_state = WR_COPIED;
+       else
+               write_state = WR_NEED_COPY;
+
+       if ((fsync_cnt = (uintptr_t)tsd_get(zfs_fsyncer_key)) != 0) {
+               (void) tsd_set(zfs_fsyncer_key, (void *)(fsync_cnt - 1));
+       }
+
+       while (resid) {
+               itx_t *itx;
+               lr_write_t *lr;
+               ssize_t len;
+
+               /*
+                * If the write would overflow the largest block then split it.
+                */
+               if (write_state != WR_INDIRECT && resid > ZIL_MAX_LOG_DATA)
+                       len = SPA_OLD_MAXBLOCKSIZE >> 1;
+               else
+                       len = resid;
+
+               itx = zil_itx_create(txtype, sizeof (*lr) +
+                   (write_state == WR_COPIED ? len : 0));
+               lr = (lr_write_t *)&itx->itx_lr;
+               if (write_state == WR_COPIED && dmu_read(ZTOZSB(zp)->z_os,
+                   zp->z_id, off, len, lr + 1, DMU_READ_NO_PREFETCH) != 0) {
+                       zil_itx_destroy(itx);
+                       itx = zil_itx_create(txtype, sizeof (*lr));
+                       lr = (lr_write_t *)&itx->itx_lr;
+                       write_state = WR_NEED_COPY;
+               }
+
+               itx->itx_wr_state = write_state;
+               if (write_state == WR_NEED_COPY)
+                       itx->itx_sod += len;
+               lr->lr_foid = zp->z_id;
+               lr->lr_offset = off;
+               lr->lr_length = len;
+               lr->lr_blkoff = 0;
+               BP_ZERO(&lr->lr_blkptr);
+
+               itx->itx_private = ZTOZSB(zp);
+
+               if (!(ioflag & (FSYNC | FDSYNC)) && (zp->z_sync_cnt == 0) &&
+                   (fsync_cnt == 0))
+                       itx->itx_sync = B_FALSE;
+
+               itx->itx_callback = callback;
+               itx->itx_callback_data = callback_data;
+               zil_itx_assign(zilog, itx, tx);
+
+               off += len;
+               resid -= len;
+       }
+}
+
+/*
+ * Handles TX_TRUNCATE transactions.
+ */
+void
+zfs_log_truncate(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+       znode_t *zp, uint64_t off, uint64_t len)
+{
+       itx_t *itx;
+       lr_truncate_t *lr;
+
+       if (zil_replaying(zilog, tx) || zp->z_unlinked)
+               return;
+
+       itx = zil_itx_create(txtype, sizeof (*lr));
+       lr = (lr_truncate_t *)&itx->itx_lr;
+       lr->lr_foid = zp->z_id;
+       lr->lr_offset = off;
+       lr->lr_length = len;
+
+       itx->itx_sync = (zp->z_sync_cnt != 0);
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * Handles TX_SETATTR transactions.
+ */
+void
+zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+    znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp)
+{
+       itx_t           *itx;
+       lr_setattr_t    *lr;
+       xvattr_t        *xvap = (xvattr_t *)vap;
+       size_t          recsize = sizeof (lr_setattr_t);
+       void            *start;
+
+       if (zil_replaying(zilog, tx) || zp->z_unlinked)
+               return;
+
+       /*
+        * If XVATTR set, then log record size needs to allow
+        * for lr_attr_t + xvattr mask, mapsize and create time
+        * plus actual attribute values
+        */
+       if (vap->va_mask & ATTR_XVATTR)
+               recsize = sizeof (*lr) + ZIL_XVAT_SIZE(xvap->xva_mapsize);
+
+       if (fuidp)
+               recsize += fuidp->z_domain_str_sz;
+
+       itx = zil_itx_create(txtype, recsize);
+       lr = (lr_setattr_t *)&itx->itx_lr;
+       lr->lr_foid = zp->z_id;
+       lr->lr_mask = (uint64_t)mask_applied;
+       lr->lr_mode = (uint64_t)vap->va_mode;
+       if ((mask_applied & ATTR_UID) && IS_EPHEMERAL(vap->va_uid))
+               lr->lr_uid = fuidp->z_fuid_owner;
+       else
+               lr->lr_uid = (uint64_t)vap->va_uid;
+
+       if ((mask_applied & ATTR_GID) && IS_EPHEMERAL(vap->va_gid))
+               lr->lr_gid = fuidp->z_fuid_group;
+       else
+               lr->lr_gid = (uint64_t)vap->va_gid;
+
+       lr->lr_size = (uint64_t)vap->va_size;
+       ZFS_TIME_ENCODE(&vap->va_atime, lr->lr_atime);
+       ZFS_TIME_ENCODE(&vap->va_mtime, lr->lr_mtime);
+       start = (lr_setattr_t *)(lr + 1);
+       if (vap->va_mask & ATTR_XVATTR) {
+               zfs_log_xvattr((lr_attr_t *)start, xvap);
+               start = (caddr_t)start + ZIL_XVAT_SIZE(xvap->xva_mapsize);
+       }
+
+       /*
+        * Now stick on domain information if any on end
+        */
+
+       if (fuidp)
+               (void) zfs_log_fuid_domains(fuidp, start);
+
+       itx->itx_sync = (zp->z_sync_cnt != 0);
+       zil_itx_assign(zilog, itx, tx);
+}
+
+/*
+ * Handles TX_ACL transactions.
+ */
+void
+zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
+    vsecattr_t *vsecp, zfs_fuid_info_t *fuidp)
+{
+       itx_t *itx;
+       lr_acl_v0_t *lrv0;
+       lr_acl_t *lr;
+       int txtype;
+       int lrsize;
+       size_t txsize;
+       size_t aclbytes = vsecp->vsa_aclentsz;
+
+       if (zil_replaying(zilog, tx) || zp->z_unlinked)
+               return;
+
+       txtype = (ZTOZSB(zp)->z_version < ZPL_VERSION_FUID) ?
+           TX_ACL_V0 : TX_ACL;
+
+       if (txtype == TX_ACL)
+               lrsize = sizeof (*lr);
+       else
+               lrsize = sizeof (*lrv0);
+
+       txsize = lrsize +
+           ((txtype == TX_ACL) ? ZIL_ACE_LENGTH(aclbytes) : aclbytes) +
+           (fuidp ? fuidp->z_domain_str_sz : 0) +
+           sizeof (uint64_t) * (fuidp ? fuidp->z_fuid_cnt : 0);
+
+       itx = zil_itx_create(txtype, txsize);
+
+       lr = (lr_acl_t *)&itx->itx_lr;
+       lr->lr_foid = zp->z_id;
+       if (txtype == TX_ACL) {
+               lr->lr_acl_bytes = aclbytes;
+               lr->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
+               lr->lr_fuidcnt = fuidp ? fuidp->z_fuid_cnt : 0;
+               if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS)
+                       lr->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
+               else
+                       lr->lr_acl_flags = 0;
+       }
+       lr->lr_aclcnt = (uint64_t)vsecp->vsa_aclcnt;
+
+       if (txtype == TX_ACL_V0) {
+               lrv0 = (lr_acl_v0_t *)lr;
+               bcopy(vsecp->vsa_aclentp, (ace_t *)(lrv0 + 1), aclbytes);
+       } else {
+               void *start = (ace_t *)(lr + 1);
+
+               bcopy(vsecp->vsa_aclentp, start, aclbytes);
+
+               start = (caddr_t)start + ZIL_ACE_LENGTH(aclbytes);
+
+               if (fuidp) {
+                       start = zfs_log_fuid_ids(fuidp, start);
+                       (void) zfs_log_fuid_domains(fuidp, start);
+               }
+       }
+
+       itx->itx_sync = (zp->z_sync_cnt != 0);
+       zil_itx_assign(zilog, itx, tx);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_immediate_write_sz, long, 0644);
+MODULE_PARM_DESC(zfs_immediate_write_sz, "Largest data block to write to zil");
+#endif
diff --git a/zfs/module/zfs/zfs_onexit.c b/zfs/module/zfs/zfs_onexit.c
new file mode 100644 (file)
index 0000000..bc38926
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/mkdev.h>
+#include <sys/zfs_onexit.h>
+#include <sys/zvol.h>
+
+/*
+ * ZFS kernel routines may add/delete callback routines to be invoked
+ * upon process exit (triggered via the close operation from the /dev/zfs
+ * driver).
+ *
+ * These cleanup callbacks are intended to allow for the accumulation
+ * of kernel state across multiple ioctls.  User processes participate
+ * simply by opening ZFS_DEV. This causes the ZFS driver to do create
+ * some private data for the file descriptor and generating a unique
+ * minor number. The process then passes along that file descriptor to
+ * each ioctl that might have a cleanup operation.
+ *
+ * Consumers of the onexit routines should call zfs_onexit_fd_hold() early
+ * on to validate the given fd and add a reference to its file table entry.
+ * This allows the consumer to do its work and then add a callback, knowing
+ * that zfs_onexit_add_cb() won't fail with EBADF.  When finished, consumers
+ * should call zfs_onexit_fd_rele().
+ *
+ * A simple example is zfs_ioc_recv(), where we might create an AVL tree
+ * with dataset/GUID mappings and then reuse that tree on subsequent
+ * zfs_ioc_recv() calls.
+ *
+ * On the first zfs_ioc_recv() call, dmu_recv_stream() will kmem_alloc()
+ * the AVL tree and pass it along with a callback function to
+ * zfs_onexit_add_cb(). The zfs_onexit_add_cb() routine will register the
+ * callback and return an action handle.
+ *
+ * The action handle is then passed from user space to subsequent
+ * zfs_ioc_recv() calls, so that dmu_recv_stream() can fetch its AVL tree
+ * by calling zfs_onexit_cb_data() with the device minor number and
+ * action handle.
+ *
+ * If the user process exits abnormally, the callback is invoked implicitly
+ * as part of the driver close operation.  Once the user space process is
+ * finished with the accumulated kernel state, it can also just call close(2)
+ * on the cleanup fd to trigger the cleanup callback.
+ */
+
+void
+zfs_onexit_init(zfs_onexit_t **zop)
+{
+       zfs_onexit_t *zo;
+
+       zo = *zop = kmem_zalloc(sizeof (zfs_onexit_t), KM_SLEEP);
+       mutex_init(&zo->zo_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&zo->zo_actions, sizeof (zfs_onexit_action_node_t),
+           offsetof(zfs_onexit_action_node_t, za_link));
+}
+
+void
+zfs_onexit_destroy(zfs_onexit_t *zo)
+{
+       zfs_onexit_action_node_t *ap;
+
+       mutex_enter(&zo->zo_lock);
+       while ((ap = list_head(&zo->zo_actions)) != NULL) {
+               list_remove(&zo->zo_actions, ap);
+               mutex_exit(&zo->zo_lock);
+               ap->za_func(ap->za_data);
+               kmem_free(ap, sizeof (zfs_onexit_action_node_t));
+               mutex_enter(&zo->zo_lock);
+       }
+       mutex_exit(&zo->zo_lock);
+
+       list_destroy(&zo->zo_actions);
+       mutex_destroy(&zo->zo_lock);
+       kmem_free(zo, sizeof (zfs_onexit_t));
+}
+
+static int
+zfs_onexit_minor_to_state(minor_t minor, zfs_onexit_t **zo)
+{
+       *zo = zfsdev_get_state(minor, ZST_ONEXIT);
+       if (*zo == NULL)
+               return (SET_ERROR(EBADF));
+
+       return (0);
+}
+
+/*
+ * Consumers might need to operate by minor number instead of fd, since
+ * they might be running in another thread (e.g. txg_sync_thread). Callers
+ * of this function must call zfs_onexit_fd_rele() when they're finished
+ * using the minor number.
+ */
+int
+zfs_onexit_fd_hold(int fd, minor_t *minorp)
+{
+       file_t *fp;
+       zfs_onexit_t *zo;
+       int error;
+
+       fp = getf(fd);
+       if (fp == NULL)
+               return (SET_ERROR(EBADF));
+
+       error = zfsdev_getminor(fp->f_file, minorp);
+       if (error == 0)
+               error = zfs_onexit_minor_to_state(*minorp, &zo);
+
+       if (error)
+               zfs_onexit_fd_rele(fd);
+
+       return (error);
+}
+
+void
+zfs_onexit_fd_rele(int fd)
+{
+       releasef(fd);
+}
+
+/*
+ * Add a callback to be invoked when the calling process exits.
+ */
+int
+zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
+    uint64_t *action_handle)
+{
+       zfs_onexit_t *zo;
+       zfs_onexit_action_node_t *ap;
+       int error;
+
+       error = zfs_onexit_minor_to_state(minor, &zo);
+       if (error)
+               return (error);
+
+       ap = kmem_alloc(sizeof (zfs_onexit_action_node_t), KM_SLEEP);
+       list_link_init(&ap->za_link);
+       ap->za_func = func;
+       ap->za_data = data;
+
+       mutex_enter(&zo->zo_lock);
+       list_insert_tail(&zo->zo_actions, ap);
+       mutex_exit(&zo->zo_lock);
+       if (action_handle)
+               *action_handle = (uint64_t)(uintptr_t)ap;
+
+       return (0);
+}
+
+static zfs_onexit_action_node_t *
+zfs_onexit_find_cb(zfs_onexit_t *zo, uint64_t action_handle)
+{
+       zfs_onexit_action_node_t *match;
+       zfs_onexit_action_node_t *ap;
+       list_t *l;
+
+       ASSERT(MUTEX_HELD(&zo->zo_lock));
+
+       match = (zfs_onexit_action_node_t *)(uintptr_t)action_handle;
+       l = &zo->zo_actions;
+       for (ap = list_head(l); ap != NULL; ap = list_next(l, ap)) {
+               if (match == ap)
+                       break;
+       }
+       return (ap);
+}
+
+/*
+ * Delete the callback, triggering it first if 'fire' is set.
+ */
+int
+zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire)
+{
+       zfs_onexit_t *zo;
+       zfs_onexit_action_node_t *ap;
+       int error;
+
+       error = zfs_onexit_minor_to_state(minor, &zo);
+       if (error)
+               return (error);
+
+       mutex_enter(&zo->zo_lock);
+       ap = zfs_onexit_find_cb(zo, action_handle);
+       if (ap != NULL) {
+               list_remove(&zo->zo_actions, ap);
+               mutex_exit(&zo->zo_lock);
+               if (fire)
+                       ap->za_func(ap->za_data);
+               kmem_free(ap, sizeof (zfs_onexit_action_node_t));
+       } else {
+               mutex_exit(&zo->zo_lock);
+               error = SET_ERROR(ENOENT);
+       }
+
+       return (error);
+}
+
+/*
+ * Return the data associated with this callback.  This allows consumers
+ * of the cleanup-on-exit interfaces to stash kernel data across system
+ * calls, knowing that it will be cleaned up if the calling process exits.
+ */
+int
+zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data)
+{
+       zfs_onexit_t *zo;
+       zfs_onexit_action_node_t *ap;
+       int error;
+
+       *data = NULL;
+
+       error = zfs_onexit_minor_to_state(minor, &zo);
+       if (error)
+               return (error);
+
+       mutex_enter(&zo->zo_lock);
+       ap = zfs_onexit_find_cb(zo, action_handle);
+       if (ap != NULL)
+               *data = ap->za_data;
+       else
+               error = SET_ERROR(ENOENT);
+       mutex_exit(&zo->zo_lock);
+
+       return (error);
+}
diff --git a/zfs/module/zfs/zfs_replay.c b/zfs/module/zfs/zfs_replay.c
new file mode 100644 (file)
index 0000000..0ca1e03
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Cyril Plisko. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/thread.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/vfs.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_dir.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_fuid.h>
+#include <sys/zfs_vnops.h>
+#include <sys/spa.h>
+#include <sys/zil.h>
+#include <sys/byteorder.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/acl.h>
+#include <sys/atomic.h>
+#include <sys/cred.h>
+#include <sys/zpl.h>
+
+/*
+ * Functions to replay ZFS intent log (ZIL) records
+ * The functions are called through a function vector (zfs_replay_vector)
+ * which is indexed by the transaction type.
+ */
+
+static void
+zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
+       uint64_t uid, uint64_t gid, uint64_t rdev, uint64_t nodeid)
+{
+       bzero(vap, sizeof (*vap));
+       vap->va_mask = (uint_t)mask;
+       vap->va_type = IFTOVT(mode);
+       vap->va_mode = mode;
+       vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid;
+       vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid;
+       vap->va_rdev = rdev;
+       vap->va_nodeid = nodeid;
+}
+
+/* ARGSUSED */
+static int
+zfs_replay_error(zfs_sb_t *zsb, lr_t *lr, boolean_t byteswap)
+{
+       return (SET_ERROR(ENOTSUP));
+}
+
+static void
+zfs_replay_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
+{
+       xoptattr_t *xoap = NULL;
+       uint64_t *attrs;
+       uint64_t *crtime;
+       uint32_t *bitmap;
+       void *scanstamp;
+       int i;
+
+       xvap->xva_vattr.va_mask |= ATTR_XVATTR;
+       if ((xoap = xva_getxoptattr(xvap)) == NULL) {
+               xvap->xva_vattr.va_mask &= ~ATTR_XVATTR; /* shouldn't happen */
+               return;
+       }
+
+       ASSERT(lrattr->lr_attr_masksize == xvap->xva_mapsize);
+
+       bitmap = &lrattr->lr_attr_bitmap;
+       for (i = 0; i != lrattr->lr_attr_masksize; i++, bitmap++)
+               xvap->xva_reqattrmap[i] = *bitmap;
+
+       attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1);
+       crtime = attrs + 1;
+       scanstamp = (caddr_t)(crtime + 2);
+
+       if (XVA_ISSET_REQ(xvap, XAT_HIDDEN))
+               xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_SYSTEM))
+               xoap->xoa_system = ((*attrs & XAT0_SYSTEM) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE))
+               xoap->xoa_archive = ((*attrs & XAT0_ARCHIVE) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_READONLY))
+               xoap->xoa_readonly = ((*attrs & XAT0_READONLY) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+               xoap->xoa_immutable = ((*attrs & XAT0_IMMUTABLE) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+               xoap->xoa_nounlink = ((*attrs & XAT0_NOUNLINK) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+               xoap->xoa_appendonly = ((*attrs & XAT0_APPENDONLY) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_NODUMP))
+               xoap->xoa_nodump = ((*attrs & XAT0_NODUMP) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+               xoap->xoa_opaque = ((*attrs & XAT0_OPAQUE) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+               xoap->xoa_av_modified = ((*attrs & XAT0_AV_MODIFIED) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED))
+               xoap->xoa_av_quarantined =
+                   ((*attrs & XAT0_AV_QUARANTINED) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_CREATETIME))
+               ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime);
+       if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+               bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
+       if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
+               xoap->xoa_reparse = ((*attrs & XAT0_REPARSE) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_OFFLINE))
+               xoap->xoa_offline = ((*attrs & XAT0_OFFLINE) != 0);
+       if (XVA_ISSET_REQ(xvap, XAT_SPARSE))
+               xoap->xoa_sparse = ((*attrs & XAT0_SPARSE) != 0);
+}
+
+static int
+zfs_replay_domain_cnt(uint64_t uid, uint64_t gid)
+{
+       uint64_t uid_idx;
+       uint64_t gid_idx;
+       int domcnt = 0;
+
+       uid_idx = FUID_INDEX(uid);
+       gid_idx = FUID_INDEX(gid);
+       if (uid_idx)
+               domcnt++;
+       if (gid_idx > 0 && gid_idx != uid_idx)
+               domcnt++;
+
+       return (domcnt);
+}
+
+static void *
+zfs_replay_fuid_domain_common(zfs_fuid_info_t *fuid_infop, void *start,
+    int domcnt)
+{
+       int i;
+
+       for (i = 0; i != domcnt; i++) {
+               fuid_infop->z_domain_table[i] = start;
+               start = (caddr_t)start + strlen(start) + 1;
+       }
+
+       return (start);
+}
+
+/*
+ * Set the uid/gid in the fuid_info structure.
+ */
+static void
+zfs_replay_fuid_ugid(zfs_fuid_info_t *fuid_infop, uint64_t uid, uint64_t gid)
+{
+       /*
+        * If owner or group are log specific FUIDs then slurp up
+        * domain information and build zfs_fuid_info_t
+        */
+       if (IS_EPHEMERAL(uid))
+               fuid_infop->z_fuid_owner = uid;
+
+       if (IS_EPHEMERAL(gid))
+               fuid_infop->z_fuid_group = gid;
+}
+
+/*
+ * Load fuid domains into fuid_info_t
+ */
+static zfs_fuid_info_t *
+zfs_replay_fuid_domain(void *buf, void **end, uint64_t uid, uint64_t gid)
+{
+       int domcnt;
+
+       zfs_fuid_info_t *fuid_infop;
+
+       fuid_infop = zfs_fuid_info_alloc();
+
+       domcnt = zfs_replay_domain_cnt(uid, gid);
+
+       if (domcnt == 0)
+               return (fuid_infop);
+
+       fuid_infop->z_domain_table =
+           kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+
+       zfs_replay_fuid_ugid(fuid_infop, uid, gid);
+
+       fuid_infop->z_domain_cnt = domcnt;
+       *end = zfs_replay_fuid_domain_common(fuid_infop, buf, domcnt);
+       return (fuid_infop);
+}
+
+/*
+ * load zfs_fuid_t's and fuid_domains into fuid_info_t
+ */
+static zfs_fuid_info_t *
+zfs_replay_fuids(void *start, void **end, int idcnt, int domcnt, uint64_t uid,
+    uint64_t gid)
+{
+       uint64_t *log_fuid = (uint64_t *)start;
+       zfs_fuid_info_t *fuid_infop;
+       int i;
+
+       fuid_infop = zfs_fuid_info_alloc();
+       fuid_infop->z_domain_cnt = domcnt;
+
+       fuid_infop->z_domain_table =
+           kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+
+       for (i = 0; i != idcnt; i++) {
+               zfs_fuid_t *zfuid;
+
+               zfuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP);
+               zfuid->z_logfuid = *log_fuid;
+               zfuid->z_id = -1;
+               zfuid->z_domidx = 0;
+               list_insert_tail(&fuid_infop->z_fuids, zfuid);
+               log_fuid++;
+       }
+
+       zfs_replay_fuid_ugid(fuid_infop, uid, gid);
+
+       *end = zfs_replay_fuid_domain_common(fuid_infop, log_fuid, domcnt);
+       return (fuid_infop);
+}
+
+static void
+zfs_replay_swap_attrs(lr_attr_t *lrattr)
+{
+       /* swap the lr_attr structure */
+       byteswap_uint32_array(lrattr, sizeof (*lrattr));
+       /* swap the bitmap */
+       byteswap_uint32_array(lrattr + 1, (lrattr->lr_attr_masksize - 1) *
+           sizeof (uint32_t));
+       /* swap the attributes, create time + 64 bit word for attributes */
+       byteswap_uint64_array((caddr_t)(lrattr + 1) + (sizeof (uint32_t) *
+           (lrattr->lr_attr_masksize - 1)), 3 * sizeof (uint64_t));
+}
+
+/*
+ * Replay file create with optional ACL, xvattr information as well
+ * as option FUID information.
+ */
+static int
+zfs_replay_create_acl(zfs_sb_t *zsb, lr_acl_create_t *lracl, boolean_t byteswap)
+{
+       char *name = NULL;              /* location determined later */
+       lr_create_t *lr = (lr_create_t *)lracl;
+       znode_t *dzp;
+       struct inode *ip = NULL;
+       xvattr_t xva;
+       int vflg = 0;
+       vsecattr_t vsec = { 0 };
+       lr_attr_t *lrattr;
+       void *aclstart;
+       void *fuidstart;
+       size_t xvatlen = 0;
+       uint64_t txtype;
+       int error;
+
+       txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
+       if (byteswap) {
+               byteswap_uint64_array(lracl, sizeof (*lracl));
+               if (txtype == TX_CREATE_ACL_ATTR ||
+                   txtype == TX_MKDIR_ACL_ATTR) {
+                       lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+                       zfs_replay_swap_attrs(lrattr);
+                       xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+               }
+
+               aclstart = (caddr_t)(lracl + 1) + xvatlen;
+               zfs_ace_byteswap(aclstart, lracl->lr_acl_bytes, B_FALSE);
+               /* swap fuids */
+               if (lracl->lr_fuidcnt) {
+                       byteswap_uint64_array((caddr_t)aclstart +
+                           ZIL_ACE_LENGTH(lracl->lr_acl_bytes),
+                           lracl->lr_fuidcnt * sizeof (uint64_t));
+               }
+       }
+
+       if ((error = zfs_zget(zsb, lr->lr_doid, &dzp)) != 0)
+               return (error);
+
+       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);
+
+       /*
+        * 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.
+        */
+       ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
+       xva.xva_vattr.va_nblocks = lr->lr_gen;
+
+       error = dmu_object_info(zsb->z_os, lr->lr_foid, NULL);
+       if (error != ENOENT)
+               goto bail;
+
+       if (lr->lr_common.lrc_txtype & TX_CI)
+               vflg |= FIGNORECASE;
+       switch (txtype) {
+       case TX_CREATE_ACL:
+               aclstart = (caddr_t)(lracl + 1);
+               fuidstart = (caddr_t)aclstart +
+                   ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
+               zsb->z_fuid_replay = zfs_replay_fuids(fuidstart,
+                   (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+                   lr->lr_uid, lr->lr_gid);
+               /*FALLTHROUGH*/
+       case TX_CREATE_ACL_ATTR:
+               if (name == NULL) {
+                       lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+                       xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+                       xva.xva_vattr.va_mask |= ATTR_XVATTR;
+                       zfs_replay_xvattr(lrattr, &xva);
+               }
+               vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+               vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
+               vsec.vsa_aclcnt = lracl->lr_aclcnt;
+               vsec.vsa_aclentsz = lracl->lr_acl_bytes;
+               vsec.vsa_aclflags = lracl->lr_acl_flags;
+               if (zsb->z_fuid_replay == NULL) {
+                       fuidstart = (caddr_t)(lracl + 1) + xvatlen +
+                           ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
+                       zsb->z_fuid_replay =
+                           zfs_replay_fuids(fuidstart,
+                           (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+                           lr->lr_uid, lr->lr_gid);
+               }
+
+               error = zfs_create(ZTOI(dzp), name, &xva.xva_vattr,
+                   0, 0, &ip, kcred, vflg, &vsec);
+               break;
+       case TX_MKDIR_ACL:
+               aclstart = (caddr_t)(lracl + 1);
+               fuidstart = (caddr_t)aclstart +
+                   ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
+               zsb->z_fuid_replay = zfs_replay_fuids(fuidstart,
+                   (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+                   lr->lr_uid, lr->lr_gid);
+               /*FALLTHROUGH*/
+       case TX_MKDIR_ACL_ATTR:
+               if (name == NULL) {
+                       lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+                       xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+                       zfs_replay_xvattr(lrattr, &xva);
+               }
+               vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+               vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
+               vsec.vsa_aclcnt = lracl->lr_aclcnt;
+               vsec.vsa_aclentsz = lracl->lr_acl_bytes;
+               vsec.vsa_aclflags = lracl->lr_acl_flags;
+               if (zsb->z_fuid_replay == NULL) {
+                       fuidstart = (caddr_t)(lracl + 1) + xvatlen +
+                           ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
+                       zsb->z_fuid_replay =
+                           zfs_replay_fuids(fuidstart,
+                           (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+                           lr->lr_uid, lr->lr_gid);
+               }
+               error = zfs_mkdir(ZTOI(dzp), name, &xva.xva_vattr,
+                   &ip, kcred, vflg, &vsec);
+               break;
+       default:
+               error = SET_ERROR(ENOTSUP);
+       }
+
+bail:
+       if (error == 0 && ip != NULL)
+               iput(ip);
+
+       iput(ZTOI(dzp));
+
+       if (zsb->z_fuid_replay)
+               zfs_fuid_info_free(zsb->z_fuid_replay);
+       zsb->z_fuid_replay = NULL;
+
+       return (error);
+}
+
+static int
+zfs_replay_create(zfs_sb_t *zsb, lr_create_t *lr, boolean_t byteswap)
+{
+       char *name = NULL;              /* location determined later */
+       char *link;                     /* symlink content follows name */
+       znode_t *dzp;
+       struct inode *ip = NULL;
+       xvattr_t xva;
+       int vflg = 0;
+       size_t lrsize = sizeof (lr_create_t);
+       lr_attr_t *lrattr;
+       void *start;
+       size_t xvatlen;
+       uint64_t txtype;
+       int error;
+
+       txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
+       if (byteswap) {
+               byteswap_uint64_array(lr, sizeof (*lr));
+               if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR)
+                       zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
+       }
+
+
+       if ((error = zfs_zget(zsb, lr->lr_doid, &dzp)) != 0)
+               return (error);
+
+       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);
+
+       /*
+        * 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.
+        */
+       ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
+       xva.xva_vattr.va_nblocks = lr->lr_gen;
+
+       error = dmu_object_info(zsb->z_os, lr->lr_foid, NULL);
+       if (error != ENOENT)
+               goto out;
+
+       if (lr->lr_common.lrc_txtype & TX_CI)
+               vflg |= FIGNORECASE;
+
+       /*
+        * Symlinks don't have fuid info, and CIFS never creates
+        * symlinks.
+        *
+        * The _ATTR versions will grab the fuid info in their subcases.
+        */
+       if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK &&
+           (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR &&
+           (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) {
+               start = (lr + 1);
+               zsb->z_fuid_replay =
+                   zfs_replay_fuid_domain(start, &start,
+                   lr->lr_uid, lr->lr_gid);
+       }
+
+       switch (txtype) {
+       case TX_CREATE_ATTR:
+               lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+               xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+               zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
+               start = (caddr_t)(lr + 1) + xvatlen;
+               zsb->z_fuid_replay =
+                   zfs_replay_fuid_domain(start, &start,
+                   lr->lr_uid, lr->lr_gid);
+               name = (char *)start;
+
+               /*FALLTHROUGH*/
+       case TX_CREATE:
+               if (name == NULL)
+                       name = (char *)start;
+
+               error = zfs_create(ZTOI(dzp), name, &xva.xva_vattr,
+                   0, 0, &ip, kcred, vflg, NULL);
+               break;
+       case TX_MKDIR_ATTR:
+               lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+               xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+               zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
+               start = (caddr_t)(lr + 1) + xvatlen;
+               zsb->z_fuid_replay =
+                   zfs_replay_fuid_domain(start, &start,
+                   lr->lr_uid, lr->lr_gid);
+               name = (char *)start;
+
+               /*FALLTHROUGH*/
+       case TX_MKDIR:
+               if (name == NULL)
+                       name = (char *)(lr + 1);
+
+               error = zfs_mkdir(ZTOI(dzp), name, &xva.xva_vattr,
+                   &ip, kcred, vflg, NULL);
+               break;
+       case TX_MKXATTR:
+               error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &ip, kcred);
+               break;
+       case TX_SYMLINK:
+               name = (char *)(lr + 1);
+               link = name + strlen(name) + 1;
+               error = zfs_symlink(ZTOI(dzp), name, &xva.xva_vattr,
+                   link, &ip, kcred, vflg);
+               break;
+       default:
+               error = SET_ERROR(ENOTSUP);
+       }
+
+out:
+       if (error == 0 && ip != NULL)
+               iput(ip);
+
+       iput(ZTOI(dzp));
+
+       if (zsb->z_fuid_replay)
+               zfs_fuid_info_free(zsb->z_fuid_replay);
+       zsb->z_fuid_replay = NULL;
+       return (error);
+}
+
+static int
+zfs_replay_remove(zfs_sb_t *zsb, lr_remove_t *lr, boolean_t byteswap)
+{
+       char *name = (char *)(lr + 1);  /* name follows lr_remove_t */
+       znode_t *dzp;
+       int error;
+       int vflg = 0;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       if ((error = zfs_zget(zsb, lr->lr_doid, &dzp)) != 0)
+               return (error);
+
+       if (lr->lr_common.lrc_txtype & TX_CI)
+               vflg |= FIGNORECASE;
+
+       switch ((int)lr->lr_common.lrc_txtype) {
+       case TX_REMOVE:
+               error = zfs_remove(ZTOI(dzp), name, kcred);
+               break;
+       case TX_RMDIR:
+               error = zfs_rmdir(ZTOI(dzp), name, NULL, kcred, vflg);
+               break;
+       default:
+               error = SET_ERROR(ENOTSUP);
+       }
+
+       iput(ZTOI(dzp));
+
+       return (error);
+}
+
+static int
+zfs_replay_link(zfs_sb_t *zsb, lr_link_t *lr, boolean_t byteswap)
+{
+       char *name = (char *)(lr + 1);  /* name follows lr_link_t */
+       znode_t *dzp, *zp;
+       int error;
+       int vflg = 0;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       if ((error = zfs_zget(zsb, lr->lr_doid, &dzp)) != 0)
+               return (error);
+
+       if ((error = zfs_zget(zsb, lr->lr_link_obj, &zp)) != 0) {
+               iput(ZTOI(dzp));
+               return (error);
+       }
+
+       if (lr->lr_common.lrc_txtype & TX_CI)
+               vflg |= FIGNORECASE;
+
+       error = zfs_link(ZTOI(dzp), ZTOI(zp), name, kcred);
+
+       iput(ZTOI(zp));
+       iput(ZTOI(dzp));
+
+       return (error);
+}
+
+static int
+zfs_replay_rename(zfs_sb_t *zsb, lr_rename_t *lr, boolean_t byteswap)
+{
+       char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */
+       char *tname = sname + strlen(sname) + 1;
+       znode_t *sdzp, *tdzp;
+       int error;
+       int vflg = 0;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       if ((error = zfs_zget(zsb, lr->lr_sdoid, &sdzp)) != 0)
+               return (error);
+
+       if ((error = zfs_zget(zsb, lr->lr_tdoid, &tdzp)) != 0) {
+               iput(ZTOI(sdzp));
+               return (error);
+       }
+
+       if (lr->lr_common.lrc_txtype & TX_CI)
+               vflg |= FIGNORECASE;
+
+       error = zfs_rename(ZTOI(sdzp), sname, ZTOI(tdzp), tname, kcred, vflg);
+
+       iput(ZTOI(tdzp));
+       iput(ZTOI(sdzp));
+
+       return (error);
+}
+
+static int
+zfs_replay_write(zfs_sb_t *zsb, lr_write_t *lr, boolean_t byteswap)
+{
+       char *data = (char *)(lr + 1);  /* data follows lr_write_t */
+       znode_t *zp;
+       int error, written;
+       uint64_t eod, offset, length;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       if ((error = zfs_zget(zsb, lr->lr_foid, &zp)) != 0) {
+               /*
+                * As we can log writes out of order, it's possible the
+                * file has been removed. In this case just drop the write
+                * and return success.
+                */
+               if (error == ENOENT)
+                       error = 0;
+               return (error);
+       }
+
+       offset = lr->lr_offset;
+       length = lr->lr_length;
+       eod = offset + length;  /* end of data for this write */
+
+       /*
+        * This may be a write from a dmu_sync() for a whole block,
+        * and may extend beyond the current end of the file.
+        * We can't just replay what was written for this TX_WRITE as
+        * a future TX_WRITE2 may extend the eof and the data for that
+        * write needs to be there. So we write the whole block and
+        * reduce the eof. This needs to be done within the single dmu
+        * transaction created within vn_rdwr -> zfs_write. So a possible
+        * new end of file is passed through in zsb->z_replay_eof
+        */
+
+       zsb->z_replay_eof = 0; /* 0 means don't change end of file */
+
+       /* 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 (zp->z_size < eod)
+                       zsb->z_replay_eof = eod;
+       }
+
+       written = zpl_write_common(ZTOI(zp), data, length, &offset,
+           UIO_SYSSPACE, 0, kcred);
+       if (written < 0)
+               error = -written;
+       else if (written < length)
+               error = SET_ERROR(EIO); /* short write */
+
+       iput(ZTOI(zp));
+       zsb->z_replay_eof = 0;  /* safety */
+
+       return (error);
+}
+
+/*
+ * TX_WRITE2 are only generated when dmu_sync() returns EALREADY
+ * meaning the pool block is already being synced. So now that we always write
+ * out full blocks, all we have to do is expand the eof if
+ * the file is grown.
+ */
+static int
+zfs_replay_write2(zfs_sb_t *zsb, lr_write_t *lr, boolean_t byteswap)
+{
+       znode_t *zp;
+       int error;
+       uint64_t end;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       if ((error = zfs_zget(zsb, lr->lr_foid, &zp)) != 0)
+               return (error);
+
+top:
+       end = lr->lr_offset + lr->lr_length;
+       if (end > zp->z_size) {
+               dmu_tx_t *tx = dmu_tx_create(zsb->z_os);
+
+               zp->z_size = end;
+               dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+               error = dmu_tx_assign(tx, TXG_WAIT);
+               if (error) {
+                       iput(ZTOI(zp));
+                       if (error == ERESTART) {
+                               dmu_tx_wait(tx);
+                               dmu_tx_abort(tx);
+                               goto top;
+                       }
+                       dmu_tx_abort(tx);
+                       return (error);
+               }
+               (void) sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(zsb),
+                   (void *)&zp->z_size, sizeof (uint64_t), tx);
+
+               /* Ensure the replayed seq is updated */
+               (void) zil_replaying(zsb->z_log, tx);
+
+               dmu_tx_commit(tx);
+       }
+
+       iput(ZTOI(zp));
+
+       return (error);
+}
+
+static int
+zfs_replay_truncate(zfs_sb_t *zsb, lr_truncate_t *lr, boolean_t byteswap)
+{
+       znode_t *zp;
+       flock64_t fl;
+       int error;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       if ((error = zfs_zget(zsb, lr->lr_foid, &zp)) != 0)
+               return (error);
+
+       bzero(&fl, sizeof (fl));
+       fl.l_type = F_WRLCK;
+       fl.l_whence = 0;
+       fl.l_start = lr->lr_offset;
+       fl.l_len = lr->lr_length;
+
+       error = zfs_space(ZTOI(zp), F_FREESP, &fl, FWRITE | FOFFMAX,
+           lr->lr_offset, kcred);
+
+       iput(ZTOI(zp));
+
+       return (error);
+}
+
+static int
+zfs_replay_setattr(zfs_sb_t *zsb, lr_setattr_t *lr, boolean_t byteswap)
+{
+       znode_t *zp;
+       xvattr_t xva;
+       vattr_t *vap = &xva.xva_vattr;
+       int error;
+       void *start;
+
+       xva_init(&xva);
+       if (byteswap) {
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+               if ((lr->lr_mask & ATTR_XVATTR) &&
+                   zsb->z_version >= ZPL_VERSION_INITIAL)
+                       zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
+       }
+
+       if ((error = zfs_zget(zsb, lr->lr_foid, &zp)) != 0)
+               return (error);
+
+       zfs_init_vattr(vap, lr->lr_mask, lr->lr_mode,
+           lr->lr_uid, lr->lr_gid, 0, lr->lr_foid);
+
+       vap->va_size = lr->lr_size;
+       ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime);
+       ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime);
+
+       /*
+        * Fill in xvattr_t portions if necessary.
+        */
+
+       start = (lr_setattr_t *)(lr + 1);
+       if (vap->va_mask & ATTR_XVATTR) {
+               zfs_replay_xvattr((lr_attr_t *)start, &xva);
+               start = (caddr_t)start +
+                   ZIL_XVAT_SIZE(((lr_attr_t *)start)->lr_attr_masksize);
+       } else
+               xva.xva_vattr.va_mask &= ~ATTR_XVATTR;
+
+       zsb->z_fuid_replay = zfs_replay_fuid_domain(start, &start,
+           lr->lr_uid, lr->lr_gid);
+
+       error = zfs_setattr(ZTOI(zp), vap, 0, kcred);
+
+       zfs_fuid_info_free(zsb->z_fuid_replay);
+       zsb->z_fuid_replay = NULL;
+       iput(ZTOI(zp));
+
+       return (error);
+}
+
+static int
+zfs_replay_acl_v0(zfs_sb_t *zsb, lr_acl_v0_t *lr, boolean_t byteswap)
+{
+       ace_t *ace = (ace_t *)(lr + 1); /* ace array follows lr_acl_t */
+       vsecattr_t vsa;
+       znode_t *zp;
+       int error;
+
+       if (byteswap) {
+               byteswap_uint64_array(lr, sizeof (*lr));
+               zfs_oldace_byteswap(ace, lr->lr_aclcnt);
+       }
+
+       if ((error = zfs_zget(zsb, lr->lr_foid, &zp)) != 0)
+               return (error);
+
+       bzero(&vsa, sizeof (vsa));
+       vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
+       vsa.vsa_aclcnt = lr->lr_aclcnt;
+       vsa.vsa_aclentsz = sizeof (ace_t) * vsa.vsa_aclcnt;
+       vsa.vsa_aclflags = 0;
+       vsa.vsa_aclentp = ace;
+
+       error = zfs_setsecattr(ZTOI(zp), &vsa, 0, kcred);
+
+       iput(ZTOI(zp));
+
+       return (error);
+}
+
+/*
+ * Replaying ACLs is complicated by FUID support.
+ * The log record may contain some optional data
+ * to be used for replaying FUID's.  These pieces
+ * are the actual FUIDs that were created initially.
+ * The FUID table index may no longer be valid and
+ * during zfs_create() a new index may be assigned.
+ * Because of this the log will contain the original
+ * doman+rid in order to create a new FUID.
+ *
+ * The individual ACEs may contain an ephemeral uid/gid which is no
+ * longer valid and will need to be replaced with an actual FUID.
+ *
+ */
+static int
+zfs_replay_acl(zfs_sb_t *zsb, lr_acl_t *lr, boolean_t byteswap)
+{
+       ace_t *ace = (ace_t *)(lr + 1);
+       vsecattr_t vsa;
+       znode_t *zp;
+       int error;
+
+       if (byteswap) {
+               byteswap_uint64_array(lr, sizeof (*lr));
+               zfs_ace_byteswap(ace, lr->lr_acl_bytes, B_FALSE);
+               if (lr->lr_fuidcnt) {
+                       byteswap_uint64_array((caddr_t)ace +
+                           ZIL_ACE_LENGTH(lr->lr_acl_bytes),
+                           lr->lr_fuidcnt * sizeof (uint64_t));
+               }
+       }
+
+       if ((error = zfs_zget(zsb, lr->lr_foid, &zp)) != 0)
+               return (error);
+
+       bzero(&vsa, sizeof (vsa));
+       vsa.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
+       vsa.vsa_aclcnt = lr->lr_aclcnt;
+       vsa.vsa_aclentp = ace;
+       vsa.vsa_aclentsz = lr->lr_acl_bytes;
+       vsa.vsa_aclflags = lr->lr_acl_flags;
+
+       if (lr->lr_fuidcnt) {
+               void *fuidstart = (caddr_t)ace +
+                   ZIL_ACE_LENGTH(lr->lr_acl_bytes);
+
+               zsb->z_fuid_replay =
+                   zfs_replay_fuids(fuidstart, &fuidstart,
+                   lr->lr_fuidcnt, lr->lr_domcnt, 0, 0);
+       }
+
+       error = zfs_setsecattr(ZTOI(zp), &vsa, 0, kcred);
+
+       if (zsb->z_fuid_replay)
+               zfs_fuid_info_free(zsb->z_fuid_replay);
+
+       zsb->z_fuid_replay = NULL;
+       iput(ZTOI(zp));
+
+       return (error);
+}
+
+/*
+ * Callback vectors for replaying records
+ */
+zil_replay_func_t zfs_replay_vector[TX_MAX_TYPE] = {
+       (zil_replay_func_t)zfs_replay_error,            /* no such type */
+       (zil_replay_func_t)zfs_replay_create,           /* TX_CREATE */
+       (zil_replay_func_t)zfs_replay_create,           /* TX_MKDIR */
+       (zil_replay_func_t)zfs_replay_create,           /* TX_MKXATTR */
+       (zil_replay_func_t)zfs_replay_create,           /* TX_SYMLINK */
+       (zil_replay_func_t)zfs_replay_remove,           /* TX_REMOVE */
+       (zil_replay_func_t)zfs_replay_remove,           /* TX_RMDIR */
+       (zil_replay_func_t)zfs_replay_link,             /* TX_LINK */
+       (zil_replay_func_t)zfs_replay_rename,           /* TX_RENAME */
+       (zil_replay_func_t)zfs_replay_write,            /* TX_WRITE */
+       (zil_replay_func_t)zfs_replay_truncate,         /* TX_TRUNCATE */
+       (zil_replay_func_t)zfs_replay_setattr,          /* TX_SETATTR */
+       (zil_replay_func_t)zfs_replay_acl_v0,           /* TX_ACL_V0 */
+       (zil_replay_func_t)zfs_replay_acl,              /* TX_ACL */
+       (zil_replay_func_t)zfs_replay_create_acl,       /* TX_CREATE_ACL */
+       (zil_replay_func_t)zfs_replay_create,           /* TX_CREATE_ATTR */
+       (zil_replay_func_t)zfs_replay_create_acl,       /* TX_CREATE_ACL_ATTR */
+       (zil_replay_func_t)zfs_replay_create_acl,       /* TX_MKDIR_ACL */
+       (zil_replay_func_t)zfs_replay_create,           /* TX_MKDIR_ATTR */
+       (zil_replay_func_t)zfs_replay_create_acl,       /* TX_MKDIR_ACL_ATTR */
+       (zil_replay_func_t)zfs_replay_write2,           /* TX_WRITE2 */
+};
diff --git a/zfs/module/zfs/zfs_rlock.c b/zfs/module/zfs/zfs_rlock.c
new file mode 100644 (file)
index 0000000..fd3e8a6
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * This file contains the code to implement file range locking in
+ * ZFS, although there isn't much specific to ZFS (all that comes to mind is
+ * support for growing the blocksize).
+ *
+ * Interface
+ * ---------
+ * Defined in zfs_rlock.h but essentially:
+ *     rl = zfs_range_lock(zp, off, len, lock_type);
+ *     zfs_range_unlock(rl);
+ *     zfs_range_reduce(rl, off, len);
+ *
+ * AVL tree
+ * --------
+ * An AVL tree is used to maintain the state of the existing ranges
+ * that are locked for exclusive (writer) or shared (reader) use.
+ * The starting range offset is used for searching and sorting the tree.
+ *
+ * Common case
+ * -----------
+ * The (hopefully) usual case is of no overlaps or contention for
+ * locks. On entry to zfs_lock_range() a rl_t is allocated; the tree
+ * searched that finds no overlap, and *this* rl_t is placed in the tree.
+ *
+ * Overlaps/Reference counting/Proxy locks
+ * ---------------------------------------
+ * The avl code only allows one node at a particular offset. Also it's very
+ * inefficient to search through all previous entries looking for overlaps
+ * (because the very 1st in the ordered list might be at offset 0 but
+ * cover the whole file).
+ * So this implementation uses reference counts and proxy range locks.
+ * Firstly, only reader locks use reference counts and proxy locks,
+ * because writer locks are exclusive.
+ * When a reader lock overlaps with another then a proxy lock is created
+ * for that range and replaces the original lock. If the overlap
+ * is exact then the reference count of the proxy is simply incremented.
+ * Otherwise, the proxy lock is split into smaller lock ranges and
+ * new proxy locks created for non overlapping ranges.
+ * The reference counts are adjusted accordingly.
+ * Meanwhile, the orginal lock is kept around (this is the callers handle)
+ * and its offset and length are used when releasing the lock.
+ *
+ * Thread coordination
+ * -------------------
+ * In order to make wakeups efficient and to ensure multiple continuous
+ * readers on a range don't starve a writer for the same range lock,
+ * two condition variables are allocated in each rl_t.
+ * If a writer (or reader) can't get a range it initialises the writer
+ * (or reader) cv; sets a flag saying there's a writer (or reader) waiting;
+ * and waits on that cv. When a thread unlocks that range it wakes up all
+ * writers then all readers before destroying the lock.
+ *
+ * Append mode writes
+ * ------------------
+ * Append mode writes need to lock a range at the end of a file.
+ * The offset of the end of the file is determined under the
+ * range locking mutex, and the lock type converted from RL_APPEND to
+ * RL_WRITER and the range locked.
+ *
+ * Grow block handling
+ * -------------------
+ * ZFS supports multiple block sizes currently upto 128K. The smallest
+ * block size is used for the file which is grown as needed. During this
+ * growth all other writers and readers must be excluded.
+ * So if the block size needs to be grown then the whole file is
+ * exclusively locked, then later the caller will reduce the lock
+ * range to just the range to be written using zfs_reduce_range.
+ */
+
+#include <sys/zfs_rlock.h>
+
+/*
+ * Check if a write lock can be grabbed, or wait and recheck until available.
+ */
+static void
+zfs_range_lock_writer(zfs_rlock_t *zrl, rl_t *new)
+{
+       avl_tree_t *tree = &zrl->zr_avl;
+       rl_t *rl;
+       avl_index_t where;
+       uint64_t end_size;
+       uint64_t off = new->r_off;
+       uint64_t len = new->r_len;
+
+       for (;;) {
+               /*
+                * Range locking is also used by zvol. However, for zvol, we
+                * don't need to append or grow blocksize, so skip that
+                * processing.
+                *
+                * Yes, this is ugly, and would be solved by not handling
+                * grow or append in range lock code. If that was done then
+                * we could make the range locking code generically available
+                * to other non-zfs consumers.
+                */
+               if (zrl->zr_size) { /* caller is ZPL */
+                       /*
+                        * If in append mode pick up the current end of file.
+                        * This is done under z_range_lock to avoid races.
+                        */
+                       if (new->r_type == RL_APPEND)
+                               new->r_off = *zrl->zr_size;
+
+                       /*
+                        * If we need to grow the block size then grab the whole
+                        * file range. This is also done under z_range_lock to
+                        * avoid races.
+                        */
+                       end_size = MAX(*zrl->zr_size, new->r_off + len);
+                       if (end_size > *zrl->zr_blksz &&
+                           (!ISP2(*zrl->zr_blksz) ||
+                           *zrl->zr_blksz < *zrl->zr_max_blksz)) {
+                               new->r_off = 0;
+                               new->r_len = UINT64_MAX;
+                       }
+               }
+
+               /*
+                * First check for the usual case of no locks
+                */
+               if (avl_numnodes(tree) == 0) {
+                       new->r_type = RL_WRITER; /* convert to writer */
+                       avl_add(tree, new);
+                       return;
+               }
+
+               /*
+                * Look for any locks in the range.
+                */
+               rl = avl_find(tree, new, &where);
+               if (rl)
+                       goto wait; /* already locked at same offset */
+
+               rl = (rl_t *)avl_nearest(tree, where, AVL_AFTER);
+               if (rl && (rl->r_off < new->r_off + new->r_len))
+                       goto wait;
+
+               rl = (rl_t *)avl_nearest(tree, where, AVL_BEFORE);
+               if (rl && rl->r_off + rl->r_len > new->r_off)
+                       goto wait;
+
+               new->r_type = RL_WRITER; /* convert possible RL_APPEND */
+               avl_insert(tree, new, where);
+               return;
+wait:
+               if (!rl->r_write_wanted) {
+                       cv_init(&rl->r_wr_cv, NULL, CV_DEFAULT, NULL);
+                       rl->r_write_wanted = B_TRUE;
+               }
+               cv_wait(&rl->r_wr_cv, &zrl->zr_mutex);
+
+               /* reset to original */
+               new->r_off = off;
+               new->r_len = len;
+       }
+}
+
+/*
+ * If this is an original (non-proxy) lock then replace it by
+ * a proxy and return the proxy.
+ */
+static rl_t *
+zfs_range_proxify(avl_tree_t *tree, rl_t *rl)
+{
+       rl_t *proxy;
+
+       if (rl->r_proxy)
+               return (rl); /* already a proxy */
+
+       ASSERT3U(rl->r_cnt, ==, 1);
+       ASSERT(rl->r_write_wanted == B_FALSE);
+       ASSERT(rl->r_read_wanted == B_FALSE);
+       avl_remove(tree, rl);
+       rl->r_cnt = 0;
+
+       /* create a proxy range lock */
+       proxy = kmem_alloc(sizeof (rl_t), KM_SLEEP);
+       proxy->r_off = rl->r_off;
+       proxy->r_len = rl->r_len;
+       proxy->r_cnt = 1;
+       proxy->r_type = RL_READER;
+       proxy->r_proxy = B_TRUE;
+       proxy->r_write_wanted = B_FALSE;
+       proxy->r_read_wanted = B_FALSE;
+       avl_add(tree, proxy);
+
+       return (proxy);
+}
+
+/*
+ * Split the range lock at the supplied offset
+ * returning the *front* proxy.
+ */
+static rl_t *
+zfs_range_split(avl_tree_t *tree, rl_t *rl, uint64_t off)
+{
+       rl_t *front, *rear;
+
+       ASSERT3U(rl->r_len, >, 1);
+       ASSERT3U(off, >, rl->r_off);
+       ASSERT3U(off, <, rl->r_off + rl->r_len);
+       ASSERT(rl->r_write_wanted == B_FALSE);
+       ASSERT(rl->r_read_wanted == B_FALSE);
+
+       /* create the rear proxy range lock */
+       rear = kmem_alloc(sizeof (rl_t), KM_SLEEP);
+       rear->r_off = off;
+       rear->r_len = rl->r_off + rl->r_len - off;
+       rear->r_cnt = rl->r_cnt;
+       rear->r_type = RL_READER;
+       rear->r_proxy = B_TRUE;
+       rear->r_write_wanted = B_FALSE;
+       rear->r_read_wanted = B_FALSE;
+
+       front = zfs_range_proxify(tree, rl);
+       front->r_len = off - rl->r_off;
+
+       avl_insert_here(tree, rear, front, AVL_AFTER);
+       return (front);
+}
+
+/*
+ * Create and add a new proxy range lock for the supplied range.
+ */
+static void
+zfs_range_new_proxy(avl_tree_t *tree, uint64_t off, uint64_t len)
+{
+       rl_t *rl;
+
+       ASSERT(len);
+       rl = kmem_alloc(sizeof (rl_t), KM_SLEEP);
+       rl->r_off = off;
+       rl->r_len = len;
+       rl->r_cnt = 1;
+       rl->r_type = RL_READER;
+       rl->r_proxy = B_TRUE;
+       rl->r_write_wanted = B_FALSE;
+       rl->r_read_wanted = B_FALSE;
+       avl_add(tree, rl);
+}
+
+static void
+zfs_range_add_reader(avl_tree_t *tree, rl_t *new, rl_t *prev, avl_index_t where)
+{
+       rl_t *next;
+       uint64_t off = new->r_off;
+       uint64_t len = new->r_len;
+
+       /*
+        * prev arrives either:
+        * - pointing to an entry at the same offset
+        * - pointing to the entry with the closest previous offset whose
+        *   range may overlap with the new range
+        * - null, if there were no ranges starting before the new one
+        */
+       if (prev) {
+               if (prev->r_off + prev->r_len <= off) {
+                       prev = NULL;
+               } else if (prev->r_off != off) {
+                       /*
+                        * convert to proxy if needed then
+                        * split this entry and bump ref count
+                        */
+                       prev = zfs_range_split(tree, prev, off);
+                       prev = AVL_NEXT(tree, prev); /* move to rear range */
+               }
+       }
+       ASSERT((prev == NULL) || (prev->r_off == off));
+
+       if (prev)
+               next = prev;
+       else
+               next = (rl_t *)avl_nearest(tree, where, AVL_AFTER);
+
+       if (next == NULL || off + len <= next->r_off) {
+               /* no overlaps, use the original new rl_t in the tree */
+               avl_insert(tree, new, where);
+               return;
+       }
+
+       if (off < next->r_off) {
+               /* Add a proxy for initial range before the overlap */
+               zfs_range_new_proxy(tree, off, next->r_off - off);
+       }
+
+       new->r_cnt = 0; /* will use proxies in tree */
+       /*
+        * We now search forward through the ranges, until we go past the end
+        * of the new range. For each entry we make it a proxy if it
+        * isn't already, then bump its reference count. If there's any
+        * gaps between the ranges then we create a new proxy range.
+        */
+       for (prev = NULL; next; prev = next, next = AVL_NEXT(tree, next)) {
+               if (off + len <= next->r_off)
+                       break;
+               if (prev && prev->r_off + prev->r_len < next->r_off) {
+                       /* there's a gap */
+                       ASSERT3U(next->r_off, >, prev->r_off + prev->r_len);
+                       zfs_range_new_proxy(tree, prev->r_off + prev->r_len,
+                           next->r_off - (prev->r_off + prev->r_len));
+               }
+               if (off + len == next->r_off + next->r_len) {
+                       /* exact overlap with end */
+                       next = zfs_range_proxify(tree, next);
+                       next->r_cnt++;
+                       return;
+               }
+               if (off + len < next->r_off + next->r_len) {
+                       /* new range ends in the middle of this block */
+                       next = zfs_range_split(tree, next, off + len);
+                       next->r_cnt++;
+                       return;
+               }
+               ASSERT3U(off + len, >, next->r_off + next->r_len);
+               next = zfs_range_proxify(tree, next);
+               next->r_cnt++;
+       }
+
+       /* Add the remaining end range. */
+       zfs_range_new_proxy(tree, prev->r_off + prev->r_len,
+           (off + len) - (prev->r_off + prev->r_len));
+}
+
+/*
+ * Check if a reader lock can be grabbed, or wait and recheck until available.
+ */
+static void
+zfs_range_lock_reader(zfs_rlock_t *zrl, rl_t *new)
+{
+       avl_tree_t *tree = &zrl->zr_avl;
+       rl_t *prev, *next;
+       avl_index_t where;
+       uint64_t off = new->r_off;
+       uint64_t len = new->r_len;
+
+       /*
+        * Look for any writer locks in the range.
+        */
+retry:
+       prev = avl_find(tree, new, &where);
+       if (prev == NULL)
+               prev = (rl_t *)avl_nearest(tree, where, AVL_BEFORE);
+
+       /*
+        * Check the previous range for a writer lock overlap.
+        */
+       if (prev && (off < prev->r_off + prev->r_len)) {
+               if ((prev->r_type == RL_WRITER) || (prev->r_write_wanted)) {
+                       if (!prev->r_read_wanted) {
+                               cv_init(&prev->r_rd_cv, NULL, CV_DEFAULT, NULL);
+                               prev->r_read_wanted = B_TRUE;
+                       }
+                       cv_wait(&prev->r_rd_cv, &zrl->zr_mutex);
+                       goto retry;
+               }
+               if (off + len < prev->r_off + prev->r_len)
+                       goto got_lock;
+       }
+
+       /*
+        * Search through the following ranges to see if there's
+        * write lock any overlap.
+        */
+       if (prev)
+               next = AVL_NEXT(tree, prev);
+       else
+               next = (rl_t *)avl_nearest(tree, where, AVL_AFTER);
+       for (; next; next = AVL_NEXT(tree, next)) {
+               if (off + len <= next->r_off)
+                       goto got_lock;
+               if ((next->r_type == RL_WRITER) || (next->r_write_wanted)) {
+                       if (!next->r_read_wanted) {
+                               cv_init(&next->r_rd_cv, NULL, CV_DEFAULT, NULL);
+                               next->r_read_wanted = B_TRUE;
+                       }
+                       cv_wait(&next->r_rd_cv, &zrl->zr_mutex);
+                       goto retry;
+               }
+               if (off + len <= next->r_off + next->r_len)
+                       goto got_lock;
+       }
+
+got_lock:
+       /*
+        * Add the read lock, which may involve splitting existing
+        * locks and bumping ref counts (r_cnt).
+        */
+       zfs_range_add_reader(tree, new, prev, where);
+}
+
+/*
+ * Lock a range (offset, length) as either shared (RL_READER)
+ * or exclusive (RL_WRITER). Returns the range lock structure
+ * for later unlocking or reduce range (if entire file
+ * previously locked as RL_WRITER).
+ */
+rl_t *
+zfs_range_lock(zfs_rlock_t *zrl, uint64_t off, uint64_t len, rl_type_t type)
+{
+       rl_t *new;
+
+       ASSERT(type == RL_READER || type == RL_WRITER || type == RL_APPEND);
+
+       new = kmem_alloc(sizeof (rl_t), KM_SLEEP);
+       new->r_zrl = zrl;
+       new->r_off = off;
+       if (len + off < off)    /* overflow */
+               len = UINT64_MAX - off;
+       new->r_len = len;
+       new->r_cnt = 1; /* assume it's going to be in the tree */
+       new->r_type = type;
+       new->r_proxy = B_FALSE;
+       new->r_write_wanted = B_FALSE;
+       new->r_read_wanted = B_FALSE;
+
+       mutex_enter(&zrl->zr_mutex);
+       if (type == RL_READER) {
+               /*
+                * First check for the usual case of no locks
+                */
+               if (avl_numnodes(&zrl->zr_avl) == 0)
+                       avl_add(&zrl->zr_avl, new);
+               else
+                       zfs_range_lock_reader(zrl, new);
+       } else /* RL_WRITER or RL_APPEND */
+               zfs_range_lock_writer(zrl, new);
+       mutex_exit(&zrl->zr_mutex);
+       return (new);
+}
+
+static void
+zfs_range_free(void *arg)
+{
+       rl_t *rl = arg;
+
+       if (rl->r_write_wanted)
+               cv_destroy(&rl->r_wr_cv);
+
+       if (rl->r_read_wanted)
+               cv_destroy(&rl->r_rd_cv);
+
+       kmem_free(rl, sizeof (rl_t));
+}
+
+/*
+ * Unlock a reader lock
+ */
+static void
+zfs_range_unlock_reader(zfs_rlock_t *zrl, rl_t *remove, list_t *free_list)
+{
+       avl_tree_t *tree = &zrl->zr_avl;
+       rl_t *rl, *next = NULL;
+       uint64_t len;
+
+       /*
+        * The common case is when the remove entry is in the tree
+        * (cnt == 1) meaning there's been no other reader locks overlapping
+        * with this one. Otherwise the remove entry will have been
+        * removed from the tree and replaced by proxies (one or
+        * more ranges mapping to the entire range).
+        */
+       if (remove->r_cnt == 1) {
+               avl_remove(tree, remove);
+
+               if (remove->r_write_wanted)
+                       cv_broadcast(&remove->r_wr_cv);
+
+               if (remove->r_read_wanted)
+                       cv_broadcast(&remove->r_rd_cv);
+
+               list_insert_tail(free_list, remove);
+       } else {
+               ASSERT0(remove->r_cnt);
+               ASSERT0(remove->r_write_wanted);
+               ASSERT0(remove->r_read_wanted);
+               /*
+                * Find start proxy representing this reader lock,
+                * then decrement ref count on all proxies
+                * that make up this range, freeing them as needed.
+                */
+               rl = avl_find(tree, remove, NULL);
+               ASSERT(rl);
+               ASSERT(rl->r_cnt);
+               ASSERT(rl->r_type == RL_READER);
+               for (len = remove->r_len; len != 0; rl = next) {
+                       len -= rl->r_len;
+                       if (len) {
+                               next = AVL_NEXT(tree, rl);
+                               ASSERT(next);
+                               ASSERT(rl->r_off + rl->r_len == next->r_off);
+                               ASSERT(next->r_cnt);
+                               ASSERT(next->r_type == RL_READER);
+                       }
+                       rl->r_cnt--;
+                       if (rl->r_cnt == 0) {
+                               avl_remove(tree, rl);
+
+                               if (rl->r_write_wanted)
+                                       cv_broadcast(&rl->r_wr_cv);
+
+                               if (rl->r_read_wanted)
+                                       cv_broadcast(&rl->r_rd_cv);
+
+                               list_insert_tail(free_list, rl);
+                       }
+               }
+
+               kmem_free(remove, sizeof (rl_t));
+       }
+}
+
+/*
+ * Unlock range and destroy range lock structure.
+ */
+void
+zfs_range_unlock(rl_t *rl)
+{
+       zfs_rlock_t *zrl = rl->r_zrl;
+       list_t free_list;
+       rl_t *free_rl;
+
+       ASSERT(rl->r_type == RL_WRITER || rl->r_type == RL_READER);
+       ASSERT(rl->r_cnt == 1 || rl->r_cnt == 0);
+       ASSERT(!rl->r_proxy);
+       list_create(&free_list, sizeof (rl_t), offsetof(rl_t, rl_node));
+
+       mutex_enter(&zrl->zr_mutex);
+       if (rl->r_type == RL_WRITER) {
+               /* writer locks can't be shared or split */
+               avl_remove(&zrl->zr_avl, rl);
+               if (rl->r_write_wanted)
+                       cv_broadcast(&rl->r_wr_cv);
+
+               if (rl->r_read_wanted)
+                       cv_broadcast(&rl->r_rd_cv);
+
+               list_insert_tail(&free_list, rl);
+       } else {
+               /*
+                * lock may be shared, let zfs_range_unlock_reader()
+                * release the zp->z_range_lock lock and free the rl_t
+                */
+               zfs_range_unlock_reader(zrl, rl, &free_list);
+       }
+       mutex_exit(&zrl->zr_mutex);
+
+       while ((free_rl = list_head(&free_list)) != NULL) {
+               list_remove(&free_list, free_rl);
+               zfs_range_free(free_rl);
+       }
+
+       list_destroy(&free_list);
+}
+
+/*
+ * Reduce range locked as RL_WRITER from whole file to specified range.
+ * Asserts the whole file is exclusivly locked and so there's only one
+ * entry in the tree.
+ */
+void
+zfs_range_reduce(rl_t *rl, uint64_t off, uint64_t len)
+{
+       zfs_rlock_t *zrl = rl->r_zrl;
+
+       /* Ensure there are no other locks */
+       ASSERT(avl_numnodes(&zrl->zr_avl) == 1);
+       ASSERT(rl->r_off == 0);
+       ASSERT(rl->r_type == RL_WRITER);
+       ASSERT(!rl->r_proxy);
+       ASSERT3U(rl->r_len, ==, UINT64_MAX);
+       ASSERT3U(rl->r_cnt, ==, 1);
+
+       mutex_enter(&zrl->zr_mutex);
+       rl->r_off = off;
+       rl->r_len = len;
+
+       if (rl->r_write_wanted)
+               cv_broadcast(&rl->r_wr_cv);
+       if (rl->r_read_wanted)
+               cv_broadcast(&rl->r_rd_cv);
+
+       mutex_exit(&zrl->zr_mutex);
+}
+
+/*
+ * AVL comparison function used to order range locks
+ * Locks are ordered on the start offset of the range.
+ */
+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);
+}
+
+#ifdef _KERNEL
+EXPORT_SYMBOL(zfs_range_lock);
+EXPORT_SYMBOL(zfs_range_unlock);
+EXPORT_SYMBOL(zfs_range_reduce);
+EXPORT_SYMBOL(zfs_range_compare);
+#endif
diff --git a/zfs/module/zfs/zfs_sa.c b/zfs/module/zfs/zfs_sa.c
new file mode 100644 (file)
index 0000000..98e6185
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 <sys/zfs_context.h>
+#include <sys/vnode.h>
+#include <sys/sa.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_sa.h>
+
+/*
+ * ZPL attribute registration table.
+ * Order of attributes doesn't matter
+ * a unique value will be assigned for each
+ * attribute that is file system specific
+ *
+ * This is just the set of ZPL attributes that this
+ * version of ZFS deals with natively.  The file system
+ * could have other attributes stored in files, but they will be
+ * ignored.  The SA framework will preserve them, just that
+ * this version of ZFS won't change or delete them.
+ */
+
+sa_attr_reg_t zfs_attr_table[ZPL_END+1] = {
+       {"ZPL_ATIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 0},
+       {"ZPL_MTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 1},
+       {"ZPL_CTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 2},
+       {"ZPL_CRTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 3},
+       {"ZPL_GEN", sizeof (uint64_t), SA_UINT64_ARRAY, 4},
+       {"ZPL_MODE", sizeof (uint64_t), SA_UINT64_ARRAY, 5},
+       {"ZPL_SIZE", sizeof (uint64_t), SA_UINT64_ARRAY, 6},
+       {"ZPL_PARENT", sizeof (uint64_t), SA_UINT64_ARRAY, 7},
+       {"ZPL_LINKS", sizeof (uint64_t), SA_UINT64_ARRAY, 8},
+       {"ZPL_XATTR", sizeof (uint64_t), SA_UINT64_ARRAY, 9},
+       {"ZPL_RDEV", sizeof (uint64_t), SA_UINT64_ARRAY, 10},
+       {"ZPL_FLAGS", sizeof (uint64_t), SA_UINT64_ARRAY, 11},
+       {"ZPL_UID", sizeof (uint64_t), SA_UINT64_ARRAY, 12},
+       {"ZPL_GID", sizeof (uint64_t), SA_UINT64_ARRAY, 13},
+       {"ZPL_PAD", sizeof (uint64_t) * 4, SA_UINT64_ARRAY, 14},
+       {"ZPL_ZNODE_ACL", 88, SA_UINT8_ARRAY, 15},
+       {"ZPL_DACL_COUNT", sizeof (uint64_t), SA_UINT64_ARRAY, 0},
+       {"ZPL_SYMLINK", 0, SA_UINT8_ARRAY, 0},
+       {"ZPL_SCANSTAMP", 32, SA_UINT8_ARRAY, 0},
+       {"ZPL_DACL_ACES", 0, SA_ACL, 0},
+       {"ZPL_DXATTR", 0, SA_UINT8_ARRAY, 0},
+       {NULL, 0, 0, 0}
+};
+
+#ifdef _KERNEL
+int
+zfs_sa_readlink(znode_t *zp, uio_t *uio)
+{
+       dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
+       size_t bufsz;
+       int error;
+
+       bufsz = zp->z_size;
+       if (bufsz + ZFS_OLD_ZNODE_PHYS_SIZE <= db->db_size) {
+               error = uiomove((caddr_t)db->db_data +
+                   ZFS_OLD_ZNODE_PHYS_SIZE,
+                   MIN((size_t)bufsz, uio->uio_resid), UIO_READ, uio);
+       } else {
+               dmu_buf_t *dbp;
+               if ((error = dmu_buf_hold(ZTOZSB(zp)->z_os, zp->z_id,
+                   0, FTAG, &dbp, DMU_READ_NO_PREFETCH)) == 0) {
+                       error = uiomove(dbp->db_data,
+                           MIN((size_t)bufsz, uio->uio_resid), UIO_READ, uio);
+                       dmu_buf_rele(dbp, FTAG);
+               }
+       }
+       return (error);
+}
+
+void
+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);
+               if (len) {
+                       bcopy(link, (caddr_t)db->db_data +
+                           ZFS_OLD_ZNODE_PHYS_SIZE, len);
+               }
+       } else {
+               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));
+
+               dmu_buf_will_dirty(dbp, tx);
+
+               ASSERT3U(len, <=, dbp->db_size);
+               bcopy(link, dbp->db_data, len);
+               dmu_buf_rele(dbp, FTAG);
+       }
+}
+
+void
+zfs_sa_get_scanstamp(znode_t *zp, xvattr_t *xvap)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       xoptattr_t *xoap;
+
+       ASSERT(MUTEX_HELD(&zp->z_lock));
+       VERIFY((xoap = xva_getxoptattr(xvap)) != NULL);
+       if (zp->z_is_sa) {
+               if (sa_lookup(zp->z_sa_hdl, SA_ZPL_SCANSTAMP(zsb),
+                   &xoap->xoa_av_scanstamp,
+                   sizeof (xoap->xoa_av_scanstamp)) != 0)
+                       return;
+       } else {
+               dmu_object_info_t doi;
+               dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
+               int len;
+
+               if (!(zp->z_pflags & ZFS_BONUS_SCANSTAMP))
+                       return;
+
+               sa_object_info(zp->z_sa_hdl, &doi);
+               len = sizeof (xoap->xoa_av_scanstamp) +
+                   ZFS_OLD_ZNODE_PHYS_SIZE;
+
+               if (len <= doi.doi_bonus_size) {
+                       (void) memcpy(xoap->xoa_av_scanstamp,
+                           (caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
+                           sizeof (xoap->xoa_av_scanstamp));
+               }
+       }
+       XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
+}
+
+void
+zfs_sa_set_scanstamp(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       xoptattr_t *xoap;
+
+       ASSERT(MUTEX_HELD(&zp->z_lock));
+       VERIFY((xoap = xva_getxoptattr(xvap)) != NULL);
+       if (zp->z_is_sa)
+               VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_SCANSTAMP(zsb),
+                   &xoap->xoa_av_scanstamp,
+                   sizeof (xoap->xoa_av_scanstamp), tx));
+       else {
+               dmu_object_info_t doi;
+               dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
+               int len;
+
+               sa_object_info(zp->z_sa_hdl, &doi);
+               len = sizeof (xoap->xoa_av_scanstamp) +
+                   ZFS_OLD_ZNODE_PHYS_SIZE;
+               if (len > doi.doi_bonus_size)
+                       VERIFY(dmu_set_bonus(db, len, tx) == 0);
+               (void) memcpy((caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
+                   xoap->xoa_av_scanstamp, sizeof (xoap->xoa_av_scanstamp));
+
+               zp->z_pflags |= ZFS_BONUS_SCANSTAMP;
+               VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_FLAGS(zsb),
+                   &zp->z_pflags, sizeof (uint64_t), tx));
+       }
+}
+
+int
+zfs_sa_get_xattr(znode_t *zp)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       char *obj;
+       int size;
+       int error;
+
+       ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
+       ASSERT(!zp->z_xattr_cached);
+       ASSERT(zp->z_is_sa);
+
+       error = sa_size(zp->z_sa_hdl, SA_ZPL_DXATTR(zsb), &size);
+       if (error) {
+               if (error == ENOENT)
+                       return nvlist_alloc(&zp->z_xattr_cached,
+                           NV_UNIQUE_NAME, KM_SLEEP);
+               else
+                       return (error);
+       }
+
+       obj = zio_buf_alloc(size);
+
+       error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DXATTR(zsb), obj, size);
+       if (error == 0)
+               error = nvlist_unpack(obj, size, &zp->z_xattr_cached, KM_SLEEP);
+
+       zio_buf_free(obj, size);
+
+       return (error);
+}
+
+int
+zfs_sa_set_xattr(znode_t *zp)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       dmu_tx_t *tx;
+       char *obj;
+       size_t size;
+       int error;
+
+       ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
+       ASSERT(zp->z_xattr_cached);
+       ASSERT(zp->z_is_sa);
+
+       error = nvlist_size(zp->z_xattr_cached, &size, NV_ENCODE_XDR);
+       if ((error == 0) && (size > SA_ATTR_MAX_LEN))
+               error = EFBIG;
+       if (error)
+               goto out;
+
+       obj = zio_buf_alloc(size);
+
+       error = nvlist_pack(zp->z_xattr_cached, &obj, &size,
+           NV_ENCODE_XDR, KM_SLEEP);
+       if (error)
+               goto out_free;
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa_create(tx, size);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+       } else {
+               VERIFY0(sa_update(zp->z_sa_hdl, SA_ZPL_DXATTR(zsb),
+                   obj, size, tx));
+               dmu_tx_commit(tx);
+       }
+out_free:
+       zio_buf_free(obj, size);
+out:
+       return (error);
+}
+
+/*
+ * I'm not convinced we should do any of this upgrade.
+ * since the SA code can read both old/new znode formats
+ * with probably little to no performance difference.
+ *
+ * All new files will be created with the new format.
+ */
+
+void
+zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
+{
+       dmu_buf_t *db = sa_get_db(hdl);
+       znode_t *zp = sa_get_userdata(hdl);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       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], atime[2];
+       zfs_acl_phys_t znode_acl;
+       char scanstamp[AV_SCANSTAMP_SZ];
+       boolean_t drop_lock = B_FALSE;
+
+       /*
+        * No upgrade if ACL isn't cached
+        * since we won't know which locks are held
+        * and ready the ACL would require special "locked"
+        * interfaces that would be messy
+        */
+       if (zp->z_acl_cached == NULL || S_ISLNK(ZTOI(zp)->i_mode))
+               return;
+
+       /*
+        * If the z_lock is held and we aren't the owner
+        * the just return since we don't want to deadlock
+        * trying to update the status of z_is_sa.  This
+        * file can then be upgraded at a later time.
+        *
+        * Otherwise, we know we are doing the
+        * sa_update() that caused us to enter this function.
+        */
+       if (mutex_owner(&zp->z_lock) != curthread) {
+               if (mutex_tryenter(&zp->z_lock) == 0)
+                       return;
+               else
+                       drop_lock = B_TRUE;
+       }
+
+       /* 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);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL, &mode, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zsb), NULL, &parent, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_XATTR(zsb), NULL, &xattr, 8);
+       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_ZNODE_ACL(zsb), NULL,
+           &znode_acl, 88);
+
+       if (sa_bulk_lookup_locked(hdl, bulk, count) != 0) {
+               kmem_free(bulk, sizeof (sa_bulk_attr_t) * 20);
+               goto done;
+       }
+
+       /*
+        * While the order here doesn't matter its best to try and organize
+        * it is such a way to pick up an already existing layout number
+        */
+       count = 0;
+       sa_attrs = kmem_zalloc(sizeof (sa_bulk_attr_t) * 20, KM_SLEEP);
+       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_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),
+           NULL, &parent, 8);
+       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,
+           &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);
+       SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_LINKS(zsb), NULL,
+           &zp->z_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);
+       SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_DACL_COUNT(zsb), NULL,
+           &zp->z_acl_cached->z_acl_count, 8);
+
+       if (zp->z_acl_cached->z_version < ZFS_ACL_VERSION_FUID)
+               zfs_acl_xform(zp, zp->z_acl_cached, CRED());
+
+       locate.cb_aclp = zp->z_acl_cached;
+       SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_DACL_ACES(zsb),
+           zfs_acl_data_locator, &locate, zp->z_acl_cached->z_acl_bytes);
+
+       if (xattr)
+               SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_XATTR(zsb),
+                   NULL, &xattr, 8);
+
+       /* if scanstamp then add scanstamp */
+
+       if (zp->z_pflags & ZFS_BONUS_SCANSTAMP) {
+               bcopy((caddr_t)db->db_data + ZFS_OLD_ZNODE_PHYS_SIZE,
+                   scanstamp, AV_SCANSTAMP_SZ);
+               SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_SCANSTAMP(zsb),
+                   NULL, scanstamp, AV_SCANSTAMP_SZ);
+               zp->z_pflags &= ~ZFS_BONUS_SCANSTAMP;
+       }
+
+       VERIFY(dmu_set_bonustype(db, DMU_OT_SA, tx) == 0);
+       VERIFY(sa_replace_all_by_template_locked(hdl, sa_attrs,
+           count, tx) == 0);
+       if (znode_acl.z_acl_extern_obj)
+               VERIFY(0 == dmu_object_free(zsb->z_os,
+                   znode_acl.z_acl_extern_obj, tx));
+
+       zp->z_is_sa = B_TRUE;
+       kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * 20);
+       kmem_free(bulk, sizeof (sa_bulk_attr_t) * 20);
+done:
+       if (drop_lock)
+               mutex_exit(&zp->z_lock);
+}
+
+void
+zfs_sa_upgrade_txholds(dmu_tx_t *tx, znode_t *zp)
+{
+       if (!ZTOZSB(zp)->z_use_sa || zp->z_is_sa)
+               return;
+
+
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+
+       if (zfs_external_acl(zp)) {
+               dmu_tx_hold_free(tx, zfs_external_acl(zp), 0,
+                   DMU_OBJECT_END);
+       }
+}
+
+EXPORT_SYMBOL(zfs_attr_table);
+EXPORT_SYMBOL(zfs_sa_readlink);
+EXPORT_SYMBOL(zfs_sa_symlink);
+EXPORT_SYMBOL(zfs_sa_get_scanstamp);
+EXPORT_SYMBOL(zfs_sa_set_scanstamp);
+EXPORT_SYMBOL(zfs_sa_get_xattr);
+EXPORT_SYMBOL(zfs_sa_set_xattr);
+EXPORT_SYMBOL(zfs_sa_upgrade);
+EXPORT_SYMBOL(zfs_sa_upgrade_txholds);
+
+#endif
diff --git a/zfs/module/zfs/zfs_vfsops.c b/zfs/module/zfs/zfs_vfsops.c
new file mode 100644 (file)
index 0000000..d7786f6
--- /dev/null
@@ -0,0 +1,1888 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/kmem.h>
+#include <sys/pathname.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/mntent.h>
+#include <sys/mount.h>
+#include <sys/cmn_err.h>
+#include "fs/fs_subr.h"
+#include <sys/zfs_znode.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_dir.h>
+#include <sys/zil.h>
+#include <sys/fs/zfs.h>
+#include <sys/dmu.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_deleg.h>
+#include <sys/spa.h>
+#include <sys/zap.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/varargs.h>
+#include <sys/policy.h>
+#include <sys/atomic.h>
+#include <sys/mkdev.h>
+#include <sys/modctl.h>
+#include <sys/refstr.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
+#include <sys/bootconf.h>
+#include <sys/sunddi.h>
+#include <sys/dnlc.h>
+#include <sys/dmu_objset.h>
+#include <sys/spa_boot.h>
+#include <sys/zpl.h>
+#include "zfs_comutil.h"
+
+/*ARGSUSED*/
+int
+zfs_sync(struct super_block *sb, int wait, cred_t *cr)
+{
+       zfs_sb_t *zsb = sb->s_fs_info;
+
+       /*
+        * Data integrity is job one.  We don't want a compromised kernel
+        * writing to the storage pool, so we never sync during panic.
+        */
+       if (unlikely(oops_in_progress))
+               return (0);
+
+       /*
+        * Semantically, the only requirement is that the sync be initiated.
+        * The DMU syncs out txgs frequently, so there's nothing to do.
+        */
+       if (!wait)
+               return (0);
+
+       if (zsb != NULL) {
+               /*
+                * Sync a specific filesystem.
+                */
+               dsl_pool_t *dp;
+
+               ZFS_ENTER(zsb);
+               dp = dmu_objset_pool(zsb->z_os);
+
+               /*
+                * If the system is shutting down, then skip any
+                * filesystems which may exist on a suspended pool.
+                */
+               if (spa_suspended(dp->dp_spa)) {
+                       ZFS_EXIT(zsb);
+                       return (0);
+               }
+
+               if (zsb->z_log != NULL)
+                       zil_commit(zsb->z_log, 0);
+
+               ZFS_EXIT(zsb);
+       } else {
+               /*
+                * Sync all ZFS filesystems.  This is what happens when you
+                * run sync(1M).  Unlike other filesystems, ZFS honors the
+                * request by waiting for all pools to commit all dirty data.
+                */
+               spa_sync_allpools();
+       }
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_sync);
+
+boolean_t
+zfs_is_readonly(zfs_sb_t *zsb)
+{
+       return (!!(zsb->z_sb->s_flags & MS_RDONLY));
+}
+EXPORT_SYMBOL(zfs_is_readonly);
+
+static void
+atime_changed_cb(void *arg, uint64_t newval)
+{
+       ((zfs_sb_t *)arg)->z_atime = newval;
+}
+
+static void
+relatime_changed_cb(void *arg, uint64_t newval)
+{
+       ((zfs_sb_t *)arg)->z_relatime = newval;
+}
+
+static void
+xattr_changed_cb(void *arg, uint64_t newval)
+{
+       zfs_sb_t *zsb = arg;
+
+       if (newval == ZFS_XATTR_OFF) {
+               zsb->z_flags &= ~ZSB_XATTR;
+       } else {
+               zsb->z_flags |= ZSB_XATTR;
+
+               if (newval == ZFS_XATTR_SA)
+                       zsb->z_xattr_sa = B_TRUE;
+               else
+                       zsb->z_xattr_sa = B_FALSE;
+       }
+}
+
+static void
+acltype_changed_cb(void *arg, uint64_t newval)
+{
+       zfs_sb_t *zsb = arg;
+
+       switch (newval) {
+       case ZFS_ACLTYPE_OFF:
+               zsb->z_acl_type = ZFS_ACLTYPE_OFF;
+               zsb->z_sb->s_flags &= ~MS_POSIXACL;
+               break;
+       case ZFS_ACLTYPE_POSIXACL:
+#ifdef CONFIG_FS_POSIX_ACL
+               zsb->z_acl_type = ZFS_ACLTYPE_POSIXACL;
+               zsb->z_sb->s_flags |= MS_POSIXACL;
+#else
+               zsb->z_acl_type = ZFS_ACLTYPE_OFF;
+               zsb->z_sb->s_flags &= ~MS_POSIXACL;
+#endif /* CONFIG_FS_POSIX_ACL */
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+blksz_changed_cb(void *arg, uint64_t newval)
+{
+       zfs_sb_t *zsb = arg;
+       ASSERT3U(newval, <=, spa_maxblocksize(dmu_objset_spa(zsb->z_os)));
+       ASSERT3U(newval, >=, SPA_MINBLOCKSIZE);
+       ASSERT(ISP2(newval));
+
+       zsb->z_max_blksz = newval;
+}
+
+static void
+readonly_changed_cb(void *arg, uint64_t newval)
+{
+       zfs_sb_t *zsb = arg;
+       struct super_block *sb = zsb->z_sb;
+
+       if (sb == NULL)
+               return;
+
+       if (newval)
+               sb->s_flags |= MS_RDONLY;
+       else
+               sb->s_flags &= ~MS_RDONLY;
+}
+
+static void
+devices_changed_cb(void *arg, uint64_t newval)
+{
+}
+
+static void
+setuid_changed_cb(void *arg, uint64_t newval)
+{
+}
+
+static void
+exec_changed_cb(void *arg, uint64_t newval)
+{
+}
+
+static void
+nbmand_changed_cb(void *arg, uint64_t newval)
+{
+       zfs_sb_t *zsb = arg;
+       struct super_block *sb = zsb->z_sb;
+
+       if (sb == NULL)
+               return;
+
+       if (newval == TRUE)
+               sb->s_flags |= MS_MANDLOCK;
+       else
+               sb->s_flags &= ~MS_MANDLOCK;
+}
+
+static void
+snapdir_changed_cb(void *arg, uint64_t newval)
+{
+       ((zfs_sb_t *)arg)->z_show_ctldir = newval;
+}
+
+static void
+vscan_changed_cb(void *arg, uint64_t newval)
+{
+       ((zfs_sb_t *)arg)->z_vscan = newval;
+}
+
+static void
+acl_inherit_changed_cb(void *arg, uint64_t newval)
+{
+       ((zfs_sb_t *)arg)->z_acl_inherit = newval;
+}
+
+int
+zfs_register_callbacks(zfs_sb_t *zsb)
+{
+       struct dsl_dataset *ds = NULL;
+       objset_t *os = zsb->z_os;
+       zfs_mntopts_t *zmo = zsb->z_mntopts;
+       int error = 0;
+
+       ASSERT(zsb);
+       ASSERT(zmo);
+
+       /*
+        * The act of registering our callbacks will destroy any mount
+        * options we may have.  In order to enable temporary overrides
+        * of mount options, we stash away the current values and
+        * restore them after we register the callbacks.
+        */
+       if (zfs_is_readonly(zsb) || !spa_writeable(dmu_objset_spa(os))) {
+               zmo->z_do_readonly = B_TRUE;
+               zmo->z_readonly = B_TRUE;
+       }
+
+       /*
+        * Register property callbacks.
+        *
+        * It would probably be fine to just check for i/o error from
+        * the first prop_register(), but I guess I like to go
+        * overboard...
+        */
+       ds = dmu_objset_ds(os);
+       dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+       error = dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_RELATIME), relatime_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_ACLTYPE), acltype_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zsb);
+       error = error ? error : dsl_prop_register(ds,
+           zfs_prop_to_name(ZFS_PROP_NBMAND), nbmand_changed_cb, zsb);
+       dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+       if (error)
+               goto unregister;
+
+       /*
+        * Invoke our callbacks to restore temporary mount options.
+        */
+       if (zmo->z_do_readonly)
+               readonly_changed_cb(zsb, zmo->z_readonly);
+       if (zmo->z_do_setuid)
+               setuid_changed_cb(zsb, zmo->z_setuid);
+       if (zmo->z_do_exec)
+               exec_changed_cb(zsb, zmo->z_exec);
+       if (zmo->z_do_devices)
+               devices_changed_cb(zsb, zmo->z_devices);
+       if (zmo->z_do_xattr)
+               xattr_changed_cb(zsb, zmo->z_xattr);
+       if (zmo->z_do_atime)
+               atime_changed_cb(zsb, zmo->z_atime);
+       if (zmo->z_do_relatime)
+               relatime_changed_cb(zsb, zmo->z_relatime);
+       if (zmo->z_do_nbmand)
+               nbmand_changed_cb(zsb, zmo->z_nbmand);
+
+       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);
+
+       return (error);
+}
+EXPORT_SYMBOL(zfs_register_callbacks);
+
+static int
+zfs_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 (SET_ERROR(ENOENT));
+
+       /*
+        * If we have a NULL data pointer
+        * then assume the id's aren't changing and
+        * return EEXIST to the dmu to let it know to
+        * use the same ids
+        */
+       if (data == NULL)
+               return (SET_ERROR(EEXIST));
+
+       if (bonustype == DMU_OT_ZNODE) {
+               znode_phys_t *znp = data;
+               *userp = znp->zp_uid;
+               *groupp = znp->zp_gid;
+       } else {
+               int hdrsize;
+               sa_hdr_phys_t *sap = data;
+               sa_hdr_phys_t sa = *sap;
+               boolean_t swap = B_FALSE;
+
+               ASSERT(bonustype == DMU_OT_SA);
+
+               if (sa.sa_magic == 0) {
+                       /*
+                        * This should only happen for newly created
+                        * files that haven't had the znode data filled
+                        * in yet.
+                        */
+                       *userp = 0;
+                       *groupp = 0;
+                       return (0);
+               }
+               if (sa.sa_magic == BSWAP_32(SA_MAGIC)) {
+                       sa.sa_magic = SA_MAGIC;
+                       sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
+                       swap = B_TRUE;
+               } else {
+                       VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
+               }
+
+               hdrsize = sa_hdrsize(&sa);
+               VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
+               *userp = *((uint64_t *)((uintptr_t)data + hdrsize +
+                   SA_UID_OFFSET));
+               *groupp = *((uint64_t *)((uintptr_t)data + hdrsize +
+                   SA_GID_OFFSET));
+               if (swap) {
+                       *userp = BSWAP_64(*userp);
+                       *groupp = BSWAP_64(*groupp);
+               }
+       }
+       return (0);
+}
+
+static void
+fuidstr_to_sid(zfs_sb_t *zsb, const char *fuidstr,
+    char *domainbuf, int buflen, uid_t *ridp)
+{
+       uint64_t fuid;
+       const char *domain;
+
+       fuid = strtonum(fuidstr, NULL);
+
+       domain = zfs_fuid_find_by_idx(zsb, FUID_INDEX(fuid));
+       if (domain)
+               (void) strlcpy(domainbuf, domain, buflen);
+       else
+               domainbuf[0] = '\0';
+       *ridp = FUID_RID(fuid);
+}
+
+static uint64_t
+zfs_userquota_prop_to_obj(zfs_sb_t *zsb, zfs_userquota_prop_t type)
+{
+       switch (type) {
+       case ZFS_PROP_USERUSED:
+               return (DMU_USERUSED_OBJECT);
+       case ZFS_PROP_GROUPUSED:
+               return (DMU_GROUPUSED_OBJECT);
+       case ZFS_PROP_USERQUOTA:
+               return (zsb->z_userquota_obj);
+       case ZFS_PROP_GROUPQUOTA:
+               return (zsb->z_groupquota_obj);
+       default:
+               return (SET_ERROR(ENOTSUP));
+       }
+       return (0);
+}
+
+int
+zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
+    uint64_t *cookiep, void *vbuf, uint64_t *bufsizep)
+{
+       int error;
+       zap_cursor_t zc;
+       zap_attribute_t za;
+       zfs_useracct_t *buf = vbuf;
+       uint64_t obj;
+
+       if (!dmu_objset_userspace_present(zsb->z_os))
+               return (SET_ERROR(ENOTSUP));
+
+       obj = zfs_userquota_prop_to_obj(zsb, type);
+       if (obj == 0) {
+               *bufsizep = 0;
+               return (0);
+       }
+
+       for (zap_cursor_init_serialized(&zc, zsb->z_os, obj, *cookiep);
+           (error = zap_cursor_retrieve(&zc, &za)) == 0;
+           zap_cursor_advance(&zc)) {
+               if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) >
+                   *bufsizep)
+                       break;
+
+               fuidstr_to_sid(zsb, za.za_name,
+                   buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
+
+               buf->zu_space = za.za_first_integer;
+               buf++;
+       }
+       if (error == ENOENT)
+               error = 0;
+
+       ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep);
+       *bufsizep = (uintptr_t)buf - (uintptr_t)vbuf;
+       *cookiep = zap_cursor_serialize(&zc);
+       zap_cursor_fini(&zc);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_userspace_many);
+
+/*
+ * buf must be big enough (eg, 32 bytes)
+ */
+static int
+id_to_fuidstr(zfs_sb_t *zsb, const char *domain, uid_t rid,
+    char *buf, boolean_t addok)
+{
+       uint64_t fuid;
+       int domainid = 0;
+
+       if (domain && domain[0]) {
+               domainid = zfs_fuid_find_by_domain(zsb, domain, NULL, addok);
+               if (domainid == -1)
+                       return (SET_ERROR(ENOENT));
+       }
+       fuid = FUID_ENCODE(domainid, rid);
+       (void) sprintf(buf, "%llx", (longlong_t)fuid);
+       return (0);
+}
+
+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];
+       int err;
+       uint64_t obj;
+
+       *valp = 0;
+
+       if (!dmu_objset_userspace_present(zsb->z_os))
+               return (SET_ERROR(ENOTSUP));
+
+       obj = zfs_userquota_prop_to_obj(zsb, type);
+       if (obj == 0)
+               return (0);
+
+       err = id_to_fuidstr(zsb, domain, rid, buf, B_FALSE);
+       if (err)
+               return (err);
+
+       err = zap_lookup(zsb->z_os, obj, buf, 8, 1, valp);
+       if (err == ENOENT)
+               err = 0;
+       return (err);
+}
+EXPORT_SYMBOL(zfs_userspace_one);
+
+int
+zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type,
+    const char *domain, uint64_t rid, uint64_t quota)
+{
+       char buf[32];
+       int err;
+       dmu_tx_t *tx;
+       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;
+
+       err = id_to_fuidstr(zsb, domain, rid, buf, B_TRUE);
+       if (err)
+               return (err);
+       fuid_dirtied = zsb->z_fuid_dirty;
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL);
+       if (*objp == 0) {
+               dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE,
+                   zfs_userquota_prop_prefixes[type]);
+       }
+       if (fuid_dirtied)
+               zfs_fuid_txhold(zsb, tx);
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err) {
+               dmu_tx_abort(tx);
+               return (err);
+       }
+
+       mutex_enter(&zsb->z_lock);
+       if (*objp == 0) {
+               *objp = zap_create(zsb->z_os, DMU_OT_USERGROUP_QUOTA,
+                   DMU_OT_NONE, 0, tx);
+               VERIFY(0 == zap_add(zsb->z_os, MASTER_NODE_OBJ,
+                   zfs_userquota_prop_prefixes[type], 8, 1, objp, tx));
+       }
+       mutex_exit(&zsb->z_lock);
+
+       if (quota == 0) {
+               err = zap_remove(zsb->z_os, *objp, buf, tx);
+               if (err == ENOENT)
+                       err = 0;
+       } else {
+               err = zap_update(zsb->z_os, *objp, buf, 8, 1, &quota, tx);
+       }
+       ASSERT(err == 0);
+       if (fuid_dirtied)
+               zfs_fuid_sync(zsb, tx);
+       dmu_tx_commit(tx);
+       return (err);
+}
+EXPORT_SYMBOL(zfs_set_userquota);
+
+boolean_t
+zfs_fuid_overquota(zfs_sb_t *zsb, boolean_t isgroup, uint64_t fuid)
+{
+       char buf[32];
+       uint64_t used, quota, usedobj, quotaobj;
+       int err;
+
+       usedobj = isgroup ? DMU_GROUPUSED_OBJECT : DMU_USERUSED_OBJECT;
+       quotaobj = isgroup ? zsb->z_groupquota_obj : zsb->z_userquota_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);
+
+       err = zap_lookup(zsb->z_os, usedobj, buf, 8, 1, &used);
+       if (err != 0)
+               return (B_FALSE);
+       return (used >= quota);
+}
+EXPORT_SYMBOL(zfs_fuid_overquota);
+
+boolean_t
+zfs_owner_overquota(zfs_sb_t *zsb, znode_t *zp, boolean_t isgroup)
+{
+       uint64_t fuid;
+       uint64_t quotaobj;
+
+       quotaobj = isgroup ? zsb->z_groupquota_obj : zsb->z_userquota_obj;
+
+       fuid = isgroup ? zp->z_gid : zp->z_uid;
+
+       if (quotaobj == 0 || zsb->z_replay)
+               return (B_FALSE);
+
+       return (zfs_fuid_overquota(zsb, isgroup, fuid));
+}
+EXPORT_SYMBOL(zfs_owner_overquota);
+
+zfs_mntopts_t *
+zfs_mntopts_alloc(void)
+{
+       return (kmem_zalloc(sizeof (zfs_mntopts_t), KM_SLEEP));
+}
+
+void
+zfs_mntopts_free(zfs_mntopts_t *zmo)
+{
+       if (zmo->z_osname)
+               strfree(zmo->z_osname);
+
+       if (zmo->z_mntpoint)
+               strfree(zmo->z_mntpoint);
+
+       kmem_free(zmo, sizeof (zfs_mntopts_t));
+}
+
+int
+zfs_sb_create(const char *osname, zfs_mntopts_t *zmo, zfs_sb_t **zsbp)
+{
+       objset_t *os;
+       zfs_sb_t *zsb;
+       uint64_t zval;
+       int i, size, error;
+       uint64_t sa_obj;
+
+       zsb = kmem_zalloc(sizeof (zfs_sb_t), KM_SLEEP);
+
+       /*
+        * Optional temporary mount options, free'd in zfs_sb_free().
+        */
+       zsb->z_mntopts = (zmo ? zmo : zfs_mntopts_alloc());
+
+       /*
+        * We claim to always be readonly so we can open snapshots;
+        * other ZPL code will prevent us from writing to snapshots.
+        */
+       error = dmu_objset_own(osname, DMU_OST_ZFS, B_TRUE, zsb, &os);
+       if (error)
+               goto out_zmo;
+
+       /*
+        * Initialize the zfs-specific filesystem structure.
+        * Should probably make this a kmem cache, shuffle fields.
+        */
+       zsb->z_sb = NULL;
+       zsb->z_parent = zsb;
+       zsb->z_max_blksz = SPA_OLD_MAXBLOCKSIZE;
+       zsb->z_show_ctldir = ZFS_SNAPDIR_VISIBLE;
+       zsb->z_os = os;
+
+       error = zfs_get_zplprop(os, ZFS_PROP_VERSION, &zsb->z_version);
+       if (error) {
+               goto out;
+       } else if (zsb->z_version > ZPL_VERSION) {
+               error = SET_ERROR(ENOTSUP);
+               goto out;
+       }
+       if ((error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &zval)) != 0)
+               goto out;
+       zsb->z_norm = (int)zval;
+
+       if ((error = zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &zval)) != 0)
+               goto out;
+       zsb->z_utf8 = (zval != 0);
+
+       if ((error = zfs_get_zplprop(os, ZFS_PROP_CASE, &zval)) != 0)
+               goto out;
+       zsb->z_case = (uint_t)zval;
+
+       if ((error = zfs_get_zplprop(os, ZFS_PROP_ACLTYPE, &zval)) != 0)
+               goto out;
+       zsb->z_acl_type = (uint_t)zval;
+
+       /*
+        * Fold case on file systems that are always or sometimes case
+        * insensitive.
+        */
+       if (zsb->z_case == ZFS_CASE_INSENSITIVE ||
+           zsb->z_case == ZFS_CASE_MIXED)
+               zsb->z_norm |= U8_TEXTPREP_TOUPPER;
+
+       zsb->z_use_fuids = USE_FUIDS(zsb->z_version, zsb->z_os);
+       zsb->z_use_sa = USE_SA(zsb->z_version, zsb->z_os);
+
+       if (zsb->z_use_sa) {
+               /* should either have both of these objects or none */
+               error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1,
+                   &sa_obj);
+               if (error)
+                       goto out;
+
+               error = zfs_get_zplprop(os, ZFS_PROP_XATTR, &zval);
+               if ((error == 0) && (zval == ZFS_XATTR_SA))
+                       zsb->z_xattr_sa = B_TRUE;
+       } else {
+               /*
+                * Pre SA versions file systems should never touch
+                * either the attribute registration or layout objects.
+                */
+               sa_obj = 0;
+       }
+
+       error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END,
+           &zsb->z_attr_table);
+       if (error)
+               goto out;
+
+       if (zsb->z_version >= ZPL_VERSION_SA)
+               sa_register_update_callback(os, zfs_sa_upgrade);
+
+       error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_ROOT_OBJ, 8, 1,
+           &zsb->z_root);
+       if (error)
+               goto out;
+       ASSERT(zsb->z_root != 0);
+
+       error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_UNLINKED_SET, 8, 1,
+           &zsb->z_unlinkedobj);
+       if (error)
+               goto out;
+
+       error = zap_lookup(os, MASTER_NODE_OBJ,
+           zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA],
+           8, 1, &zsb->z_userquota_obj);
+       if (error && error != ENOENT)
+               goto out;
+
+       error = zap_lookup(os, MASTER_NODE_OBJ,
+           zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA],
+           8, 1, &zsb->z_groupquota_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)
+               goto out;
+
+       error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SHARES_DIR, 8, 1,
+           &zsb->z_shares_dir);
+       if (error && error != ENOENT)
+               goto out;
+
+       mutex_init(&zsb->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&zsb->z_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&zsb->z_all_znodes, sizeof (znode_t),
+           offsetof(znode_t, z_link_node));
+       rrm_init(&zsb->z_teardown_lock, B_FALSE);
+       rw_init(&zsb->z_teardown_inactive_lock, NULL, RW_DEFAULT, NULL);
+       rw_init(&zsb->z_fuid_lock, NULL, RW_DEFAULT, NULL);
+
+       size = MIN(1 << (highbit64(zfs_object_mutex_size)-1), ZFS_OBJ_MTX_MAX);
+       zsb->z_hold_size = size;
+       zsb->z_hold_trees = vmem_zalloc(sizeof (avl_tree_t) * size, KM_SLEEP);
+       zsb->z_hold_locks = vmem_zalloc(sizeof (kmutex_t) * size, KM_SLEEP);
+       for (i = 0; i != size; i++) {
+               avl_create(&zsb->z_hold_trees[i], zfs_znode_hold_compare,
+                   sizeof (znode_hold_t), offsetof(znode_hold_t, zh_node));
+               mutex_init(&zsb->z_hold_locks[i], NULL, MUTEX_DEFAULT, NULL);
+       }
+
+       *zsbp = zsb;
+       return (0);
+
+out:
+       dmu_objset_disown(os, zsb);
+out_zmo:
+       *zsbp = NULL;
+       zfs_mntopts_free(zsb->z_mntopts);
+       kmem_free(zsb, sizeof (zfs_sb_t));
+       return (error);
+}
+EXPORT_SYMBOL(zfs_sb_create);
+
+int
+zfs_sb_setup(zfs_sb_t *zsb, boolean_t mounting)
+{
+       int error;
+
+       error = zfs_register_callbacks(zsb);
+       if (error)
+               return (error);
+
+       /*
+        * Set the objset user_ptr to track its zsb.
+        */
+       mutex_enter(&zsb->z_os->os_user_ptr_lock);
+       dmu_objset_set_user(zsb->z_os, zsb);
+       mutex_exit(&zsb->z_os->os_user_ptr_lock);
+
+       zsb->z_log = zil_open(zsb->z_os, zfs_get_data);
+
+       /*
+        * If we are not mounting (ie: online recv), then we don't
+        * have to worry about replaying the log as we blocked all
+        * operations out since we closed the ZIL.
+        */
+       if (mounting) {
+               boolean_t readonly;
+
+               /*
+                * During replay we remove the read only flag to
+                * allow replays to succeed.
+                */
+               readonly = zfs_is_readonly(zsb);
+               if (readonly != 0)
+                       readonly_changed_cb(zsb, B_FALSE);
+               else
+                       zfs_unlinked_drain(zsb);
+
+               /*
+                * Parse and replay the intent log.
+                *
+                * Because of ziltest, this must be done after
+                * zfs_unlinked_drain().  (Further note: ziltest
+                * doesn't use readonly mounts, where
+                * zfs_unlinked_drain() isn't called.)  This is because
+                * ziltest causes spa_sync() to think it's committed,
+                * but actually it is not, so the intent log contains
+                * many txg's worth of changes.
+                *
+                * In particular, if object N is in the unlinked set in
+                * the last txg to actually sync, then it could be
+                * actually freed in a later txg and then reallocated
+                * in a yet later txg.  This would write a "create
+                * object N" record to the intent log.  Normally, this
+                * would be fine because the spa_sync() would have
+                * written out the fact that object N is free, before
+                * we could write the "create object N" intent log
+                * record.
+                *
+                * But when we are in ziltest mode, we advance the "open
+                * txg" without actually spa_sync()-ing the changes to
+                * disk.  So we would see that object N is still
+                * allocated and in the unlinked set, and there is an
+                * intent log record saying to allocate it.
+                */
+               if (spa_writeable(dmu_objset_spa(zsb->z_os))) {
+                       if (zil_replay_disable) {
+                               zil_destroy(zsb->z_log, B_FALSE);
+                       } else {
+                               zsb->z_replay = B_TRUE;
+                               zil_replay(zsb->z_os, zsb,
+                                   zfs_replay_vector);
+                               zsb->z_replay = B_FALSE;
+                       }
+               }
+
+               /* restore readonly bit */
+               if (readonly != 0)
+                       readonly_changed_cb(zsb, B_TRUE);
+       }
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_sb_setup);
+
+void
+zfs_sb_free(zfs_sb_t *zsb)
+{
+       int i, size = zsb->z_hold_size;
+
+       zfs_fuid_destroy(zsb);
+
+       mutex_destroy(&zsb->z_znodes_lock);
+       mutex_destroy(&zsb->z_lock);
+       list_destroy(&zsb->z_all_znodes);
+       rrm_destroy(&zsb->z_teardown_lock);
+       rw_destroy(&zsb->z_teardown_inactive_lock);
+       rw_destroy(&zsb->z_fuid_lock);
+       for (i = 0; i != size; i++) {
+               avl_destroy(&zsb->z_hold_trees[i]);
+               mutex_destroy(&zsb->z_hold_locks[i]);
+       }
+       vmem_free(zsb->z_hold_trees, sizeof (avl_tree_t) * size);
+       vmem_free(zsb->z_hold_locks, sizeof (kmutex_t) * size);
+       zfs_mntopts_free(zsb->z_mntopts);
+       kmem_free(zsb, sizeof (zfs_sb_t));
+}
+EXPORT_SYMBOL(zfs_sb_free);
+
+static void
+zfs_set_fuid_feature(zfs_sb_t *zsb)
+{
+       zsb->z_use_fuids = USE_FUIDS(zsb->z_version, zsb->z_os);
+       zsb->z_use_sa = USE_SA(zsb->z_version, zsb->z_os);
+}
+
+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);
+       }
+}
+EXPORT_SYMBOL(zfs_unregister_callbacks);
+
+#ifdef HAVE_MLSLABEL
+/*
+ * Check that the hex label string is appropriate for the dataset being
+ * mounted into the global_zone proper.
+ *
+ * Return an error if the hex label string is not default or
+ * admin_low/admin_high.  For admin_low labels, the corresponding
+ * dataset must be readonly.
+ */
+int
+zfs_check_global_label(const char *dsname, const char *hexsl)
+{
+       if (strcasecmp(hexsl, ZFS_MLSLABEL_DEFAULT) == 0)
+               return (0);
+       if (strcasecmp(hexsl, ADMIN_HIGH) == 0)
+               return (0);
+       if (strcasecmp(hexsl, ADMIN_LOW) == 0) {
+               /* must be readonly */
+               uint64_t rdonly;
+
+               if (dsl_prop_get_integer(dsname,
+                   zfs_prop_to_name(ZFS_PROP_READONLY), &rdonly, NULL))
+                       return (SET_ERROR(EACCES));
+               return (rdonly ? 0 : EACCES);
+       }
+       return (SET_ERROR(EACCES));
+}
+EXPORT_SYMBOL(zfs_check_global_label);
+#endif /* HAVE_MLSLABEL */
+
+int
+zfs_statvfs(struct dentry *dentry, struct kstatfs *statp)
+{
+       zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
+       uint64_t refdbytes, availbytes, usedobjs, availobjs;
+       uint64_t fsid;
+       uint32_t bshift;
+
+       ZFS_ENTER(zsb);
+
+       dmu_objset_space(zsb->z_os,
+           &refdbytes, &availbytes, &usedobjs, &availobjs);
+
+       fsid = dmu_objset_fsid_guid(zsb->z_os);
+       /*
+        * The underlying storage pool actually uses multiple block
+        * size.  Under Solaris frsize (fragment size) is reported as
+        * the smallest block size we support, and bsize (block size)
+        * as the filesystem's maximum block size.  Unfortunately,
+        * under Linux the fragment size and block size are often used
+        * interchangeably.  Thus we are forced to report both of them
+        * as the filesystem's maximum block size.
+        */
+       statp->f_frsize = zsb->z_max_blksz;
+       statp->f_bsize = zsb->z_max_blksz;
+       bshift = fls(statp->f_bsize) - 1;
+
+       /*
+        * The following report "total" blocks of various kinds in
+        * the file system, but reported in terms of f_bsize - the
+        * "preferred" size.
+        */
+
+       statp->f_blocks = (refdbytes + availbytes) >> bshift;
+       statp->f_bfree = availbytes >> bshift;
+       statp->f_bavail = statp->f_bfree; /* no root reservation */
+
+       /*
+        * statvfs() should really be called statufs(), because it assumes
+        * static metadata.  ZFS doesn't preallocate files, so the best
+        * we can do is report the max that could possibly fit in f_files,
+        * and that minus the number actually used in f_ffree.
+        * For f_ffree, report the smaller of the number of object available
+        * and the number of blocks (each object will take at least a block).
+        */
+       statp->f_ffree = MIN(availobjs, availbytes >> DNODE_SHIFT);
+       statp->f_files = statp->f_ffree + usedobjs;
+       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;
+
+       /*
+        * We have all of 40 characters to stuff a string here.
+        * Is there anything useful we could/should provide?
+        */
+       bzero(statp->f_spare, sizeof (statp->f_spare));
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_statvfs);
+
+int
+zfs_root(zfs_sb_t *zsb, struct inode **ipp)
+{
+       znode_t *rootzp;
+       int error;
+
+       ZFS_ENTER(zsb);
+
+       error = zfs_zget(zsb, zsb->z_root, &rootzp);
+       if (error == 0)
+               *ipp = ZTOI(rootzp);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_root);
+
+#ifdef HAVE_D_PRUNE_ALIASES
+/*
+ * Linux kernels older than 3.1 do not support a per-filesystem shrinker.
+ * To accommodate this we must improvise and manually walk the list of znodes
+ * attempting to prune dentries in order to be able to drop the inodes.
+ *
+ * To avoid scanning the same znodes multiple times they are always rotated
+ * to the end of the z_all_znodes list.  New znodes are inserted at the
+ * end of the list so we're always scanning the oldest znodes first.
+ */
+static int
+zfs_sb_prune_aliases(zfs_sb_t *zsb, unsigned long nr_to_scan)
+{
+       znode_t **zp_array, *zp;
+       int max_array = MIN(nr_to_scan, PAGE_SIZE * 8 / sizeof (znode_t *));
+       int objects = 0;
+       int i = 0, j = 0;
+
+       zp_array = kmem_zalloc(max_array * sizeof (znode_t *), KM_SLEEP);
+
+       mutex_enter(&zsb->z_znodes_lock);
+       while ((zp = list_head(&zsb->z_all_znodes)) != NULL) {
+
+               if ((i++ > nr_to_scan) || (j >= max_array))
+                       break;
+
+               ASSERT(list_link_active(&zp->z_link_node));
+               list_remove(&zsb->z_all_znodes, zp);
+               list_insert_tail(&zsb->z_all_znodes, zp);
+
+               /* Skip active znodes and .zfs entries */
+               if (MUTEX_HELD(&zp->z_lock) || zp->z_is_ctldir)
+                       continue;
+
+               if (igrab(ZTOI(zp)) == NULL)
+                       continue;
+
+               zp_array[j] = zp;
+               j++;
+       }
+       mutex_exit(&zsb->z_znodes_lock);
+
+       for (i = 0; i < j; i++) {
+               zp = zp_array[i];
+
+               ASSERT3P(zp, !=, NULL);
+               d_prune_aliases(ZTOI(zp));
+
+               if (atomic_read(&ZTOI(zp)->i_count) == 1)
+                       objects++;
+
+               iput(ZTOI(zp));
+       }
+
+       kmem_free(zp_array, max_array * sizeof (znode_t *));
+
+       return (objects);
+}
+#endif /* HAVE_D_PRUNE_ALIASES */
+
+/*
+ * The ARC has requested that the filesystem drop entries from the dentry
+ * and inode caches.  This can occur when the ARC needs to free meta data
+ * blocks but can't because they are all pinned by entries in these caches.
+ */
+int
+zfs_sb_prune(struct super_block *sb, unsigned long nr_to_scan, int *objects)
+{
+       zfs_sb_t *zsb = sb->s_fs_info;
+       int error = 0;
+#if defined(HAVE_SHRINK) || defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+       struct shrinker *shrinker = &sb->s_shrink;
+       struct shrink_control sc = {
+               .nr_to_scan = nr_to_scan,
+               .gfp_mask = GFP_KERNEL,
+       };
+#endif
+
+       ZFS_ENTER(zsb);
+
+#if defined(HAVE_SPLIT_SHRINKER_CALLBACK) && \
+       defined(SHRINK_CONTROL_HAS_NID) && \
+       defined(SHRINKER_NUMA_AWARE)
+       if (sb->s_shrink.flags & SHRINKER_NUMA_AWARE) {
+               *objects = 0;
+               for_each_online_node(sc.nid)
+                       *objects += (*shrinker->scan_objects)(shrinker, &sc);
+       } else {
+                       *objects = (*shrinker->scan_objects)(shrinker, &sc);
+       }
+
+#elif defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+       *objects = (*shrinker->scan_objects)(shrinker, &sc);
+#elif defined(HAVE_SHRINK)
+       *objects = (*shrinker->shrink)(shrinker, &sc);
+#elif defined(HAVE_D_PRUNE_ALIASES)
+#define        D_PRUNE_ALIASES_IS_DEFAULT
+       *objects = zfs_sb_prune_aliases(zsb, nr_to_scan);
+#else
+#error "No available dentry and inode cache pruning mechanism."
+#endif
+
+#if defined(HAVE_D_PRUNE_ALIASES) && !defined(D_PRUNE_ALIASES_IS_DEFAULT)
+#undef D_PRUNE_ALIASES_IS_DEFAULT
+       /*
+        * Fall back to zfs_sb_prune_aliases if the kernel's per-superblock
+        * shrinker couldn't free anything, possibly due to the inodes being
+        * allocated in a different memcg.
+        */
+       if (*objects == 0)
+               *objects = zfs_sb_prune_aliases(zsb, nr_to_scan);
+#endif
+
+       ZFS_EXIT(zsb);
+
+       dprintf_ds(zsb->z_os->os_dsl_dataset,
+           "pruning, nr_to_scan=%lu objects=%d error=%d\n",
+           nr_to_scan, *objects, error);
+
+       return (error);
+}
+EXPORT_SYMBOL(zfs_sb_prune);
+
+/*
+ * Teardown the zfs_sb_t.
+ *
+ * Note, if 'unmounting' if FALSE, we return with the 'z_teardown_lock'
+ * and 'z_teardown_inactive_lock' held.
+ */
+int
+zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
+{
+       znode_t *zp;
+
+       /*
+        * If someone has not already unmounted this file system,
+        * drain the iput_taskq to ensure all active references to the
+        * zfs_sb_t have been handled only then can it be safely destroyed.
+        */
+       if (zsb->z_os) {
+               /*
+                * If we're unmounting we have to wait for the list to
+                * drain completely.
+                *
+                * If we're not unmounting there's no guarantee the list
+                * will drain completely, but iputs run from the taskq
+                * may add the parents of dir-based xattrs to the taskq
+                * so we want to wait for these.
+                *
+                * We can safely read z_nr_znodes without locking because the
+                * VFS has already blocked operations which add to the
+                * z_all_znodes list and thus increment z_nr_znodes.
+                */
+               int round = 0;
+               while (zsb->z_nr_znodes > 0) {
+                       taskq_wait_outstanding(dsl_pool_iput_taskq(
+                           dmu_objset_pool(zsb->z_os)), 0);
+                       if (++round > 1 && !unmounting)
+                               break;
+               }
+       }
+
+       rrm_enter(&zsb->z_teardown_lock, RW_WRITER, FTAG);
+
+       if (!unmounting) {
+               /*
+                * We purge the parent filesystem's super block as the
+                * parent filesystem and all of its snapshots have their
+                * inode's super block set to the parent's filesystem's
+                * super block.  Note,  'z_parent' is self referential
+                * for non-snapshots.
+                */
+               shrink_dcache_sb(zsb->z_parent->z_sb);
+       }
+
+       /*
+        * Close the zil. NB: Can't close the zil while zfs_inactive
+        * threads are blocked as zil_close can call zfs_inactive.
+        */
+       if (zsb->z_log) {
+               zil_close(zsb->z_log);
+               zsb->z_log = NULL;
+       }
+
+       rw_enter(&zsb->z_teardown_inactive_lock, RW_WRITER);
+
+       /*
+        * If we are not unmounting (ie: online recv) and someone already
+        * unmounted this file system while we were doing the switcheroo,
+        * or a reopen of z_os failed then just bail out now.
+        */
+       if (!unmounting && (zsb->z_unmounted || zsb->z_os == NULL)) {
+               rw_exit(&zsb->z_teardown_inactive_lock);
+               rrm_exit(&zsb->z_teardown_lock, FTAG);
+               return (SET_ERROR(EIO));
+       }
+
+       /*
+        * At this point there are no VFS ops active, and any new VFS ops
+        * will fail with EIO since we have z_teardown_lock for writer (only
+        * relevant for forced unmount).
+        *
+        * Release all holds on dbufs.
+        */
+       if (!unmounting) {
+               mutex_enter(&zsb->z_znodes_lock);
+               for (zp = list_head(&zsb->z_all_znodes); zp != NULL;
+               zp = list_next(&zsb->z_all_znodes, zp)) {
+                       if (zp->z_sa_hdl)
+                               zfs_znode_dmu_fini(zp);
+               }
+               mutex_exit(&zsb->z_znodes_lock);
+       }
+
+       /*
+        * If we are unmounting, set the unmounted flag and let new VFS ops
+        * unblock.  zfs_inactive will have the unmounted behavior, and all
+        * other VFS ops will fail with EIO.
+        */
+       if (unmounting) {
+               zsb->z_unmounted = B_TRUE;
+               rrm_exit(&zsb->z_teardown_lock, FTAG);
+               rw_exit(&zsb->z_teardown_inactive_lock);
+       }
+
+       /*
+        * z_os will be NULL if there was an error in attempting to reopen
+        * zsb, so just return as the properties had already been
+        *
+        * unregistered and cached data had been evicted before.
+        */
+       if (zsb->z_os == NULL)
+               return (0);
+
+       /*
+        * Unregister properties.
+        */
+       zfs_unregister_callbacks(zsb);
+
+       /*
+        * Evict cached data
+        */
+       if (dsl_dataset_is_dirty(dmu_objset_ds(zsb->z_os)) &&
+           !zfs_is_readonly(zsb))
+               txg_wait_synced(dmu_objset_pool(zsb->z_os), 0);
+       dmu_objset_evict_dbufs(zsb->z_os);
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_sb_teardown);
+
+#if !defined(HAVE_2ARGS_BDI_SETUP_AND_REGISTER) && \
+       !defined(HAVE_3ARGS_BDI_SETUP_AND_REGISTER)
+atomic_long_t zfs_bdi_seq = ATOMIC_LONG_INIT(0);
+#endif
+
+int
+zfs_domount(struct super_block *sb, zfs_mntopts_t *zmo, int silent)
+{
+       const char *osname = zmo->z_osname;
+       zfs_sb_t *zsb;
+       struct inode *root_inode;
+       uint64_t recordsize;
+       int error;
+
+       error = zfs_sb_create(osname, zmo, &zsb);
+       if (error)
+               return (error);
+
+       if ((error = dsl_prop_get_integer(osname, "recordsize",
+           &recordsize, NULL)))
+               goto out;
+
+       zsb->z_sb = sb;
+       sb->s_fs_info = zsb;
+       sb->s_magic = ZFS_SUPER_MAGIC;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
+       sb->s_time_gran = 1;
+       sb->s_blocksize = recordsize;
+       sb->s_blocksize_bits = ilog2(recordsize);
+       zsb->z_bdi.ra_pages = 0;
+       sb->s_bdi = &zsb->z_bdi;
+
+       error = -zpl_bdi_setup_and_register(&zsb->z_bdi, "zfs");
+       if (error)
+               goto out;
+
+       /* Set callback operations for the file system. */
+       sb->s_op = &zpl_super_operations;
+       sb->s_xattr = zpl_xattr_handlers;
+       sb->s_export_op = &zpl_export_operations;
+#ifdef HAVE_S_D_OP
+       sb->s_d_op = &zpl_dentry_operations;
+#endif /* HAVE_S_D_OP */
+
+       /* Set features for file system. */
+       zfs_set_fuid_feature(zsb);
+
+       if (dmu_objset_is_snapshot(zsb->z_os)) {
+               uint64_t pval;
+
+               atime_changed_cb(zsb, B_FALSE);
+               readonly_changed_cb(zsb, B_TRUE);
+               if ((error = dsl_prop_get_integer(osname,
+                   "xattr", &pval, NULL)))
+                       goto out;
+               xattr_changed_cb(zsb, pval);
+               if ((error = dsl_prop_get_integer(osname,
+                   "acltype", &pval, NULL)))
+                       goto out;
+               acltype_changed_cb(zsb, pval);
+               zsb->z_issnap = B_TRUE;
+               zsb->z_os->os_sync = ZFS_SYNC_DISABLED;
+               zsb->z_snap_defer_time = jiffies;
+
+               mutex_enter(&zsb->z_os->os_user_ptr_lock);
+               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);
+       }
+
+       /* Allocate a root inode for the filesystem. */
+       error = zfs_root(zsb, &root_inode);
+       if (error) {
+               (void) zfs_umount(sb);
+               goto out;
+       }
+
+       /* Allocate a root dentry for the filesystem */
+       sb->s_root = d_make_root(root_inode);
+       if (sb->s_root == NULL) {
+               (void) zfs_umount(sb);
+               error = SET_ERROR(ENOMEM);
+               goto out;
+       }
+
+       if (!zsb->z_issnap)
+               zfsctl_create(zsb);
+
+       zsb->z_arc_prune = arc_add_prune_callback(zpl_prune_sb, sb);
+out:
+       if (error) {
+               dmu_objset_disown(zsb->z_os, zsb);
+               zfs_sb_free(zsb);
+       }
+
+       return (error);
+}
+EXPORT_SYMBOL(zfs_domount);
+
+/*
+ * Called when an unmount is requested and certain sanity checks have
+ * already passed.  At this point no dentries or inodes have been reclaimed
+ * from their respective caches.  We drop the extra reference on the .zfs
+ * control directory to allow everything to be reclaimed.  All snapshots
+ * must already have been unmounted to reach this point.
+ */
+void
+zfs_preumount(struct super_block *sb)
+{
+       zfs_sb_t *zsb = sb->s_fs_info;
+
+       if (zsb)
+               zfsctl_destroy(sb->s_fs_info);
+}
+EXPORT_SYMBOL(zfs_preumount);
+
+/*
+ * Called once all other unmount released tear down has occurred.
+ * It is our responsibility to release any remaining infrastructure.
+ */
+/*ARGSUSED*/
+int
+zfs_umount(struct super_block *sb)
+{
+       zfs_sb_t *zsb = sb->s_fs_info;
+       objset_t *os;
+
+       arc_remove_prune_callback(zsb->z_arc_prune);
+       VERIFY(zfs_sb_teardown(zsb, B_TRUE) == 0);
+       os = zsb->z_os;
+       bdi_destroy(sb->s_bdi);
+
+       /*
+        * z_os will be NULL if there was an error in
+        * attempting to reopen zsb.
+        */
+       if (os != NULL) {
+               /*
+                * Unset the objset user_ptr.
+                */
+               mutex_enter(&os->os_user_ptr_lock);
+               dmu_objset_set_user(os, NULL);
+               mutex_exit(&os->os_user_ptr_lock);
+
+               /*
+                * Finally release the objset
+                */
+               dmu_objset_disown(os, zsb);
+       }
+
+       zfs_sb_free(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_umount);
+
+int
+zfs_remount(struct super_block *sb, int *flags, zfs_mntopts_t *zmo)
+{
+       zfs_sb_t *zsb = sb->s_fs_info;
+       int error;
+
+       zfs_unregister_callbacks(zsb);
+       error = zfs_register_callbacks(zsb);
+
+       return (error);
+}
+EXPORT_SYMBOL(zfs_remount);
+
+int
+zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp)
+{
+       zfs_sb_t        *zsb = sb->s_fs_info;
+       znode_t         *zp;
+       uint64_t        object = 0;
+       uint64_t        fid_gen = 0;
+       uint64_t        gen_mask;
+       uint64_t        zp_gen;
+       int             i, err;
+
+       *ipp = NULL;
+
+       ZFS_ENTER(zsb);
+
+       if (fidp->fid_len == LONG_FID_LEN) {
+               zfid_long_t     *zlfid = (zfid_long_t *)fidp;
+               uint64_t        objsetid = 0;
+               uint64_t        setgen = 0;
+
+               for (i = 0; i < sizeof (zlfid->zf_setid); i++)
+                       objsetid |= ((uint64_t)zlfid->zf_setid[i]) << (8 * i);
+
+               for (i = 0; i < sizeof (zlfid->zf_setgen); i++)
+                       setgen |= ((uint64_t)zlfid->zf_setgen[i]) << (8 * i);
+
+               ZFS_EXIT(zsb);
+
+               err = zfsctl_lookup_objset(sb, objsetid, &zsb);
+               if (err)
+                       return (SET_ERROR(EINVAL));
+
+               ZFS_ENTER(zsb);
+       }
+
+       if (fidp->fid_len == SHORT_FID_LEN || fidp->fid_len == LONG_FID_LEN) {
+               zfid_short_t    *zfid = (zfid_short_t *)fidp;
+
+               for (i = 0; i < sizeof (zfid->zf_object); i++)
+                       object |= ((uint64_t)zfid->zf_object[i]) << (8 * i);
+
+               for (i = 0; i < sizeof (zfid->zf_gen); i++)
+                       fid_gen |= ((uint64_t)zfid->zf_gen[i]) << (8 * i);
+       } else {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /* A zero fid_gen means we are in the .zfs control directories */
+       if (fid_gen == 0 &&
+           (object == ZFSCTL_INO_ROOT || object == ZFSCTL_INO_SNAPDIR)) {
+               *ipp = zsb->z_ctldir;
+               ASSERT(*ipp != NULL);
+               if (object == ZFSCTL_INO_SNAPDIR) {
+                       VERIFY(zfsctl_root_lookup(*ipp, "snapshot", ipp,
+                           0, kcred, NULL, NULL) == 0);
+               } else {
+                       igrab(*ipp);
+               }
+               ZFS_EXIT(zsb);
+               return (0);
+       }
+
+       gen_mask = -1ULL >> (64 - 8 * i);
+
+       dprintf("getting %llu [%llu mask %llx]\n", object, fid_gen, gen_mask);
+       if ((err = zfs_zget(zsb, object, &zp))) {
+               ZFS_EXIT(zsb);
+               return (err);
+       }
+
+       /* Don't export xattr stuff */
+       if (zp->z_pflags & ZFS_XATTR) {
+               iput(ZTOI(zp));
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENOENT));
+       }
+
+       (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zsb), &zp_gen,
+           sizeof (uint64_t));
+       zp_gen = zp_gen & gen_mask;
+       if (zp_gen == 0)
+               zp_gen = 1;
+       if ((fid_gen == 0) && (zsb->z_root == object))
+               fid_gen = zp_gen;
+       if (zp->z_unlinked || zp_gen != fid_gen) {
+               dprintf("znode gen (%llu) != fid gen (%llu)\n", zp_gen,
+                   fid_gen);
+               iput(ZTOI(zp));
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENOENT));
+       }
+
+       *ipp = ZTOI(zp);
+       if (*ipp)
+               zfs_inode_update(ITOZ(*ipp));
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_vget);
+
+/*
+ * Block out VFS ops and close zfs_sb_t
+ *
+ * Note, if successful, then we return with the 'z_teardown_lock' and
+ * 'z_teardown_inactive_lock' write held.  We leave ownership of the underlying
+ * dataset and objset intact so that they can be atomically handed off during
+ * a subsequent rollback or recv operation and the resume thereafter.
+ */
+int
+zfs_suspend_fs(zfs_sb_t *zsb)
+{
+       int error;
+
+       if ((error = zfs_sb_teardown(zsb, B_FALSE)) != 0)
+               return (error);
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_suspend_fs);
+
+/*
+ * Reopen zfs_sb_t and release VFS ops.
+ */
+int
+zfs_resume_fs(zfs_sb_t *zsb, const char *osname)
+{
+       int err, err2;
+       znode_t *zp;
+       uint64_t sa_obj = 0;
+
+       ASSERT(RRM_WRITE_HELD(&zsb->z_teardown_lock));
+       ASSERT(RW_WRITE_HELD(&zsb->z_teardown_inactive_lock));
+
+       /*
+        * We already own this, so just hold and rele it to update the
+        * objset_t, as the one we had before may have been evicted.
+        */
+       VERIFY0(dmu_objset_hold(osname, zsb, &zsb->z_os));
+       VERIFY3P(zsb->z_os->os_dsl_dataset->ds_owner, ==, zsb);
+       VERIFY(dsl_dataset_long_held(zsb->z_os->os_dsl_dataset));
+       dmu_objset_rele(zsb->z_os, zsb);
+
+       /*
+        * Make sure version hasn't changed
+        */
+
+       err = zfs_get_zplprop(zsb->z_os, ZFS_PROP_VERSION,
+           &zsb->z_version);
+
+       if (err)
+               goto bail;
+
+       err = zap_lookup(zsb->z_os, MASTER_NODE_OBJ,
+           ZFS_SA_ATTRS, 8, 1, &sa_obj);
+
+       if (err && zsb->z_version >= ZPL_VERSION_SA)
+               goto bail;
+
+       if ((err = sa_setup(zsb->z_os, sa_obj,
+           zfs_attr_table,  ZPL_END, &zsb->z_attr_table)) != 0)
+               goto bail;
+
+       if (zsb->z_version >= ZPL_VERSION_SA)
+               sa_register_update_callback(zsb->z_os,
+                   zfs_sa_upgrade);
+
+       VERIFY(zfs_sb_setup(zsb, B_FALSE) == 0);
+
+       zfs_set_fuid_feature(zsb);
+       zsb->z_rollback_time = jiffies;
+
+       /*
+        * Attempt to re-establish all the active inodes with their
+        * dbufs.  If a zfs_rezget() fails, then we unhash the inode
+        * and mark it stale.  This prevents a collision if a new
+        * inode/object is created which must use the same inode
+        * number.  The stale inode will be be released when the
+        * VFS prunes the dentry holding the remaining references
+        * on the stale inode.
+        */
+       mutex_enter(&zsb->z_znodes_lock);
+       for (zp = list_head(&zsb->z_all_znodes); zp;
+           zp = list_next(&zsb->z_all_znodes, zp)) {
+               err2 = zfs_rezget(zp);
+               if (err2) {
+                       remove_inode_hash(ZTOI(zp));
+                       zp->z_is_stale = B_TRUE;
+               }
+       }
+       mutex_exit(&zsb->z_znodes_lock);
+
+bail:
+       /* release the VFS ops */
+       rw_exit(&zsb->z_teardown_inactive_lock);
+       rrm_exit(&zsb->z_teardown_lock, FTAG);
+
+       if (err) {
+               /*
+                * Since we couldn't setup the sa framework, try to force
+                * unmount this file system.
+                */
+               if (zsb->z_os)
+                       (void) zfs_umount(zsb->z_sb);
+       }
+       return (err);
+}
+EXPORT_SYMBOL(zfs_resume_fs);
+
+int
+zfs_set_version(zfs_sb_t *zsb, uint64_t newvers)
+{
+       int error;
+       objset_t *os = zsb->z_os;
+       dmu_tx_t *tx;
+
+       if (newvers < ZPL_VERSION_INITIAL || newvers > ZPL_VERSION)
+               return (SET_ERROR(EINVAL));
+
+       if (newvers < zsb->z_version)
+               return (SET_ERROR(EINVAL));
+
+       if (zfs_spa_version_map(newvers) >
+           spa_version(dmu_objset_spa(zsb->z_os)))
+               return (SET_ERROR(ENOTSUP));
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_FALSE, ZPL_VERSION_STR);
+       if (newvers >= ZPL_VERSION_SA && !zsb->z_use_sa) {
+               dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE,
+                   ZFS_SA_ATTRS);
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
+       }
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+               return (error);
+       }
+
+       error = zap_update(os, MASTER_NODE_OBJ, ZPL_VERSION_STR,
+           8, 1, &newvers, tx);
+
+       if (error) {
+               dmu_tx_commit(tx);
+               return (error);
+       }
+
+       if (newvers >= ZPL_VERSION_SA && !zsb->z_use_sa) {
+               uint64_t sa_obj;
+
+               ASSERT3U(spa_version(dmu_objset_spa(zsb->z_os)), >=,
+                   SPA_VERSION_SA);
+               sa_obj = zap_create(os, DMU_OT_SA_MASTER_NODE,
+                   DMU_OT_NONE, 0, tx);
+
+               error = zap_add(os, MASTER_NODE_OBJ,
+                   ZFS_SA_ATTRS, 8, 1, &sa_obj, tx);
+               ASSERT0(error);
+
+               VERIFY(0 == sa_set_sa_object(os, sa_obj));
+               sa_register_update_callback(os, zfs_sa_upgrade);
+       }
+
+       spa_history_log_internal_ds(dmu_objset_ds(os), "upgrade", tx,
+           "from %llu to %llu", zsb->z_version, newvers);
+
+       dmu_tx_commit(tx);
+
+       zsb->z_version = newvers;
+
+       zfs_set_fuid_feature(zsb);
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_set_version);
+
+/*
+ * Read a property stored within the master node.
+ */
+int
+zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
+{
+       const char *pname;
+       int error = SET_ERROR(ENOENT);
+
+       /*
+        * Look up the file system's value for the property.  For the
+        * version property, we look up a slightly different string.
+        */
+       if (prop == ZFS_PROP_VERSION)
+               pname = ZPL_VERSION_STR;
+       else
+               pname = zfs_prop_to_name(prop);
+
+       if (os != NULL)
+               error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value);
+
+       if (error == ENOENT) {
+               /* No value set, use the default value */
+               switch (prop) {
+               case ZFS_PROP_VERSION:
+                       *value = ZPL_VERSION;
+                       break;
+               case ZFS_PROP_NORMALIZE:
+               case ZFS_PROP_UTF8ONLY:
+                       *value = 0;
+                       break;
+               case ZFS_PROP_CASE:
+                       *value = ZFS_CASE_SENSITIVE;
+                       break;
+               case ZFS_PROP_ACLTYPE:
+                       *value = ZFS_ACLTYPE_OFF;
+                       break;
+               default:
+                       return (error);
+               }
+               error = 0;
+       }
+       return (error);
+}
+EXPORT_SYMBOL(zfs_get_zplprop);
+
+void
+zfs_init(void)
+{
+       zfsctl_init();
+       zfs_znode_init();
+       dmu_objset_register_type(DMU_OST_ZFS, zfs_space_delta_cb);
+       register_filesystem(&zpl_fs_type);
+}
+
+void
+zfs_fini(void)
+{
+       /*
+        * we don't use outstanding because zpl_posix_acl_free might add more.
+        */
+       taskq_wait(system_taskq);
+       unregister_filesystem(&zpl_fs_type);
+       zfs_znode_fini();
+       zfsctl_fini();
+}
diff --git a/zfs/module/zfs/zfs_vnops.c b/zfs/module/zfs/zfs_vnops.c
new file mode 100644 (file)
index 0000000..384a37f
--- /dev/null
@@ -0,0 +1,4681 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+/* Portions Copyright 2007 Jeremy Teo */
+/* Portions Copyright 2010 Robert Milkowski */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/resource.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/kmem.h>
+#include <sys/taskq.h>
+#include <sys/uio.h>
+#include <sys/vmsystm.h>
+#include <sys/atomic.h>
+#include <vm/pvn.h>
+#include <sys/pathname.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/unistd.h>
+#include <sys/zfs_dir.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/fs/zfs.h>
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/dbuf.h>
+#include <sys/zap.h>
+#include <sys/sa.h>
+#include <sys/dirent.h>
+#include <sys/policy.h>
+#include <sys/sunddi.h>
+#include <sys/sid.h>
+#include <sys/mode.h>
+#include "fs/fs_subr.h"
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
+#include <sys/zfs_sa.h>
+#include <sys/zfs_vnops.h>
+#include <sys/dnlc.h>
+#include <sys/zfs_rlock.h>
+#include <sys/extdirent.h>
+#include <sys/kidmap.h>
+#include <sys/cred.h>
+#include <sys/attr.h>
+#include <sys/zpl.h>
+
+/*
+ * Programming rules.
+ *
+ * Each vnode op performs some logical unit of work.  To do this, the ZPL must
+ * properly lock its in-core state, create a DMU transaction, do the work,
+ * record this work in the intent log (ZIL), commit the DMU transaction,
+ * and wait for the intent log to commit if it is a synchronous operation.
+ * Moreover, the vnode ops must work in both normal and log replay context.
+ * The ordering of events is important to avoid deadlocks and references
+ * to freed memory.  The example below illustrates the following Big Rules:
+ *
+ *  (1) A check must be made in each zfs thread for a mounted file system.
+ *     This is done avoiding races using ZFS_ENTER(zsb).
+ *      A ZFS_EXIT(zsb) is needed before all returns.  Any znodes
+ *      must be checked with ZFS_VERIFY_ZP(zp).  Both of these macros
+ *      can return EIO from the calling function.
+ *
+ *  (2)        iput() should always be the last thing except for zil_commit()
+ *     (if necessary) and ZFS_EXIT(). This is for 3 reasons:
+ *     First, if it's the last reference, the vnode/znode
+ *     can be freed, so the zp may point to freed memory.  Second, the last
+ *     reference will call zfs_zinactive(), which may induce a lot of work --
+ *     pushing cached pages (which acquires range locks) and syncing out
+ *     cached atime changes.  Third, zfs_zinactive() may require a new tx,
+ *     which could deadlock the system if you were already holding one.
+ *     If you must call iput() within a tx then use zfs_iput_async().
+ *
+ *  (3)        All range locks must be grabbed before calling dmu_tx_assign(),
+ *     as they can span dmu_tx_assign() calls.
+ *
+ *  (4) If ZPL locks are held, pass TXG_NOWAIT as the second argument to
+ *      dmu_tx_assign().  This is critical because we don't want to block
+ *      while holding locks.
+ *
+ *     If no ZPL locks are held (aside from ZFS_ENTER()), use TXG_WAIT.  This
+ *     reduces lock contention and CPU usage when we must wait (note that if
+ *     throughput is constrained by the storage, nearly every transaction
+ *     must wait).
+ *
+ *      Note, in particular, that if a lock is sometimes acquired before
+ *      the tx assigns, and sometimes after (e.g. z_lock), then failing
+ *      to use a non-blocking assign can deadlock the system.  The scenario:
+ *
+ *     Thread A has grabbed a lock before calling dmu_tx_assign().
+ *     Thread B is in an already-assigned tx, and blocks for this lock.
+ *     Thread A calls dmu_tx_assign(TXG_WAIT) and blocks in txg_wait_open()
+ *     forever, because the previous txg can't quiesce until B's tx commits.
+ *
+ *     If dmu_tx_assign() returns ERESTART and zsb->z_assign is TXG_NOWAIT,
+ *     then drop all locks, call dmu_tx_wait(), and try again.  On subsequent
+ *     calls to dmu_tx_assign(), pass TXG_WAITED rather than TXG_NOWAIT,
+ *     to indicate that this operation has already called dmu_tx_wait().
+ *     This will ensure that we don't retry forever, waiting a short bit
+ *     each time.
+ *
+ *  (5)        If the operation succeeded, generate the intent log entry for it
+ *     before dropping locks.  This ensures that the ordering of events
+ *     in the intent log matches the order in which they actually occurred.
+ *     During ZIL replay the zfs_log_* functions will update the sequence
+ *     number to indicate the zil transaction has replayed.
+ *
+ *  (6)        At the end of each vnode op, the DMU tx must always commit,
+ *     regardless of whether there were any errors.
+ *
+ *  (7)        After dropping all locks, invoke zil_commit(zilog, foid)
+ *     to ensure that synchronous semantics are provided when necessary.
+ *
+ * In general, this is how things should be ordered in each vnode op:
+ *
+ *     ZFS_ENTER(zsb);         // exit if unmounted
+ * top:
+ *     zfs_dirent_lock(&dl, ...)       // lock directory entry (may igrab())
+ *     rw_enter(...);                  // grab any other locks you need
+ *     tx = dmu_tx_create(...);        // get DMU tx
+ *     dmu_tx_hold_*();                // hold each object you might modify
+ *     error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+ *     if (error) {
+ *             rw_exit(...);           // drop locks
+ *             zfs_dirent_unlock(dl);  // unlock directory entry
+ *             iput(...);              // release held vnodes
+ *             if (error == ERESTART) {
+ *                     waited = B_TRUE;
+ *                     dmu_tx_wait(tx);
+ *                     dmu_tx_abort(tx);
+ *                     goto top;
+ *             }
+ *             dmu_tx_abort(tx);       // abort DMU tx
+ *             ZFS_EXIT(zsb);  // finished in zfs
+ *             return (error);         // really out of space
+ *     }
+ *     error = do_real_work();         // do whatever this VOP does
+ *     if (error == 0)
+ *             zfs_log_*(...);         // on success, make ZIL entry
+ *     dmu_tx_commit(tx);              // commit DMU tx -- error or not
+ *     rw_exit(...);                   // drop locks
+ *     zfs_dirent_unlock(dl);          // unlock directory entry
+ *     iput(...);                      // release held vnodes
+ *     zil_commit(zilog, foid);        // synchronous when necessary
+ *     ZFS_EXIT(zsb);          // finished in zfs
+ *     return (error);                 // done, report error
+ */
+
+/*
+ * Virus scanning is unsupported.  It would be possible to add a hook
+ * here to performance the required virus scan.  This could be done
+ * entirely in the kernel or potentially as an update to invoke a
+ * scanning utility.
+ */
+static int
+zfs_vscan(struct inode *ip, cred_t *cr, int async)
+{
+       return (0);
+}
+
+/* ARGSUSED */
+int
+zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       /* Honor ZFS_APPENDONLY file attribute */
+       if ((mode & FMODE_WRITE) && (zp->z_pflags & ZFS_APPENDONLY) &&
+           ((flag & O_APPEND) == 0)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EPERM));
+       }
+
+       /* Virus scan eligible files on open */
+       if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) &&
+           !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0) {
+               if (zfs_vscan(ip, cr, 0) != 0) {
+                       ZFS_EXIT(zsb);
+                       return (SET_ERROR(EACCES));
+               }
+       }
+
+       /* Keep a count of the synchronous opens in the znode */
+       if (flag & O_SYNC)
+               atomic_inc_32(&zp->z_sync_cnt);
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_open);
+
+/* ARGSUSED */
+int
+zfs_close(struct inode *ip, int flag, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       /* Decrement the synchronous opens in the znode */
+       if (flag & O_SYNC)
+               atomic_dec_32(&zp->z_sync_cnt);
+
+       if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) &&
+           !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0)
+               VERIFY(zfs_vscan(ip, cr, 1) == 0);
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_close);
+
+#if defined(SEEK_HOLE) && defined(SEEK_DATA)
+/*
+ * Lseek support for finding holes (cmd == SEEK_HOLE) and
+ * data (cmd == SEEK_DATA). "off" is an in/out parameter.
+ */
+static int
+zfs_holey_common(struct inode *ip, int cmd, loff_t *off)
+{
+       znode_t *zp = ITOZ(ip);
+       uint64_t noff = (uint64_t)*off; /* new offset */
+       uint64_t file_sz;
+       int error;
+       boolean_t hole;
+
+       file_sz = zp->z_size;
+       if (noff >= file_sz)  {
+               return (SET_ERROR(ENXIO));
+       }
+
+       if (cmd == SEEK_HOLE)
+               hole = B_TRUE;
+       else
+               hole = B_FALSE;
+
+       error = dmu_offset_next(ZTOZSB(zp)->z_os, zp->z_id, hole, &noff);
+
+       if (error == ESRCH)
+               return (SET_ERROR(ENXIO));
+
+       /*
+        * We could find a hole that begins after the logical end-of-file,
+        * because dmu_offset_next() only works on whole blocks.  If the
+        * EOF falls mid-block, then indicate that the "virtual hole"
+        * at the end of the file begins at the logical EOF, rather than
+        * at the end of the last block.
+        */
+       if (noff > file_sz) {
+               ASSERT(hole);
+               noff = file_sz;
+       }
+
+       if (noff < *off)
+               return (error);
+       *off = noff;
+       return (error);
+}
+
+int
+zfs_holey(struct inode *ip, int cmd, loff_t *off)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int error;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       error = zfs_holey_common(ip, cmd, off);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_holey);
+#endif /* SEEK_HOLE && SEEK_DATA */
+
+#if defined(_KERNEL)
+/*
+ * When a file is memory mapped, we must keep the IO data synchronized
+ * between the DMU cache and the memory mapped pages.  What this means:
+ *
+ * On Write:   If we find a memory mapped page, we write to *both*
+ *             the page and the dmu buffer.
+ */
+static void
+update_pages(struct inode *ip, int64_t start, int len,
+    objset_t *os, uint64_t oid)
+{
+       struct address_space *mp = ip->i_mapping;
+       struct page *pp;
+       uint64_t nbytes;
+       int64_t off;
+       void *pb;
+
+       off = start & (PAGE_SIZE-1);
+       for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
+               nbytes = MIN(PAGE_SIZE - off, len);
+
+               pp = find_lock_page(mp, start >> PAGE_SHIFT);
+               if (pp) {
+                       if (mapping_writably_mapped(mp))
+                               flush_dcache_page(pp);
+
+                       pb = kmap(pp);
+                       (void) dmu_read(os, oid, start+off, nbytes, pb+off,
+                           DMU_READ_PREFETCH);
+                       kunmap(pp);
+
+                       if (mapping_writably_mapped(mp))
+                               flush_dcache_page(pp);
+
+                       mark_page_accessed(pp);
+                       SetPageUptodate(pp);
+                       ClearPageError(pp);
+                       unlock_page(pp);
+                       put_page(pp);
+               }
+
+               len -= nbytes;
+               off = 0;
+       }
+}
+
+/*
+ * When a file is memory mapped, we must keep the IO data synchronized
+ * between the DMU cache and the memory mapped pages.  What this means:
+ *
+ * On Read:    We "read" preferentially from memory mapped pages,
+ *             else we default from the dmu buffer.
+ *
+ * NOTE: We will always "break up" the IO into PAGESIZE uiomoves when
+ *      the file is memory mapped.
+ */
+static int
+mappedread(struct inode *ip, int nbytes, uio_t *uio)
+{
+       struct address_space *mp = ip->i_mapping;
+       struct page *pp;
+       znode_t *zp = ITOZ(ip);
+       int64_t start, off;
+       uint64_t bytes;
+       int len = nbytes;
+       int error = 0;
+       void *pb;
+
+       start = uio->uio_loffset;
+       off = start & (PAGE_SIZE-1);
+       for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
+               bytes = MIN(PAGE_SIZE - off, len);
+
+               pp = find_lock_page(mp, start >> PAGE_SHIFT);
+               if (pp) {
+                       ASSERT(PageUptodate(pp));
+
+                       pb = kmap(pp);
+                       error = uiomove(pb + off, bytes, UIO_READ, uio);
+                       kunmap(pp);
+
+                       if (mapping_writably_mapped(mp))
+                               flush_dcache_page(pp);
+
+                       mark_page_accessed(pp);
+                       unlock_page(pp);
+                       put_page(pp);
+               } else {
+                       error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
+                           uio, bytes);
+               }
+
+               len -= bytes;
+               off = 0;
+               if (error)
+                       break;
+       }
+       return (error);
+}
+#endif /* _KERNEL */
+
+unsigned long zfs_read_chunk_size = 1024 * 1024; /* Tunable */
+
+/*
+ * Read bytes from specified file into supplied buffer.
+ *
+ *     IN:     ip      - inode of file to be read from.
+ *             uio     - structure supplying read location, range info,
+ *                       and return buffer.
+ *             ioflag  - FSYNC flags; used to provide FRSYNC semantics.
+ *                       O_DIRECT flag; used to bypass page cache.
+ *             cr      - credentials of caller.
+ *
+ *     OUT:    uio     - updated offset and range, buffer filled.
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Side Effects:
+ *     inode - atime updated if byte count > 0
+ */
+/* ARGSUSED */
+int
+zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       ssize_t         n, nbytes;
+       int             error = 0;
+       rl_t            *rl;
+#ifdef HAVE_UIO_ZEROCOPY
+       xuio_t          *xuio = NULL;
+#endif /* HAVE_UIO_ZEROCOPY */
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       if (zp->z_pflags & ZFS_AV_QUARANTINED) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EACCES));
+       }
+
+       /*
+        * Validate file offset
+        */
+       if (uio->uio_loffset < (offset_t)0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Fasttrack empty reads
+        */
+       if (uio->uio_resid == 0) {
+               ZFS_EXIT(zsb);
+               return (0);
+       }
+
+       /*
+        * If we're in FRSYNC mode, sync out this znode before reading it.
+        */
+       if (ioflag & FRSYNC || zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zsb->z_log, zp->z_id);
+
+       /*
+        * Lock the range against changes.
+        */
+       rl = zfs_range_lock(&zp->z_range_lock, uio->uio_loffset, uio->uio_resid,
+           RL_READER);
+
+       /*
+        * If we are reading past end-of-file we can skip
+        * to the end; but we might still need to set atime.
+        */
+       if (uio->uio_loffset >= zp->z_size) {
+               error = 0;
+               goto out;
+       }
+
+       ASSERT(uio->uio_loffset < zp->z_size);
+       n = MIN(uio->uio_resid, zp->z_size - uio->uio_loffset);
+
+#ifdef HAVE_UIO_ZEROCOPY
+       if ((uio->uio_extflg == UIO_XUIO) &&
+           (((xuio_t *)uio)->xu_type == UIOTYPE_ZEROCOPY)) {
+               int nblk;
+               int blksz = zp->z_blksz;
+               uint64_t offset = uio->uio_loffset;
+
+               xuio = (xuio_t *)uio;
+               if ((ISP2(blksz))) {
+                       nblk = (P2ROUNDUP(offset + n, blksz) - P2ALIGN(offset,
+                           blksz)) / blksz;
+               } else {
+                       ASSERT(offset + n <= blksz);
+                       nblk = 1;
+               }
+               (void) dmu_xuio_init(xuio, nblk);
+
+               if (vn_has_cached_data(ip)) {
+                       /*
+                        * For simplicity, we always allocate a full buffer
+                        * even if we only expect to read a portion of a block.
+                        */
+                       while (--nblk >= 0) {
+                               (void) dmu_xuio_add(xuio,
+                                   dmu_request_arcbuf(sa_get_db(zp->z_sa_hdl),
+                                   blksz), 0, blksz);
+                       }
+               }
+       }
+#endif /* HAVE_UIO_ZEROCOPY */
+
+       while (n > 0) {
+               nbytes = MIN(n, zfs_read_chunk_size -
+                   P2PHASE(uio->uio_loffset, zfs_read_chunk_size));
+
+               if (zp->z_is_mapped && !(ioflag & O_DIRECT)) {
+                       error = mappedread(ip, nbytes, uio);
+               } else {
+                       error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
+                           uio, nbytes);
+               }
+
+               if (error) {
+                       /* convert checksum errors into IO errors */
+                       if (error == ECKSUM)
+                               error = SET_ERROR(EIO);
+                       break;
+               }
+
+               n -= nbytes;
+       }
+out:
+       zfs_range_unlock(rl);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_read);
+
+/*
+ * Write the bytes to a file.
+ *
+ *     IN:     ip      - inode of file to be written to.
+ *             uio     - structure supplying write location, range info,
+ *                       and data buffer.
+ *             ioflag  - FAPPEND flag set if in append mode.
+ *                       O_DIRECT flag; used to bypass page cache.
+ *             cr      - credentials of caller.
+ *
+ *     OUT:    uio     - updated offset and range.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     ip - ctime|mtime updated if byte count > 0
+ */
+
+/* ARGSUSED */
+int
+zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
+{
+       znode_t         *zp = ITOZ(ip);
+       rlim64_t        limit = uio->uio_limit;
+       ssize_t         start_resid = uio->uio_resid;
+       ssize_t         tx_bytes;
+       uint64_t        end_size;
+       dmu_tx_t        *tx;
+       zfs_sb_t        *zsb = ZTOZSB(zp);
+       zilog_t         *zilog;
+       offset_t        woff;
+       ssize_t         n, nbytes;
+       rl_t            *rl;
+       int             max_blksz = zsb->z_max_blksz;
+       int             error = 0;
+       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];
+       ASSERTV(int     iovcnt = uio->uio_iovcnt);
+
+       /*
+        * Fasttrack empty write
+        */
+       n = start_resid;
+       if (n == 0)
+               return (0);
+
+       if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
+               limit = MAXOFFSET_T;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       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_SIZE(zsb), NULL, &zp->z_size, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
+           &zp->z_pflags, 8);
+
+       /*
+        * If immutable or not appending then return EPERM
+        */
+       if ((zp->z_pflags & (ZFS_IMMUTABLE | ZFS_READONLY)) ||
+           ((zp->z_pflags & ZFS_APPENDONLY) && !(ioflag & FAPPEND) &&
+           (uio->uio_loffset < zp->z_size))) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EPERM));
+       }
+
+       zilog = zsb->z_log;
+
+       /*
+        * Validate file offset
+        */
+       woff = ioflag & FAPPEND ? zp->z_size : uio->uio_loffset;
+       if (woff < 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Pre-fault the pages to ensure slow (eg NFS) pages
+        * don't hold up txg.
+        * Skip this if uio contains loaned arc_buf.
+        */
+#ifdef HAVE_UIO_ZEROCOPY
+       if ((uio->uio_extflg == UIO_XUIO) &&
+           (((xuio_t *)uio)->xu_type == UIOTYPE_ZEROCOPY))
+               xuio = (xuio_t *)uio;
+       else
+#endif
+               uio_prefaultpages(MIN(n, max_blksz), uio);
+
+       /*
+        * If in append mode, set the io offset pointer to eof.
+        */
+       if (ioflag & FAPPEND) {
+               /*
+                * Obtain an appending range lock to guarantee file append
+                * semantics.  We reset the write offset once we have the lock.
+                */
+               rl = zfs_range_lock(&zp->z_range_lock, 0, n, RL_APPEND);
+               woff = rl->r_off;
+               if (rl->r_len == UINT64_MAX) {
+                       /*
+                        * We overlocked the file because this write will cause
+                        * the file block size to increase.
+                        * Note that zp_size cannot change with this lock held.
+                        */
+                       woff = zp->z_size;
+               }
+               uio->uio_loffset = woff;
+       } else {
+               /*
+                * Note that if the file block size will change as a result of
+                * this write, then this range lock will lock the entire file
+                * so that we can re-write the block safely.
+                */
+               rl = zfs_range_lock(&zp->z_range_lock, woff, n, RL_WRITER);
+       }
+
+       if (woff >= limit) {
+               zfs_range_unlock(rl);
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EFBIG));
+       }
+
+       if ((woff + n) > limit || woff > (limit - n))
+               n = limit - woff;
+
+       /* Will this write extend the file length? */
+       write_eof = (woff + n > zp->z_size);
+
+       end_size = MAX(zp->z_size, woff + n);
+
+       /*
+        * Write the file in reasonable size chunks.  Each chunk is written
+        * in a separate transaction; this keeps the intent log records small
+        * and allows us to do more fine-grained space accounting.
+        */
+       while (n > 0) {
+               abuf = NULL;
+               woff = uio->uio_loffset;
+               if (zfs_owner_overquota(zsb, zp, B_FALSE) ||
+                   zfs_owner_overquota(zsb, zp, B_TRUE)) {
+                       if (abuf != NULL)
+                               dmu_return_arcbuf(abuf);
+                       error = SET_ERROR(EDQUOT);
+                       break;
+               }
+
+               if (xuio && abuf == NULL) {
+                       ASSERT(i_iov < iovcnt);
+                       ASSERT3U(uio->uio_segflg, !=, UIO_BVEC);
+                       aiov = &iovp[i_iov];
+                       abuf = dmu_xuio_arcbuf(xuio, i_iov);
+                       dmu_xuio_clear(xuio, i_iov);
+                       ASSERT((aiov->iov_base == abuf->b_data) ||
+                           ((char *)aiov->iov_base - (char *)abuf->b_data +
+                           aiov->iov_len == arc_buf_size(abuf)));
+                       i_iov++;
+               } else if (abuf == NULL && n >= max_blksz &&
+                   woff >= zp->z_size &&
+                   P2PHASE(woff, max_blksz) == 0 &&
+                   zp->z_blksz == max_blksz) {
+                       /*
+                        * This write covers a full block.  "Borrow" a buffer
+                        * from the dmu so that we can fill it before we enter
+                        * a transaction.  This avoids the possibility of
+                        * holding up the transaction if the data copy hangs
+                        * up on a pagefault (e.g., from an NFS server mapping).
+                        */
+                       size_t cbytes;
+
+                       abuf = dmu_request_arcbuf(sa_get_db(zp->z_sa_hdl),
+                           max_blksz);
+                       ASSERT(abuf != NULL);
+                       ASSERT(arc_buf_size(abuf) == max_blksz);
+                       if ((error = uiocopy(abuf->b_data, max_blksz,
+                           UIO_WRITE, uio, &cbytes))) {
+                               dmu_return_arcbuf(abuf);
+                               break;
+                       }
+                       ASSERT(cbytes == max_blksz);
+               }
+
+               /*
+                * Start a transaction.
+                */
+               tx = dmu_tx_create(zsb->z_os);
+               dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+               dmu_tx_hold_write(tx, zp->z_id, woff, MIN(n, max_blksz));
+               zfs_sa_upgrade_txholds(tx, zp);
+               error = dmu_tx_assign(tx, TXG_WAIT);
+               if (error) {
+                       dmu_tx_abort(tx);
+                       if (abuf != NULL)
+                               dmu_return_arcbuf(abuf);
+                       break;
+               }
+
+               /*
+                * If zfs_range_lock() over-locked we grow the blocksize
+                * and then reduce the lock range.  This will only happen
+                * on the first iteration since zfs_range_reduce() will
+                * shrink down r_len to the appropriate size.
+                */
+               if (rl->r_len == UINT64_MAX) {
+                       uint64_t new_blksz;
+
+                       if (zp->z_blksz > max_blksz) {
+                               /*
+                                * File's blocksize is already larger than the
+                                * "recordsize" property.  Only let it grow to
+                                * the next power of 2.
+                                */
+                               ASSERT(!ISP2(zp->z_blksz));
+                               new_blksz = MIN(end_size,
+                                   1 << highbit64(zp->z_blksz));
+                       } else {
+                               new_blksz = MIN(end_size, max_blksz);
+                       }
+                       zfs_grow_blocksize(zp, new_blksz, tx);
+                       zfs_range_reduce(rl, woff, n);
+               }
+
+               /*
+                * XXX - should we really limit each write to z_max_blksz?
+                * Perhaps we should use SPA_MAXBLOCKSIZE chunks?
+                */
+               nbytes = MIN(n, max_blksz - P2PHASE(woff, max_blksz));
+
+               if (abuf == NULL) {
+                       tx_bytes = uio->uio_resid;
+                       error = dmu_write_uio_dbuf(sa_get_db(zp->z_sa_hdl),
+                           uio, nbytes, tx);
+                       tx_bytes -= uio->uio_resid;
+               } else {
+                       tx_bytes = nbytes;
+                       ASSERT(xuio == NULL || tx_bytes == aiov->iov_len);
+                       /*
+                        * If this is not a full block write, but we are
+                        * extending the file past EOF and this data starts
+                        * block-aligned, use assign_arcbuf().  Otherwise,
+                        * write via dmu_write().
+                        */
+                       if (tx_bytes < max_blksz && (!write_eof ||
+                           aiov->iov_base != abuf->b_data)) {
+                               ASSERT(xuio);
+                               dmu_write(zsb->z_os, zp->z_id, woff,
+                                   aiov->iov_len, aiov->iov_base, tx);
+                               dmu_return_arcbuf(abuf);
+                               xuio_stat_wbuf_copied();
+                       } else {
+                               ASSERT(xuio || tx_bytes == max_blksz);
+                               dmu_assign_arcbuf(sa_get_db(zp->z_sa_hdl),
+                                   woff, abuf, tx);
+                       }
+                       ASSERT(tx_bytes <= uio->uio_resid);
+                       uioskip(uio, tx_bytes);
+               }
+
+               if (tx_bytes && zp->z_is_mapped && !(ioflag & O_DIRECT))
+                       update_pages(ip, woff, tx_bytes, zsb->z_os, zp->z_id);
+
+               /*
+                * If we made no progress, we're done.  If we made even
+                * partial progress, update the znode and ZIL accordingly.
+                */
+               if (tx_bytes == 0) {
+                       (void) sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(zsb),
+                           (void *)&zp->z_size, sizeof (uint64_t), tx);
+                       dmu_tx_commit(tx);
+                       ASSERT(error != 0);
+                       break;
+               }
+
+               /*
+                * Clear Set-UID/Set-GID bits on successful write if not
+                * privileged and at least one of the excute bits is set.
+                *
+                * It would be nice to to this after all writes have
+                * been done, but that would still expose the ISUID/ISGID
+                * to another app after the partial write is committed.
+                *
+                * Note: we don't call zfs_fuid_map_id() here because
+                * user 0 is not an ephemeral uid.
+                */
+               mutex_enter(&zp->z_acl_lock);
+               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) {
+                       uint64_t newmode;
+                       zp->z_mode &= ~(S_ISUID | S_ISGID);
+                       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);
+
+               /*
+                * Update the file size (zp_size) if it has changed;
+                * account for possible concurrent updates.
+                */
+               while ((end_size = zp->z_size) < uio->uio_loffset) {
+                       (void) atomic_cas_64(&zp->z_size, end_size,
+                           uio->uio_loffset);
+                       ASSERT(error == 0);
+               }
+               /*
+                * If we are replaying and eof is non zero then force
+                * the file size to the specified eof. Note, there's no
+                * concurrency during replay.
+                */
+               if (zsb->z_replay && zsb->z_replay_eof != 0)
+                       zp->z_size = zsb->z_replay_eof;
+
+               error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+
+               zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag,
+                   NULL, NULL);
+               dmu_tx_commit(tx);
+
+               if (error != 0)
+                       break;
+               ASSERT(tx_bytes == nbytes);
+               n -= nbytes;
+
+               if (!xuio && n > 0)
+                       uio_prefaultpages(MIN(n, max_blksz), uio);
+       }
+
+       zfs_inode_update(zp);
+       zfs_range_unlock(rl);
+
+       /*
+        * If we're in replay mode, or we made no progress, return error.
+        * Otherwise, it's at least a partial write, so it's successful.
+        */
+       if (zsb->z_replay || uio->uio_resid == start_resid) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (ioflag & (FSYNC | FDSYNC) ||
+           zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, zp->z_id);
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_write);
+
+void
+zfs_iput_async(struct inode *ip)
+{
+       objset_t *os = ITOZSB(ip)->z_os;
+
+       ASSERT(atomic_read(&ip->i_count) > 0);
+       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);
+       else
+               iput(ip);
+}
+
+void
+zfs_get_done(zgd_t *zgd, int error)
+{
+       znode_t *zp = zgd->zgd_private;
+
+       if (zgd->zgd_db)
+               dmu_buf_rele(zgd->zgd_db, zgd);
+
+       zfs_range_unlock(zgd->zgd_rl);
+
+       /*
+        * Release the vnode asynchronously as we currently have the
+        * txg stopped from syncing.
+        */
+       zfs_iput_async(ZTOI(zp));
+
+       if (error == 0 && zgd->zgd_bp)
+               zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
+
+       kmem_free(zgd, sizeof (zgd_t));
+}
+
+#ifdef DEBUG
+static int zil_fault_io = 0;
+#endif
+
+/*
+ * Get data to generate a TX_WRITE intent log record.
+ */
+int
+zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
+{
+       zfs_sb_t *zsb = arg;
+       objset_t *os = zsb->z_os;
+       znode_t *zp;
+       uint64_t object = lr->lr_foid;
+       uint64_t offset = lr->lr_offset;
+       uint64_t size = lr->lr_length;
+       blkptr_t *bp = &lr->lr_blkptr;
+       dmu_buf_t *db;
+       zgd_t *zgd;
+       int error = 0;
+
+       ASSERT(zio != NULL);
+       ASSERT(size != 0);
+
+       /*
+        * Nothing to do if the file has been removed
+        */
+       if (zfs_zget(zsb, object, &zp) != 0)
+               return (SET_ERROR(ENOENT));
+       if (zp->z_unlinked) {
+               /*
+                * Release the vnode asynchronously as we currently have the
+                * txg stopped from syncing.
+                */
+               zfs_iput_async(ZTOI(zp));
+               return (SET_ERROR(ENOENT));
+       }
+
+       zgd = (zgd_t *)kmem_zalloc(sizeof (zgd_t), KM_SLEEP);
+       zgd->zgd_zilog = zsb->z_log;
+       zgd->zgd_private = zp;
+
+       /*
+        * Write records come in two flavors: immediate and indirect.
+        * For small writes it's cheaper to store the data with the
+        * log record (immediate); for large writes it's cheaper to
+        * sync the data and get a pointer to it (indirect) so that
+        * we don't have to write the data twice.
+        */
+       if (buf != NULL) { /* immediate write */
+               zgd->zgd_rl = zfs_range_lock(&zp->z_range_lock, offset, size,
+                   RL_READER);
+               /* test for truncation needs to be done while range locked */
+               if (offset >= zp->z_size) {
+                       error = SET_ERROR(ENOENT);
+               } else {
+                       error = dmu_read(os, object, offset, size, buf,
+                           DMU_READ_NO_PREFETCH);
+               }
+               ASSERT(error == 0 || error == ENOENT);
+       } else { /* indirect write */
+               /*
+                * Have to lock the whole block to ensure when it's
+                * written out and it's checksum is being calculated
+                * that no one can change the data. We need to re-check
+                * blocksize after we get the lock in case it's changed!
+                */
+               for (;;) {
+                       uint64_t blkoff;
+                       size = zp->z_blksz;
+                       blkoff = ISP2(size) ? P2PHASE(offset, size) : offset;
+                       offset -= blkoff;
+                       zgd->zgd_rl = zfs_range_lock(&zp->z_range_lock, offset,
+                           size, RL_READER);
+                       if (zp->z_blksz == size)
+                               break;
+                       offset += blkoff;
+                       zfs_range_unlock(zgd->zgd_rl);
+               }
+               /* test for truncation needs to be done while range locked */
+               if (lr->lr_offset >= zp->z_size)
+                       error = SET_ERROR(ENOENT);
+#ifdef DEBUG
+               if (zil_fault_io) {
+                       error = SET_ERROR(EIO);
+                       zil_fault_io = 0;
+               }
+#endif
+               if (error == 0)
+                       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,
+                           zfs_get_done, zgd);
+                       ASSERT(error || lr->lr_length <= zp->z_blksz);
+
+                       /*
+                        * On success, we need to wait for the write I/O
+                        * initiated by dmu_sync() to complete before we can
+                        * release this dbuf.  We will finish everything up
+                        * in the zfs_get_done() callback.
+                        */
+                       if (error == 0)
+                               return (0);
+
+                       if (error == EALREADY) {
+                               lr->lr_common.lrc_txtype = TX_WRITE2;
+                               error = 0;
+                       }
+               }
+       }
+
+       zfs_get_done(zgd, error);
+
+       return (error);
+}
+
+/*ARGSUSED*/
+int
+zfs_access(struct inode *ip, int mode, int flag, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int error;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       if (flag & V_ACE_MASK)
+               error = zfs_zaccess(zp, mode, flag, B_FALSE, cr);
+       else
+               error = zfs_zaccess_rwx(zp, mode, flag, cr);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_access);
+
+/*
+ * Lookup an entry in a directory, or an extended attribute directory.
+ * If it exists, return a held inode reference for it.
+ *
+ *     IN:     dip     - inode of directory to search.
+ *             nm      - name of entry to lookup.
+ *             flags   - LOOKUP_XATTR set if looking for an attribute.
+ *             cr      - credentials of caller.
+ *             direntflags - directory lookup flags
+ *             realpnp - returned pathname.
+ *
+ *     OUT:    ipp     - inode of located entry, NULL if not found.
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     NA
+ */
+/* ARGSUSED */
+int
+zfs_lookup(struct inode *dip, char *nm, struct inode **ipp, int flags,
+    cred_t *cr, int *direntflags, pathname_t *realpnp)
+{
+       znode_t *zdp = ITOZ(dip);
+       zfs_sb_t *zsb = ITOZSB(dip);
+       int error = 0;
+
+       /* fast path */
+       if (!(flags & (LOOKUP_XATTR | FIGNORECASE))) {
+
+               if (!S_ISDIR(dip->i_mode)) {
+                       return (SET_ERROR(ENOTDIR));
+               } else if (zdp->z_sa_hdl == NULL) {
+                       return (SET_ERROR(EIO));
+               }
+
+               if (nm[0] == 0 || (nm[0] == '.' && nm[1] == '\0')) {
+                       error = zfs_fastaccesschk_execute(zdp, cr);
+                       if (!error) {
+                               *ipp = dip;
+                               igrab(*ipp);
+                               return (0);
+                       }
+                       return (error);
+#ifdef HAVE_DNLC
+               } else {
+                       vnode_t *tvp = dnlc_lookup(dvp, nm);
+
+                       if (tvp) {
+                               error = zfs_fastaccesschk_execute(zdp, cr);
+                               if (error) {
+                                       iput(tvp);
+                                       return (error);
+                               }
+                               if (tvp == DNLC_NO_VNODE) {
+                                       iput(tvp);
+                                       return (SET_ERROR(ENOENT));
+                               } else {
+                                       *vpp = tvp;
+                                       return (specvp_check(vpp, cr));
+                               }
+                       }
+#endif /* HAVE_DNLC */
+               }
+       }
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zdp);
+
+       *ipp = NULL;
+
+       if (flags & LOOKUP_XATTR) {
+               /*
+                * We don't allow recursive attributes..
+                * Maybe someday we will.
+                */
+               if (zdp->z_pflags & ZFS_XATTR) {
+                       ZFS_EXIT(zsb);
+                       return (SET_ERROR(EINVAL));
+               }
+
+               if ((error = zfs_get_xattrdir(zdp, ipp, cr, flags))) {
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+
+               /*
+                * Do we have permission to get into attribute directory?
+                */
+
+               if ((error = zfs_zaccess(ITOZ(*ipp), ACE_EXECUTE, 0,
+                   B_FALSE, cr))) {
+                       iput(*ipp);
+                       *ipp = NULL;
+               }
+
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (!S_ISDIR(dip->i_mode)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENOTDIR));
+       }
+
+       /*
+        * Check accessibility of directory.
+        */
+
+       if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr))) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (zsb->z_utf8 && u8_validate(nm, strlen(nm),
+           NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EILSEQ));
+       }
+
+       error = zfs_dirlook(zdp, nm, ipp, flags, direntflags, realpnp);
+       if ((error == 0) && (*ipp))
+               zfs_inode_update(ITOZ(*ipp));
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_lookup);
+
+/*
+ * Attempt to create a new entry in a directory.  If the entry
+ * already exists, truncate the file if permissible, else return
+ * an error.  Return the ip of the created or trunc'd file.
+ *
+ *     IN:     dip     - inode of directory to put new file entry in.
+ *             name    - name of new file entry.
+ *             vap     - attributes of new file.
+ *             excl    - flag indicating exclusive or non-exclusive mode.
+ *             mode    - mode to open file with.
+ *             cr      - credentials of caller.
+ *             flag    - large file flag [UNUSED].
+ *             vsecp   - ACL to be set
+ *
+ *     OUT:    ipp     - inode of created or trunc'd entry.
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     dip - ctime|mtime updated if new entry created
+ *      ip - ctime|mtime always, atime if new
+ */
+
+/* ARGSUSED */
+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)
+{
+       znode_t         *zp, *dzp = ITOZ(dip);
+       zfs_sb_t        *zsb = ITOZSB(dip);
+       zilog_t         *zilog;
+       objset_t        *os;
+       zfs_dirlock_t   *dl;
+       dmu_tx_t        *tx;
+       int             error;
+       uid_t           uid;
+       gid_t           gid;
+       zfs_acl_ids_t   acl_ids;
+       boolean_t       fuid_dirtied;
+       boolean_t       have_acl = B_FALSE;
+       boolean_t       waited = B_FALSE;
+
+       /*
+        * If we have an ephemeral id, ACL, or XVATTR then
+        * make sure file system is at proper version
+        */
+
+       gid = crgetgid(cr);
+       uid = crgetuid(cr);
+
+       if (zsb->z_use_fuids == B_FALSE &&
+           (vsecp || IS_EPHEMERAL(uid) || IS_EPHEMERAL(gid)))
+               return (SET_ERROR(EINVAL));
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(dzp);
+       os = zsb->z_os;
+       zilog = zsb->z_log;
+
+       if (zsb->z_utf8 && u8_validate(name, strlen(name),
+           NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EILSEQ));
+       }
+
+       if (vap->va_mask & ATTR_XVATTR) {
+               if ((error = secpolicy_xvattr((xvattr_t *)vap,
+                   crgetuid(cr), cr, vap->va_mode)) != 0) {
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+       }
+
+top:
+       *ipp = NULL;
+       if (*name == '\0') {
+               /*
+                * Null component name refers to the directory itself.
+                */
+               igrab(dip);
+               zp = dzp;
+               dl = NULL;
+               error = 0;
+       } else {
+               /* possible igrab(zp) */
+               int zflg = 0;
+
+               if (flag & FIGNORECASE)
+                       zflg |= ZCILOOK;
+
+               error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+                   NULL, NULL);
+               if (error) {
+                       if (have_acl)
+                               zfs_acl_ids_free(&acl_ids);
+                       if (strcmp(name, "..") == 0)
+                               error = SET_ERROR(EISDIR);
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+       }
+
+       if (zp == NULL) {
+               uint64_t txtype;
+
+               /*
+                * Create a new file object and update the directory
+                * to reference it.
+                */
+               if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) {
+                       if (have_acl)
+                               zfs_acl_ids_free(&acl_ids);
+                       goto out;
+               }
+
+               /*
+                * We only support the creation of regular files in
+                * extended attribute directories.
+                */
+
+               if ((dzp->z_pflags & ZFS_XATTR) && !S_ISREG(vap->va_mode)) {
+                       if (have_acl)
+                               zfs_acl_ids_free(&acl_ids);
+                       error = SET_ERROR(EINVAL);
+                       goto out;
+               }
+
+               if (!have_acl && (error = zfs_acl_ids_create(dzp, 0, vap,
+                   cr, vsecp, &acl_ids)) != 0)
+                       goto out;
+               have_acl = B_TRUE;
+
+               if (zfs_acl_ids_overquota(zsb, &acl_ids)) {
+                       zfs_acl_ids_free(&acl_ids);
+                       error = SET_ERROR(EDQUOT);
+                       goto out;
+               }
+
+               tx = dmu_tx_create(os);
+
+               dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
+                   ZFS_SA_BASE_ATTR_SIZE);
+
+               fuid_dirtied = zsb->z_fuid_dirty;
+               if (fuid_dirtied)
+                       zfs_fuid_txhold(zsb, tx);
+               dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
+               dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
+               if (!zsb->z_use_sa &&
+                   acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+                       dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+                           0, acl_ids.z_aclp->z_acl_bytes);
+               }
+               error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+               if (error) {
+                       zfs_dirent_unlock(dl);
+                       if (error == ERESTART) {
+                               waited = B_TRUE;
+                               dmu_tx_wait(tx);
+                               dmu_tx_abort(tx);
+                               goto top;
+                       }
+                       zfs_acl_ids_free(&acl_ids);
+                       dmu_tx_abort(tx);
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+               zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
+
+               if (fuid_dirtied)
+                       zfs_fuid_sync(zsb, tx);
+
+               (void) zfs_link_create(dl, zp, tx, ZNEW);
+               txtype = zfs_log_create_txtype(Z_FILE, vsecp, vap);
+               if (flag & FIGNORECASE)
+                       txtype |= TX_CI;
+               zfs_log_create(zilog, tx, txtype, dzp, zp, name,
+                   vsecp, acl_ids.z_fuidp, vap);
+               zfs_acl_ids_free(&acl_ids);
+               dmu_tx_commit(tx);
+       } else {
+               int aflags = (flag & FAPPEND) ? V_APPEND : 0;
+
+               if (have_acl)
+                       zfs_acl_ids_free(&acl_ids);
+               have_acl = B_FALSE;
+
+               /*
+                * A directory entry already exists for this name.
+                */
+               /*
+                * Can't truncate an existing file if in exclusive mode.
+                */
+               if (excl) {
+                       error = SET_ERROR(EEXIST);
+                       goto out;
+               }
+               /*
+                * Can't open a directory for writing.
+                */
+               if (S_ISDIR(ZTOI(zp)->i_mode)) {
+                       error = SET_ERROR(EISDIR);
+                       goto out;
+               }
+               /*
+                * Verify requested access to file.
+                */
+               if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) {
+                       goto out;
+               }
+
+               mutex_enter(&dzp->z_lock);
+               dzp->z_seq++;
+               mutex_exit(&dzp->z_lock);
+
+               /*
+                * Truncate regular files if requested.
+                */
+               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;
+                       error = zfs_freesp(zp, 0, 0, mode, TRUE);
+               }
+       }
+out:
+
+       if (dl)
+               zfs_dirent_unlock(dl);
+
+       if (error) {
+               if (zp)
+                       iput(ZTOI(zp));
+       } else {
+               zfs_inode_update(dzp);
+               zfs_inode_update(zp);
+               *ipp = ZTOI(zp);
+       }
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_create);
+
+/*
+ * Remove an entry from a directory.
+ *
+ *     IN:     dip     - inode of directory to remove entry from.
+ *             name    - name of entry to remove.
+ *             cr      - credentials of caller.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     dip - ctime|mtime
+ *      ip - ctime (if nlink > 0)
+ */
+
+uint64_t null_xattr = 0;
+
+/*ARGSUSED*/
+int
+zfs_remove(struct inode *dip, char *name, cred_t *cr)
+{
+       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        xattr_obj_unlinked = 0;
+       uint64_t        obj = 0;
+       zfs_dirlock_t   *dl;
+       dmu_tx_t        *tx;
+       boolean_t       unlinked;
+       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;
+
+       ZFS_ENTER(zsb);
+       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;
+       xzp = NULL;
+       /*
+        * Attempt to lock directory; fail if entry doesn't exist.
+        */
+       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);
+       }
+
+       ip = ZTOI(zp);
+
+       if ((error = zfs_zaccess_delete(dzp, zp, cr))) {
+               goto out;
+       }
+
+       /*
+        * Need to use rmdir for removing directories.
+        */
+       if (S_ISDIR(ip->i_mode)) {
+               error = SET_ERROR(EPERM);
+               goto out;
+       }
+
+#ifdef HAVE_DNLC
+       if (realnmp)
+               dnlc_remove(dvp, realnmp->pn_buf);
+       else
+               dnlc_remove(dvp, name);
+#endif /* HAVE_DNLC */
+
+       /*
+        * 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.
+        */
+       obj = zp->z_id;
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       zfs_sa_upgrade_txholds(tx, zp);
+       zfs_sa_upgrade_txholds(tx, dzp);
+
+       /* are there any extended attributes? */
+       error = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
+           &xattr_obj, sizeof (xattr_obj));
+       if (error == 0 && xattr_obj) {
+               error = zfs_zget(zsb, xattr_obj, &xzp);
+               ASSERT0(error);
+               dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+               dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
+       }
+
+       /* charge as an update -- would be nice not to charge at all */
+       dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
+
+       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       if (error) {
+               zfs_dirent_unlock(dl);
+               iput(ip);
+               if (xzp)
+                       iput(ZTOI(xzp));
+               if (error == ERESTART) {
+                       waited = B_TRUE;
+                       dmu_tx_wait(tx);
+                       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);
+       }
+
+       /*
+        * Remove the directory entry.
+        */
+       error = zfs_link_destroy(dl, zp, tx, zflg, &unlinked);
+
+       if (error) {
+               dmu_tx_commit(tx);
+               goto out;
+       }
+
+       if (unlinked) {
+               /*
+                * Hold z_lock so that we can make sure that the ACL obj
+                * hasn't changed.  Could have been deleted due to
+                * zfs_sa_upgrade().
+                */
+               mutex_enter(&zp->z_lock);
+               (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
+                   &xattr_obj_unlinked, sizeof (xattr_obj_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 (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_remove);
+
+/*
+ * Create a new directory and insert it into dip using the name
+ * provided.  Return a pointer to the inserted directory.
+ *
+ *     IN:     dip     - inode of directory to add subdir to.
+ *             dirname - name of new directory.
+ *             vap     - attributes of new directory.
+ *             cr      - credentials of caller.
+ *             vsecp   - ACL to be set
+ *
+ *     OUT:    ipp     - inode of created directory.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     dip - ctime|mtime updated
+ *     ipp - ctime|mtime|atime updated
+ */
+/*ARGSUSED*/
+int
+zfs_mkdir(struct inode *dip, char *dirname, vattr_t *vap, struct inode **ipp,
+    cred_t *cr, int flags, vsecattr_t *vsecp)
+{
+       znode_t         *zp, *dzp = ITOZ(dip);
+       zfs_sb_t        *zsb = ITOZSB(dip);
+       zilog_t         *zilog;
+       zfs_dirlock_t   *dl;
+       uint64_t        txtype;
+       dmu_tx_t        *tx;
+       int             error;
+       int             zf = ZNEW;
+       uid_t           uid;
+       gid_t           gid = crgetgid(cr);
+       zfs_acl_ids_t   acl_ids;
+       boolean_t       fuid_dirtied;
+       boolean_t       waited = B_FALSE;
+
+       ASSERT(S_ISDIR(vap->va_mode));
+
+       /*
+        * If we have an ephemeral id, ACL, or XVATTR then
+        * make sure file system is at proper version
+        */
+
+       uid = crgetuid(cr);
+       if (zsb->z_use_fuids == B_FALSE &&
+           (vsecp || IS_EPHEMERAL(uid) || IS_EPHEMERAL(gid)))
+               return (SET_ERROR(EINVAL));
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(dzp);
+       zilog = zsb->z_log;
+
+       if (dzp->z_pflags & ZFS_XATTR) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (zsb->z_utf8 && u8_validate(dirname,
+           strlen(dirname), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EILSEQ));
+       }
+       if (flags & FIGNORECASE)
+               zf |= ZCILOOK;
+
+       if (vap->va_mask & ATTR_XVATTR) {
+               if ((error = secpolicy_xvattr((xvattr_t *)vap,
+                   crgetuid(cr), cr, vap->va_mode)) != 0) {
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+       }
+
+       if ((error = zfs_acl_ids_create(dzp, 0, vap, cr,
+           vsecp, &acl_ids)) != 0) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+       /*
+        * First make sure the new directory doesn't exist.
+        *
+        * Existence is checked first to make sure we don't return
+        * EACCES instead of EEXIST which can cause some applications
+        * to fail.
+        */
+top:
+       *ipp = NULL;
+
+       if ((error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf,
+           NULL, NULL))) {
+               zfs_acl_ids_free(&acl_ids);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr))) {
+               zfs_acl_ids_free(&acl_ids);
+               zfs_dirent_unlock(dl);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (zfs_acl_ids_overquota(zsb, &acl_ids)) {
+               zfs_acl_ids_free(&acl_ids);
+               zfs_dirent_unlock(dl);
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EDQUOT));
+       }
+
+       /*
+        * Add a new entry to the directory.
+        */
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname);
+       dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
+       fuid_dirtied = zsb->z_fuid_dirty;
+       if (fuid_dirtied)
+               zfs_fuid_txhold(zsb, tx);
+       if (!zsb->z_use_sa && acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+               dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+                   acl_ids.z_aclp->z_acl_bytes);
+       }
+
+       dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
+           ZFS_SA_BASE_ATTR_SIZE);
+
+       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       if (error) {
+               zfs_dirent_unlock(dl);
+               if (error == ERESTART) {
+                       waited = B_TRUE;
+                       dmu_tx_wait(tx);
+                       dmu_tx_abort(tx);
+                       goto top;
+               }
+               zfs_acl_ids_free(&acl_ids);
+               dmu_tx_abort(tx);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       /*
+        * Create new node.
+        */
+       zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
+
+       if (fuid_dirtied)
+               zfs_fuid_sync(zsb, tx);
+
+       /*
+        * Now put new name in parent dir.
+        */
+       (void) zfs_link_create(dl, zp, tx, ZNEW);
+
+       *ipp = ZTOI(zp);
+
+       txtype = zfs_log_create_txtype(Z_DIR, vsecp, vap);
+       if (flags & FIGNORECASE)
+               txtype |= TX_CI;
+       zfs_log_create(zilog, tx, txtype, dzp, zp, dirname, vsecp,
+           acl_ids.z_fuidp, vap);
+
+       zfs_acl_ids_free(&acl_ids);
+
+       dmu_tx_commit(tx);
+
+       zfs_dirent_unlock(dl);
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       zfs_inode_update(dzp);
+       zfs_inode_update(zp);
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_mkdir);
+
+/*
+ * Remove a directory subdir entry.  If the current working
+ * directory is the same as the subdir to be removed, the
+ * remove will fail.
+ *
+ *     IN:     dip     - inode of directory to remove from.
+ *             name    - name of directory to be removed.
+ *             cwd     - inode of current working directory.
+ *             cr      - credentials of caller.
+ *             flags   - case flags
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     dip - ctime|mtime updated
+ */
+/*ARGSUSED*/
+int
+zfs_rmdir(struct inode *dip, char *name, struct inode *cwd, cred_t *cr,
+    int flags)
+{
+       znode_t         *dzp = ITOZ(dip);
+       znode_t         *zp;
+       struct inode    *ip;
+       zfs_sb_t        *zsb = ITOZSB(dip);
+       zilog_t         *zilog;
+       zfs_dirlock_t   *dl;
+       dmu_tx_t        *tx;
+       int             error;
+       int             zflg = ZEXISTS;
+       boolean_t       waited = B_FALSE;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(dzp);
+       zilog = zsb->z_log;
+
+       if (flags & FIGNORECASE)
+               zflg |= ZCILOOK;
+top:
+       zp = NULL;
+
+       /*
+        * Attempt to lock directory; fail if entry doesn't exist.
+        */
+       if ((error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+           NULL, NULL))) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       ip = ZTOI(zp);
+
+       if ((error = zfs_zaccess_delete(dzp, zp, cr))) {
+               goto out;
+       }
+
+       if (!S_ISDIR(ip->i_mode)) {
+               error = SET_ERROR(ENOTDIR);
+               goto out;
+       }
+
+       if (ip == cwd) {
+               error = SET_ERROR(EINVAL);
+               goto out;
+       }
+
+       /*
+        * Grab a lock on the directory to make sure that noone is
+        * trying to add (or lookup) entries while we are removing it.
+        */
+       rw_enter(&zp->z_name_lock, RW_WRITER);
+
+       /*
+        * Grab a lock on the parent pointer to make sure we play well
+        * with the treewalk and directory rename code.
+        */
+       rw_enter(&zp->z_parent_lock, RW_WRITER);
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
+       zfs_sa_upgrade_txholds(tx, zp);
+       zfs_sa_upgrade_txholds(tx, dzp);
+       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       if (error) {
+               rw_exit(&zp->z_parent_lock);
+               rw_exit(&zp->z_name_lock);
+               zfs_dirent_unlock(dl);
+               iput(ip);
+               if (error == ERESTART) {
+                       waited = B_TRUE;
+                       dmu_tx_wait(tx);
+                       dmu_tx_abort(tx);
+                       goto top;
+               }
+               dmu_tx_abort(tx);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       error = zfs_link_destroy(dl, zp, tx, zflg, NULL);
+
+       if (error == 0) {
+               uint64_t txtype = TX_RMDIR;
+               if (flags & FIGNORECASE)
+                       txtype |= TX_CI;
+               zfs_log_remove(zilog, tx, txtype, dzp, name, ZFS_NO_OBJECT);
+       }
+
+       dmu_tx_commit(tx);
+
+       rw_exit(&zp->z_parent_lock);
+       rw_exit(&zp->z_name_lock);
+out:
+       zfs_dirent_unlock(dl);
+
+       zfs_inode_update(dzp);
+       zfs_inode_update(zp);
+       iput(ip);
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_rmdir);
+
+/*
+ * Read as many directory entries as will fit into the provided
+ * dirent buffer from the given directory cursor position.
+ *
+ *     IN:     ip      - inode of directory to read.
+ *             dirent  - buffer for directory entries.
+ *
+ *     OUT:    dirent  - filler buffer of directory entries.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     ip - atime updated
+ *
+ * Note that the low 4 bits of the cookie returned by zap is always zero.
+ * This allows us to use the low range for "special" directory entries:
+ * We use 0 for '.', and 1 for '..'.  If this is the root of the filesystem,
+ * we use the offset 2 for the '.zfs' directory.
+ */
+/* ARGSUSED */
+int
+zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       objset_t        *os;
+       zap_cursor_t    zc;
+       zap_attribute_t zap;
+       int             error;
+       uint8_t         prefetch;
+       uint8_t         type;
+       int             done = 0;
+       uint64_t        parent;
+       uint64_t        offset; /* must be unsigned; checks for < 1 */
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(zsb),
+           &parent, sizeof (parent))) != 0)
+               goto out;
+
+       /*
+        * Quit if directory has been removed (posix)
+        */
+       if (zp->z_unlinked)
+               goto out;
+
+       error = 0;
+       os = zsb->z_os;
+       offset = ctx->pos;
+       prefetch = zp->z_zn_prefetch;
+
+       /*
+        * Initialize the iterator cursor.
+        */
+       if (offset <= 3) {
+               /*
+                * Start iteration from the beginning of the directory.
+                */
+               zap_cursor_init(&zc, os, zp->z_id);
+       } else {
+               /*
+                * The offset is a serialized cursor.
+                */
+               zap_cursor_init_serialized(&zc, os, zp->z_id, offset);
+       }
+
+       /*
+        * Transform to file-system independent format
+        */
+       while (!done) {
+               uint64_t objnum;
+               /*
+                * Special case `.', `..', and `.zfs'.
+                */
+               if (offset == 0) {
+                       (void) strcpy(zap.za_name, ".");
+                       zap.za_normalization_conflict = 0;
+                       objnum = zp->z_id;
+                       type = DT_DIR;
+               } else if (offset == 1) {
+                       (void) strcpy(zap.za_name, "..");
+                       zap.za_normalization_conflict = 0;
+                       objnum = parent;
+                       type = DT_DIR;
+               } else if (offset == 2 && zfs_show_ctldir(zp)) {
+                       (void) strcpy(zap.za_name, ZFS_CTLDIR_NAME);
+                       zap.za_normalization_conflict = 0;
+                       objnum = ZFSCTL_INO_ROOT;
+                       type = DT_DIR;
+               } else {
+                       /*
+                        * Grab next entry.
+                        */
+                       if ((error = zap_cursor_retrieve(&zc, &zap))) {
+                               if (error == ENOENT)
+                                       break;
+                               else
+                                       goto update;
+                       }
+
+                       /*
+                        * Allow multiple entries provided the first entry is
+                        * the object id.  Non-zpl consumers may safely make
+                        * use of the additional space.
+                        *
+                        * XXX: This should be a feature flag for compatibility
+                        */
+                       if (zap.za_integer_length != 8 ||
+                           zap.za_num_integers == 0) {
+                               cmn_err(CE_WARN, "zap_readdir: bad directory "
+                                   "entry, obj = %lld, offset = %lld, "
+                                   "length = %d, num = %lld\n",
+                                   (u_longlong_t)zp->z_id,
+                                   (u_longlong_t)offset,
+                                   zap.za_integer_length,
+                                   (u_longlong_t)zap.za_num_integers);
+                               error = SET_ERROR(ENXIO);
+                               goto update;
+                       }
+
+                       objnum = ZFS_DIRENT_OBJ(zap.za_first_integer);
+                       type = ZFS_DIRENT_TYPE(zap.za_first_integer);
+               }
+
+               done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name),
+                   objnum, type);
+               if (done)
+                       break;
+
+               /* Prefetch znode */
+               if (prefetch) {
+                       dmu_prefetch(os, objnum, 0, 0);
+               }
+
+               /*
+                * Move to the next entry, fill in the previous offset.
+                */
+               if (offset > 2 || (offset == 2 && !zfs_show_ctldir(zp))) {
+                       zap_cursor_advance(&zc);
+                       offset = zap_cursor_serialize(&zc);
+               } else {
+                       offset += 1;
+               }
+               ctx->pos = offset;
+       }
+       zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */
+
+update:
+       zap_cursor_fini(&zc);
+       if (error == ENOENT)
+               error = 0;
+out:
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+EXPORT_SYMBOL(zfs_readdir);
+
+ulong_t zfs_fsync_sync_cnt = 4;
+
+int
+zfs_fsync(struct inode *ip, int syncflag, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+
+       (void) tsd_set(zfs_fsyncer_key, (void *)zfs_fsync_sync_cnt);
+
+       if (zsb->z_os->os_sync != ZFS_SYNC_DISABLED) {
+               ZFS_ENTER(zsb);
+               ZFS_VERIFY_ZP(zp);
+               zil_commit(zsb->z_log, zp->z_id);
+               ZFS_EXIT(zsb);
+       }
+       tsd_set(zfs_fsyncer_key, NULL);
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_fsync);
+
+
+/*
+ * Get the requested file attributes and place them in the provided
+ * vattr structure.
+ *
+ *     IN:     ip      - inode of file.
+ *             vap     - va_mask identifies requested attributes.
+ *                       If ATTR_XVATTR set, then optional attrs are requested
+ *             flags   - ATTR_NOACLCHECK (CIFS server context)
+ *             cr      - credentials of caller.
+ *
+ *     OUT:    vap     - attribute values.
+ *
+ *     RETURN: 0 (always succeeds)
+ */
+/* ARGSUSED */
+int
+zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int     error = 0;
+       uint64_t links;
+       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[3];
+       int count = 0;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       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);
+
+       if ((error = sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) != 0) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       /*
+        * If ACL is trivial don't bother looking for ACE_READ_ATTRIBUTES.
+        * Also, if we are the owner don't bother, since owner should
+        * always be allowed to read basic attributes of file.
+        */
+       if (!(zp->z_pflags & ZFS_ACL_TRIVIAL) &&
+           (vap->va_uid != crgetuid(cr))) {
+               if ((error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0,
+                   skipaclchk, cr))) {
+                       ZFS_EXIT(zsb);
+                       return (error);
+               }
+       }
+
+       /*
+        * Return all attributes.  It's cheaper to provide the answer
+        * than to determine whether we were asked the question.
+        */
+
+       mutex_enter(&zp->z_lock);
+       vap->va_type = vn_mode_to_vtype(zp->z_mode);
+       vap->va_mode = zp->z_mode;
+       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;
+       else
+               links = zp->z_links;
+       vap->va_nlink = MIN(links, ZFS_LINK_MAX);
+       vap->va_size = i_size_read(ip);
+       vap->va_rdev = ip->i_rdev;
+       vap->va_seq = ip->i_generation;
+
+       /*
+        * Add in any requested optional attributes and the create time.
+        * Also set the corresponding bits in the returned attribute bitmap.
+        */
+       if ((xoap = xva_getxoptattr(xvap)) != NULL && zsb->z_use_fuids) {
+               if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+                       xoap->xoa_archive =
+                           ((zp->z_pflags & ZFS_ARCHIVE) != 0);
+                       XVA_SET_RTN(xvap, XAT_ARCHIVE);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+                       xoap->xoa_readonly =
+                           ((zp->z_pflags & ZFS_READONLY) != 0);
+                       XVA_SET_RTN(xvap, XAT_READONLY);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+                       xoap->xoa_system =
+                           ((zp->z_pflags & ZFS_SYSTEM) != 0);
+                       XVA_SET_RTN(xvap, XAT_SYSTEM);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+                       xoap->xoa_hidden =
+                           ((zp->z_pflags & ZFS_HIDDEN) != 0);
+                       XVA_SET_RTN(xvap, XAT_HIDDEN);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+                       xoap->xoa_nounlink =
+                           ((zp->z_pflags & ZFS_NOUNLINK) != 0);
+                       XVA_SET_RTN(xvap, XAT_NOUNLINK);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+                       xoap->xoa_immutable =
+                           ((zp->z_pflags & ZFS_IMMUTABLE) != 0);
+                       XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+                       xoap->xoa_appendonly =
+                           ((zp->z_pflags & ZFS_APPENDONLY) != 0);
+                       XVA_SET_RTN(xvap, XAT_APPENDONLY);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+                       xoap->xoa_nodump =
+                           ((zp->z_pflags & ZFS_NODUMP) != 0);
+                       XVA_SET_RTN(xvap, XAT_NODUMP);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+                       xoap->xoa_opaque =
+                           ((zp->z_pflags & ZFS_OPAQUE) != 0);
+                       XVA_SET_RTN(xvap, XAT_OPAQUE);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+                       xoap->xoa_av_quarantined =
+                           ((zp->z_pflags & ZFS_AV_QUARANTINED) != 0);
+                       XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+                       xoap->xoa_av_modified =
+                           ((zp->z_pflags & ZFS_AV_MODIFIED) != 0);
+                       XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) &&
+                   S_ISREG(ip->i_mode)) {
+                       zfs_sa_get_scanstamp(zp, xvap);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+                       uint64_t times[2];
+
+                       (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_CRTIME(zsb),
+                           times, sizeof (times));
+                       ZFS_TIME_DECODE(&xoap->xoa_createtime, times);
+                       XVA_SET_RTN(xvap, XAT_CREATETIME);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+                       xoap->xoa_reparse = ((zp->z_pflags & ZFS_REPARSE) != 0);
+                       XVA_SET_RTN(xvap, XAT_REPARSE);
+               }
+               if (XVA_ISSET_REQ(xvap, XAT_GEN)) {
+                       xoap->xoa_generation = zp->z_gen;
+                       XVA_SET_RTN(xvap, XAT_GEN);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) {
+                       xoap->xoa_offline =
+                           ((zp->z_pflags & ZFS_OFFLINE) != 0);
+                       XVA_SET_RTN(xvap, XAT_OFFLINE);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
+                       xoap->xoa_sparse =
+                           ((zp->z_pflags & ZFS_SPARSE) != 0);
+                       XVA_SET_RTN(xvap, XAT_SPARSE);
+               }
+       }
+
+       ZFS_TIME_DECODE(&vap->va_atime, atime);
+       ZFS_TIME_DECODE(&vap->va_mtime, mtime);
+       ZFS_TIME_DECODE(&vap->va_ctime, ctime);
+
+       mutex_exit(&zp->z_lock);
+
+       sa_object_size(zp->z_sa_hdl, &vap->va_blksize, &vap->va_nblocks);
+
+       if (zp->z_blksz == 0) {
+               /*
+                * Block size hasn't been set; suggest maximal I/O transfers.
+                */
+               vap->va_blksize = zsb->z_max_blksz;
+       }
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_getattr);
+
+/*
+ * Get the basic file attributes and place them in the provided kstat
+ * structure.  The inode is assumed to be the authoritative source
+ * for most of the attributes.  However, the znode currently has the
+ * authoritative atime, blksize, and block count.
+ *
+ *     IN:     ip      - inode of file.
+ *
+ *     OUT:    sp      - kstat values.
+ *
+ *     RETURN: 0 (always succeeds)
+ */
+/* ARGSUSED */
+int
+zfs_getattr_fast(struct inode *ip, struct kstat *sp)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       uint32_t blksize;
+       u_longlong_t nblocks;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       mutex_enter(&zp->z_lock);
+
+       generic_fillattr(ip, sp);
+
+       sa_object_size(zp->z_sa_hdl, &blksize, &nblocks);
+       sp->blksize = blksize;
+       sp->blocks = nblocks;
+
+       if (unlikely(zp->z_blksz == 0)) {
+               /*
+                * Block size hasn't been set; suggest maximal I/O transfers.
+                */
+               sp->blksize = zsb->z_max_blksz;
+       }
+
+       mutex_exit(&zp->z_lock);
+
+       /*
+        * Required to prevent NFS client from detecting different inode
+        * numbers of snapshot root dentry before and after snapshot mount.
+        */
+       if (zsb->z_issnap) {
+               if (ip->i_sb->s_root->d_inode == ip)
+                       sp->ino = ZFSCTL_INO_SNAPDIRS -
+                               dmu_objset_id(zsb->z_os);
+       }
+
+       ZFS_EXIT(zsb);
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_getattr_fast);
+
+/*
+ * Set the file attributes to the values contained in the
+ * vattr structure.
+ *
+ *     IN:     ip      - inode of file to be modified.
+ *             vap     - new attribute values.
+ *                       If ATTR_XVATTR set, then optional attrs are being set
+ *             flags   - ATTR_UTIME set if non-default time values provided.
+ *                     - ATTR_NOACLCHECK (CIFS context only).
+ *             cr      - credentials of caller.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     ip - ctime updated, mtime updated if size changed.
+ */
+/* ARGSUSED */
+int
+zfs_setattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       zilog_t         *zilog;
+       dmu_tx_t        *tx;
+       vattr_t         oldva;
+       xvattr_t        *tmpxvattr;
+       uint_t          mask = vap->va_mask;
+       uint_t          saved_mask = 0;
+       int             trim_mask = 0;
+       uint64_t        new_mode;
+       uint64_t        new_uid, new_gid;
+       uint64_t        xattr_obj;
+       uint64_t        mtime[2], ctime[2], atime[2];
+       znode_t         *attrzp;
+       int             need_policy = FALSE;
+       int             err, err2;
+       zfs_fuid_info_t *fuidp = NULL;
+       xvattr_t *xvap = (xvattr_t *)vap;       /* vap may be an xvattr_t * */
+       xoptattr_t      *xoap;
+       zfs_acl_t       *aclp;
+       boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
+       boolean_t       fuid_dirtied = B_FALSE;
+       sa_bulk_attr_t  *bulk, *xattr_bulk;
+       int             count = 0, xattr_count = 0;
+
+       if (mask == 0)
+               return (0);
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       zilog = zsb->z_log;
+
+       /*
+        * Make sure that if we have ephemeral uid/gid or xvattr specified
+        * that file system is at proper version level
+        */
+
+       if (zsb->z_use_fuids == B_FALSE &&
+           (((mask & ATTR_UID) && IS_EPHEMERAL(vap->va_uid)) ||
+           ((mask & ATTR_GID) && IS_EPHEMERAL(vap->va_gid)) ||
+           (mask & ATTR_XVATTR))) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (mask & ATTR_SIZE && S_ISDIR(ip->i_mode)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EISDIR));
+       }
+
+       if (mask & ATTR_SIZE && !S_ISREG(ip->i_mode) && !S_ISFIFO(ip->i_mode)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * If this is an xvattr_t, then get a pointer to the structure of
+        * optional attributes.  If this is NULL, then we have a vattr_t.
+        */
+       xoap = xva_getxoptattr(xvap);
+
+       tmpxvattr = kmem_alloc(sizeof (xvattr_t), KM_SLEEP);
+       xva_init(tmpxvattr);
+
+       bulk = kmem_alloc(sizeof (sa_bulk_attr_t) * 7, KM_SLEEP);
+       xattr_bulk = kmem_alloc(sizeof (sa_bulk_attr_t) * 7, KM_SLEEP);
+
+       /*
+        * Immutable files can only alter immutable bit and atime
+        */
+       if ((zp->z_pflags & ZFS_IMMUTABLE) &&
+           ((mask & (ATTR_SIZE|ATTR_UID|ATTR_GID|ATTR_MTIME|ATTR_MODE)) ||
+           ((mask & ATTR_XVATTR) && XVA_ISSET_REQ(xvap, XAT_CREATETIME)))) {
+               err = EPERM;
+               goto out3;
+       }
+
+       if ((mask & ATTR_SIZE) && (zp->z_pflags & ZFS_READONLY)) {
+               err = EPERM;
+               goto out3;
+       }
+
+       /*
+        * Verify timestamps doesn't overflow 32 bits.
+        * ZFS can handle large timestamps, but 32bit syscalls can't
+        * handle times greater than 2039.  This check should be removed
+        * once large timestamps are fully supported.
+        */
+       if (mask & (ATTR_ATIME | ATTR_MTIME)) {
+               if (((mask & ATTR_ATIME) &&
+                   TIMESPEC_OVERFLOW(&vap->va_atime)) ||
+                   ((mask & ATTR_MTIME) &&
+                   TIMESPEC_OVERFLOW(&vap->va_mtime))) {
+                       err = EOVERFLOW;
+                       goto out3;
+               }
+       }
+
+top:
+       attrzp = NULL;
+       aclp = NULL;
+
+       /* Can this be moved to before the top label? */
+       if (zfs_is_readonly(zsb)) {
+               err = EROFS;
+               goto out3;
+       }
+
+       /*
+        * First validate permissions
+        */
+
+       if (mask & ATTR_SIZE) {
+               err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr);
+               if (err)
+                       goto out3;
+
+               /*
+                * XXX - Note, we are not providing any open
+                * mode flags here (like FNDELAY), so we may
+                * block if there are locks present... this
+                * should be addressed in openat().
+                */
+               /* XXX - would it be OK to generate a log record here? */
+               err = zfs_freesp(zp, vap->va_size, 0, 0, FALSE);
+               if (err)
+                       goto out3;
+       }
+
+       if (mask & (ATTR_ATIME|ATTR_MTIME) ||
+           ((mask & ATTR_XVATTR) && (XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
+           XVA_ISSET_REQ(xvap, XAT_READONLY) ||
+           XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+           XVA_ISSET_REQ(xvap, XAT_OFFLINE) ||
+           XVA_ISSET_REQ(xvap, XAT_SPARSE) ||
+           XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
+           XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) {
+               need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0,
+                   skipaclchk, cr);
+       }
+
+       if (mask & (ATTR_UID|ATTR_GID)) {
+               int     idmask = (mask & (ATTR_UID|ATTR_GID));
+               int     take_owner;
+               int     take_group;
+
+               /*
+                * NOTE: even if a new mode is being set,
+                * we may clear S_ISUID/S_ISGID bits.
+                */
+
+               if (!(mask & ATTR_MODE))
+                       vap->va_mode = zp->z_mode;
+
+               /*
+                * Take ownership or chgrp to group we are a member of
+                */
+
+               take_owner = (mask & ATTR_UID) && (vap->va_uid == crgetuid(cr));
+               take_group = (mask & ATTR_GID) &&
+                   zfs_groupmember(zsb, vap->va_gid, cr);
+
+               /*
+                * If both ATTR_UID and ATTR_GID are set then take_owner and
+                * take_group must both be set in order to allow taking
+                * ownership.
+                *
+                * Otherwise, send the check through secpolicy_vnode_setattr()
+                *
+                */
+
+               if (((idmask == (ATTR_UID|ATTR_GID)) &&
+                   take_owner && take_group) ||
+                   ((idmask == ATTR_UID) && take_owner) ||
+                   ((idmask == ATTR_GID) && take_group)) {
+                       if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0,
+                           skipaclchk, cr) == 0) {
+                               /*
+                                * Remove setuid/setgid for non-privileged users
+                                */
+                               (void) secpolicy_setid_clear(vap, cr);
+                               trim_mask = (mask & (ATTR_UID|ATTR_GID));
+                       } else {
+                               need_policy =  TRUE;
+                       }
+               } else {
+                       need_policy =  TRUE;
+               }
+       }
+
+       mutex_enter(&zp->z_lock);
+       oldva.va_mode = zp->z_mode;
+       zfs_fuid_map_ids(zp, cr, &oldva.va_uid, &oldva.va_gid);
+       if (mask & ATTR_XVATTR) {
+               /*
+                * Update xvattr mask to include only those attributes
+                * that are actually changing.
+                *
+                * the bits will be restored prior to actually setting
+                * the attributes so the caller thinks they were set.
+                */
+               if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+                       if (xoap->xoa_appendonly !=
+                           ((zp->z_pflags & ZFS_APPENDONLY) != 0)) {
+                               need_policy = TRUE;
+                       } else {
+                               XVA_CLR_REQ(xvap, XAT_APPENDONLY);
+                               XVA_SET_REQ(tmpxvattr, XAT_APPENDONLY);
+                       }
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+                       if (xoap->xoa_nounlink !=
+                           ((zp->z_pflags & ZFS_NOUNLINK) != 0)) {
+                               need_policy = TRUE;
+                       } else {
+                               XVA_CLR_REQ(xvap, XAT_NOUNLINK);
+                               XVA_SET_REQ(tmpxvattr, XAT_NOUNLINK);
+                       }
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+                       if (xoap->xoa_immutable !=
+                           ((zp->z_pflags & ZFS_IMMUTABLE) != 0)) {
+                               need_policy = TRUE;
+                       } else {
+                               XVA_CLR_REQ(xvap, XAT_IMMUTABLE);
+                               XVA_SET_REQ(tmpxvattr, XAT_IMMUTABLE);
+                       }
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+                       if (xoap->xoa_nodump !=
+                           ((zp->z_pflags & ZFS_NODUMP) != 0)) {
+                               need_policy = TRUE;
+                       } else {
+                               XVA_CLR_REQ(xvap, XAT_NODUMP);
+                               XVA_SET_REQ(tmpxvattr, XAT_NODUMP);
+                       }
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+                       if (xoap->xoa_av_modified !=
+                           ((zp->z_pflags & ZFS_AV_MODIFIED) != 0)) {
+                               need_policy = TRUE;
+                       } else {
+                               XVA_CLR_REQ(xvap, XAT_AV_MODIFIED);
+                               XVA_SET_REQ(tmpxvattr, XAT_AV_MODIFIED);
+                       }
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+                       if ((!S_ISREG(ip->i_mode) &&
+                           xoap->xoa_av_quarantined) ||
+                           xoap->xoa_av_quarantined !=
+                           ((zp->z_pflags & ZFS_AV_QUARANTINED) != 0)) {
+                               need_policy = TRUE;
+                       } else {
+                               XVA_CLR_REQ(xvap, XAT_AV_QUARANTINED);
+                               XVA_SET_REQ(tmpxvattr, XAT_AV_QUARANTINED);
+                       }
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+                       mutex_exit(&zp->z_lock);
+                       err = EPERM;
+                       goto out3;
+               }
+
+               if (need_policy == FALSE &&
+                   (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) ||
+                   XVA_ISSET_REQ(xvap, XAT_OPAQUE))) {
+                       need_policy = TRUE;
+               }
+       }
+
+       mutex_exit(&zp->z_lock);
+
+       if (mask & ATTR_MODE) {
+               if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) {
+                       err = secpolicy_setid_setsticky_clear(ip, vap,
+                           &oldva, cr);
+                       if (err)
+                               goto out3;
+
+                       trim_mask |= ATTR_MODE;
+               } else {
+                       need_policy = TRUE;
+               }
+       }
+
+       if (need_policy) {
+               /*
+                * If trim_mask is set then take ownership
+                * has been granted or write_acl is present and user
+                * has the ability to modify mode.  In that case remove
+                * UID|GID and or MODE from mask so that
+                * secpolicy_vnode_setattr() doesn't revoke it.
+                */
+
+               if (trim_mask) {
+                       saved_mask = vap->va_mask;
+                       vap->va_mask &= ~trim_mask;
+               }
+               err = secpolicy_vnode_setattr(cr, ip, vap, &oldva, flags,
+                   (int (*)(void *, int, cred_t *))zfs_zaccess_unix, zp);
+               if (err)
+                       goto out3;
+
+               if (trim_mask)
+                       vap->va_mask |= saved_mask;
+       }
+
+       /*
+        * secpolicy_vnode_setattr, or take ownership may have
+        * changed va_mask
+        */
+       mask = vap->va_mask;
+
+       if ((mask & (ATTR_UID | ATTR_GID))) {
+               err = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
+                   &xattr_obj, sizeof (xattr_obj));
+
+               if (err == 0 && xattr_obj) {
+                       err = zfs_zget(ZTOZSB(zp), xattr_obj, &attrzp);
+                       if (err)
+                               goto out2;
+               }
+               if (mask & ATTR_UID) {
+                       new_uid = 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 (attrzp)
+                                       iput(ZTOI(attrzp));
+                               err = EDQUOT;
+                               goto out2;
+                       }
+               }
+
+               if (mask & ATTR_GID) {
+                       new_gid = 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 (attrzp)
+                                       iput(ZTOI(attrzp));
+                               err = EDQUOT;
+                               goto out2;
+                       }
+               }
+       }
+       tx = dmu_tx_create(zsb->z_os);
+
+       if (mask & ATTR_MODE) {
+               uint64_t pmode = zp->z_mode;
+               uint64_t acl_obj;
+               new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT);
+
+               zfs_acl_chmod_setattr(zp, &aclp, new_mode);
+
+               mutex_enter(&zp->z_lock);
+               if (!zp->z_is_sa && ((acl_obj = zfs_external_acl(zp)) != 0)) {
+                       /*
+                        * Are we upgrading ACL from old V0 format
+                        * to V1 format?
+                        */
+                       if (zsb->z_version >= ZPL_VERSION_FUID &&
+                           zfs_znode_acl_version(zp) ==
+                           ZFS_ACL_VERSION_INITIAL) {
+                               dmu_tx_hold_free(tx, acl_obj, 0,
+                                   DMU_OBJECT_END);
+                               dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+                                   0, aclp->z_acl_bytes);
+                       } else {
+                               dmu_tx_hold_write(tx, acl_obj, 0,
+                                   aclp->z_acl_bytes);
+                       }
+               } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+                       dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+                           0, aclp->z_acl_bytes);
+               }
+               mutex_exit(&zp->z_lock);
+               dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+       } else {
+               if ((mask & ATTR_XVATTR) &&
+                   XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+                       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
+               else
+                       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       }
+
+       if (attrzp) {
+               dmu_tx_hold_sa(tx, attrzp->z_sa_hdl, B_FALSE);
+       }
+
+       fuid_dirtied = zsb->z_fuid_dirty;
+       if (fuid_dirtied)
+               zfs_fuid_txhold(zsb, tx);
+
+       zfs_sa_upgrade_txholds(tx, zp);
+
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err)
+               goto out;
+
+       count = 0;
+       /*
+        * Set each attribute requested.
+        * We group settings according to the locks they need to acquire.
+        *
+        * Note: you cannot set ctime directly, although it will be
+        * updated as a side-effect of calling this function.
+        */
+
+
+       if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE))
+               mutex_enter(&zp->z_acl_lock);
+       mutex_enter(&zp->z_lock);
+
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
+           &zp->z_pflags, sizeof (zp->z_pflags));
+
+       if (attrzp) {
+               if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE))
+                       mutex_enter(&attrzp->z_acl_lock);
+               mutex_enter(&attrzp->z_lock);
+               SA_ADD_BULK_ATTR(xattr_bulk, xattr_count,
+                   SA_ZPL_FLAGS(zsb), NULL, &attrzp->z_pflags,
+                   sizeof (attrzp->z_pflags));
+       }
+
+       if (mask & (ATTR_UID|ATTR_GID)) {
+
+               if (mask & ATTR_UID) {
+                       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;
+                       }
+               }
+
+               if (mask & ATTR_GID) {
+                       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;
+                       }
+               }
+               if (!(mask & ATTR_MODE)) {
+                       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb),
+                           NULL, &new_mode, sizeof (new_mode));
+                       new_mode = zp->z_mode;
+               }
+               err = zfs_acl_chown_setattr(zp);
+               ASSERT(err == 0);
+               if (attrzp) {
+                       err = zfs_acl_chown_setattr(attrzp);
+                       ASSERT(err == 0);
+               }
+       }
+
+       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;
+               ASSERT3P(aclp, !=, NULL);
+               err = zfs_aclset_common(zp, aclp, cr, tx);
+               ASSERT0(err);
+               if (zp->z_acl_cached)
+                       zfs_acl_free(zp->z_acl_cached);
+               zp->z_acl_cached = aclp;
+               aclp = NULL;
+       }
+
+
+       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,
+                   &atime, sizeof (atime));
+       }
+
+       if (mask & ATTR_MTIME) {
+               ZFS_TIME_ENCODE(&vap->va_mtime, mtime);
+               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);
+       } else if (mask != 0) {
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
+                   &ctime, sizeof (ctime));
+               zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, ctime);
+               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);
+               }
+       }
+       /*
+        * Do this after setting timestamps to prevent timestamp
+        * update from toggling bit
+        */
+
+       if (xoap && (mask & ATTR_XVATTR)) {
+
+               /*
+                * restore trimmed off masks
+                * so that return masks can be set for caller.
+                */
+
+               if (XVA_ISSET_REQ(tmpxvattr, XAT_APPENDONLY)) {
+                       XVA_SET_REQ(xvap, XAT_APPENDONLY);
+               }
+               if (XVA_ISSET_REQ(tmpxvattr, XAT_NOUNLINK)) {
+                       XVA_SET_REQ(xvap, XAT_NOUNLINK);
+               }
+               if (XVA_ISSET_REQ(tmpxvattr, XAT_IMMUTABLE)) {
+                       XVA_SET_REQ(xvap, XAT_IMMUTABLE);
+               }
+               if (XVA_ISSET_REQ(tmpxvattr, XAT_NODUMP)) {
+                       XVA_SET_REQ(xvap, XAT_NODUMP);
+               }
+               if (XVA_ISSET_REQ(tmpxvattr, XAT_AV_MODIFIED)) {
+                       XVA_SET_REQ(xvap, XAT_AV_MODIFIED);
+               }
+               if (XVA_ISSET_REQ(tmpxvattr, XAT_AV_QUARANTINED)) {
+                       XVA_SET_REQ(xvap, XAT_AV_QUARANTINED);
+               }
+
+               if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+                       ASSERT(S_ISREG(ip->i_mode));
+
+               zfs_xvattr_set(zp, xvap, tx);
+       }
+
+       if (fuid_dirtied)
+               zfs_fuid_sync(zsb, tx);
+
+       if (mask != 0)
+               zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp);
+
+       mutex_exit(&zp->z_lock);
+       if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE))
+               mutex_exit(&zp->z_acl_lock);
+
+       if (attrzp) {
+               if (mask & (ATTR_UID|ATTR_GID|ATTR_MODE))
+                       mutex_exit(&attrzp->z_acl_lock);
+               mutex_exit(&attrzp->z_lock);
+       }
+out:
+       if (err == 0 && attrzp) {
+               err2 = sa_bulk_update(attrzp->z_sa_hdl, xattr_bulk,
+                   xattr_count, tx);
+               ASSERT(err2 == 0);
+       }
+
+       if (attrzp)
+               iput(ZTOI(attrzp));
+       if (aclp)
+               zfs_acl_free(aclp);
+
+       if (fuidp) {
+               zfs_fuid_info_free(fuidp);
+               fuidp = NULL;
+       }
+
+       if (err) {
+               dmu_tx_abort(tx);
+               if (err == ERESTART)
+                       goto top;
+       } else {
+               err2 = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+               dmu_tx_commit(tx);
+               zfs_inode_update(zp);
+       }
+
+out2:
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+out3:
+       kmem_free(xattr_bulk, sizeof (sa_bulk_attr_t) * 7);
+       kmem_free(bulk, sizeof (sa_bulk_attr_t) * 7);
+       kmem_free(tmpxvattr, sizeof (xvattr_t));
+       ZFS_EXIT(zsb);
+       return (err);
+}
+EXPORT_SYMBOL(zfs_setattr);
+
+typedef struct zfs_zlock {
+       krwlock_t       *zl_rwlock;     /* lock we acquired */
+       znode_t         *zl_znode;      /* znode we held */
+       struct zfs_zlock *zl_next;      /* next in list */
+} zfs_zlock_t;
+
+/*
+ * Drop locks and release vnodes that were held by zfs_rename_lock().
+ */
+static void
+zfs_rename_unlock(zfs_zlock_t **zlpp)
+{
+       zfs_zlock_t *zl;
+
+       while ((zl = *zlpp) != NULL) {
+               if (zl->zl_znode != NULL)
+                       iput(ZTOI(zl->zl_znode));
+               rw_exit(zl->zl_rwlock);
+               *zlpp = zl->zl_next;
+               kmem_free(zl, sizeof (*zl));
+       }
+}
+
+/*
+ * Search back through the directory tree, using the ".." entries.
+ * Lock each directory in the chain to prevent concurrent renames.
+ * Fail any attempt to move a directory into one of its own descendants.
+ * XXX - z_parent_lock can overlap with map or grow locks
+ */
+static int
+zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp)
+{
+       zfs_zlock_t     *zl;
+       znode_t         *zp = tdzp;
+       uint64_t        rootid = ZTOZSB(zp)->z_root;
+       uint64_t        oidp = zp->z_id;
+       krwlock_t       *rwlp = &szp->z_parent_lock;
+       krw_t           rw = RW_WRITER;
+
+       /*
+        * First pass write-locks szp and compares to zp->z_id.
+        * Later passes read-lock zp and compare to zp->z_parent.
+        */
+       do {
+               if (!rw_tryenter(rwlp, rw)) {
+                       /*
+                        * Another thread is renaming in this path.
+                        * Note that if we are a WRITER, we don't have any
+                        * parent_locks held yet.
+                        */
+                       if (rw == RW_READER && zp->z_id > szp->z_id) {
+                               /*
+                                * Drop our locks and restart
+                                */
+                               zfs_rename_unlock(&zl);
+                               *zlpp = NULL;
+                               zp = tdzp;
+                               oidp = zp->z_id;
+                               rwlp = &szp->z_parent_lock;
+                               rw = RW_WRITER;
+                               continue;
+                       } else {
+                               /*
+                                * Wait for other thread to drop its locks
+                                */
+                               rw_enter(rwlp, rw);
+                       }
+               }
+
+               zl = kmem_alloc(sizeof (*zl), KM_SLEEP);
+               zl->zl_rwlock = rwlp;
+               zl->zl_znode = NULL;
+               zl->zl_next = *zlpp;
+               *zlpp = zl;
+
+               if (oidp == szp->z_id)          /* We're a descendant of szp */
+                       return (SET_ERROR(EINVAL));
+
+               if (oidp == rootid)             /* We've hit the top */
+                       return (0);
+
+               if (rw == RW_READER) {          /* i.e. not the first pass */
+                       int error = zfs_zget(ZTOZSB(zp), oidp, &zp);
+                       if (error)
+                               return (error);
+                       zl->zl_znode = zp;
+               }
+               (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(ZTOZSB(zp)),
+                   &oidp, sizeof (oidp));
+               rwlp = &zp->z_parent_lock;
+               rw = RW_READER;
+
+       } while (zp->z_id != sdzp->z_id);
+
+       return (0);
+}
+
+/*
+ * Move an entry from the provided source directory to the target
+ * directory.  Change the entry name as indicated.
+ *
+ *     IN:     sdip    - Source directory containing the "old entry".
+ *             snm     - Old entry name.
+ *             tdip    - Target directory to contain the "new entry".
+ *             tnm     - New entry name.
+ *             cr      - credentials of caller.
+ *             flags   - case flags
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     sdip,tdip - ctime|mtime updated
+ */
+/*ARGSUSED*/
+int
+zfs_rename(struct inode *sdip, char *snm, struct inode *tdip, char *tnm,
+    cred_t *cr, int flags)
+{
+       znode_t         *tdzp, *szp, *tzp;
+       znode_t         *sdzp = ITOZ(sdip);
+       zfs_sb_t        *zsb = ITOZSB(sdip);
+       zilog_t         *zilog;
+       zfs_dirlock_t   *sdl, *tdl;
+       dmu_tx_t        *tx;
+       zfs_zlock_t     *zl;
+       int             cmp, serr, terr;
+       int             error = 0;
+       int             zflg = 0;
+       boolean_t       waited = B_FALSE;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(sdzp);
+       zilog = zsb->z_log;
+
+       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);
+               return (SET_ERROR(EILSEQ));
+       }
+
+       if (flags & FIGNORECASE)
+               zflg |= ZCILOOK;
+
+top:
+       szp = NULL;
+       tzp = NULL;
+       zl = NULL;
+
+       /*
+        * This is to prevent the creation of links into attribute space
+        * by renaming a linked file into/outof an attribute directory.
+        * See the comment in zfs_link() for why this is considered bad.
+        */
+       if ((tdzp->z_pflags & ZFS_XATTR) != (sdzp->z_pflags & ZFS_XATTR)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Lock source and target directory entries.  To prevent deadlock,
+        * a lock ordering must be defined.  We lock the directory with
+        * the smallest object id first, or if it's a tie, the one with
+        * the lexically first name.
+        */
+       if (sdzp->z_id < tdzp->z_id) {
+               cmp = -1;
+       } else if (sdzp->z_id > tdzp->z_id) {
+               cmp = 1;
+       } else {
+               /*
+                * First compare the two name arguments without
+                * considering any case folding.
+                */
+               int nofold = (zsb->z_norm & ~U8_TEXTPREP_TOUPPER);
+
+               cmp = u8_strcmp(snm, tnm, 0, nofold, U8_UNICODE_LATEST, &error);
+               ASSERT(error == 0 || !zsb->z_utf8);
+               if (cmp == 0) {
+                       /*
+                        * POSIX: "If the old argument and the new argument
+                        * both refer to links to the same existing file,
+                        * the rename() function shall return successfully
+                        * and perform no other action."
+                        */
+                       ZFS_EXIT(zsb);
+                       return (0);
+               }
+               /*
+                * If the file system is case-folding, then we may
+                * have some more checking to do.  A case-folding file
+                * system is either supporting mixed case sensitivity
+                * access or is completely case-insensitive.  Note
+                * that the file system is always case preserving.
+                *
+                * In mixed sensitivity mode case sensitive behavior
+                * is the default.  FIGNORECASE must be used to
+                * explicitly request case insensitive behavior.
+                *
+                * If the source and target names provided differ only
+                * by case (e.g., a request to rename 'tim' to 'Tim'),
+                * we will treat this as a special case in the
+                * case-insensitive mode: as long as the source name
+                * is an exact match, we will allow this to proceed as
+                * a name-change request.
+                */
+               if ((zsb->z_case == ZFS_CASE_INSENSITIVE ||
+                   (zsb->z_case == ZFS_CASE_MIXED &&
+                   flags & FIGNORECASE)) &&
+                   u8_strcmp(snm, tnm, 0, zsb->z_norm, U8_UNICODE_LATEST,
+                   &error) == 0) {
+                       /*
+                        * case preserving rename request, require exact
+                        * name matches
+                        */
+                       zflg |= ZCIEXACT;
+                       zflg &= ~ZCILOOK;
+               }
+       }
+
+       /*
+        * If the source and destination directories are the same, we should
+        * grab the z_name_lock of that directory only once.
+        */
+       if (sdzp == tdzp) {
+               zflg |= ZHAVELOCK;
+               rw_enter(&sdzp->z_name_lock, RW_READER);
+       }
+
+       if (cmp < 0) {
+               serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp,
+                   ZEXISTS | zflg, NULL, NULL);
+               terr = zfs_dirent_lock(&tdl,
+                   tdzp, tnm, &tzp, ZRENAMING | zflg, NULL, NULL);
+       } else {
+               terr = zfs_dirent_lock(&tdl,
+                   tdzp, tnm, &tzp, zflg, NULL, NULL);
+               serr = zfs_dirent_lock(&sdl,
+                   sdzp, snm, &szp, ZEXISTS | ZRENAMING | zflg,
+                   NULL, NULL);
+       }
+
+       if (serr) {
+               /*
+                * Source entry invalid or not there.
+                */
+               if (!terr) {
+                       zfs_dirent_unlock(tdl);
+                       if (tzp)
+                               iput(ZTOI(tzp));
+               }
+
+               if (sdzp == tdzp)
+                       rw_exit(&sdzp->z_name_lock);
+
+               if (strcmp(snm, "..") == 0)
+                       serr = EINVAL;
+               ZFS_EXIT(zsb);
+               return (serr);
+       }
+       if (terr) {
+               zfs_dirent_unlock(sdl);
+               iput(ZTOI(szp));
+
+               if (sdzp == tdzp)
+                       rw_exit(&sdzp->z_name_lock);
+
+               if (strcmp(tnm, "..") == 0)
+                       terr = EINVAL;
+               ZFS_EXIT(zsb);
+               return (terr);
+       }
+
+       /*
+        * Must have write access at the source to remove the old entry
+        * and write access at the target to create the new entry.
+        * Note that if target and source are the same, this can be
+        * done in a single check.
+        */
+
+       if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)))
+               goto out;
+
+       if (S_ISDIR(ZTOI(szp)->i_mode)) {
+               /*
+                * Check to make sure rename is valid.
+                * Can't do a move like this: /usr/a/b to /usr/a/b/c/d
+                */
+               if ((error = zfs_rename_lock(szp, tdzp, sdzp, &zl)))
+                       goto out;
+       }
+
+       /*
+        * Does target exist?
+        */
+       if (tzp) {
+               /*
+                * Source and target must be the same type.
+                */
+               if (S_ISDIR(ZTOI(szp)->i_mode)) {
+                       if (!S_ISDIR(ZTOI(tzp)->i_mode)) {
+                               error = SET_ERROR(ENOTDIR);
+                               goto out;
+                       }
+               } else {
+                       if (S_ISDIR(ZTOI(tzp)->i_mode)) {
+                               error = SET_ERROR(EISDIR);
+                               goto out;
+                       }
+               }
+               /*
+                * POSIX dictates that when the source and target
+                * entries refer to the same file object, rename
+                * must do nothing and exit without error.
+                */
+               if (szp->z_id == tzp->z_id) {
+                       error = 0;
+                       goto out;
+               }
+       }
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
+       dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE);
+       dmu_tx_hold_zap(tx, sdzp->z_id, FALSE, snm);
+       dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, tnm);
+       if (sdzp != tdzp) {
+               dmu_tx_hold_sa(tx, tdzp->z_sa_hdl, B_FALSE);
+               zfs_sa_upgrade_txholds(tx, tdzp);
+       }
+       if (tzp) {
+               dmu_tx_hold_sa(tx, tzp->z_sa_hdl, B_FALSE);
+               zfs_sa_upgrade_txholds(tx, tzp);
+       }
+
+       zfs_sa_upgrade_txholds(tx, szp);
+       dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
+       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       if (error) {
+               if (zl != NULL)
+                       zfs_rename_unlock(&zl);
+               zfs_dirent_unlock(sdl);
+               zfs_dirent_unlock(tdl);
+
+               if (sdzp == tdzp)
+                       rw_exit(&sdzp->z_name_lock);
+
+               iput(ZTOI(szp));
+               if (tzp)
+                       iput(ZTOI(tzp));
+               if (error == ERESTART) {
+                       waited = B_TRUE;
+                       dmu_tx_wait(tx);
+                       dmu_tx_abort(tx);
+                       goto top;
+               }
+               dmu_tx_abort(tx);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (tzp)        /* Attempt to remove the existing target */
+               error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL);
+
+       if (error == 0) {
+               error = zfs_link_create(tdl, szp, tx, ZRENAMING);
+               if (error == 0) {
+                       szp->z_pflags |= ZFS_AV_MODIFIED;
+
+                       error = sa_update(szp->z_sa_hdl, SA_ZPL_FLAGS(zsb),
+                           (void *)&szp->z_pflags, sizeof (uint64_t), tx);
+                       ASSERT0(error);
+
+                       error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL);
+                       if (error == 0) {
+                               zfs_log_rename(zilog, tx, TX_RENAME |
+                                   (flags & FIGNORECASE ? TX_CI : 0), sdzp,
+                                   sdl->dl_name, tdzp, tdl->dl_name, szp);
+                       } else {
+                               /*
+                                * At this point, we have successfully created
+                                * the target name, but have failed to remove
+                                * the source name.  Since the create was done
+                                * with the ZRENAMING flag, there are
+                                * complications; for one, the link count is
+                                * wrong.  The easiest way to deal with this
+                                * is to remove the newly created target, and
+                                * return the original error.  This must
+                                * succeed; fortunately, it is very unlikely to
+                                * fail, since we just created it.
+                                */
+                               VERIFY3U(zfs_link_destroy(tdl, szp, tx,
+                                   ZRENAMING, NULL), ==, 0);
+                       }
+               }
+       }
+
+       dmu_tx_commit(tx);
+out:
+       if (zl != NULL)
+               zfs_rename_unlock(&zl);
+
+       zfs_dirent_unlock(sdl);
+       zfs_dirent_unlock(tdl);
+
+       zfs_inode_update(sdzp);
+       if (sdzp == tdzp)
+               rw_exit(&sdzp->z_name_lock);
+
+       if (sdzp != tdzp)
+               zfs_inode_update(tdzp);
+
+       zfs_inode_update(szp);
+       iput(ZTOI(szp));
+       if (tzp) {
+               zfs_inode_update(tzp);
+               iput(ZTOI(tzp));
+       }
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_rename);
+
+/*
+ * Insert the indicated symbolic reference entry into the directory.
+ *
+ *     IN:     dip     - Directory to contain new symbolic link.
+ *             link    - Name for new symlink entry.
+ *             vap     - Attributes of new entry.
+ *             target  - Target path of new symlink.
+ *
+ *             cr      - credentials of caller.
+ *             flags   - case flags
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     dip - ctime|mtime updated
+ */
+/*ARGSUSED*/
+int
+zfs_symlink(struct inode *dip, char *name, vattr_t *vap, char *link,
+    struct inode **ipp, cred_t *cr, int flags)
+{
+       znode_t         *zp, *dzp = ITOZ(dip);
+       zfs_dirlock_t   *dl;
+       dmu_tx_t        *tx;
+       zfs_sb_t        *zsb = ITOZSB(dip);
+       zilog_t         *zilog;
+       uint64_t        len = strlen(link);
+       int             error;
+       int             zflg = ZNEW;
+       zfs_acl_ids_t   acl_ids;
+       boolean_t       fuid_dirtied;
+       uint64_t        txtype = TX_SYMLINK;
+       boolean_t       waited = B_FALSE;
+
+       ASSERT(S_ISLNK(vap->va_mode));
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(dzp);
+       zilog = zsb->z_log;
+
+       if (zsb->z_utf8 && u8_validate(name, strlen(name),
+           NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EILSEQ));
+       }
+       if (flags & FIGNORECASE)
+               zflg |= ZCILOOK;
+
+       if (len > MAXPATHLEN) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENAMETOOLONG));
+       }
+
+       if ((error = zfs_acl_ids_create(dzp, 0,
+           vap, cr, NULL, &acl_ids)) != 0) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+top:
+       *ipp = NULL;
+
+       /*
+        * Attempt to lock directory; fail if entry already exists.
+        */
+       error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL);
+       if (error) {
+               zfs_acl_ids_free(&acl_ids);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) {
+               zfs_acl_ids_free(&acl_ids);
+               zfs_dirent_unlock(dl);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (zfs_acl_ids_overquota(zsb, &acl_ids)) {
+               zfs_acl_ids_free(&acl_ids);
+               zfs_dirent_unlock(dl);
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EDQUOT));
+       }
+       tx = dmu_tx_create(zsb->z_os);
+       fuid_dirtied = zsb->z_fuid_dirty;
+       dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, MAX(1, len));
+       dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
+       dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
+           ZFS_SA_BASE_ATTR_SIZE + len);
+       dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
+       if (!zsb->z_use_sa && acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+               dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+                   acl_ids.z_aclp->z_acl_bytes);
+       }
+       if (fuid_dirtied)
+               zfs_fuid_txhold(zsb, tx);
+       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       if (error) {
+               zfs_dirent_unlock(dl);
+               if (error == ERESTART) {
+                       waited = B_TRUE;
+                       dmu_tx_wait(tx);
+                       dmu_tx_abort(tx);
+                       goto top;
+               }
+               zfs_acl_ids_free(&acl_ids);
+               dmu_tx_abort(tx);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       /*
+        * Create a new object for the symlink.
+        * for version 4 ZPL datsets the symlink will be an SA attribute
+        */
+       zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
+
+       if (fuid_dirtied)
+               zfs_fuid_sync(zsb, tx);
+
+       mutex_enter(&zp->z_lock);
+       if (zp->z_is_sa)
+               error = sa_update(zp->z_sa_hdl, SA_ZPL_SYMLINK(zsb),
+                   link, len, tx);
+       else
+               zfs_sa_symlink(zp, link, len, tx);
+       mutex_exit(&zp->z_lock);
+
+       zp->z_size = len;
+       (void) sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(zsb),
+           &zp->z_size, sizeof (zp->z_size), tx);
+       /*
+        * Insert the new object into the directory.
+        */
+       (void) zfs_link_create(dl, zp, tx, ZNEW);
+
+       if (flags & FIGNORECASE)
+               txtype |= TX_CI;
+       zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
+
+       zfs_inode_update(dzp);
+       zfs_inode_update(zp);
+
+       zfs_acl_ids_free(&acl_ids);
+
+       dmu_tx_commit(tx);
+
+       zfs_dirent_unlock(dl);
+
+       *ipp = ZTOI(zp);
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_symlink);
+
+/*
+ * Return, in the buffer contained in the provided uio structure,
+ * the symbolic path referred to by ip.
+ *
+ *     IN:     ip      - inode of symbolic link
+ *             uio     - structure to contain the link path.
+ *             cr      - credentials of caller.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     ip - atime updated
+ */
+/* ARGSUSED */
+int
+zfs_readlink(struct inode *ip, uio_t *uio, cred_t *cr)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       int             error;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       mutex_enter(&zp->z_lock);
+       if (zp->z_is_sa)
+               error = sa_lookup_uio(zp->z_sa_hdl,
+                   SA_ZPL_SYMLINK(zsb), uio);
+       else
+               error = zfs_sa_readlink(zp, uio);
+       mutex_exit(&zp->z_lock);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_readlink);
+
+/*
+ * Insert a new entry into directory tdip referencing sip.
+ *
+ *     IN:     tdip    - Directory to contain new entry.
+ *             sip     - inode of new entry.
+ *             name    - name of new entry.
+ *             cr      - credentials of caller.
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     tdip - ctime|mtime updated
+ *      sip - ctime updated
+ */
+/* ARGSUSED */
+int
+zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr)
+{
+       znode_t         *dzp = ITOZ(tdip);
+       znode_t         *tzp, *szp;
+       zfs_sb_t        *zsb = ITOZSB(tdip);
+       zilog_t         *zilog;
+       zfs_dirlock_t   *dl;
+       dmu_tx_t        *tx;
+       int             error;
+       int             zf = ZNEW;
+       uint64_t        parent;
+       uid_t           owner;
+       boolean_t       waited = B_FALSE;
+
+       ASSERT(S_ISDIR(tdip->i_mode));
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(dzp);
+       zilog = zsb->z_log;
+
+       /*
+        * POSIX dictates that we return EPERM here.
+        * Better choices include ENOTSUP or EISDIR.
+        */
+       if (S_ISDIR(sip->i_mode)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EPERM));
+       }
+
+       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),
+           &parent, sizeof (uint64_t))) != 0) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+       if (parent == zsb->z_shares_dir) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EPERM));
+       }
+
+       if (zsb->z_utf8 && u8_validate(name,
+           strlen(name), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+               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
+        * because of the potential security risk of creating links
+        * into "normal" file space in order to circumvent restrictions
+        * imposed in attribute space.
+        */
+       if ((szp->z_pflags & ZFS_XATTR) != (dzp->z_pflags & ZFS_XATTR)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       owner = zfs_fuid_map_id(zsb, szp->z_uid, cr, ZFS_OWNER);
+       if (owner != crgetuid(cr) && secpolicy_basic_link(cr) != 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EPERM));
+       }
+
+       if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+top:
+       /*
+        * Attempt to lock directory; fail if entry already exists.
+        */
+       error = zfs_dirent_lock(&dl, dzp, name, &tzp, zf, NULL, NULL);
+       if (error) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
+       dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
+       zfs_sa_upgrade_txholds(tx, szp);
+       zfs_sa_upgrade_txholds(tx, dzp);
+       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       if (error) {
+               zfs_dirent_unlock(dl);
+               if (error == ERESTART) {
+                       waited = B_TRUE;
+                       dmu_tx_wait(tx);
+                       dmu_tx_abort(tx);
+                       goto top;
+               }
+               dmu_tx_abort(tx);
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       error = zfs_link_create(dl, szp, tx, 0);
+
+       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);
+       }
+
+       dmu_tx_commit(tx);
+
+       zfs_dirent_unlock(dl);
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       zfs_inode_update(dzp);
+       zfs_inode_update(szp);
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_link);
+
+static void
+zfs_putpage_commit_cb(void *arg)
+{
+       struct page *pp = arg;
+
+       ClearPageError(pp);
+       end_page_writeback(pp);
+}
+
+/*
+ * Push a page out to disk, once the page is on stable storage the
+ * registered commit callback will be run as notification of completion.
+ *
+ *     IN:     ip      - page mapped for inode.
+ *             pp      - page to push (page is locked)
+ *             wbc     - writeback control data
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ *
+ * Timestamps:
+ *     ip - ctime|mtime updated
+ */
+/* ARGSUSED */
+int
+zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       loff_t          offset;
+       loff_t          pgoff;
+       unsigned int    pglen;
+       rl_t            *rl;
+       dmu_tx_t        *tx;
+       caddr_t         va;
+       int             err = 0;
+       uint64_t        mtime[2], ctime[2];
+       sa_bulk_attr_t  bulk[3];
+       int             cnt = 0;
+       struct address_space *mapping;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       ASSERT(PageLocked(pp));
+
+       pgoff = page_offset(pp);        /* Page byte-offset in file */
+       offset = i_size_read(ip);       /* File length in bytes */
+       pglen = MIN(PAGE_SIZE,          /* Page length in bytes */
+           P2ROUNDUP(offset, PAGE_SIZE)-pgoff);
+
+       /* Page is beyond end of file */
+       if (pgoff >= offset) {
+               unlock_page(pp);
+               ZFS_EXIT(zsb);
+               return (0);
+       }
+
+       /* Truncate page length to end of file */
+       if (pgoff + pglen > offset)
+               pglen = offset - pgoff;
+
+#if 0
+       /*
+        * FIXME: Allow mmap writes past its quota.  The correct fix
+        * is to register a page_mkwrite() handler to count the page
+        * against its quota when it is about to be dirtied.
+        */
+       if (zfs_owner_overquota(zsb, zp, B_FALSE) ||
+           zfs_owner_overquota(zsb, zp, B_TRUE)) {
+               err = EDQUOT;
+       }
+#endif
+
+       /*
+        * The ordering here is critical and must adhere to the following
+        * rules in order to avoid deadlocking in either zfs_read() or
+        * zfs_free_range() due to a lock inversion.
+        *
+        * 1) The page must be unlocked prior to acquiring the range lock.
+        *    This is critical because zfs_read() calls find_lock_page()
+        *    which may block on the page lock while holding the range lock.
+        *
+        * 2) Before setting or clearing write back on a page the range lock
+        *    must be held in order to prevent a lock inversion with the
+        *    zfs_free_range() function.
+        *
+        * This presents a problem because upon entering this function the
+        * page lock is already held.  To safely acquire the range lock the
+        * page lock must be dropped.  This creates a window where another
+        * process could truncate, invalidate, dirty, or write out the page.
+        *
+        * Therefore, after successfully reacquiring the range and page locks
+        * the current page state is checked.  In the common case everything
+        * will be as is expected and it can be written out.  However, if
+        * the page state has changed it must be handled accordingly.
+        */
+       mapping = pp->mapping;
+       redirty_page_for_writepage(wbc, pp);
+       unlock_page(pp);
+
+       rl = zfs_range_lock(&zp->z_range_lock, pgoff, pglen, RL_WRITER);
+       lock_page(pp);
+
+       /* Page mapping changed or it was no longer dirty, we're done */
+       if (unlikely((mapping != pp->mapping) || !PageDirty(pp))) {
+               unlock_page(pp);
+               zfs_range_unlock(rl);
+               ZFS_EXIT(zsb);
+               return (0);
+       }
+
+       /* Another process started write block if required */
+       if (PageWriteback(pp)) {
+               unlock_page(pp);
+               zfs_range_unlock(rl);
+
+               if (wbc->sync_mode != WB_SYNC_NONE)
+                       wait_on_page_writeback(pp);
+
+               ZFS_EXIT(zsb);
+               return (0);
+       }
+
+       /* Clear the dirty flag the required locks are held */
+       if (!clear_page_dirty_for_io(pp)) {
+               unlock_page(pp);
+               zfs_range_unlock(rl);
+               ZFS_EXIT(zsb);
+               return (0);
+       }
+
+       /*
+        * Counterpart for redirty_page_for_writepage() above.  This page
+        * was in fact not skipped and should not be counted as if it were.
+        */
+       wbc->pages_skipped--;
+       set_page_writeback(pp);
+       unlock_page(pp);
+
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       zfs_sa_upgrade_txholds(tx, zp);
+
+       err = dmu_tx_assign(tx, TXG_NOWAIT);
+       if (err != 0) {
+               if (err == ERESTART)
+                       dmu_tx_wait(tx);
+
+               dmu_tx_abort(tx);
+               __set_page_dirty_nobuffers(pp);
+               ClearPageError(pp);
+               end_page_writeback(pp);
+               zfs_range_unlock(rl);
+               ZFS_EXIT(zsb);
+               return (err);
+       }
+
+       va = kmap(pp);
+       ASSERT3U(pglen, <=, PAGE_SIZE);
+       dmu_write(zsb->z_os, zp->z_id, pgoff, pglen, va, tx);
+       kunmap(pp);
+
+       SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
+       SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
+       SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_FLAGS(zsb), NULL, &zp->z_pflags, 8);
+
+       /* Preserve the mtime and ctime provided by the inode */
+       ZFS_TIME_ENCODE(&ip->i_mtime, mtime);
+       ZFS_TIME_ENCODE(&ip->i_ctime, ctime);
+       zp->z_atime_dirty = 0;
+       zp->z_seq++;
+
+       err = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
+
+       zfs_log_write(zsb->z_log, tx, TX_WRITE, zp, pgoff, pglen, 0,
+           zfs_putpage_commit_cb, pp);
+       dmu_tx_commit(tx);
+
+       zfs_range_unlock(rl);
+
+       if (wbc->sync_mode != WB_SYNC_NONE) {
+               /*
+                * Note that this is rarely called under writepages(), because
+                * writepages() normally handles the entire commit for
+                * performance reasons.
+                */
+               if (zsb->z_log != NULL)
+                       zil_commit(zsb->z_log, zp->z_id);
+       }
+
+       ZFS_EXIT(zsb);
+       return (err);
+}
+
+/*
+ * Update the system attributes when the inode has been dirtied.  For the
+ * moment we only update the mode, atime, mtime, and ctime.
+ */
+int
+zfs_dirty_inode(struct inode *ip, int flags)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       dmu_tx_t        *tx;
+       uint64_t        mode, atime[2], mtime[2], ctime[2];
+       sa_bulk_attr_t  bulk[4];
+       int             error = 0;
+       int             cnt = 0;
+
+       if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os))
+               return (0);
+
+       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);
+       zfs_sa_upgrade_txholds(tx, zp);
+
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+               goto out;
+       }
+
+       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);
+       SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
+
+       /* Preserve the mode, mtime and ctime provided by the inode */
+       ZFS_TIME_ENCODE(&ip->i_atime, atime);
+       ZFS_TIME_ENCODE(&ip->i_mtime, mtime);
+       ZFS_TIME_ENCODE(&ip->i_ctime, ctime);
+       mode = ip->i_mode;
+
+       zp->z_mode = mode;
+
+       error = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
+       mutex_exit(&zp->z_lock);
+
+       dmu_tx_commit(tx);
+out:
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_dirty_inode);
+
+/*ARGSUSED*/
+void
+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;
+
+       /* Only read lock if we haven't already write locked, e.g. rollback */
+       if (!RW_WRITE_HELD(&zsb->z_teardown_inactive_lock)) {
+               need_unlock = 1;
+               rw_enter(&zsb->z_teardown_inactive_lock, RW_READER);
+       }
+       if (zp->z_sa_hdl == NULL) {
+               if (need_unlock)
+                       rw_exit(&zsb->z_teardown_inactive_lock);
+               return;
+       }
+
+       if (zp->z_atime_dirty && zp->z_unlinked == 0) {
+               dmu_tx_t *tx = dmu_tx_create(zsb->z_os);
+
+               dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+               zfs_sa_upgrade_txholds(tx, zp);
+               error = dmu_tx_assign(tx, TXG_WAIT);
+               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 *)&atime, sizeof (atime), tx);
+                       zp->z_atime_dirty = 0;
+                       mutex_exit(&zp->z_lock);
+                       dmu_tx_commit(tx);
+               }
+       }
+
+       zfs_zinactive(zp);
+       if (need_unlock)
+               rw_exit(&zsb->z_teardown_inactive_lock);
+}
+EXPORT_SYMBOL(zfs_inactive);
+
+/*
+ * Bounds-check the seek operation.
+ *
+ *     IN:     ip      - inode seeking within
+ *             ooff    - old file offset
+ *             noffp   - pointer to new file offset
+ *             ct      - caller context
+ *
+ *     RETURN: 0 if success
+ *             EINVAL if new offset invalid
+ */
+/* ARGSUSED */
+int
+zfs_seek(struct inode *ip, offset_t ooff, offset_t *noffp)
+{
+       if (S_ISDIR(ip->i_mode))
+               return (0);
+       return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
+}
+EXPORT_SYMBOL(zfs_seek);
+
+/*
+ * Fill pages with data from the disk.
+ */
+static int
+zfs_fillpage(struct inode *ip, struct page *pl[], int nr_pages)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       objset_t *os;
+       struct page *cur_pp;
+       u_offset_t io_off, total;
+       size_t io_len;
+       loff_t i_size;
+       unsigned page_idx;
+       int err;
+
+       os = zsb->z_os;
+       io_len = nr_pages << PAGE_SHIFT;
+       i_size = i_size_read(ip);
+       io_off = page_offset(pl[0]);
+
+       if (io_off + io_len > i_size)
+               io_len = i_size - io_off;
+
+       /*
+        * Iterate over list of pages and read each page individually.
+        */
+       page_idx = 0;
+       for (total = io_off + io_len; io_off < total; io_off += PAGESIZE) {
+               caddr_t va;
+
+               cur_pp = pl[page_idx++];
+               va = kmap(cur_pp);
+               err = dmu_read(os, zp->z_id, io_off, PAGESIZE, va,
+                   DMU_READ_PREFETCH);
+               kunmap(cur_pp);
+               if (err) {
+                       /* convert checksum errors into IO errors */
+                       if (err == ECKSUM)
+                               err = SET_ERROR(EIO);
+                       return (err);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Uses zfs_fillpage to read data from the file and fill the pages.
+ *
+ *     IN:     ip       - inode of file to get data from.
+ *             pl       - list of pages to read
+ *             nr_pages - number of pages to read
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     vp - atime updated
+ */
+/* ARGSUSED */
+int
+zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages)
+{
+       znode_t  *zp  = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int      err;
+
+       if (pl == NULL)
+               return (0);
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       err = zfs_fillpage(ip, pl, nr_pages);
+
+       ZFS_EXIT(zsb);
+       return (err);
+}
+EXPORT_SYMBOL(zfs_getpage);
+
+/*
+ * Check ZFS specific permissions to memory map a section of a file.
+ *
+ *     IN:     ip      - inode of the file to mmap
+ *             off     - file offset
+ *             addrp   - start address in memory region
+ *             len     - length of memory region
+ *             vm_flags- address flags
+ *
+ *     RETURN: 0 if success
+ *             error code if failure
+ */
+/*ARGSUSED*/
+int
+zfs_map(struct inode *ip, offset_t off, caddr_t *addrp, size_t len,
+    unsigned long vm_flags)
+{
+       znode_t  *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       if ((vm_flags & VM_WRITE) && (zp->z_pflags &
+           (ZFS_IMMUTABLE | ZFS_READONLY | ZFS_APPENDONLY))) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EPERM));
+       }
+
+       if ((vm_flags & (VM_READ | VM_EXEC)) &&
+           (zp->z_pflags & ZFS_AV_QUARANTINED)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EACCES));
+       }
+
+       if (off < 0 || len > MAXOFFSET_T - off) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENXIO));
+       }
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_map);
+
+/*
+ * convoff - converts the given data (start, whence) to the
+ * given whence.
+ */
+int
+convoff(struct inode *ip, flock64_t *lckdat, int  whence, offset_t offset)
+{
+       vattr_t vap;
+       int error;
+
+       if ((lckdat->l_whence == 2) || (whence == 2)) {
+               if ((error = zfs_getattr(ip, &vap, 0, CRED()) != 0))
+                       return (error);
+       }
+
+       switch (lckdat->l_whence) {
+       case 1:
+               lckdat->l_start += offset;
+               break;
+       case 2:
+               lckdat->l_start += vap.va_size;
+               /* FALLTHRU */
+       case 0:
+               break;
+       default:
+               return (SET_ERROR(EINVAL));
+       }
+
+       if (lckdat->l_start < 0)
+               return (SET_ERROR(EINVAL));
+
+       switch (whence) {
+       case 1:
+               lckdat->l_start -= offset;
+               break;
+       case 2:
+               lckdat->l_start -= vap.va_size;
+               /* FALLTHRU */
+       case 0:
+               break;
+       default:
+               return (SET_ERROR(EINVAL));
+       }
+
+       lckdat->l_whence = (short)whence;
+       return (0);
+}
+
+/*
+ * Free or allocate space in a file.  Currently, this function only
+ * supports the `F_FREESP' command.  However, this command is somewhat
+ * misnamed, as its functionality includes the ability to allocate as
+ * well as free space.
+ *
+ *     IN:     ip      - inode of file to free data in.
+ *             cmd     - action to take (only F_FREESP supported).
+ *             bfp     - section of file to free/alloc.
+ *             flag    - current file open mode flags.
+ *             offset  - current file offset.
+ *             cr      - credentials of caller [UNUSED].
+ *
+ *     RETURN: 0 on success, error code on failure.
+ *
+ * Timestamps:
+ *     ip - ctime|mtime updated
+ */
+/* ARGSUSED */
+int
+zfs_space(struct inode *ip, int cmd, flock64_t *bfp, int flag,
+    offset_t offset, cred_t *cr)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       uint64_t        off, len;
+       int             error;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       if (cmd != F_FREESP) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       if ((error = convoff(ip, bfp, 0, offset))) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       if (bfp->l_len < 0) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Permissions aren't checked on Solaris because on this OS
+        * zfs_space() can only be called with an opened file handle.
+        * On Linux we can get here through truncate_range() which
+        * operates directly on inodes, so we need to check access rights.
+        */
+       if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr))) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       off = bfp->l_start;
+       len = bfp->l_len; /* 0 means from off to end of file */
+
+       error = zfs_freesp(zp, off, len, flag, TRUE);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_space);
+
+/*ARGSUSED*/
+int
+zfs_fid(struct inode *ip, fid_t *fidp)
+{
+       znode_t         *zp = ITOZ(ip);
+       zfs_sb_t        *zsb = ITOZSB(ip);
+       uint32_t        gen;
+       uint64_t        gen64;
+       uint64_t        object = zp->z_id;
+       zfid_short_t    *zfid;
+       int             size, i, error;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zsb),
+           &gen64, sizeof (uint64_t))) != 0) {
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       gen = (uint32_t)gen64;
+
+       size = (zsb->z_parent != zsb) ? LONG_FID_LEN : SHORT_FID_LEN;
+       if (fidp->fid_len < size) {
+               fidp->fid_len = size;
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(ENOSPC));
+       }
+
+       zfid = (zfid_short_t *)fidp;
+
+       zfid->zf_len = size;
+
+       for (i = 0; i < sizeof (zfid->zf_object); i++)
+               zfid->zf_object[i] = (uint8_t)(object >> (8 * i));
+
+       /* Must have a non-zero generation number to distinguish from .zfs */
+       if (gen == 0)
+               gen = 1;
+       for (i = 0; i < sizeof (zfid->zf_gen); i++)
+               zfid->zf_gen[i] = (uint8_t)(gen >> (8 * i));
+
+       if (size == LONG_FID_LEN) {
+               uint64_t        objsetid = dmu_objset_id(zsb->z_os);
+               zfid_long_t     *zlfid;
+
+               zlfid = (zfid_long_t *)fidp;
+
+               for (i = 0; i < sizeof (zlfid->zf_setid); i++)
+                       zlfid->zf_setid[i] = (uint8_t)(objsetid >> (8 * i));
+
+               /* XXX - this should be the generation number for the objset */
+               for (i = 0; i < sizeof (zlfid->zf_setgen); i++)
+                       zlfid->zf_setgen[i] = 0;
+       }
+
+       ZFS_EXIT(zsb);
+       return (0);
+}
+EXPORT_SYMBOL(zfs_fid);
+
+/*ARGSUSED*/
+int
+zfs_getsecattr(struct inode *ip, vsecattr_t *vsecp, int flag, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int error;
+       boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+       error = zfs_getacl(zp, vsecp, skipaclchk, cr);
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+EXPORT_SYMBOL(zfs_getsecattr);
+
+/*ARGSUSED*/
+int
+zfs_setsecattr(struct inode *ip, vsecattr_t *vsecp, int flag, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int error;
+       boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
+       zilog_t *zilog = zsb->z_log;
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+
+       error = zfs_setacl(zp, vsecp, skipaclchk, cr);
+
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zilog, 0);
+
+       ZFS_EXIT(zsb);
+       return (error);
+}
+EXPORT_SYMBOL(zfs_setsecattr);
+
+#ifdef HAVE_UIO_ZEROCOPY
+/*
+ * Tunable, both must be a power of 2.
+ *
+ * zcr_blksz_min: the smallest read we may consider to loan out an arcbuf
+ * zcr_blksz_max: if set to less than the file block size, allow loaning out of
+ *             an arcbuf for a partial block read
+ */
+int zcr_blksz_min = (1 << 10); /* 1K */
+int zcr_blksz_max = (1 << 17); /* 128K */
+
+/*ARGSUSED*/
+static int
+zfs_reqzcbuf(struct inode *ip, enum uio_rw ioflag, xuio_t *xuio, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+       int max_blksz = zsb->z_max_blksz;
+       uio_t *uio = &xuio->xu_uio;
+       ssize_t size = uio->uio_resid;
+       offset_t offset = uio->uio_loffset;
+       int blksz;
+       int fullblk, i;
+       arc_buf_t *abuf;
+       ssize_t maxsize;
+       int preamble, postamble;
+
+       if (xuio->xu_type != UIOTYPE_ZEROCOPY)
+               return (SET_ERROR(EINVAL));
+
+       ZFS_ENTER(zsb);
+       ZFS_VERIFY_ZP(zp);
+       switch (ioflag) {
+       case UIO_WRITE:
+               /*
+                * Loan out an arc_buf for write if write size is bigger than
+                * max_blksz, and the file's block size is also max_blksz.
+                */
+               blksz = max_blksz;
+               if (size < blksz || zp->z_blksz != blksz) {
+                       ZFS_EXIT(zsb);
+                       return (SET_ERROR(EINVAL));
+               }
+               /*
+                * Caller requests buffers for write before knowing where the
+                * write offset might be (e.g. NFS TCP write).
+                */
+               if (offset == -1) {
+                       preamble = 0;
+               } else {
+                       preamble = P2PHASE(offset, blksz);
+                       if (preamble) {
+                               preamble = blksz - preamble;
+                               size -= preamble;
+                       }
+               }
+
+               postamble = P2PHASE(size, blksz);
+               size -= postamble;
+
+               fullblk = size / blksz;
+               (void) dmu_xuio_init(xuio,
+                   (preamble != 0) + fullblk + (postamble != 0));
+
+               /*
+                * Have to fix iov base/len for partial buffers.  They
+                * currently represent full arc_buf's.
+                */
+               if (preamble) {
+                       /* data begins in the middle of the arc_buf */
+                       abuf = dmu_request_arcbuf(sa_get_db(zp->z_sa_hdl),
+                           blksz);
+                       ASSERT(abuf);
+                       (void) dmu_xuio_add(xuio, abuf,
+                           blksz - preamble, preamble);
+               }
+
+               for (i = 0; i < fullblk; i++) {
+                       abuf = dmu_request_arcbuf(sa_get_db(zp->z_sa_hdl),
+                           blksz);
+                       ASSERT(abuf);
+                       (void) dmu_xuio_add(xuio, abuf, 0, blksz);
+               }
+
+               if (postamble) {
+                       /* data ends in the middle of the arc_buf */
+                       abuf = dmu_request_arcbuf(sa_get_db(zp->z_sa_hdl),
+                           blksz);
+                       ASSERT(abuf);
+                       (void) dmu_xuio_add(xuio, abuf, 0, postamble);
+               }
+               break;
+       case UIO_READ:
+               /*
+                * Loan out an arc_buf for read if the read size is larger than
+                * the current file block size.  Block alignment is not
+                * considered.  Partial arc_buf will be loaned out for read.
+                */
+               blksz = zp->z_blksz;
+               if (blksz < zcr_blksz_min)
+                       blksz = zcr_blksz_min;
+               if (blksz > zcr_blksz_max)
+                       blksz = zcr_blksz_max;
+               /* avoid potential complexity of dealing with it */
+               if (blksz > max_blksz) {
+                       ZFS_EXIT(zsb);
+                       return (SET_ERROR(EINVAL));
+               }
+
+               maxsize = zp->z_size - uio->uio_loffset;
+               if (size > maxsize)
+                       size = maxsize;
+
+               if (size < blksz) {
+                       ZFS_EXIT(zsb);
+                       return (SET_ERROR(EINVAL));
+               }
+               break;
+       default:
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EINVAL));
+       }
+
+       uio->uio_extflg = UIO_XUIO;
+       XUIO_XUZC_RW(xuio) = ioflag;
+       ZFS_EXIT(zsb);
+       return (0);
+}
+
+/*ARGSUSED*/
+static int
+zfs_retzcbuf(struct inode *ip, xuio_t *xuio, cred_t *cr)
+{
+       int i;
+       arc_buf_t *abuf;
+       int ioflag = XUIO_XUZC_RW(xuio);
+
+       ASSERT(xuio->xu_type == UIOTYPE_ZEROCOPY);
+
+       i = dmu_xuio_cnt(xuio);
+       while (i-- > 0) {
+               abuf = dmu_xuio_arcbuf(xuio, i);
+               /*
+                * if abuf == NULL, it must be a write buffer
+                * that has been returned in zfs_write().
+                */
+               if (abuf)
+                       dmu_return_arcbuf(abuf);
+               ASSERT(abuf || ioflag == UIO_WRITE);
+       }
+
+       dmu_xuio_fini(xuio);
+       return (0);
+}
+#endif /* HAVE_UIO_ZEROCOPY */
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_read_chunk_size, long, 0644);
+MODULE_PARM_DESC(zfs_read_chunk_size, "Bytes to read per chunk");
+#endif
diff --git a/zfs/module/zfs/zfs_znode.c b/zfs/module/zfs/zfs_znode.c
new file mode 100644 (file)
index 0000000..e76bdc4
--- /dev/null
@@ -0,0 +1,2108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+/* Portions Copyright 2007 Jeremy Teo */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/resource.h>
+#include <sys/mntent.h>
+#include <sys/mkdev.h>
+#include <sys/u8_textprep.h>
+#include <sys/dsl_dataset.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/errno.h>
+#include <sys/unistd.h>
+#include <sys/mode.h>
+#include <sys/atomic.h>
+#include <vm/pvn.h>
+#include "fs/fs_subr.h"
+#include <sys/zfs_dir.h>
+#include <sys/zfs_acl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_rlock.h>
+#include <sys/zfs_fuid.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/dnode.h>
+#include <sys/fs/zfs.h>
+#include <sys/kidmap.h>
+#include <sys/zpl.h>
+#endif /* _KERNEL */
+
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/refcount.h>
+#include <sys/stat.h>
+#include <sys/zap.h>
+#include <sys/zfs_znode.h>
+#include <sys/sa.h>
+#include <sys/zfs_sa.h>
+#include <sys/zfs_stat.h>
+
+#include "zfs_prop.h"
+#include "zfs_comutil.h"
+
+/*
+ * Define ZNODE_STATS to turn on statistic gathering. By default, it is only
+ * turned on when DEBUG is also defined.
+ */
+#ifdef DEBUG
+#define        ZNODE_STATS
+#endif /* DEBUG */
+
+#ifdef ZNODE_STATS
+#define        ZNODE_STAT_ADD(stat)                    ((stat)++)
+#else
+#define        ZNODE_STAT_ADD(stat)                    /* nothing */
+#endif /* ZNODE_STATS */
+
+/*
+ * Functions needed for userland (ie: libzpool) are not put under
+ * #ifdef_KERNEL; the rest of the functions have dependencies
+ * (such as VFS logic) that will not compile easily in userland.
+ */
+#ifdef _KERNEL
+
+static kmem_cache_t *znode_cache = NULL;
+static kmem_cache_t *znode_hold_cache = NULL;
+unsigned int zfs_object_mutex_size = ZFS_OBJ_MTX_SZ;
+
+/*ARGSUSED*/
+static int
+zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
+{
+       znode_t *zp = buf;
+
+       inode_init_once(ZTOI(zp));
+       list_link_init(&zp->z_link_node);
+
+       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);
+       mutex_init(&zp->z_acl_lock, NULL, MUTEX_DEFAULT, NULL);
+       rw_init(&zp->z_xattr_lock, NULL, RW_DEFAULT, NULL);
+
+       zfs_rlock_init(&zp->z_range_lock);
+
+       zp->z_dirlocks = NULL;
+       zp->z_acl_cached = NULL;
+       zp->z_xattr_cached = NULL;
+       zp->z_moved = 0;
+       return (0);
+}
+
+/*ARGSUSED*/
+static void
+zfs_znode_cache_destructor(void *buf, void *arg)
+{
+       znode_t *zp = buf;
+
+       ASSERT(!list_link_active(&zp->z_link_node));
+       mutex_destroy(&zp->z_lock);
+       rw_destroy(&zp->z_parent_lock);
+       rw_destroy(&zp->z_name_lock);
+       mutex_destroy(&zp->z_acl_lock);
+       rw_destroy(&zp->z_xattr_lock);
+       zfs_rlock_destroy(&zp->z_range_lock);
+
+       ASSERT(zp->z_dirlocks == NULL);
+       ASSERT(zp->z_acl_cached == NULL);
+       ASSERT(zp->z_xattr_cached == NULL);
+}
+
+static int
+zfs_znode_hold_cache_constructor(void *buf, void *arg, int kmflags)
+{
+       znode_hold_t *zh = buf;
+
+       mutex_init(&zh->zh_lock, NULL, MUTEX_DEFAULT, NULL);
+       refcount_create(&zh->zh_refcount);
+       zh->zh_obj = ZFS_NO_OBJECT;
+
+       return (0);
+}
+
+static void
+zfs_znode_hold_cache_destructor(void *buf, void *arg)
+{
+       znode_hold_t *zh = buf;
+
+       mutex_destroy(&zh->zh_lock);
+       refcount_destroy(&zh->zh_refcount);
+}
+
+void
+zfs_znode_init(void)
+{
+       /*
+        * Initialize zcache.  The KMC_SLAB hint is used in order that it be
+        * backed by kmalloc() when on the Linux slab in order that any
+        * wait_on_bit() operations on the related inode operate properly.
+        */
+       ASSERT(znode_cache == NULL);
+       znode_cache = kmem_cache_create("zfs_znode_cache",
+           sizeof (znode_t), 0, zfs_znode_cache_constructor,
+           zfs_znode_cache_destructor, NULL, NULL, NULL, KMC_SLAB);
+
+       ASSERT(znode_hold_cache == NULL);
+       znode_hold_cache = kmem_cache_create("zfs_znode_hold_cache",
+           sizeof (znode_hold_t), 0, zfs_znode_hold_cache_constructor,
+           zfs_znode_hold_cache_destructor, NULL, NULL, NULL, 0);
+}
+
+void
+zfs_znode_fini(void)
+{
+       /*
+        * Cleanup zcache
+        */
+       if (znode_cache)
+               kmem_cache_destroy(znode_cache);
+       znode_cache = NULL;
+
+       if (znode_hold_cache)
+               kmem_cache_destroy(znode_hold_cache);
+       znode_hold_cache = NULL;
+}
+
+/*
+ * The zfs_znode_hold_enter() / zfs_znode_hold_exit() functions are used to
+ * serialize access to a znode and its SA buffer while the object is being
+ * created or destroyed.  This kind of locking would normally reside in the
+ * znode itself but in this case that's impossible because the znode and SA
+ * buffer may not yet exist.  Therefore the locking is handled externally
+ * with an array of mutexs and AVLs trees which contain per-object locks.
+ *
+ * In zfs_znode_hold_enter() a per-object lock is created as needed, inserted
+ * in to the correct AVL tree and finally the per-object lock is held.  In
+ * zfs_znode_hold_exit() the process is reversed.  The per-object lock is
+ * released, removed from the AVL tree and destroyed if there are no waiters.
+ *
+ * This scheme has two important properties:
+ *
+ * 1) No memory allocations are performed while holding one of the z_hold_locks.
+ *    This ensures evict(), which can be called from direct memory reclaim, will
+ *    never block waiting on a z_hold_locks which just happens to have hashed
+ *    to the same index.
+ *
+ * 2) All locks used to serialize access to an object are per-object and never
+ *    shared.  This minimizes lock contention without creating a large number
+ *    of dedicated locks.
+ *
+ * On the downside it does require znode_lock_t structures to be frequently
+ * allocated and freed.  However, because these are backed by a kmem cache
+ * and very short lived this cost is minimal.
+ */
+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;
+
+       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);
+}
+
+boolean_t
+zfs_znode_held(zfs_sb_t *zsb, uint64_t obj)
+{
+       znode_hold_t *zh, search;
+       int i = ZFS_OBJ_HASH(zsb, obj);
+       boolean_t held;
+
+       search.zh_obj = obj;
+
+       mutex_enter(&zsb->z_hold_locks[i]);
+       zh = avl_find(&zsb->z_hold_trees[i], &search, NULL);
+       held = (zh && MUTEX_HELD(&zh->zh_lock)) ? B_TRUE : B_FALSE;
+       mutex_exit(&zsb->z_hold_locks[i]);
+
+       return (held);
+}
+
+static znode_hold_t *
+zfs_znode_hold_enter(zfs_sb_t *zsb, uint64_t obj)
+{
+       znode_hold_t *zh, *zh_new, search;
+       int i = ZFS_OBJ_HASH(zsb, obj);
+       boolean_t found = B_FALSE;
+
+       zh_new = kmem_cache_alloc(znode_hold_cache, KM_SLEEP);
+       zh_new->zh_obj = obj;
+       search.zh_obj = obj;
+
+       mutex_enter(&zsb->z_hold_locks[i]);
+       zh = avl_find(&zsb->z_hold_trees[i], &search, NULL);
+       if (likely(zh == NULL)) {
+               zh = zh_new;
+               avl_add(&zsb->z_hold_trees[i], zh);
+       } else {
+               ASSERT3U(zh->zh_obj, ==, obj);
+               found = B_TRUE;
+       }
+       refcount_add(&zh->zh_refcount, NULL);
+       mutex_exit(&zsb->z_hold_locks[i]);
+
+       if (found == B_TRUE)
+               kmem_cache_free(znode_hold_cache, zh_new);
+
+       ASSERT(MUTEX_NOT_HELD(&zh->zh_lock));
+       ASSERT3S(refcount_count(&zh->zh_refcount), >, 0);
+       mutex_enter(&zh->zh_lock);
+
+       return (zh);
+}
+
+static void
+zfs_znode_hold_exit(zfs_sb_t *zsb, znode_hold_t *zh)
+{
+       int i = ZFS_OBJ_HASH(zsb, zh->zh_obj);
+       boolean_t remove = B_FALSE;
+
+       ASSERT(zfs_znode_held(zsb, zh->zh_obj));
+       ASSERT3S(refcount_count(&zh->zh_refcount), >, 0);
+       mutex_exit(&zh->zh_lock);
+
+       mutex_enter(&zsb->z_hold_locks[i]);
+       if (refcount_remove(&zh->zh_refcount, NULL) == 0) {
+               avl_remove(&zsb->z_hold_trees[i], zh);
+               remove = B_TRUE;
+       }
+       mutex_exit(&zsb->z_hold_locks[i]);
+
+       if (remove == B_TRUE)
+               kmem_cache_free(znode_hold_cache, zh);
+}
+
+int
+zfs_create_share_dir(zfs_sb_t *zsb, dmu_tx_t *tx)
+{
+#ifdef HAVE_SMB_SHARE
+       zfs_acl_ids_t acl_ids;
+       vattr_t vattr;
+       znode_t *sharezp;
+       vnode_t *vp;
+       znode_t *zp;
+       int error;
+
+       vattr.va_mask = AT_MODE|AT_UID|AT_GID|AT_TYPE;
+       vattr.va_mode = S_IFDIR | 0555;
+       vattr.va_uid = crgetuid(kcred);
+       vattr.va_gid = crgetgid(kcred);
+
+       sharezp = kmem_cache_alloc(znode_cache, KM_SLEEP);
+       sharezp->z_moved = 0;
+       sharezp->z_unlinked = 0;
+       sharezp->z_atime_dirty = 0;
+       sharezp->z_zfsvfs = zfsvfs;
+       sharezp->z_is_sa = zfsvfs->z_use_sa;
+
+       vp = ZTOV(sharezp);
+       vn_reinit(vp);
+       vp->v_type = VDIR;
+
+       VERIFY(0 == zfs_acl_ids_create(sharezp, IS_ROOT_NODE, &vattr,
+           kcred, NULL, &acl_ids));
+       zfs_mknode(sharezp, &vattr, tx, kcred, IS_ROOT_NODE, &zp, &acl_ids);
+       ASSERT3P(zp, ==, sharezp);
+       ASSERT(!vn_in_dnlc(ZTOV(sharezp))); /* not valid to move */
+       POINTER_INVALIDATE(&sharezp->z_zfsvfs);
+       error = zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
+           ZFS_SHARES_DIR, 8, 1, &sharezp->z_id, tx);
+       zfsvfs->z_shares_dir = sharezp->z_id;
+
+       zfs_acl_ids_free(&acl_ids);
+       // ZTOV(sharezp)->v_count = 0;
+       sa_handle_destroy(sharezp->z_sa_hdl);
+       kmem_cache_free(znode_cache, sharezp);
+
+       return (error);
+#else
+       return (0);
+#endif /* HAVE_SMB_SHARE */
+}
+
+static void
+zfs_znode_sa_init(zfs_sb_t *zsb, znode_t *zp,
+    dmu_buf_t *db, dmu_object_type_t obj_type, sa_handle_t *sa_hdl)
+{
+       ASSERT(zfs_znode_held(zsb, zp->z_id));
+
+       mutex_enter(&zp->z_lock);
+
+       ASSERT(zp->z_sa_hdl == NULL);
+       ASSERT(zp->z_acl_cached == NULL);
+       if (sa_hdl == NULL) {
+               VERIFY(0 == sa_handle_get_from_db(zsb->z_os, db, zp,
+                   SA_HDL_SHARED, &zp->z_sa_hdl));
+       } else {
+               zp->z_sa_hdl = sa_hdl;
+               sa_set_userp(sa_hdl, zp);
+       }
+
+       zp->z_is_sa = (obj_type == DMU_OT_SA) ? B_TRUE : B_FALSE;
+
+       mutex_exit(&zp->z_lock);
+}
+
+void
+zfs_znode_dmu_fini(znode_t *zp)
+{
+       ASSERT(zfs_znode_held(ZTOZSB(zp), zp->z_id) || zp->z_unlinked ||
+           RW_WRITE_HELD(&ZTOZSB(zp)->z_teardown_inactive_lock));
+
+       sa_handle_destroy(zp->z_sa_hdl);
+       zp->z_sa_hdl = NULL;
+}
+
+/*
+ * Called by new_inode() to allocate a new inode.
+ */
+int
+zfs_inode_alloc(struct super_block *sb, struct inode **ip)
+{
+       znode_t *zp;
+
+       zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
+       *ip = ZTOI(zp);
+
+       return (0);
+}
+
+/*
+ * Called in multiple places when an inode should be destroyed.
+ */
+void
+zfs_inode_destroy(struct inode *ip)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+
+       mutex_enter(&zsb->z_znodes_lock);
+       if (list_link_active(&zp->z_link_node)) {
+               list_remove(&zsb->z_all_znodes, zp);
+               zsb->z_nr_znodes--;
+       }
+       mutex_exit(&zsb->z_znodes_lock);
+
+       if (zp->z_acl_cached) {
+               zfs_acl_free(zp->z_acl_cached);
+               zp->z_acl_cached = NULL;
+       }
+
+       if (zp->z_xattr_cached) {
+               nvlist_free(zp->z_xattr_cached);
+               zp->z_xattr_cached = NULL;
+       }
+
+       kmem_cache_free(znode_cache, zp);
+}
+
+static void
+zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip)
+{
+       uint64_t rdev = 0;
+
+       switch (ip->i_mode & S_IFMT) {
+       case S_IFREG:
+               ip->i_op = &zpl_inode_operations;
+               ip->i_fop = &zpl_file_operations;
+               ip->i_mapping->a_ops = &zpl_address_space_operations;
+               break;
+
+       case S_IFDIR:
+               ip->i_op = &zpl_dir_inode_operations;
+               ip->i_fop = &zpl_dir_file_operations;
+               ITOZ(ip)->z_zn_prefetch = B_TRUE;
+               break;
+
+       case S_IFLNK:
+               ip->i_op = &zpl_symlink_inode_operations;
+               break;
+
+       /*
+        * rdev is only stored in a SA only for device files.
+        */
+       case S_IFCHR:
+       case S_IFBLK:
+               sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zsb), &rdev,
+                   sizeof (rdev));
+               /*FALLTHROUGH*/
+       case S_IFIFO:
+       case S_IFSOCK:
+               init_special_inode(ip, ip->i_mode, rdev);
+               ip->i_op = &zpl_special_inode_operations;
+               break;
+
+       default:
+               zfs_panic_recover("inode %llu has invalid mode: 0x%x\n",
+                   (u_longlong_t)ip->i_ino, ip->i_mode);
+
+               /* Assume the inode is a file and attempt to continue */
+               ip->i_mode = S_IFREG | 0644;
+               ip->i_op = &zpl_inode_operations;
+               ip->i_fop = &zpl_file_operations;
+               ip->i_mapping->a_ops = &zpl_address_space_operations;
+               break;
+       }
+}
+
+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.
+ */
+static void
+zfs_inode_update_impl(znode_t *zp, boolean_t new)
+{
+       zfs_sb_t        *zsb;
+       struct inode    *ip;
+       uint32_t        blksize;
+       u_longlong_t    i_blocks;
+       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);
+
+       dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, &i_blocks);
+
+       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;
+       ip->i_blocks = i_blocks;
+
+       /*
+        * Only read atime from SA if we are newly created inode (or rezget),
+        * otherwise i_atime might be dirty.
+        */
+       if (new)
+               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);
+}
+
+static void
+zfs_inode_update_new(znode_t *zp)
+{
+       zfs_inode_update_impl(zp, B_TRUE);
+}
+
+void
+zfs_inode_update(znode_t *zp)
+{
+       zfs_inode_update_impl(zp, B_FALSE);
+}
+
+/*
+ * Construct a znode+inode and initialize.
+ *
+ * This does not do a call to dmu_set_user() that is
+ * up to the caller to do, in case you don't want to
+ * return the znode
+ */
+static znode_t *
+zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz,
+    dmu_object_type_t obj_type, uint64_t obj, sa_handle_t *hdl)
+{
+       znode_t *zp;
+       struct inode *ip;
+       uint64_t mode;
+       uint64_t parent;
+       sa_bulk_attr_t bulk[8];
+       int count = 0;
+
+       ASSERT(zsb != NULL);
+
+       ip = new_inode(zsb->z_sb);
+       if (ip == NULL)
+               return (NULL);
+
+       zp = ITOZ(ip);
+       ASSERT(zp->z_dirlocks == NULL);
+       ASSERT3P(zp->z_acl_cached, ==, NULL);
+       ASSERT3P(zp->z_xattr_cached, ==, NULL);
+       zp->z_moved = 0;
+       zp->z_sa_hdl = NULL;
+       zp->z_unlinked = 0;
+       zp->z_atime_dirty = 0;
+       zp->z_mapcnt = 0;
+       zp->z_id = db->db_object;
+       zp->z_blksz = blksz;
+       zp->z_seq = 0x7A4653;
+       zp->z_sync_cnt = 0;
+       zp->z_is_mapped = B_FALSE;
+       zp->z_is_ctldir = B_FALSE;
+       zp->z_is_stale = B_FALSE;
+       zp->z_range_lock.zr_size = &zp->z_size;
+       zp->z_range_lock.zr_blksz = &zp->z_blksz;
+       zp->z_range_lock.zr_max_blksz = &ZTOZSB(zp)->z_max_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_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_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_UID(zsb), NULL, &zp->z_uid, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb), NULL, &zp->z_gid, 8);
+
+       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;
+
+       ip->i_ino = obj;
+       zfs_inode_update_new(zp);
+       zfs_inode_set_ops(zsb, ip);
+
+       /*
+        * The only way insert_inode_locked() can fail is if the ip->i_ino
+        * number is already hashed for this super block.  This can never
+        * happen because the inode numbers map 1:1 with the object numbers.
+        *
+        * The one exception is rolling back a mounted file system, but in
+        * this case all the active inode are unhashed during the rollback.
+        */
+       VERIFY3S(insert_inode_locked(ip), ==, 0);
+
+       mutex_enter(&zsb->z_znodes_lock);
+       list_insert_tail(&zsb->z_all_znodes, zp);
+       zsb->z_nr_znodes++;
+       membar_producer();
+       mutex_exit(&zsb->z_znodes_lock);
+
+       unlock_new_inode(ip);
+       return (zp);
+
+error:
+       iput(ip);
+       return (NULL);
+}
+
+/*
+ * Safely mark an inode dirty.  Inodes which are part of a read-only
+ * file system or snapshot may not be dirtied.
+ */
+void
+zfs_mark_inode_dirty(struct inode *ip)
+{
+       zfs_sb_t *zsb = ITOZSB(ip);
+
+       if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os))
+               return;
+
+       mark_inode_dirty(ip);
+}
+
+static uint64_t empty_xattr;
+static uint64_t pad[4];
+static zfs_acl_phys_t acl_phys;
+/*
+ * Create a new DMU object to hold a zfs znode.
+ *
+ *     IN:     dzp     - parent directory for new znode
+ *             vap     - file attributes for new znode
+ *             tx      - dmu transaction id for zap operations
+ *             cr      - credentials of caller
+ *             flag    - flags:
+ *                       IS_ROOT_NODE  - new object will be root
+ *                       IS_XATTR      - new object is an attribute
+ *             bonuslen - length of bonus buffer
+ *             setaclp  - File/Dir initial ACL
+ *             fuidp    - Tracks fuid allocation.
+ *
+ *     OUT:    zpp     - allocated znode
+ *
+ */
+void
+zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
+    uint_t flag, znode_t **zpp, zfs_acl_ids_t *acl_ids)
+{
+       uint64_t        crtime[2], atime[2], mtime[2], ctime[2];
+       uint64_t        mode, size, links, parent, pflags;
+       uint64_t        dzp_pflags = 0;
+       uint64_t        rdev = 0;
+       zfs_sb_t        *zsb = ZTOZSB(dzp);
+       dmu_buf_t       *db;
+       timestruc_t     now;
+       uint64_t        gen, obj;
+       int             bonuslen;
+       sa_handle_t     *sa_hdl;
+       dmu_object_type_t obj_type;
+       sa_bulk_attr_t  *sa_attrs;
+       int             cnt = 0;
+       zfs_acl_locator_cb_t locate = { 0 };
+       znode_hold_t    *zh;
+
+       if (zsb->z_replay) {
+               obj = vap->va_nodeid;
+               now = vap->va_ctime;            /* see zfs_replay_create() */
+               gen = vap->va_nblocks;          /* ditto */
+       } else {
+               obj = 0;
+               gethrestime(&now);
+               gen = dmu_tx_get_txg(tx);
+       }
+
+       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;
+
+       /*
+        * Create a new DMU object.
+        */
+       /*
+        * There's currently no mechanism for pre-reading the blocks that will
+        * be needed to allocate a new object, so we accept the small chance
+        * that there will be an i/o error and we will fail one of the
+        * assertions below.
+        */
+       if (S_ISDIR(vap->va_mode)) {
+               if (zsb->z_replay) {
+                       VERIFY0(zap_create_claim_norm(zsb->z_os, obj,
+                           zsb->z_norm, DMU_OT_DIRECTORY_CONTENTS,
+                           obj_type, bonuslen, tx));
+               } else {
+                       obj = zap_create_norm(zsb->z_os,
+                           zsb->z_norm, DMU_OT_DIRECTORY_CONTENTS,
+                           obj_type, bonuslen, tx);
+               }
+       } else {
+               if (zsb->z_replay) {
+                       VERIFY0(dmu_object_claim(zsb->z_os, obj,
+                           DMU_OT_PLAIN_FILE_CONTENTS, 0,
+                           obj_type, bonuslen, tx));
+               } else {
+                       obj = dmu_object_alloc(zsb->z_os,
+                           DMU_OT_PLAIN_FILE_CONTENTS, 0,
+                           obj_type, bonuslen, tx);
+               }
+       }
+
+       zh = zfs_znode_hold_enter(zsb, obj);
+       VERIFY(0 == sa_buf_hold(zsb->z_os, obj, NULL, &db));
+
+       /*
+        * If this is the root, fix up the half-initialized parent pointer
+        * to reference the just-allocated physical data area.
+        */
+       if (flag & IS_ROOT_NODE) {
+               dzp->z_id = obj;
+       } else {
+               dzp_pflags = dzp->z_pflags;
+       }
+
+       /*
+        * If parent is an xattr, so am I.
+        */
+       if (dzp_pflags & ZFS_XATTR) {
+               flag |= IS_XATTR;
+       }
+
+       if (zsb->z_use_fuids)
+               pflags = ZFS_ARCHIVE | ZFS_AV_MODIFIED;
+       else
+               pflags = 0;
+
+       if (S_ISDIR(vap->va_mode)) {
+               size = 2;               /* contents ("." and "..") */
+               links = (flag & (IS_ROOT_NODE | IS_XATTR)) ? 2 : 1;
+       } else {
+               size = links = 0;
+       }
+
+       if (S_ISBLK(vap->va_mode) || S_ISCHR(vap->va_mode))
+               rdev = vap->va_rdev;
+
+       parent = dzp->z_id;
+       mode = acl_ids->z_mode;
+       if (flag & IS_XATTR)
+               pflags |= ZFS_XATTR;
+
+       /*
+        * No execs denied will be deterimed when zfs_mode_compute() is called.
+        */
+       pflags |= acl_ids->z_aclp->z_hints &
+           (ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|ZFS_ACL_AUTO_INHERIT|
+           ZFS_ACL_DEFAULTED|ZFS_ACL_PROTECTED);
+
+       ZFS_TIME_ENCODE(&now, crtime);
+       ZFS_TIME_ENCODE(&now, ctime);
+
+       if (vap->va_mask & ATTR_ATIME) {
+               ZFS_TIME_ENCODE(&vap->va_atime, atime);
+       } else {
+               ZFS_TIME_ENCODE(&now, atime);
+       }
+
+       if (vap->va_mask & ATTR_MTIME) {
+               ZFS_TIME_ENCODE(&vap->va_mtime, mtime);
+       } else {
+               ZFS_TIME_ENCODE(&now, mtime);
+       }
+
+       /* Now add in all of the "SA" attributes */
+       VERIFY(0 == sa_handle_get_from_db(zsb->z_os, db, NULL, SA_HDL_SHARED,
+           &sa_hdl));
+
+       /*
+        * Setup the array of attributes to be replaced/set on the new file
+        *
+        * order for  DMU_OT_ZNODE is critical since it needs to be constructed
+        * in the old znode_phys_t format.  Don't change this ordering
+        */
+       sa_attrs = kmem_alloc(sizeof (sa_bulk_attr_t) * ZPL_END, KM_SLEEP);
+
+       if (obj_type == DMU_OT_ZNODE) {
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_ATIME(zsb),
+                   NULL, &atime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_MTIME(zsb),
+                   NULL, &mtime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_CTIME(zsb),
+                   NULL, &ctime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_CRTIME(zsb),
+                   NULL, &crtime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_GEN(zsb),
+                   NULL, &gen, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_MODE(zsb),
+                   NULL, &mode, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_SIZE(zsb),
+                   NULL, &size, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_PARENT(zsb),
+                   NULL, &parent, 8);
+       } else {
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_MODE(zsb),
+                   NULL, &mode, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_SIZE(zsb),
+                   NULL, &size, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_GEN(zsb),
+                   NULL, &gen, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_UID(zsb),
+                   NULL, &acl_ids->z_fuid, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_GID(zsb),
+                   NULL, &acl_ids->z_fgid, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_PARENT(zsb),
+                   NULL, &parent, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_FLAGS(zsb),
+                   NULL, &pflags, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_ATIME(zsb),
+                   NULL, &atime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_MTIME(zsb),
+                   NULL, &mtime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_CTIME(zsb),
+                   NULL, &ctime, 16);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_CRTIME(zsb),
+                   NULL, &crtime, 16);
+       }
+
+       SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_LINKS(zsb), NULL, &links, 8);
+
+       if (obj_type == DMU_OT_ZNODE) {
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_XATTR(zsb), NULL,
+                   &empty_xattr, 8);
+       }
+       if (obj_type == DMU_OT_ZNODE ||
+           (S_ISBLK(vap->va_mode) || S_ISCHR(vap->va_mode))) {
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_RDEV(zsb),
+                   NULL, &rdev, 8);
+       }
+       if (obj_type == DMU_OT_ZNODE) {
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_FLAGS(zsb),
+                   NULL, &pflags, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_UID(zsb), NULL,
+                   &acl_ids->z_fuid, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_GID(zsb), NULL,
+                   &acl_ids->z_fgid, 8);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_PAD(zsb), NULL, pad,
+                   sizeof (uint64_t) * 4);
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_ZNODE_ACL(zsb), NULL,
+                   &acl_phys, sizeof (zfs_acl_phys_t));
+       } else if (acl_ids->z_aclp->z_version >= ZFS_ACL_VERSION_FUID) {
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_DACL_COUNT(zsb), NULL,
+                   &acl_ids->z_aclp->z_acl_count, 8);
+               locate.cb_aclp = acl_ids->z_aclp;
+               SA_ADD_BULK_ATTR(sa_attrs, cnt, SA_ZPL_DACL_ACES(zsb),
+                   zfs_acl_data_locator, &locate,
+                   acl_ids->z_aclp->z_acl_bytes);
+               mode = zfs_mode_compute(mode, acl_ids->z_aclp, &pflags,
+                   acl_ids->z_fuid, acl_ids->z_fgid);
+       }
+
+       VERIFY(sa_replace_all_by_template(sa_hdl, sa_attrs, cnt, tx) == 0);
+
+       if (!(flag & IS_ROOT_NODE)) {
+               *zpp = zfs_znode_alloc(zsb, db, 0, obj_type, obj, sa_hdl);
+               VERIFY(*zpp != NULL);
+               VERIFY(dzp != NULL);
+       } else {
+               /*
+                * If we are creating the root node, the "parent" we
+                * passed in is the znode for the root.
+                */
+               *zpp = dzp;
+
+               (*zpp)->z_sa_hdl = sa_hdl;
+       }
+
+       (*zpp)->z_pflags = pflags;
+       (*zpp)->z_mode = mode;
+
+       if (obj_type == DMU_OT_ZNODE ||
+           acl_ids->z_aclp->z_version < ZFS_ACL_VERSION_FUID) {
+               VERIFY0(zfs_aclset_common(*zpp, acl_ids->z_aclp, cr, tx));
+       }
+       kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * ZPL_END);
+       zfs_znode_hold_exit(zsb, zh);
+}
+
+/*
+ * Update in-core attributes.  It is assumed the caller will be doing an
+ * sa_bulk_update to push the changes out.
+ */
+void
+zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
+{
+       xoptattr_t *xoap;
+
+       xoap = xva_getxoptattr(xvap);
+       ASSERT(xoap);
+
+       if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+               uint64_t times[2];
+               ZFS_TIME_ENCODE(&xoap->xoa_createtime, times);
+               (void) sa_update(zp->z_sa_hdl, SA_ZPL_CRTIME(ZTOZSB(zp)),
+                   &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);
+               XVA_SET_RTN(xvap, XAT_READONLY);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+               ZFS_ATTR_SET(zp, ZFS_HIDDEN, xoap->xoa_hidden,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_HIDDEN);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+               ZFS_ATTR_SET(zp, ZFS_SYSTEM, xoap->xoa_system,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_SYSTEM);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+               ZFS_ATTR_SET(zp, ZFS_ARCHIVE, xoap->xoa_archive,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_ARCHIVE);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+               ZFS_ATTR_SET(zp, ZFS_IMMUTABLE, xoap->xoa_immutable,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+               ZFS_ATTR_SET(zp, ZFS_NOUNLINK, xoap->xoa_nounlink,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_NOUNLINK);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+               ZFS_ATTR_SET(zp, ZFS_APPENDONLY, xoap->xoa_appendonly,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_APPENDONLY);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+               ZFS_ATTR_SET(zp, ZFS_NODUMP, xoap->xoa_nodump,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_NODUMP);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+               ZFS_ATTR_SET(zp, ZFS_OPAQUE, xoap->xoa_opaque,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_OPAQUE);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+               ZFS_ATTR_SET(zp, ZFS_AV_QUARANTINED,
+                   xoap->xoa_av_quarantined, zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+               ZFS_ATTR_SET(zp, ZFS_AV_MODIFIED, xoap->xoa_av_modified,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+               zfs_sa_set_scanstamp(zp, xvap, tx);
+               XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
+               ZFS_ATTR_SET(zp, ZFS_REPARSE, xoap->xoa_reparse,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_REPARSE);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) {
+               ZFS_ATTR_SET(zp, ZFS_OFFLINE, xoap->xoa_offline,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_OFFLINE);
+       }
+       if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
+               ZFS_ATTR_SET(zp, ZFS_SPARSE, xoap->xoa_sparse,
+                   zp->z_pflags, tx);
+               XVA_SET_RTN(xvap, XAT_SPARSE);
+       }
+}
+
+int
+zfs_zget(zfs_sb_t *zsb, uint64_t obj_num, znode_t **zpp)
+{
+       dmu_object_info_t doi;
+       dmu_buf_t       *db;
+       znode_t         *zp;
+       znode_hold_t    *zh;
+       int err;
+       sa_handle_t     *hdl;
+
+       *zpp = NULL;
+
+again:
+       zh = zfs_znode_hold_enter(zsb, obj_num);
+
+       err = sa_buf_hold(zsb->z_os, obj_num, NULL, &db);
+       if (err) {
+               zfs_znode_hold_exit(zsb, zh);
+               return (err);
+       }
+
+       dmu_object_info_from_db(db, &doi);
+       if (doi.doi_bonus_type != DMU_OT_SA &&
+           (doi.doi_bonus_type != DMU_OT_ZNODE ||
+           (doi.doi_bonus_type == DMU_OT_ZNODE &&
+           doi.doi_bonus_size < sizeof (znode_phys_t)))) {
+               sa_buf_rele(db, NULL);
+               zfs_znode_hold_exit(zsb, zh);
+               return (SET_ERROR(EINVAL));
+       }
+
+       hdl = dmu_buf_get_user(db);
+       if (hdl != NULL) {
+               zp = sa_get_userdata(hdl);
+
+
+               /*
+                * Since "SA" does immediate eviction we
+                * should never find a sa handle that doesn't
+                * know about the znode.
+                */
+
+               ASSERT3P(zp, !=, NULL);
+
+               mutex_enter(&zp->z_lock);
+               ASSERT3U(zp->z_id, ==, obj_num);
+               if (zp->z_unlinked) {
+                       err = SET_ERROR(ENOENT);
+               } else {
+                       /*
+                        * If igrab() returns NULL the VFS has independently
+                        * determined the inode should be evicted and has
+                        * called iput_final() to start the eviction process.
+                        * The SA handle is still valid but because the VFS
+                        * requires that the eviction succeed we must drop
+                        * our locks and references to allow the eviction to
+                        * complete.  The zfs_zget() may then be retried.
+                        *
+                        * This unlikely case could be optimized by registering
+                        * a sops->drop_inode() callback.  The callback would
+                        * need to detect the active SA hold thereby informing
+                        * the VFS that this inode should not be evicted.
+                        */
+                       if (igrab(ZTOI(zp)) == NULL) {
+                               mutex_exit(&zp->z_lock);
+                               sa_buf_rele(db, NULL);
+                               zfs_znode_hold_exit(zsb, zh);
+                               /* inode might need this to finish evict */
+                               cond_resched();
+                               goto again;
+                       }
+                       *zpp = zp;
+                       err = 0;
+               }
+               mutex_exit(&zp->z_lock);
+               sa_buf_rele(db, NULL);
+               zfs_znode_hold_exit(zsb, zh);
+               return (err);
+       }
+
+       /*
+        * Not found create new znode/vnode but only if file exists.
+        *
+        * There is a small window where zfs_vget() could
+        * find this object while a file create is still in
+        * progress.  This is checked for in zfs_znode_alloc()
+        *
+        * if zfs_znode_alloc() fails it will drop the hold on the
+        * bonus buffer.
+        */
+       zp = zfs_znode_alloc(zsb, db, doi.doi_data_block_size,
+           doi.doi_bonus_type, obj_num, NULL);
+       if (zp == NULL) {
+               err = SET_ERROR(ENOENT);
+       } else {
+               *zpp = zp;
+       }
+       zfs_znode_hold_exit(zsb, zh);
+       return (err);
+}
+
+int
+zfs_rezget(znode_t *zp)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       dmu_object_info_t doi;
+       dmu_buf_t *db;
+       uint64_t obj_num = zp->z_id;
+       uint64_t mode;
+       sa_bulk_attr_t bulk[7];
+       int err;
+       int count = 0;
+       uint64_t gen;
+       znode_hold_t *zh;
+
+       /*
+        * skip ctldir, otherwise they will always get invalidated. This will
+        * cause funny behaviour for the mounted snapdirs. Especially for
+        * Linux >= 3.18, d_invalidate will detach the mountpoint and prevent
+        * anyone automount it again as long as someone is still using the
+        * detached mount.
+        */
+       if (zp->z_is_ctldir)
+               return (0);
+
+       zh = zfs_znode_hold_enter(zsb, obj_num);
+
+       mutex_enter(&zp->z_acl_lock);
+       if (zp->z_acl_cached) {
+               zfs_acl_free(zp->z_acl_cached);
+               zp->z_acl_cached = NULL;
+       }
+       mutex_exit(&zp->z_acl_lock);
+
+       rw_enter(&zp->z_xattr_lock, RW_WRITER);
+       if (zp->z_xattr_cached) {
+               nvlist_free(zp->z_xattr_cached);
+               zp->z_xattr_cached = NULL;
+       }
+       rw_exit(&zp->z_xattr_lock);
+
+       ASSERT(zp->z_sa_hdl == NULL);
+       err = sa_buf_hold(zsb->z_os, obj_num, NULL, &db);
+       if (err) {
+               zfs_znode_hold_exit(zsb, zh);
+               return (err);
+       }
+
+       dmu_object_info_from_db(db, &doi);
+       if (doi.doi_bonus_type != DMU_OT_SA &&
+           (doi.doi_bonus_type != DMU_OT_ZNODE ||
+           (doi.doi_bonus_type == DMU_OT_ZNODE &&
+           doi.doi_bonus_size < sizeof (znode_phys_t)))) {
+               sa_buf_rele(db, NULL);
+               zfs_znode_hold_exit(zsb, zh);
+               return (SET_ERROR(EINVAL));
+       }
+
+       zfs_znode_sa_init(zsb, zp, db, doi.doi_bonus_type, NULL);
+
+       /* reload cached values */
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zsb), NULL,
+           &gen, sizeof (gen));
+       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));
+       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_UID(zsb), NULL,
+           &zp->z_uid, sizeof (zp->z_uid));
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb), NULL,
+           &zp->z_gid, sizeof (zp->z_gid));
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL,
+           &mode, sizeof (mode));
+
+       if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) {
+               zfs_znode_dmu_fini(zp);
+               zfs_znode_hold_exit(zsb, zh);
+               return (SET_ERROR(EIO));
+       }
+
+       zp->z_mode = mode;
+
+       if (gen != zp->z_gen) {
+               zfs_znode_dmu_fini(zp);
+               zfs_znode_hold_exit(zsb, zh);
+               return (SET_ERROR(EIO));
+       }
+
+       zp->z_unlinked = (zp->z_links == 0);
+       zp->z_blksz = doi.doi_data_block_size;
+       zp->z_atime_dirty = 0;
+       zfs_inode_update_new(zp);
+
+       zfs_znode_hold_exit(zsb, zh);
+
+       return (0);
+}
+
+void
+zfs_znode_delete(znode_t *zp, dmu_tx_t *tx)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       objset_t *os = zsb->z_os;
+       uint64_t obj = zp->z_id;
+       uint64_t acl_obj = zfs_external_acl(zp);
+       znode_hold_t *zh;
+
+       zh = zfs_znode_hold_enter(zsb, obj);
+       if (acl_obj) {
+               VERIFY(!zp->z_is_sa);
+               VERIFY(0 == dmu_object_free(os, acl_obj, tx));
+       }
+       VERIFY(0 == dmu_object_free(os, obj, tx));
+       zfs_znode_dmu_fini(zp);
+       zfs_znode_hold_exit(zsb, zh);
+}
+
+void
+zfs_zinactive(znode_t *zp)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       uint64_t z_id = zp->z_id;
+       znode_hold_t *zh;
+
+       ASSERT(zp->z_sa_hdl);
+
+       /*
+        * Don't allow a zfs_zget() while were trying to release this znode.
+        */
+       zh = zfs_znode_hold_enter(zsb, z_id);
+
+       mutex_enter(&zp->z_lock);
+
+       /*
+        * If this was the last reference to a file with no links,
+        * remove the file from the file system.
+        */
+       if (zp->z_unlinked) {
+               mutex_exit(&zp->z_lock);
+               zfs_znode_hold_exit(zsb, zh);
+               zfs_rmnode(zp);
+               return;
+       }
+
+       mutex_exit(&zp->z_lock);
+       zfs_znode_dmu_fini(zp);
+
+       zfs_znode_hold_exit(zsb, zh);
+}
+
+static inline int
+zfs_compare_timespec(struct timespec *t1, struct timespec *t2)
+{
+       if (t1->tv_sec < t2->tv_sec)
+               return (-1);
+
+       if (t1->tv_sec > t2->tv_sec)
+               return (1);
+
+       return (t1->tv_nsec - t2->tv_nsec);
+}
+
+/*
+ * Prepare to update znode time stamps.
+ *
+ *     IN:     zp      - znode requiring timestamp update
+ *             flag    - ATTR_MTIME, ATTR_CTIME flags
+ *
+ *     OUT:    zp      - z_seq
+ *             mtime   - new mtime
+ *             ctime   - new ctime
+ *
+ *     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])
+{
+       timestruc_t     now;
+
+       gethrestime(&now);
+
+       zp->z_seq++;
+
+       if (flag & ATTR_MTIME) {
+               ZFS_TIME_ENCODE(&now, mtime);
+               if (ZTOZSB(zp)->z_use_fuids) {
+                       zp->z_pflags |= (ZFS_ARCHIVE |
+                           ZFS_AV_MODIFIED);
+               }
+       }
+
+       if (flag & ATTR_CTIME) {
+               ZFS_TIME_ENCODE(&now, ctime);
+               if (ZTOZSB(zp)->z_use_fuids)
+                       zp->z_pflags |= ZFS_ARCHIVE;
+       }
+}
+
+/*
+ * Grow the block size for a file.
+ *
+ *     IN:     zp      - znode of file to free data in.
+ *             size    - requested block size
+ *             tx      - open transaction.
+ *
+ * NOTE: this function assumes that the znode is write locked.
+ */
+void
+zfs_grow_blocksize(znode_t *zp, uint64_t size, dmu_tx_t *tx)
+{
+       int             error;
+       u_longlong_t    dummy;
+
+       if (size <= zp->z_blksz)
+               return;
+       /*
+        * If the file size is already greater than the current blocksize,
+        * we will not grow.  If there is more than one block in a file,
+        * the blocksize cannot change.
+        */
+       if (zp->z_blksz && zp->z_size > zp->z_blksz)
+               return;
+
+       error = dmu_object_set_blocksize(ZTOZSB(zp)->z_os, zp->z_id,
+           size, 0, tx);
+
+       if (error == ENOTSUP)
+               return;
+       ASSERT0(error);
+
+       /* What blocksize did we actually get? */
+       dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &zp->z_blksz, &dummy);
+}
+
+/*
+ * Increase the file length
+ *
+ *     IN:     zp      - znode of file to free data in.
+ *             end     - new end-of-file
+ *
+ *     RETURN: 0 on success, error code on failure
+ */
+static int
+zfs_extend(znode_t *zp, uint64_t end)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       dmu_tx_t *tx;
+       rl_t *rl;
+       uint64_t newblksz;
+       int error;
+
+       /*
+        * We will change zp_size, lock the whole file.
+        */
+       rl = zfs_range_lock(&zp->z_range_lock, 0, UINT64_MAX, RL_WRITER);
+
+       /*
+        * Nothing to do if file already at desired length.
+        */
+       if (end <= zp->z_size) {
+               zfs_range_unlock(rl);
+               return (0);
+       }
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       zfs_sa_upgrade_txholds(tx, zp);
+       if (end > zp->z_blksz &&
+           (!ISP2(zp->z_blksz) || zp->z_blksz < zsb->z_max_blksz)) {
+               /*
+                * We are growing the file past the current block size.
+                */
+               if (zp->z_blksz > ZTOZSB(zp)->z_max_blksz) {
+                       /*
+                        * File's blocksize is already larger than the
+                        * "recordsize" property.  Only let it grow to
+                        * the next power of 2.
+                        */
+                       ASSERT(!ISP2(zp->z_blksz));
+                       newblksz = MIN(end, 1 << highbit64(zp->z_blksz));
+               } else {
+                       newblksz = MIN(end, ZTOZSB(zp)->z_max_blksz);
+               }
+               dmu_tx_hold_write(tx, zp->z_id, 0, newblksz);
+       } else {
+               newblksz = 0;
+       }
+
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+               zfs_range_unlock(rl);
+               return (error);
+       }
+
+       if (newblksz)
+               zfs_grow_blocksize(zp, newblksz, tx);
+
+       zp->z_size = end;
+
+       VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(ZTOZSB(zp)),
+           &zp->z_size, sizeof (zp->z_size), tx));
+
+       zfs_range_unlock(rl);
+
+       dmu_tx_commit(tx);
+
+       return (0);
+}
+
+/*
+ * zfs_zero_partial_page - Modeled after update_pages() but
+ * with different arguments and semantics for use by zfs_freesp().
+ *
+ * Zeroes a piece of a single page cache entry for zp at offset
+ * start and length len.
+ *
+ * Caller must acquire a range lock on the file for the region
+ * being zeroed in order that the ARC and page cache stay in sync.
+ */
+static void
+zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
+{
+       struct address_space *mp = ZTOI(zp)->i_mapping;
+       struct page *pp;
+       int64_t off;
+       void *pb;
+
+       ASSERT((start & PAGE_MASK) == ((start + len - 1) & PAGE_MASK));
+
+       off = start & (PAGE_SIZE - 1);
+       start &= PAGE_MASK;
+
+       pp = find_lock_page(mp, start >> PAGE_SHIFT);
+       if (pp) {
+               if (mapping_writably_mapped(mp))
+                       flush_dcache_page(pp);
+
+               pb = kmap(pp);
+               bzero(pb + off, len);
+               kunmap(pp);
+
+               if (mapping_writably_mapped(mp))
+                       flush_dcache_page(pp);
+
+               mark_page_accessed(pp);
+               SetPageUptodate(pp);
+               ClearPageError(pp);
+               unlock_page(pp);
+               put_page(pp);
+       }
+}
+
+/*
+ * Free space in a file.
+ *
+ *     IN:     zp      - znode of file to free data in.
+ *             off     - start of section to free.
+ *             len     - length of section to free.
+ *
+ *     RETURN: 0 on success, error code on failure
+ */
+static int
+zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       rl_t *rl;
+       int error;
+
+       /*
+        * Lock the range being freed.
+        */
+       rl = zfs_range_lock(&zp->z_range_lock, off, len, RL_WRITER);
+
+       /*
+        * Nothing to do if file already at desired length.
+        */
+       if (off >= zp->z_size) {
+               zfs_range_unlock(rl);
+               return (0);
+       }
+
+       if (off + len > zp->z_size)
+               len = zp->z_size - off;
+
+       error = dmu_free_long_range(zsb->z_os, zp->z_id, off, len);
+
+       /*
+        * Zero partial page cache entries.  This must be done under a
+        * range lock in order to keep the ARC and page cache in sync.
+        */
+       if (zp->z_is_mapped) {
+               loff_t first_page, last_page, page_len;
+               loff_t first_page_offset, last_page_offset;
+
+               /* first possible full page in hole */
+               first_page = (off + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               /* last page of hole */
+               last_page = (off + len) >> PAGE_SHIFT;
+
+               /* offset of first_page */
+               first_page_offset = first_page << PAGE_SHIFT;
+               /* offset of last_page */
+               last_page_offset = last_page << PAGE_SHIFT;
+
+               /* truncate whole pages */
+               if (last_page_offset > first_page_offset) {
+                       truncate_inode_pages_range(ZTOI(zp)->i_mapping,
+                           first_page_offset, last_page_offset - 1);
+               }
+
+               /* truncate sub-page ranges */
+               if (first_page > last_page) {
+                       /* entire punched area within a single page */
+                       zfs_zero_partial_page(zp, off, len);
+               } else {
+                       /* beginning of punched area at the end of a page */
+                       page_len  = first_page_offset - off;
+                       if (page_len > 0)
+                               zfs_zero_partial_page(zp, off, page_len);
+
+                       /* end of punched area at the beginning of a page */
+                       page_len = off + len - last_page_offset;
+                       if (page_len > 0)
+                               zfs_zero_partial_page(zp, last_page_offset,
+                                   page_len);
+               }
+       }
+       zfs_range_unlock(rl);
+
+       return (error);
+}
+
+/*
+ * Truncate a file
+ *
+ *     IN:     zp      - znode of file to free data in.
+ *             end     - new end-of-file.
+ *
+ *     RETURN: 0 on success, error code on failure
+ */
+static int
+zfs_trunc(znode_t *zp, uint64_t end)
+{
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       dmu_tx_t *tx;
+       rl_t *rl;
+       int error;
+       sa_bulk_attr_t bulk[2];
+       int count = 0;
+
+       /*
+        * We will change zp_size, lock the whole file.
+        */
+       rl = zfs_range_lock(&zp->z_range_lock, 0, UINT64_MAX, RL_WRITER);
+
+       /*
+        * Nothing to do if file already at desired length.
+        */
+       if (end >= zp->z_size) {
+               zfs_range_unlock(rl);
+               return (0);
+       }
+
+       error = dmu_free_long_range(zsb->z_os, zp->z_id, end,  -1);
+       if (error) {
+               zfs_range_unlock(rl);
+               return (error);
+       }
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       zfs_sa_upgrade_txholds(tx, zp);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+               zfs_range_unlock(rl);
+               return (error);
+       }
+
+       zp->z_size = end;
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zsb),
+           NULL, &zp->z_size, sizeof (zp->z_size));
+
+       if (end == 0) {
+               zp->z_pflags &= ~ZFS_SPARSE;
+               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb),
+                   NULL, &zp->z_pflags, 8);
+       }
+       VERIFY(sa_bulk_update(zp->z_sa_hdl, bulk, count, tx) == 0);
+
+       dmu_tx_commit(tx);
+
+       zfs_range_unlock(rl);
+
+       return (0);
+}
+
+/*
+ * Free space in a file
+ *
+ *     IN:     zp      - znode of file to free data in.
+ *             off     - start of range
+ *             len     - end of range (0 => EOF)
+ *             flag    - current file open mode flags.
+ *             log     - TRUE if this action should be logged
+ *
+ *     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)
+{
+       dmu_tx_t *tx;
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       zilog_t *zilog = zsb->z_log;
+       uint64_t mode;
+       uint64_t mtime[2], ctime[2];
+       sa_bulk_attr_t bulk[3];
+       int count = 0;
+       int error;
+
+       if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_MODE(zsb), &mode,
+           sizeof (mode))) != 0)
+               return (error);
+
+       if (off > zp->z_size) {
+               error =  zfs_extend(zp, off+len);
+               if (error == 0 && log)
+                       goto log;
+               goto out;
+       }
+
+       if (len == 0) {
+               error = zfs_trunc(zp, off);
+       } else {
+               if ((error = zfs_free_range(zp, off, len)) == 0 &&
+                   off + len > zp->z_size)
+                       error = zfs_extend(zp, off+len);
+       }
+       if (error || !log)
+               goto out;
+log:
+       tx = dmu_tx_create(zsb->z_os);
+       dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+       zfs_sa_upgrade_txholds(tx, zp);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+               goto out;
+       }
+
+       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_FLAGS(zsb),
+           NULL, &zp->z_pflags, 8);
+       zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);
+       error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+       ASSERT(error == 0);
+
+       zfs_log_truncate(zilog, tx, TX_TRUNCATE, zp, off, len);
+
+       dmu_tx_commit(tx);
+
+       zfs_inode_update(zp);
+       error = 0;
+
+out:
+       /*
+        * Truncate the page cache - for file truncate operations, use
+        * the purpose-built API for truncations.  For punching operations,
+        * the truncation is handled under a range lock in zfs_free_range.
+        */
+       if (len == 0)
+               truncate_setsize(ZTOI(zp), off);
+       return (error);
+}
+
+void
+zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
+{
+       struct super_block *sb;
+       zfs_sb_t        *zsb;
+       uint64_t        moid, obj, sa_obj, version;
+       uint64_t        sense = ZFS_CASE_SENSITIVE;
+       uint64_t        norm = 0;
+       nvpair_t        *elem;
+       int             size;
+       int             error;
+       int             i;
+       znode_t         *rootzp = NULL;
+       vattr_t         vattr;
+       znode_t         *zp;
+       zfs_acl_ids_t   acl_ids;
+
+       /*
+        * First attempt to create master node.
+        */
+       /*
+        * In an empty objset, there are no blocks to read and thus
+        * there can be no i/o errors (which we assert below).
+        */
+       moid = MASTER_NODE_OBJ;
+       error = zap_create_claim(os, moid, DMU_OT_MASTER_NODE,
+           DMU_OT_NONE, 0, tx);
+       ASSERT(error == 0);
+
+       /*
+        * Set starting attributes.
+        */
+       version = zfs_zpl_version_map(spa_version(dmu_objset_spa(os)));
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(zplprops, elem)) != NULL) {
+               /* For the moment we expect all zpl props to be uint64_ts */
+               uint64_t val;
+               char *name;
+
+               ASSERT(nvpair_type(elem) == DATA_TYPE_UINT64);
+               VERIFY(nvpair_value_uint64(elem, &val) == 0);
+               name = nvpair_name(elem);
+               if (strcmp(name, zfs_prop_to_name(ZFS_PROP_VERSION)) == 0) {
+                       if (val < version)
+                               version = val;
+               } else {
+                       error = zap_update(os, moid, name, 8, 1, &val, tx);
+               }
+               ASSERT(error == 0);
+               if (strcmp(name, zfs_prop_to_name(ZFS_PROP_NORMALIZE)) == 0)
+                       norm = val;
+               else if (strcmp(name, zfs_prop_to_name(ZFS_PROP_CASE)) == 0)
+                       sense = val;
+       }
+       ASSERT(version != 0);
+       error = zap_update(os, moid, ZPL_VERSION_STR, 8, 1, &version, tx);
+
+       /*
+        * Create zap object used for SA attribute registration
+        */
+
+       if (version >= ZPL_VERSION_SA) {
+               sa_obj = zap_create(os, DMU_OT_SA_MASTER_NODE,
+                   DMU_OT_NONE, 0, tx);
+               error = zap_add(os, moid, ZFS_SA_ATTRS, 8, 1, &sa_obj, tx);
+               ASSERT(error == 0);
+       } else {
+               sa_obj = 0;
+       }
+       /*
+        * Create a delete queue.
+        */
+       obj = zap_create(os, DMU_OT_UNLINKED_SET, DMU_OT_NONE, 0, tx);
+
+       error = zap_add(os, moid, ZFS_UNLINKED_SET, 8, 1, &obj, tx);
+       ASSERT(error == 0);
+
+       /*
+        * Create root znode.  Create minimal znode/inode/zsb/sb
+        * to allow zfs_mknode to work.
+        */
+       vattr.va_mask = ATTR_MODE|ATTR_UID|ATTR_GID;
+       vattr.va_mode = S_IFDIR|0755;
+       vattr.va_uid = crgetuid(cr);
+       vattr.va_gid = crgetgid(cr);
+
+       rootzp = kmem_cache_alloc(znode_cache, KM_SLEEP);
+       rootzp->z_moved = 0;
+       rootzp->z_unlinked = 0;
+       rootzp->z_atime_dirty = 0;
+       rootzp->z_is_sa = USE_SA(version, os);
+
+       zsb = kmem_zalloc(sizeof (zfs_sb_t), KM_SLEEP);
+       zsb->z_os = os;
+       zsb->z_parent = zsb;
+       zsb->z_version = version;
+       zsb->z_use_fuids = USE_FUIDS(version, os);
+       zsb->z_use_sa = USE_SA(version, os);
+       zsb->z_norm = norm;
+
+       sb = kmem_zalloc(sizeof (struct super_block), KM_SLEEP);
+       sb->s_fs_info = zsb;
+
+       ZTOI(rootzp)->i_sb = sb;
+
+       error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END,
+           &zsb->z_attr_table);
+
+       ASSERT(error == 0);
+
+       /*
+        * Fold case on file systems that are always or sometimes case
+        * insensitive.
+        */
+       if (sense == ZFS_CASE_INSENSITIVE || sense == ZFS_CASE_MIXED)
+               zsb->z_norm |= U8_TEXTPREP_TOUPPER;
+
+       mutex_init(&zsb->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&zsb->z_all_znodes, sizeof (znode_t),
+           offsetof(znode_t, z_link_node));
+
+       size = MIN(1 << (highbit64(zfs_object_mutex_size)-1), ZFS_OBJ_MTX_MAX);
+       zsb->z_hold_size = size;
+       zsb->z_hold_trees = vmem_zalloc(sizeof (avl_tree_t) * size, KM_SLEEP);
+       zsb->z_hold_locks = vmem_zalloc(sizeof (kmutex_t) * size, KM_SLEEP);
+       for (i = 0; i != size; i++) {
+               avl_create(&zsb->z_hold_trees[i], zfs_znode_hold_compare,
+                   sizeof (znode_hold_t), offsetof(znode_hold_t, zh_node));
+               mutex_init(&zsb->z_hold_locks[i], NULL, MUTEX_DEFAULT, NULL);
+       }
+
+       VERIFY(0 == zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr,
+           cr, NULL, &acl_ids));
+       zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids);
+       ASSERT3P(zp, ==, rootzp);
+       error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx);
+       ASSERT(error == 0);
+       zfs_acl_ids_free(&acl_ids);
+
+       atomic_set(&ZTOI(rootzp)->i_count, 0);
+       sa_handle_destroy(rootzp->z_sa_hdl);
+       kmem_cache_free(znode_cache, rootzp);
+
+       /*
+        * Create shares directory
+        */
+       error = zfs_create_share_dir(zsb, tx);
+       ASSERT(error == 0);
+
+       for (i = 0; i != size; i++) {
+               avl_destroy(&zsb->z_hold_trees[i]);
+               mutex_destroy(&zsb->z_hold_locks[i]);
+       }
+
+       vmem_free(zsb->z_hold_trees, sizeof (avl_tree_t) * size);
+       vmem_free(zsb->z_hold_locks, sizeof (kmutex_t) * size);
+       kmem_free(sb, sizeof (struct super_block));
+       kmem_free(zsb, sizeof (zfs_sb_t));
+}
+#endif /* _KERNEL */
+
+static int
+zfs_sa_setup(objset_t *osp, sa_attr_type_t **sa_table)
+{
+       uint64_t sa_obj = 0;
+       int error;
+
+       error = zap_lookup(osp, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, &sa_obj);
+       if (error != 0 && error != ENOENT)
+               return (error);
+
+       error = sa_setup(osp, sa_obj, zfs_attr_table, ZPL_END, sa_table);
+       return (error);
+}
+
+static int
+zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
+    dmu_buf_t **db, void *tag)
+{
+       dmu_object_info_t doi;
+       int error;
+
+       if ((error = sa_buf_hold(osp, obj, tag, db)) != 0)
+               return (error);
+
+       dmu_object_info_from_db(*db, &doi);
+       if ((doi.doi_bonus_type != DMU_OT_SA &&
+           doi.doi_bonus_type != DMU_OT_ZNODE) ||
+           (doi.doi_bonus_type == DMU_OT_ZNODE &&
+           doi.doi_bonus_size < sizeof (znode_phys_t))) {
+               sa_buf_rele(*db, tag);
+               return (SET_ERROR(ENOTSUP));
+       }
+
+       error = sa_handle_get(osp, obj, NULL, SA_HDL_PRIVATE, hdlp);
+       if (error != 0) {
+               sa_buf_rele(*db, tag);
+               return (error);
+       }
+
+       return (0);
+}
+
+void
+zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, void *tag)
+{
+       sa_handle_destroy(hdl);
+       sa_buf_rele(db, tag);
+}
+
+/*
+ * Given an object number, return its parent object number and whether
+ * 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)
+{
+       uint64_t parent;
+       uint64_t pflags;
+       uint64_t mode;
+       sa_bulk_attr_t bulk[3];
+       int count = 0;
+       int error;
+
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_PARENT], NULL,
+           &parent, sizeof (parent));
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_FLAGS], NULL,
+           &pflags, sizeof (pflags));
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
+           &mode, sizeof (mode));
+
+       if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0)
+               return (error);
+
+       *pobjp = parent;
+       *is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode);
+
+       return (0);
+}
+
+/*
+ * Given an object number, return some zpl level statistics
+ */
+static int
+zfs_obj_to_stats_impl(sa_handle_t *hdl, sa_attr_type_t *sa_table,
+    zfs_stat_t *sb)
+{
+       sa_bulk_attr_t bulk[4];
+       int count = 0;
+
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
+           &sb->zs_mode, sizeof (sb->zs_mode));
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL,
+           &sb->zs_gen, sizeof (sb->zs_gen));
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_LINKS], NULL,
+           &sb->zs_links, sizeof (sb->zs_links));
+       SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CTIME], NULL,
+           &sb->zs_ctime, sizeof (sb->zs_ctime));
+
+       return (sa_bulk_lookup(hdl, bulk, count));
+}
+
+static int
+zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
+    sa_attr_type_t *sa_table, char *buf, int len)
+{
+       sa_handle_t *sa_hdl;
+       sa_handle_t *prevhdl = NULL;
+       dmu_buf_t *prevdb = NULL;
+       dmu_buf_t *sa_db = NULL;
+       char *path = buf + len - 1;
+       int error;
+
+       *path = '\0';
+       sa_hdl = hdl;
+
+       for (;;) {
+               uint64_t pobj = 0;
+               char component[MAXNAMELEN + 2];
+               size_t complen;
+               int is_xattrdir = 0;
+
+               if (prevdb)
+                       zfs_release_sa_handle(prevhdl, prevdb, FTAG);
+
+               if ((error = zfs_obj_to_pobj(sa_hdl, sa_table, &pobj,
+                   &is_xattrdir)) != 0)
+                       break;
+
+               if (pobj == obj) {
+                       if (path[0] != '/')
+                               *--path = '/';
+                       break;
+               }
+
+               component[0] = '/';
+               if (is_xattrdir) {
+                       (void) sprintf(component + 1, "<xattrdir>");
+               } else {
+                       error = zap_value_search(osp, pobj, obj,
+                           ZFS_DIRENT_OBJ(-1ULL), component + 1);
+                       if (error != 0)
+                               break;
+               }
+
+               complen = strlen(component);
+               path -= complen;
+               ASSERT(path >= buf);
+               bcopy(component, path, complen);
+               obj = pobj;
+
+               if (sa_hdl != hdl) {
+                       prevhdl = sa_hdl;
+                       prevdb = sa_db;
+               }
+               error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG);
+               if (error != 0) {
+                       sa_hdl = prevhdl;
+                       sa_db = prevdb;
+                       break;
+               }
+       }
+
+       if (sa_hdl != NULL && sa_hdl != hdl) {
+               ASSERT(sa_db != NULL);
+               zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
+       }
+
+       if (error == 0)
+               (void) memmove(buf, path, buf + len - path);
+
+       return (error);
+}
+
+int
+zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len)
+{
+       sa_attr_type_t *sa_table;
+       sa_handle_t *hdl;
+       dmu_buf_t *db;
+       int error;
+
+       error = zfs_sa_setup(osp, &sa_table);
+       if (error != 0)
+               return (error);
+
+       error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
+
+       zfs_release_sa_handle(hdl, db, FTAG);
+       return (error);
+}
+
+int
+zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
+    char *buf, int len)
+{
+       char *path = buf + len - 1;
+       sa_attr_type_t *sa_table;
+       sa_handle_t *hdl;
+       dmu_buf_t *db;
+       int error;
+
+       *path = '\0';
+
+       error = zfs_sa_setup(osp, &sa_table);
+       if (error != 0)
+               return (error);
+
+       error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = zfs_obj_to_stats_impl(hdl, sa_table, sb);
+       if (error != 0) {
+               zfs_release_sa_handle(hdl, db, FTAG);
+               return (error);
+       }
+
+       error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
+
+       zfs_release_sa_handle(hdl, db, FTAG);
+       return (error);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zfs_create_fs);
+EXPORT_SYMBOL(zfs_obj_to_path);
+
+module_param(zfs_object_mutex_size, uint, 0644);
+MODULE_PARM_DESC(zfs_object_mutex_size, "Size of znode hold array");
+#endif
diff --git a/zfs/module/zfs/zil.c b/zfs/module/zfs/zil.c
new file mode 100644 (file)
index 0000000..289b23c
--- /dev/null
@@ -0,0 +1,2285 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+/* Portions Copyright 2010 Robert Milkowski */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/arc.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/dsl_dataset.h>
+#include <sys/vdev_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dsl_pool.h>
+#include <sys/metaslab.h>
+#include <sys/trace_zil.h>
+
+/*
+ * The zfs intent log (ZIL) saves transaction records of system calls
+ * that change the file system in memory with enough information
+ * to be able to replay them. These are stored in memory until
+ * either the DMU transaction group (txg) commits them to the stable pool
+ * and they can be discarded, or they are flushed to the stable log
+ * (also in the pool) due to a fsync, O_DSYNC or other synchronous
+ * requirement. In the event of a panic or power fail then those log
+ * records (transactions) are replayed.
+ *
+ * There is one ZIL per file system. Its on-disk (pool) format consists
+ * of 3 parts:
+ *
+ *     - ZIL header
+ *     - ZIL blocks
+ *     - ZIL records
+ *
+ * A log record holds a system call transaction. Log blocks can
+ * hold many log records and the blocks are chained together.
+ * Each ZIL block contains a block pointer (blkptr_t) to the next
+ * ZIL block in the chain. The ZIL header points to the first
+ * block in the chain. Note there is not a fixed place in the pool
+ * to hold blocks. They are dynamically allocated and freed as
+ * needed from the blocks available. Figure X shows the ZIL structure:
+ */
+
+/*
+ * See zil.h for more information about these fields.
+ */
+zil_stats_t zil_stats = {
+       { "zil_commit_count",                   KSTAT_DATA_UINT64 },
+       { "zil_commit_writer_count",            KSTAT_DATA_UINT64 },
+       { "zil_itx_count",                      KSTAT_DATA_UINT64 },
+       { "zil_itx_indirect_count",             KSTAT_DATA_UINT64 },
+       { "zil_itx_indirect_bytes",             KSTAT_DATA_UINT64 },
+       { "zil_itx_copied_count",               KSTAT_DATA_UINT64 },
+       { "zil_itx_copied_bytes",               KSTAT_DATA_UINT64 },
+       { "zil_itx_needcopy_count",             KSTAT_DATA_UINT64 },
+       { "zil_itx_needcopy_bytes",             KSTAT_DATA_UINT64 },
+       { "zil_itx_metaslab_normal_count",      KSTAT_DATA_UINT64 },
+       { "zil_itx_metaslab_normal_bytes",      KSTAT_DATA_UINT64 },
+       { "zil_itx_metaslab_slog_count",        KSTAT_DATA_UINT64 },
+       { "zil_itx_metaslab_slog_bytes",        KSTAT_DATA_UINT64 },
+};
+
+static kstat_t *zil_ksp;
+
+/*
+ * Disable intent logging replay.  This global ZIL switch affects all pools.
+ */
+int zil_replay_disable = 0;
+
+/*
+ * Tunable parameter for debugging or performance analysis.  Setting
+ * zfs_nocacheflush will cause corruption on power loss if a volatile
+ * out-of-order write cache is enabled.
+ */
+int zfs_nocacheflush = 0;
+
+static kmem_cache_t *zil_lwb_cache;
+
+static void zil_async_to_sync(zilog_t *zilog, uint64_t foid);
+
+#define        LWB_EMPTY(lwb) ((BP_GET_LSIZE(&lwb->lwb_blk) - \
+    sizeof (zil_chain_t)) == (lwb->lwb_sz - lwb->lwb_nused))
+
+
+/*
+ * ziltest is by and large an ugly hack, but very useful in
+ * checking replay without tedious work.
+ * When running ziltest we want to keep all itx's and so maintain
+ * a single list in the zl_itxg[] that uses a high txg: ZILTEST_TXG
+ * We subtract TXG_CONCURRENT_STATES to allow for common code.
+ */
+#define        ZILTEST_TXG (UINT64_MAX - TXG_CONCURRENT_STATES)
+
+static int
+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);
+
+       if (DVA_GET_OFFSET(dva1) < DVA_GET_OFFSET(dva2))
+               return (-1);
+       if (DVA_GET_OFFSET(dva1) > DVA_GET_OFFSET(dva2))
+               return (1);
+
+       return (0);
+}
+
+static void
+zil_bp_tree_init(zilog_t *zilog)
+{
+       avl_create(&zilog->zl_bp_tree, zil_bp_compare,
+           sizeof (zil_bp_node_t), offsetof(zil_bp_node_t, zn_node));
+}
+
+static void
+zil_bp_tree_fini(zilog_t *zilog)
+{
+       avl_tree_t *t = &zilog->zl_bp_tree;
+       zil_bp_node_t *zn;
+       void *cookie = NULL;
+
+       while ((zn = avl_destroy_nodes(t, &cookie)) != NULL)
+               kmem_free(zn, sizeof (zil_bp_node_t));
+
+       avl_destroy(t);
+}
+
+int
+zil_bp_tree_add(zilog_t *zilog, const blkptr_t *bp)
+{
+       avl_tree_t *t = &zilog->zl_bp_tree;
+       const dva_t *dva;
+       zil_bp_node_t *zn;
+       avl_index_t where;
+
+       if (BP_IS_EMBEDDED(bp))
+               return (0);
+
+       dva = BP_IDENTITY(bp);
+
+       if (avl_find(t, dva, &where) != NULL)
+               return (SET_ERROR(EEXIST));
+
+       zn = kmem_alloc(sizeof (zil_bp_node_t), KM_SLEEP);
+       zn->zn_dva = *dva;
+       avl_insert(t, zn, where);
+
+       return (0);
+}
+
+static zil_header_t *
+zil_header_in_syncing_context(zilog_t *zilog)
+{
+       return ((zil_header_t *)zilog->zl_header);
+}
+
+static void
+zil_init_log_chain(zilog_t *zilog, blkptr_t *bp)
+{
+       zio_cksum_t *zc = &bp->blk_cksum;
+
+       zc->zc_word[ZIL_ZC_GUID_0] = spa_get_random(-1ULL);
+       zc->zc_word[ZIL_ZC_GUID_1] = spa_get_random(-1ULL);
+       zc->zc_word[ZIL_ZC_OBJSET] = dmu_objset_id(zilog->zl_os);
+       zc->zc_word[ZIL_ZC_SEQ] = 1ULL;
+}
+
+/*
+ * Read a log block and make sure it's valid.
+ */
+static int
+zil_read_log_block(zilog_t *zilog, const blkptr_t *bp, blkptr_t *nbp, void *dst,
+    char **end)
+{
+       enum zio_flag zio_flags = ZIO_FLAG_CANFAIL;
+       arc_flags_t aflags = ARC_FLAG_WAIT;
+       arc_buf_t *abuf = NULL;
+       zbookmark_phys_t zb;
+       int error;
+
+       if (zilog->zl_header->zh_claim_txg == 0)
+               zio_flags |= ZIO_FLAG_SPECULATIVE | ZIO_FLAG_SCRUB;
+
+       if (!(zilog->zl_header->zh_flags & ZIL_CLAIM_LR_SEQ_VALID))
+               zio_flags |= ZIO_FLAG_SPECULATIVE;
+
+       SET_BOOKMARK(&zb, bp->blk_cksum.zc_word[ZIL_ZC_OBJSET],
+           ZB_ZIL_OBJECT, ZB_ZIL_LEVEL, bp->blk_cksum.zc_word[ZIL_ZC_SEQ]);
+
+       error = arc_read(NULL, zilog->zl_spa, bp, arc_getbuf_func, &abuf,
+           ZIO_PRIORITY_SYNC_READ, zio_flags, &aflags, &zb);
+
+       if (error == 0) {
+               zio_cksum_t cksum = bp->blk_cksum;
+
+               /*
+                * Validate the checksummed log block.
+                *
+                * Sequence numbers should be... sequential.  The checksum
+                * verifier for the next block should be bp's checksum plus 1.
+                *
+                * Also check the log chain linkage and size used.
+                */
+               cksum.zc_word[ZIL_ZC_SEQ]++;
+
+               if (BP_GET_CHECKSUM(bp) == ZIO_CHECKSUM_ZILOG2) {
+                       zil_chain_t *zilc = abuf->b_data;
+                       char *lr = (char *)(zilc + 1);
+                       uint64_t len = zilc->zc_nused - sizeof (zil_chain_t);
+
+                       if (bcmp(&cksum, &zilc->zc_next_blk.blk_cksum,
+                           sizeof (cksum)) || BP_IS_HOLE(&zilc->zc_next_blk)) {
+                               error = SET_ERROR(ECKSUM);
+                       } else {
+                               ASSERT3U(len, <=, SPA_OLD_MAXBLOCKSIZE);
+                               bcopy(lr, dst, len);
+                               *end = (char *)dst + len;
+                               *nbp = zilc->zc_next_blk;
+                       }
+               } else {
+                       char *lr = abuf->b_data;
+                       uint64_t size = BP_GET_LSIZE(bp);
+                       zil_chain_t *zilc = (zil_chain_t *)(lr + size) - 1;
+
+                       if (bcmp(&cksum, &zilc->zc_next_blk.blk_cksum,
+                           sizeof (cksum)) || BP_IS_HOLE(&zilc->zc_next_blk) ||
+                           (zilc->zc_nused > (size - sizeof (*zilc)))) {
+                               error = SET_ERROR(ECKSUM);
+                       } else {
+                               ASSERT3U(zilc->zc_nused, <=,
+                                   SPA_OLD_MAXBLOCKSIZE);
+                               bcopy(lr, dst, zilc->zc_nused);
+                               *end = (char *)dst + zilc->zc_nused;
+                               *nbp = zilc->zc_next_blk;
+                       }
+               }
+
+               VERIFY(arc_buf_remove_ref(abuf, &abuf));
+       }
+
+       return (error);
+}
+
+/*
+ * Read a TX_WRITE log data block.
+ */
+static int
+zil_read_log_data(zilog_t *zilog, const lr_write_t *lr, void *wbuf)
+{
+       enum zio_flag zio_flags = ZIO_FLAG_CANFAIL;
+       const blkptr_t *bp = &lr->lr_blkptr;
+       arc_flags_t aflags = ARC_FLAG_WAIT;
+       arc_buf_t *abuf = NULL;
+       zbookmark_phys_t zb;
+       int error;
+
+       if (BP_IS_HOLE(bp)) {
+               if (wbuf != NULL)
+                       bzero(wbuf, MAX(BP_GET_LSIZE(bp), lr->lr_length));
+               return (0);
+       }
+
+       if (zilog->zl_header->zh_claim_txg == 0)
+               zio_flags |= ZIO_FLAG_SPECULATIVE | ZIO_FLAG_SCRUB;
+
+       SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os), lr->lr_foid,
+           ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp));
+
+       error = arc_read(NULL, zilog->zl_spa, bp, arc_getbuf_func, &abuf,
+           ZIO_PRIORITY_SYNC_READ, zio_flags, &aflags, &zb);
+
+       if (error == 0) {
+               if (wbuf != NULL)
+                       bcopy(abuf->b_data, wbuf, arc_buf_size(abuf));
+               (void) arc_buf_remove_ref(abuf, &abuf);
+       }
+
+       return (error);
+}
+
+/*
+ * Parse the intent log, and call parse_func for each valid record within.
+ */
+int
+zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func,
+    zil_parse_lr_func_t *parse_lr_func, void *arg, uint64_t txg)
+{
+       const zil_header_t *zh = zilog->zl_header;
+       boolean_t claimed = !!zh->zh_claim_txg;
+       uint64_t claim_blk_seq = claimed ? zh->zh_claim_blk_seq : UINT64_MAX;
+       uint64_t claim_lr_seq = claimed ? zh->zh_claim_lr_seq : UINT64_MAX;
+       uint64_t max_blk_seq = 0;
+       uint64_t max_lr_seq = 0;
+       uint64_t blk_count = 0;
+       uint64_t lr_count = 0;
+       blkptr_t blk, next_blk;
+       char *lrbuf, *lrp;
+       int error = 0;
+
+       bzero(&next_blk, sizeof (blkptr_t));
+
+       /*
+        * Old logs didn't record the maximum zh_claim_lr_seq.
+        */
+       if (!(zh->zh_flags & ZIL_CLAIM_LR_SEQ_VALID))
+               claim_lr_seq = UINT64_MAX;
+
+       /*
+        * Starting at the block pointed to by zh_log we read the log chain.
+        * For each block in the chain we strongly check that block to
+        * ensure its validity.  We stop when an invalid block is found.
+        * For each block pointer in the chain we call parse_blk_func().
+        * For each record in each valid block we call parse_lr_func().
+        * If the log has been claimed, stop if we encounter a sequence
+        * number greater than the highest claimed sequence number.
+        */
+       lrbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE);
+       zil_bp_tree_init(zilog);
+
+       for (blk = zh->zh_log; !BP_IS_HOLE(&blk); blk = next_blk) {
+               uint64_t blk_seq = blk.blk_cksum.zc_word[ZIL_ZC_SEQ];
+               int reclen;
+               char *end = NULL;
+
+               if (blk_seq > claim_blk_seq)
+                       break;
+               if ((error = parse_blk_func(zilog, &blk, arg, txg)) != 0)
+                       break;
+               ASSERT3U(max_blk_seq, <, blk_seq);
+               max_blk_seq = blk_seq;
+               blk_count++;
+
+               if (max_lr_seq == claim_lr_seq && max_blk_seq == claim_blk_seq)
+                       break;
+
+               error = zil_read_log_block(zilog, &blk, &next_blk, lrbuf, &end);
+               if (error != 0)
+                       break;
+
+               for (lrp = lrbuf; lrp < end; lrp += reclen) {
+                       lr_t *lr = (lr_t *)lrp;
+                       reclen = lr->lrc_reclen;
+                       ASSERT3U(reclen, >=, sizeof (lr_t));
+                       if (lr->lrc_seq > claim_lr_seq)
+                               goto done;
+                       if ((error = parse_lr_func(zilog, lr, arg, txg)) != 0)
+                               goto done;
+                       ASSERT3U(max_lr_seq, <, lr->lrc_seq);
+                       max_lr_seq = lr->lrc_seq;
+                       lr_count++;
+               }
+       }
+done:
+       zilog->zl_parse_error = error;
+       zilog->zl_parse_blk_seq = max_blk_seq;
+       zilog->zl_parse_lr_seq = max_lr_seq;
+       zilog->zl_parse_blk_count = blk_count;
+       zilog->zl_parse_lr_count = lr_count;
+
+       ASSERT(!claimed || !(zh->zh_flags & ZIL_CLAIM_LR_SEQ_VALID) ||
+           (max_blk_seq == claim_blk_seq && max_lr_seq == claim_lr_seq));
+
+       zil_bp_tree_fini(zilog);
+       zio_buf_free(lrbuf, SPA_OLD_MAXBLOCKSIZE);
+
+       return (error);
+}
+
+static int
+zil_claim_log_block(zilog_t *zilog, blkptr_t *bp, void *tx, uint64_t first_txg)
+{
+       /*
+        * Claim log block if not already committed and not already claimed.
+        * If tx == NULL, just verify that the block is claimable.
+        */
+       if (BP_IS_HOLE(bp) || bp->blk_birth < first_txg ||
+           zil_bp_tree_add(zilog, bp) != 0)
+               return (0);
+
+       return (zio_wait(zio_claim(NULL, zilog->zl_spa,
+           tx == NULL ? 0 : first_txg, bp, spa_claim_notify, NULL,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE | ZIO_FLAG_SCRUB)));
+}
+
+static int
+zil_claim_log_record(zilog_t *zilog, lr_t *lrc, void *tx, uint64_t first_txg)
+{
+       lr_write_t *lr = (lr_write_t *)lrc;
+       int error;
+
+       if (lrc->lrc_txtype != TX_WRITE)
+               return (0);
+
+       /*
+        * If the block is not readable, don't claim it.  This can happen
+        * in normal operation when a log block is written to disk before
+        * some of the dmu_sync() blocks it points to.  In this case, the
+        * transaction cannot have been committed to anyone (we would have
+        * waited for all writes to be stable first), so it is semantically
+        * correct to declare this the end of the log.
+        */
+       if (lr->lr_blkptr.blk_birth >= first_txg &&
+           (error = zil_read_log_data(zilog, lr, NULL)) != 0)
+               return (error);
+       return (zil_claim_log_block(zilog, &lr->lr_blkptr, tx, first_txg));
+}
+
+/* ARGSUSED */
+static int
+zil_free_log_block(zilog_t *zilog, blkptr_t *bp, void *tx, uint64_t claim_txg)
+{
+       zio_free_zil(zilog->zl_spa, dmu_tx_get_txg(tx), bp);
+
+       return (0);
+}
+
+static int
+zil_free_log_record(zilog_t *zilog, lr_t *lrc, void *tx, uint64_t claim_txg)
+{
+       lr_write_t *lr = (lr_write_t *)lrc;
+       blkptr_t *bp = &lr->lr_blkptr;
+
+       /*
+        * If we previously claimed it, we need to free it.
+        */
+       if (claim_txg != 0 && lrc->lrc_txtype == TX_WRITE &&
+           bp->blk_birth >= claim_txg && zil_bp_tree_add(zilog, bp) == 0 &&
+           !BP_IS_HOLE(bp))
+               zio_free(zilog->zl_spa, dmu_tx_get_txg(tx), bp);
+
+       return (0);
+}
+
+static lwb_t *
+zil_alloc_lwb(zilog_t *zilog, blkptr_t *bp, uint64_t txg, boolean_t fastwrite)
+{
+       lwb_t *lwb;
+
+       lwb = kmem_cache_alloc(zil_lwb_cache, KM_SLEEP);
+       lwb->lwb_zilog = zilog;
+       lwb->lwb_blk = *bp;
+       lwb->lwb_fastwrite = fastwrite;
+       lwb->lwb_buf = zio_buf_alloc(BP_GET_LSIZE(bp));
+       lwb->lwb_max_txg = txg;
+       lwb->lwb_zio = NULL;
+       lwb->lwb_tx = NULL;
+       if (BP_GET_CHECKSUM(bp) == ZIO_CHECKSUM_ZILOG2) {
+               lwb->lwb_nused = sizeof (zil_chain_t);
+               lwb->lwb_sz = BP_GET_LSIZE(bp);
+       } else {
+               lwb->lwb_nused = 0;
+               lwb->lwb_sz = BP_GET_LSIZE(bp) - sizeof (zil_chain_t);
+       }
+
+       mutex_enter(&zilog->zl_lock);
+       list_insert_tail(&zilog->zl_lwb_list, lwb);
+       mutex_exit(&zilog->zl_lock);
+
+       return (lwb);
+}
+
+/*
+ * Called when we create in-memory log transactions so that we know
+ * to cleanup the itxs at the end of spa_sync().
+ */
+void
+zilog_dirty(zilog_t *zilog, uint64_t txg)
+{
+       dsl_pool_t *dp = zilog->zl_dmu_pool;
+       dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os);
+
+       if (ds->ds_is_snapshot)
+               panic("dirtying snapshot!");
+
+       if (txg_list_add(&dp->dp_dirty_zilogs, zilog, txg)) {
+               /* up the hold count until we can be written out */
+               dmu_buf_add_ref(ds->ds_dbuf, zilog);
+       }
+}
+
+boolean_t
+zilog_is_dirty(zilog_t *zilog)
+{
+       dsl_pool_t *dp = zilog->zl_dmu_pool;
+       int t;
+
+       for (t = 0; t < TXG_SIZE; t++) {
+               if (txg_list_member(&dp->dp_dirty_zilogs, zilog, t))
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Create an on-disk intent log.
+ */
+static lwb_t *
+zil_create(zilog_t *zilog)
+{
+       const zil_header_t *zh = zilog->zl_header;
+       lwb_t *lwb = NULL;
+       uint64_t txg = 0;
+       dmu_tx_t *tx = NULL;
+       blkptr_t blk;
+       int error = 0;
+       boolean_t fastwrite = FALSE;
+
+       /*
+        * Wait for any previous destroy to complete.
+        */
+       txg_wait_synced(zilog->zl_dmu_pool, zilog->zl_destroy_txg);
+
+       ASSERT(zh->zh_claim_txg == 0);
+       ASSERT(zh->zh_replay_seq == 0);
+
+       blk = zh->zh_log;
+
+       /*
+        * Allocate an initial log block if:
+        *    - there isn't one already
+        *    - the existing block is the wrong endianess
+        */
+       if (BP_IS_HOLE(&blk) || BP_SHOULD_BYTESWAP(&blk)) {
+               tx = dmu_tx_create(zilog->zl_os);
+               VERIFY(dmu_tx_assign(tx, TXG_WAIT) == 0);
+               dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
+               txg = dmu_tx_get_txg(tx);
+
+               if (!BP_IS_HOLE(&blk)) {
+                       zio_free_zil(zilog->zl_spa, txg, &blk);
+                       BP_ZERO(&blk);
+               }
+
+               error = zio_alloc_zil(zilog->zl_spa, txg, &blk,
+                   ZIL_MIN_BLKSZ, B_TRUE);
+               fastwrite = TRUE;
+
+               if (error == 0)
+                       zil_init_log_chain(zilog, &blk);
+       }
+
+       /*
+        * Allocate a log write buffer (lwb) for the first log block.
+        */
+       if (error == 0)
+               lwb = zil_alloc_lwb(zilog, &blk, txg, fastwrite);
+
+       /*
+        * If we just allocated the first log block, commit our transaction
+        * and wait for zil_sync() to stuff the block poiner into zh_log.
+        * (zh is part of the MOS, so we cannot modify it in open context.)
+        */
+       if (tx != NULL) {
+               dmu_tx_commit(tx);
+               txg_wait_synced(zilog->zl_dmu_pool, txg);
+       }
+
+       ASSERT(bcmp(&blk, &zh->zh_log, sizeof (blk)) == 0);
+
+       return (lwb);
+}
+
+/*
+ * In one tx, free all log blocks and clear the log header.
+ * If keep_first is set, then we're replaying a log with no content.
+ * We want to keep the first block, however, so that the first
+ * synchronous transaction doesn't require a txg_wait_synced()
+ * in zil_create().  We don't need to txg_wait_synced() here either
+ * when keep_first is set, because both zil_create() and zil_destroy()
+ * will wait for any in-progress destroys to complete.
+ */
+void
+zil_destroy(zilog_t *zilog, boolean_t keep_first)
+{
+       const zil_header_t *zh = zilog->zl_header;
+       lwb_t *lwb;
+       dmu_tx_t *tx;
+       uint64_t txg;
+
+       /*
+        * Wait for any previous destroy to complete.
+        */
+       txg_wait_synced(zilog->zl_dmu_pool, zilog->zl_destroy_txg);
+
+       zilog->zl_old_header = *zh;             /* debugging aid */
+
+       if (BP_IS_HOLE(&zh->zh_log))
+               return;
+
+       tx = dmu_tx_create(zilog->zl_os);
+       VERIFY(dmu_tx_assign(tx, TXG_WAIT) == 0);
+       dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
+       txg = dmu_tx_get_txg(tx);
+
+       mutex_enter(&zilog->zl_lock);
+
+       ASSERT3U(zilog->zl_destroy_txg, <, txg);
+       zilog->zl_destroy_txg = txg;
+       zilog->zl_keep_first = keep_first;
+
+       if (!list_is_empty(&zilog->zl_lwb_list)) {
+               ASSERT(zh->zh_claim_txg == 0);
+               VERIFY(!keep_first);
+               while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) {
+                       ASSERT(lwb->lwb_zio == NULL);
+                       if (lwb->lwb_fastwrite)
+                               metaslab_fastwrite_unmark(zilog->zl_spa,
+                                   &lwb->lwb_blk);
+                       list_remove(&zilog->zl_lwb_list, lwb);
+                       if (lwb->lwb_buf != NULL)
+                               zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
+                       zio_free_zil(zilog->zl_spa, txg, &lwb->lwb_blk);
+                       kmem_cache_free(zil_lwb_cache, lwb);
+               }
+       } else if (!keep_first) {
+               zil_destroy_sync(zilog, tx);
+       }
+       mutex_exit(&zilog->zl_lock);
+
+       dmu_tx_commit(tx);
+}
+
+void
+zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx)
+{
+       ASSERT(list_is_empty(&zilog->zl_lwb_list));
+       (void) zil_parse(zilog, zil_free_log_block,
+           zil_free_log_record, tx, zilog->zl_header->zh_claim_txg);
+}
+
+int
+zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg)
+{
+       dmu_tx_t *tx = txarg;
+       uint64_t first_txg = dmu_tx_get_txg(tx);
+       zilog_t *zilog;
+       zil_header_t *zh;
+       objset_t *os;
+       int error;
+
+       error = dmu_objset_own_obj(dp, ds->ds_object,
+           DMU_OST_ANY, B_FALSE, FTAG, &os);
+       if (error != 0) {
+               /*
+                * EBUSY indicates that the objset is inconsistent, in which
+                * case it can not have a ZIL.
+                */
+               if (error != EBUSY) {
+                       cmn_err(CE_WARN, "can't open objset for %llu, error %u",
+                           (unsigned long long)ds->ds_object, error);
+               }
+
+               return (0);
+       }
+
+       zilog = dmu_objset_zil(os);
+       zh = zil_header_in_syncing_context(zilog);
+
+       if (spa_get_log_state(zilog->zl_spa) == SPA_LOG_CLEAR) {
+               if (!BP_IS_HOLE(&zh->zh_log))
+                       zio_free_zil(zilog->zl_spa, first_txg, &zh->zh_log);
+               BP_ZERO(&zh->zh_log);
+               dsl_dataset_dirty(dmu_objset_ds(os), tx);
+               dmu_objset_disown(os, FTAG);
+               return (0);
+       }
+
+       /*
+        * Claim all log blocks if we haven't already done so, and remember
+        * the highest claimed sequence number.  This ensures that if we can
+        * read only part of the log now (e.g. due to a missing device),
+        * but we can read the entire log later, we will not try to replay
+        * or destroy beyond the last block we successfully claimed.
+        */
+       ASSERT3U(zh->zh_claim_txg, <=, first_txg);
+       if (zh->zh_claim_txg == 0 && !BP_IS_HOLE(&zh->zh_log)) {
+               (void) zil_parse(zilog, zil_claim_log_block,
+                   zil_claim_log_record, tx, first_txg);
+               zh->zh_claim_txg = first_txg;
+               zh->zh_claim_blk_seq = zilog->zl_parse_blk_seq;
+               zh->zh_claim_lr_seq = zilog->zl_parse_lr_seq;
+               if (zilog->zl_parse_lr_count || zilog->zl_parse_blk_count > 1)
+                       zh->zh_flags |= ZIL_REPLAY_NEEDED;
+               zh->zh_flags |= ZIL_CLAIM_LR_SEQ_VALID;
+               dsl_dataset_dirty(dmu_objset_ds(os), tx);
+       }
+
+       ASSERT3U(first_txg, ==, (spa_last_synced_txg(zilog->zl_spa) + 1));
+       dmu_objset_disown(os, FTAG);
+       return (0);
+}
+
+/*
+ * Check the log by walking the log chain.
+ * Checksum errors are ok as they indicate the end of the chain.
+ * Any other error (no device or read failure) returns an error.
+ */
+/* ARGSUSED */
+int
+zil_check_log_chain(dsl_pool_t *dp, dsl_dataset_t *ds, void *tx)
+{
+       zilog_t *zilog;
+       objset_t *os;
+       blkptr_t *bp;
+       int error;
+
+       ASSERT(tx == NULL);
+
+       error = dmu_objset_from_ds(ds, &os);
+       if (error != 0) {
+               cmn_err(CE_WARN, "can't open objset %llu, error %d",
+                   (unsigned long long)ds->ds_object, error);
+               return (0);
+       }
+
+       zilog = dmu_objset_zil(os);
+       bp = (blkptr_t *)&zilog->zl_header->zh_log;
+
+       /*
+        * Check the first block and determine if it's on a log device
+        * which may have been removed or faulted prior to loading this
+        * pool.  If so, there's no point in checking the rest of the log
+        * as its content should have already been synced to the pool.
+        */
+       if (!BP_IS_HOLE(bp)) {
+               vdev_t *vd;
+               boolean_t valid = B_TRUE;
+
+               spa_config_enter(os->os_spa, SCL_STATE, FTAG, RW_READER);
+               vd = vdev_lookup_top(os->os_spa, DVA_GET_VDEV(&bp->blk_dva[0]));
+               if (vd->vdev_islog && vdev_is_dead(vd))
+                       valid = vdev_log_state_valid(vd);
+               spa_config_exit(os->os_spa, SCL_STATE, FTAG);
+
+               if (!valid)
+                       return (0);
+       }
+
+       /*
+        * Because tx == NULL, zil_claim_log_block() will not actually claim
+        * any blocks, but just determine whether it is possible to do so.
+        * In addition to checking the log chain, zil_claim_log_block()
+        * will invoke zio_claim() with a done func of spa_claim_notify(),
+        * which will update spa_max_claim_txg.  See spa_load() for details.
+        */
+       error = zil_parse(zilog, zil_claim_log_block, zil_claim_log_record, tx,
+           zilog->zl_header->zh_claim_txg ? -1ULL : spa_first_txg(os->os_spa));
+
+       return ((error == ECKSUM || error == ENOENT) ? 0 : error);
+}
+
+static int
+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);
+}
+
+void
+zil_add_block(zilog_t *zilog, const blkptr_t *bp)
+{
+       avl_tree_t *t = &zilog->zl_vdev_tree;
+       avl_index_t where;
+       zil_vdev_node_t *zv, zvsearch;
+       int ndvas = BP_GET_NDVAS(bp);
+       int i;
+
+       if (zfs_nocacheflush)
+               return;
+
+       ASSERT(zilog->zl_writer);
+
+       /*
+        * Even though we're zl_writer, we still need a lock because the
+        * zl_get_data() callbacks may have dmu_sync() done callbacks
+        * that will run concurrently.
+        */
+       mutex_enter(&zilog->zl_vdev_lock);
+       for (i = 0; i < ndvas; i++) {
+               zvsearch.zv_vdev = DVA_GET_VDEV(&bp->blk_dva[i]);
+               if (avl_find(t, &zvsearch, &where) == NULL) {
+                       zv = kmem_alloc(sizeof (*zv), KM_SLEEP);
+                       zv->zv_vdev = zvsearch.zv_vdev;
+                       avl_insert(t, zv, where);
+               }
+       }
+       mutex_exit(&zilog->zl_vdev_lock);
+}
+
+static void
+zil_flush_vdevs(zilog_t *zilog)
+{
+       spa_t *spa = zilog->zl_spa;
+       avl_tree_t *t = &zilog->zl_vdev_tree;
+       void *cookie = NULL;
+       zil_vdev_node_t *zv;
+       zio_t *zio;
+
+       ASSERT(zilog->zl_writer);
+
+       /*
+        * We don't need zl_vdev_lock here because we're the zl_writer,
+        * and all zl_get_data() callbacks are done.
+        */
+       if (avl_numnodes(t) == 0)
+               return;
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+
+       zio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
+
+       while ((zv = avl_destroy_nodes(t, &cookie)) != NULL) {
+               vdev_t *vd = vdev_lookup_top(spa, zv->zv_vdev);
+               if (vd != NULL)
+                       zio_flush(zio, vd);
+               kmem_free(zv, sizeof (*zv));
+       }
+
+       /*
+        * Wait for all the flushes to complete.  Not all devices actually
+        * support the DKIOCFLUSHWRITECACHE ioctl, so it's OK if it fails.
+        */
+       (void) zio_wait(zio);
+
+       spa_config_exit(spa, SCL_STATE, FTAG);
+}
+
+/*
+ * Function called when a log block write completes
+ */
+static void
+zil_lwb_write_done(zio_t *zio)
+{
+       lwb_t *lwb = zio->io_private;
+       zilog_t *zilog = lwb->lwb_zilog;
+       dmu_tx_t *tx = lwb->lwb_tx;
+
+       ASSERT(BP_GET_COMPRESS(zio->io_bp) == ZIO_COMPRESS_OFF);
+       ASSERT(BP_GET_TYPE(zio->io_bp) == DMU_OT_INTENT_LOG);
+       ASSERT(BP_GET_LEVEL(zio->io_bp) == 0);
+       ASSERT(BP_GET_BYTEORDER(zio->io_bp) == ZFS_HOST_BYTEORDER);
+       ASSERT(!BP_IS_GANG(zio->io_bp));
+       ASSERT(!BP_IS_HOLE(zio->io_bp));
+       ASSERT(BP_GET_FILL(zio->io_bp) == 0);
+
+       /*
+        * Ensure the lwb buffer pointer is cleared before releasing
+        * the txg. If we have had an allocation failure and
+        * the txg is waiting to sync then we want want zil_sync()
+        * to remove the lwb so that it's not picked up as the next new
+        * one in zil_commit_writer(). zil_sync() will only remove
+        * the lwb if lwb_buf is null.
+        */
+       zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
+       mutex_enter(&zilog->zl_lock);
+       lwb->lwb_zio = NULL;
+       lwb->lwb_fastwrite = FALSE;
+       lwb->lwb_buf = NULL;
+       lwb->lwb_tx = NULL;
+       mutex_exit(&zilog->zl_lock);
+
+       /*
+        * Now that we've written this log block, we have a stable pointer
+        * to the next block in the chain, so it's OK to let the txg in
+        * which we allocated the next block sync.
+        */
+       dmu_tx_commit(tx);
+}
+
+/*
+ * Initialize the io for a log block.
+ */
+static void
+zil_lwb_write_init(zilog_t *zilog, lwb_t *lwb)
+{
+       zbookmark_phys_t zb;
+
+       SET_BOOKMARK(&zb, lwb->lwb_blk.blk_cksum.zc_word[ZIL_ZC_OBJSET],
+           ZB_ZIL_OBJECT, ZB_ZIL_LEVEL,
+           lwb->lwb_blk.blk_cksum.zc_word[ZIL_ZC_SEQ]);
+
+       if (zilog->zl_root_zio == NULL) {
+               zilog->zl_root_zio = zio_root(zilog->zl_spa, NULL, NULL,
+                   ZIO_FLAG_CANFAIL);
+       }
+
+       /* Lock so zil_sync() doesn't fastwrite_unmark after zio is created */
+       mutex_enter(&zilog->zl_lock);
+       if (lwb->lwb_zio == NULL) {
+               if (!lwb->lwb_fastwrite) {
+                       metaslab_fastwrite_mark(zilog->zl_spa, &lwb->lwb_blk);
+                       lwb->lwb_fastwrite = 1;
+               }
+               lwb->lwb_zio = zio_rewrite(zilog->zl_root_zio, zilog->zl_spa,
+                   0, &lwb->lwb_blk, lwb->lwb_buf, BP_GET_LSIZE(&lwb->lwb_blk),
+                   zil_lwb_write_done, lwb, ZIO_PRIORITY_SYNC_WRITE,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_DONT_PROPAGATE |
+                   ZIO_FLAG_FASTWRITE, &zb);
+       }
+       mutex_exit(&zilog->zl_lock);
+}
+
+/*
+ * Define a limited set of intent log block sizes.
+ *
+ * These must be a multiple of 4KB. Note only the amount used (again
+ * aligned to 4KB) actually gets written. However, we can't always just
+ * allocate SPA_OLD_MAXBLOCKSIZE as the slog space could be exhausted.
+ */
+uint64_t zil_block_buckets[] = {
+    4096,              /* non TX_WRITE */
+    8192+4096,         /* data base */
+    32*1024 + 4096,    /* NFS writes */
+    UINT64_MAX
+};
+
+/*
+ * Use the slog as long as the current commit size is less than the
+ * limit or the total list size is less than 2X the limit.  Limit
+ * checking is disabled by setting zil_slog_limit to UINT64_MAX.
+ */
+unsigned long zil_slog_limit = 1024 * 1024;
+#define        USE_SLOG(zilog) (((zilog)->zl_cur_used < zil_slog_limit) || \
+       ((zilog)->zl_itx_list_sz < (zil_slog_limit << 1)))
+
+/*
+ * Start a log block write and advance to the next log block.
+ * Calls are serialized.
+ */
+static lwb_t *
+zil_lwb_write_start(zilog_t *zilog, lwb_t *lwb)
+{
+       lwb_t *nlwb = NULL;
+       zil_chain_t *zilc;
+       spa_t *spa = zilog->zl_spa;
+       blkptr_t *bp;
+       dmu_tx_t *tx;
+       uint64_t txg;
+       uint64_t zil_blksz, wsz;
+       int i, error;
+       boolean_t use_slog;
+
+       if (BP_GET_CHECKSUM(&lwb->lwb_blk) == ZIO_CHECKSUM_ZILOG2) {
+               zilc = (zil_chain_t *)lwb->lwb_buf;
+               bp = &zilc->zc_next_blk;
+       } else {
+               zilc = (zil_chain_t *)(lwb->lwb_buf + lwb->lwb_sz);
+               bp = &zilc->zc_next_blk;
+       }
+
+       ASSERT(lwb->lwb_nused <= lwb->lwb_sz);
+
+       /*
+        * Allocate the next block and save its address in this block
+        * before writing it in order to establish the log chain.
+        * Note that if the allocation of nlwb synced before we wrote
+        * the block that points at it (lwb), we'd leak it if we crashed.
+        * Therefore, we don't do dmu_tx_commit() until zil_lwb_write_done().
+        * We dirty the dataset to ensure that zil_sync() will be called
+        * to clean up in the event of allocation failure or I/O failure.
+        */
+       tx = dmu_tx_create(zilog->zl_os);
+       VERIFY(dmu_tx_assign(tx, TXG_WAIT) == 0);
+       dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
+       txg = dmu_tx_get_txg(tx);
+
+       lwb->lwb_tx = tx;
+
+       /*
+        * Log blocks are pre-allocated. Here we select the size of the next
+        * block, based on size used in the last block.
+        * - first find the smallest bucket that will fit the block from a
+        *   limited set of block sizes. This is because it's faster to write
+        *   blocks allocated from the same metaslab as they are adjacent or
+        *   close.
+        * - next find the maximum from the new suggested size and an array of
+        *   previous sizes. This lessens a picket fence effect of wrongly
+        *   guesssing the size if we have a stream of say 2k, 64k, 2k, 64k
+        *   requests.
+        *
+        * Note we only write what is used, but we can't just allocate
+        * the maximum block size because we can exhaust the available
+        * pool log space.
+        */
+       zil_blksz = zilog->zl_cur_used + sizeof (zil_chain_t);
+       for (i = 0; zil_blksz > zil_block_buckets[i]; i++)
+               continue;
+       zil_blksz = zil_block_buckets[i];
+       if (zil_blksz == UINT64_MAX)
+               zil_blksz = SPA_OLD_MAXBLOCKSIZE;
+       zilog->zl_prev_blks[zilog->zl_prev_rotor] = zil_blksz;
+       for (i = 0; i < ZIL_PREV_BLKS; i++)
+               zil_blksz = MAX(zil_blksz, zilog->zl_prev_blks[i]);
+       zilog->zl_prev_rotor = (zilog->zl_prev_rotor + 1) & (ZIL_PREV_BLKS - 1);
+
+       BP_ZERO(bp);
+       use_slog = USE_SLOG(zilog);
+       error = zio_alloc_zil(spa, txg, bp, zil_blksz,
+           USE_SLOG(zilog));
+       if (use_slog) {
+               ZIL_STAT_BUMP(zil_itx_metaslab_slog_count);
+               ZIL_STAT_INCR(zil_itx_metaslab_slog_bytes, lwb->lwb_nused);
+       } else {
+               ZIL_STAT_BUMP(zil_itx_metaslab_normal_count);
+               ZIL_STAT_INCR(zil_itx_metaslab_normal_bytes, lwb->lwb_nused);
+       }
+       if (error == 0) {
+               ASSERT3U(bp->blk_birth, ==, txg);
+               bp->blk_cksum = lwb->lwb_blk.blk_cksum;
+               bp->blk_cksum.zc_word[ZIL_ZC_SEQ]++;
+
+               /*
+                * Allocate a new log write buffer (lwb).
+                */
+               nlwb = zil_alloc_lwb(zilog, bp, txg, TRUE);
+
+               /* Record the block for later vdev flushing */
+               zil_add_block(zilog, &lwb->lwb_blk);
+       }
+
+       if (BP_GET_CHECKSUM(&lwb->lwb_blk) == ZIO_CHECKSUM_ZILOG2) {
+               /* For Slim ZIL only write what is used. */
+               wsz = P2ROUNDUP_TYPED(lwb->lwb_nused, ZIL_MIN_BLKSZ, uint64_t);
+               ASSERT3U(wsz, <=, lwb->lwb_sz);
+               zio_shrink(lwb->lwb_zio, wsz);
+
+       } else {
+               wsz = lwb->lwb_sz;
+       }
+
+       zilc->zc_pad = 0;
+       zilc->zc_nused = lwb->lwb_nused;
+       zilc->zc_eck.zec_cksum = lwb->lwb_blk.blk_cksum;
+
+       /*
+        * clear unused data for security
+        */
+       bzero(lwb->lwb_buf + lwb->lwb_nused, wsz - lwb->lwb_nused);
+
+       zio_nowait(lwb->lwb_zio); /* Kick off the write for the old log block */
+
+       /*
+        * If there was an allocation failure then nlwb will be null which
+        * forces a txg_wait_synced().
+        */
+       return (nlwb);
+}
+
+static lwb_t *
+zil_lwb_commit(zilog_t *zilog, itx_t *itx, lwb_t *lwb)
+{
+       lr_t *lrc = &itx->itx_lr; /* common log record */
+       lr_write_t *lrw = (lr_write_t *)lrc;
+       char *lr_buf;
+       uint64_t txg = lrc->lrc_txg;
+       uint64_t reclen = lrc->lrc_reclen;
+       uint64_t dlen = 0;
+
+       if (lwb == NULL)
+               return (NULL);
+
+       ASSERT(lwb->lwb_buf != NULL);
+       ASSERT(zilog_is_dirty(zilog) ||
+           spa_freeze_txg(zilog->zl_spa) != UINT64_MAX);
+
+       if (lrc->lrc_txtype == TX_WRITE && itx->itx_wr_state == WR_NEED_COPY)
+               dlen = P2ROUNDUP_TYPED(
+                   lrw->lr_length, sizeof (uint64_t), uint64_t);
+
+       zilog->zl_cur_used += (reclen + dlen);
+
+       zil_lwb_write_init(zilog, lwb);
+
+       /*
+        * If this record won't fit in the current log block, start a new one.
+        */
+       if (lwb->lwb_nused + reclen + dlen > lwb->lwb_sz) {
+               lwb = zil_lwb_write_start(zilog, lwb);
+               if (lwb == NULL)
+                       return (NULL);
+               zil_lwb_write_init(zilog, lwb);
+               ASSERT(LWB_EMPTY(lwb));
+               if (lwb->lwb_nused + reclen + dlen > lwb->lwb_sz) {
+                       txg_wait_synced(zilog->zl_dmu_pool, txg);
+                       return (lwb);
+               }
+       }
+
+       lr_buf = lwb->lwb_buf + lwb->lwb_nused;
+       bcopy(lrc, lr_buf, reclen);
+       lrc = (lr_t *)lr_buf;
+       lrw = (lr_write_t *)lrc;
+
+       ZIL_STAT_BUMP(zil_itx_count);
+
+       /*
+        * If it's a write, fetch the data or get its blkptr as appropriate.
+        */
+       if (lrc->lrc_txtype == TX_WRITE) {
+               if (txg > spa_freeze_txg(zilog->zl_spa))
+                       txg_wait_synced(zilog->zl_dmu_pool, txg);
+               if (itx->itx_wr_state == WR_COPIED) {
+                       ZIL_STAT_BUMP(zil_itx_copied_count);
+                       ZIL_STAT_INCR(zil_itx_copied_bytes, lrw->lr_length);
+               } else {
+                       char *dbuf;
+                       int error;
+
+                       if (dlen) {
+                               ASSERT(itx->itx_wr_state == WR_NEED_COPY);
+                               dbuf = lr_buf + reclen;
+                               lrw->lr_common.lrc_reclen += dlen;
+                               ZIL_STAT_BUMP(zil_itx_needcopy_count);
+                               ZIL_STAT_INCR(zil_itx_needcopy_bytes,
+                                   lrw->lr_length);
+                       } else {
+                               ASSERT(itx->itx_wr_state == WR_INDIRECT);
+                               dbuf = NULL;
+                               ZIL_STAT_BUMP(zil_itx_indirect_count);
+                               ZIL_STAT_INCR(zil_itx_indirect_bytes,
+                                   lrw->lr_length);
+                       }
+                       error = zilog->zl_get_data(
+                           itx->itx_private, lrw, dbuf, lwb->lwb_zio);
+                       if (error == EIO) {
+                               txg_wait_synced(zilog->zl_dmu_pool, txg);
+                               return (lwb);
+                       }
+                       if (error != 0) {
+                               ASSERT(error == ENOENT || error == EEXIST ||
+                                   error == EALREADY);
+                               return (lwb);
+                       }
+               }
+       }
+
+       /*
+        * We're actually making an entry, so update lrc_seq to be the
+        * log record sequence number.  Note that this is generally not
+        * equal to the itx sequence number because not all transactions
+        * are synchronous, and sometimes spa_sync() gets there first.
+        */
+       lrc->lrc_seq = ++zilog->zl_lr_seq; /* we are single threaded */
+       lwb->lwb_nused += reclen + dlen;
+       lwb->lwb_max_txg = MAX(lwb->lwb_max_txg, txg);
+       ASSERT3U(lwb->lwb_nused, <=, lwb->lwb_sz);
+       ASSERT0(P2PHASE(lwb->lwb_nused, sizeof (uint64_t)));
+
+       return (lwb);
+}
+
+itx_t *
+zil_itx_create(uint64_t txtype, size_t lrsize)
+{
+       itx_t *itx;
+
+       lrsize = P2ROUNDUP_TYPED(lrsize, sizeof (uint64_t), size_t);
+
+       itx = zio_data_buf_alloc(offsetof(itx_t, itx_lr) + lrsize);
+       itx->itx_lr.lrc_txtype = txtype;
+       itx->itx_lr.lrc_reclen = lrsize;
+       itx->itx_sod = lrsize; /* if write & WR_NEED_COPY will be increased */
+       itx->itx_lr.lrc_seq = 0;        /* defensive */
+       itx->itx_sync = B_TRUE;         /* default is synchronous */
+       itx->itx_callback = NULL;
+       itx->itx_callback_data = NULL;
+
+       return (itx);
+}
+
+void
+zil_itx_destroy(itx_t *itx)
+{
+       zio_data_buf_free(itx, offsetof(itx_t, itx_lr)+itx->itx_lr.lrc_reclen);
+}
+
+/*
+ * Free up the sync and async itxs. The itxs_t has already been detached
+ * so no locks are needed.
+ */
+static void
+zil_itxg_clean(itxs_t *itxs)
+{
+       itx_t *itx;
+       list_t *list;
+       avl_tree_t *t;
+       void *cookie;
+       itx_async_node_t *ian;
+
+       list = &itxs->i_sync_list;
+       while ((itx = list_head(list)) != NULL) {
+               if (itx->itx_callback != NULL)
+                       itx->itx_callback(itx->itx_callback_data);
+               list_remove(list, itx);
+               zil_itx_destroy(itx);
+       }
+
+       cookie = NULL;
+       t = &itxs->i_async_tree;
+       while ((ian = avl_destroy_nodes(t, &cookie)) != NULL) {
+               list = &ian->ia_list;
+               while ((itx = list_head(list)) != NULL) {
+                       if (itx->itx_callback != NULL)
+                               itx->itx_callback(itx->itx_callback_data);
+                       list_remove(list, itx);
+                       zil_itx_destroy(itx);
+               }
+               list_destroy(list);
+               kmem_free(ian, sizeof (itx_async_node_t));
+       }
+       avl_destroy(t);
+
+       kmem_free(itxs, sizeof (itxs_t));
+}
+
+static int
+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);
+}
+
+/*
+ * Remove all async itx with the given oid.
+ */
+static void
+zil_remove_async(zilog_t *zilog, uint64_t oid)
+{
+       uint64_t otxg, txg;
+       itx_async_node_t *ian;
+       avl_tree_t *t;
+       avl_index_t where;
+       list_t clean_list;
+       itx_t *itx;
+
+       ASSERT(oid != 0);
+       list_create(&clean_list, sizeof (itx_t), offsetof(itx_t, itx_node));
+
+       if (spa_freeze_txg(zilog->zl_spa) != UINT64_MAX) /* ziltest support */
+               otxg = ZILTEST_TXG;
+       else
+               otxg = spa_last_synced_txg(zilog->zl_spa) + 1;
+
+       for (txg = otxg; txg < (otxg + TXG_CONCURRENT_STATES); txg++) {
+               itxg_t *itxg = &zilog->zl_itxg[txg & TXG_MASK];
+
+               mutex_enter(&itxg->itxg_lock);
+               if (itxg->itxg_txg != txg) {
+                       mutex_exit(&itxg->itxg_lock);
+                       continue;
+               }
+
+               /*
+                * Locate the object node and append its list.
+                */
+               t = &itxg->itxg_itxs->i_async_tree;
+               ian = avl_find(t, &oid, &where);
+               if (ian != NULL)
+                       list_move_tail(&clean_list, &ian->ia_list);
+               mutex_exit(&itxg->itxg_lock);
+       }
+       while ((itx = list_head(&clean_list)) != NULL) {
+               if (itx->itx_callback != NULL)
+                       itx->itx_callback(itx->itx_callback_data);
+               list_remove(&clean_list, itx);
+               zil_itx_destroy(itx);
+       }
+       list_destroy(&clean_list);
+}
+
+void
+zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx)
+{
+       uint64_t txg;
+       itxg_t *itxg;
+       itxs_t *itxs, *clean = NULL;
+
+       /*
+        * Object ids can be re-instantiated in the next txg so
+        * remove any async transactions to avoid future leaks.
+        * This can happen if a fsync occurs on the re-instantiated
+        * object for a WR_INDIRECT or WR_NEED_COPY write, which gets
+        * the new file data and flushes a write record for the old object.
+        */
+       if ((itx->itx_lr.lrc_txtype & ~TX_CI) == TX_REMOVE)
+               zil_remove_async(zilog, itx->itx_oid);
+
+       /*
+        * Ensure the data of a renamed file is committed before the rename.
+        */
+       if ((itx->itx_lr.lrc_txtype & ~TX_CI) == TX_RENAME)
+               zil_async_to_sync(zilog, itx->itx_oid);
+
+       if (spa_freeze_txg(zilog->zl_spa) != UINT64_MAX)
+               txg = ZILTEST_TXG;
+       else
+               txg = dmu_tx_get_txg(tx);
+
+       itxg = &zilog->zl_itxg[txg & TXG_MASK];
+       mutex_enter(&itxg->itxg_lock);
+       itxs = itxg->itxg_itxs;
+       if (itxg->itxg_txg != txg) {
+               if (itxs != NULL) {
+                       /*
+                        * The zil_clean callback hasn't got around to cleaning
+                        * this itxg. Save the itxs for release below.
+                        * This should be rare.
+                        */
+                       atomic_add_64(&zilog->zl_itx_list_sz, -itxg->itxg_sod);
+                       itxg->itxg_sod = 0;
+                       clean = itxg->itxg_itxs;
+               }
+               ASSERT(itxg->itxg_sod == 0);
+               itxg->itxg_txg = txg;
+               itxs = itxg->itxg_itxs = kmem_zalloc(sizeof (itxs_t),
+                   KM_SLEEP);
+
+               list_create(&itxs->i_sync_list, sizeof (itx_t),
+                   offsetof(itx_t, itx_node));
+               avl_create(&itxs->i_async_tree, zil_aitx_compare,
+                   sizeof (itx_async_node_t),
+                   offsetof(itx_async_node_t, ia_node));
+       }
+       if (itx->itx_sync) {
+               list_insert_tail(&itxs->i_sync_list, itx);
+               atomic_add_64(&zilog->zl_itx_list_sz, itx->itx_sod);
+               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;
+               itx_async_node_t *ian;
+               avl_index_t where;
+
+               ian = avl_find(t, &foid, &where);
+               if (ian == NULL) {
+                       ian = kmem_alloc(sizeof (itx_async_node_t),
+                           KM_SLEEP);
+                       list_create(&ian->ia_list, sizeof (itx_t),
+                           offsetof(itx_t, itx_node));
+                       ian->ia_foid = foid;
+                       avl_insert(t, ian, where);
+               }
+               list_insert_tail(&ian->ia_list, itx);
+       }
+
+       itx->itx_lr.lrc_txg = dmu_tx_get_txg(tx);
+       zilog_dirty(zilog, txg);
+       mutex_exit(&itxg->itxg_lock);
+
+       /* Release the old itxs now we've dropped the lock */
+       if (clean != NULL)
+               zil_itxg_clean(clean);
+}
+
+/*
+ * If there are any in-memory intent log transactions which have now been
+ * synced then start up a taskq to free them. We should only do this after we
+ * have written out the uberblocks (i.e. txg has been comitted) so that
+ * don't inadvertently clean out in-memory log records that would be required
+ * by zil_commit().
+ */
+void
+zil_clean(zilog_t *zilog, uint64_t synced_txg)
+{
+       itxg_t *itxg = &zilog->zl_itxg[synced_txg & TXG_MASK];
+       itxs_t *clean_me;
+
+       mutex_enter(&itxg->itxg_lock);
+       if (itxg->itxg_itxs == NULL || itxg->itxg_txg == ZILTEST_TXG) {
+               mutex_exit(&itxg->itxg_lock);
+               return;
+       }
+       ASSERT3U(itxg->itxg_txg, <=, synced_txg);
+       ASSERT(itxg->itxg_txg != 0);
+       ASSERT(zilog->zl_clean_taskq != NULL);
+       atomic_add_64(&zilog->zl_itx_list_sz, -itxg->itxg_sod);
+       itxg->itxg_sod = 0;
+       clean_me = itxg->itxg_itxs;
+       itxg->itxg_itxs = NULL;
+       itxg->itxg_txg = 0;
+       mutex_exit(&itxg->itxg_lock);
+       /*
+        * Preferably start a task queue to free up the old itxs but
+        * if taskq_dispatch can't allocate resources to do that then
+        * free it in-line. This should be rare. Note, using TQ_SLEEP
+        * created a bad performance problem.
+        */
+       if (taskq_dispatch(zilog->zl_clean_taskq,
+           (void (*)(void *))zil_itxg_clean, clean_me, TQ_NOSLEEP) == 0)
+               zil_itxg_clean(clean_me);
+}
+
+/*
+ * Get the list of itxs to commit into zl_itx_commit_list.
+ */
+static void
+zil_get_commit_list(zilog_t *zilog)
+{
+       uint64_t otxg, txg;
+       list_t *commit_list = &zilog->zl_itx_commit_list;
+       uint64_t push_sod = 0;
+
+       if (spa_freeze_txg(zilog->zl_spa) != UINT64_MAX) /* ziltest support */
+               otxg = ZILTEST_TXG;
+       else
+               otxg = spa_last_synced_txg(zilog->zl_spa) + 1;
+
+       for (txg = otxg; txg < (otxg + TXG_CONCURRENT_STATES); txg++) {
+               itxg_t *itxg = &zilog->zl_itxg[txg & TXG_MASK];
+
+               mutex_enter(&itxg->itxg_lock);
+               if (itxg->itxg_txg != txg) {
+                       mutex_exit(&itxg->itxg_lock);
+                       continue;
+               }
+
+               list_move_tail(commit_list, &itxg->itxg_itxs->i_sync_list);
+               push_sod += itxg->itxg_sod;
+               itxg->itxg_sod = 0;
+
+               mutex_exit(&itxg->itxg_lock);
+       }
+       atomic_add_64(&zilog->zl_itx_list_sz, -push_sod);
+}
+
+/*
+ * Move the async itxs for a specified object to commit into sync lists.
+ */
+static void
+zil_async_to_sync(zilog_t *zilog, uint64_t foid)
+{
+       uint64_t otxg, txg;
+       itx_async_node_t *ian;
+       avl_tree_t *t;
+       avl_index_t where;
+
+       if (spa_freeze_txg(zilog->zl_spa) != UINT64_MAX) /* ziltest support */
+               otxg = ZILTEST_TXG;
+       else
+               otxg = spa_last_synced_txg(zilog->zl_spa) + 1;
+
+       for (txg = otxg; txg < (otxg + TXG_CONCURRENT_STATES); txg++) {
+               itxg_t *itxg = &zilog->zl_itxg[txg & TXG_MASK];
+
+               mutex_enter(&itxg->itxg_lock);
+               if (itxg->itxg_txg != txg) {
+                       mutex_exit(&itxg->itxg_lock);
+                       continue;
+               }
+
+               /*
+                * If a foid is specified then find that node and append its
+                * list. Otherwise walk the tree appending all the lists
+                * to the sync list. We add to the end rather than the
+                * beginning to ensure the create has happened.
+                */
+               t = &itxg->itxg_itxs->i_async_tree;
+               if (foid != 0) {
+                       ian = avl_find(t, &foid, &where);
+                       if (ian != NULL) {
+                               list_move_tail(&itxg->itxg_itxs->i_sync_list,
+                                   &ian->ia_list);
+                       }
+               } else {
+                       void *cookie = NULL;
+
+                       while ((ian = avl_destroy_nodes(t, &cookie)) != NULL) {
+                               list_move_tail(&itxg->itxg_itxs->i_sync_list,
+                                   &ian->ia_list);
+                               list_destroy(&ian->ia_list);
+                               kmem_free(ian, sizeof (itx_async_node_t));
+                       }
+               }
+               mutex_exit(&itxg->itxg_lock);
+       }
+}
+
+static void
+zil_commit_writer(zilog_t *zilog)
+{
+       uint64_t txg;
+       itx_t *itx;
+       lwb_t *lwb;
+       spa_t *spa = zilog->zl_spa;
+       int error = 0;
+
+       ASSERT(zilog->zl_root_zio == NULL);
+
+       mutex_exit(&zilog->zl_lock);
+
+       zil_get_commit_list(zilog);
+
+       /*
+        * Return if there's nothing to commit before we dirty the fs by
+        * calling zil_create().
+        */
+       if (list_head(&zilog->zl_itx_commit_list) == NULL) {
+               mutex_enter(&zilog->zl_lock);
+               return;
+       }
+
+       if (zilog->zl_suspend) {
+               lwb = NULL;
+       } else {
+               lwb = list_tail(&zilog->zl_lwb_list);
+               if (lwb == NULL)
+                       lwb = zil_create(zilog);
+       }
+
+       DTRACE_PROBE1(zil__cw1, zilog_t *, zilog);
+       for (itx = list_head(&zilog->zl_itx_commit_list); itx != NULL;
+           itx = list_next(&zilog->zl_itx_commit_list, itx)) {
+               txg = itx->itx_lr.lrc_txg;
+               ASSERT(txg);
+
+               if (txg > spa_last_synced_txg(spa) || txg > spa_freeze_txg(spa))
+                       lwb = zil_lwb_commit(zilog, itx, lwb);
+       }
+       DTRACE_PROBE1(zil__cw2, zilog_t *, zilog);
+
+       /* write the last block out */
+       if (lwb != NULL && lwb->lwb_zio != NULL)
+               lwb = zil_lwb_write_start(zilog, lwb);
+
+       zilog->zl_cur_used = 0;
+
+       /*
+        * Wait if necessary for the log blocks to be on stable storage.
+        */
+       if (zilog->zl_root_zio) {
+               error = zio_wait(zilog->zl_root_zio);
+               zilog->zl_root_zio = NULL;
+               zil_flush_vdevs(zilog);
+       }
+
+       if (error || lwb == NULL)
+               txg_wait_synced(zilog->zl_dmu_pool, 0);
+
+       while ((itx = list_head(&zilog->zl_itx_commit_list))) {
+               txg = itx->itx_lr.lrc_txg;
+               ASSERT(txg);
+
+               if (itx->itx_callback != NULL)
+                       itx->itx_callback(itx->itx_callback_data);
+               list_remove(&zilog->zl_itx_commit_list, itx);
+               zil_itx_destroy(itx);
+       }
+
+       mutex_enter(&zilog->zl_lock);
+
+       /*
+        * Remember the highest committed log sequence number for ztest.
+        * We only update this value when all the log writes succeeded,
+        * because ztest wants to ASSERT that it got the whole log chain.
+        */
+       if (error == 0 && lwb != NULL)
+               zilog->zl_commit_lr_seq = zilog->zl_lr_seq;
+}
+
+/*
+ * Commit zfs transactions to stable storage.
+ * If foid is 0 push out all transactions, otherwise push only those
+ * for that object or might reference that object.
+ *
+ * itxs are committed in batches. In a heavily stressed zil there will be
+ * a commit writer thread who is writing out a bunch of itxs to the log
+ * for a set of committing threads (cthreads) in the same batch as the writer.
+ * Those cthreads are all waiting on the same cv for that batch.
+ *
+ * There will also be a different and growing batch of threads that are
+ * waiting to commit (qthreads). When the committing batch completes
+ * a transition occurs such that the cthreads exit and the qthreads become
+ * cthreads. One of the new cthreads becomes the writer thread for the
+ * batch. Any new threads arriving become new qthreads.
+ *
+ * Only 2 condition variables are needed and there's no transition
+ * between the two cvs needed. They just flip-flop between qthreads
+ * and cthreads.
+ *
+ * Using this scheme we can efficiently wakeup up only those threads
+ * that have been committed.
+ */
+void
+zil_commit(zilog_t *zilog, uint64_t foid)
+{
+       uint64_t mybatch;
+
+       if (zilog->zl_sync == ZFS_SYNC_DISABLED)
+               return;
+
+       ZIL_STAT_BUMP(zil_commit_count);
+
+       /* move the async itxs for the foid to the sync queues */
+       zil_async_to_sync(zilog, foid);
+
+       mutex_enter(&zilog->zl_lock);
+       mybatch = zilog->zl_next_batch;
+       while (zilog->zl_writer) {
+               cv_wait(&zilog->zl_cv_batch[mybatch & 1], &zilog->zl_lock);
+               if (mybatch <= zilog->zl_com_batch) {
+                       mutex_exit(&zilog->zl_lock);
+                       return;
+               }
+       }
+
+       zilog->zl_next_batch++;
+       zilog->zl_writer = B_TRUE;
+       ZIL_STAT_BUMP(zil_commit_writer_count);
+       zil_commit_writer(zilog);
+       zilog->zl_com_batch = mybatch;
+       zilog->zl_writer = B_FALSE;
+
+       /* wake up one thread to become the next writer */
+       cv_signal(&zilog->zl_cv_batch[(mybatch+1) & 1]);
+
+       /* wake up all threads waiting for this batch to be committed */
+       cv_broadcast(&zilog->zl_cv_batch[mybatch & 1]);
+
+       mutex_exit(&zilog->zl_lock);
+}
+
+/*
+ * Called in syncing context to free committed log blocks and update log header.
+ */
+void
+zil_sync(zilog_t *zilog, dmu_tx_t *tx)
+{
+       zil_header_t *zh = zil_header_in_syncing_context(zilog);
+       uint64_t txg = dmu_tx_get_txg(tx);
+       spa_t *spa = zilog->zl_spa;
+       uint64_t *replayed_seq = &zilog->zl_replayed_seq[txg & TXG_MASK];
+       lwb_t *lwb;
+
+       /*
+        * We don't zero out zl_destroy_txg, so make sure we don't try
+        * to destroy it twice.
+        */
+       if (spa_sync_pass(spa) != 1)
+               return;
+
+       mutex_enter(&zilog->zl_lock);
+
+       ASSERT(zilog->zl_stop_sync == 0);
+
+       if (*replayed_seq != 0) {
+               ASSERT(zh->zh_replay_seq < *replayed_seq);
+               zh->zh_replay_seq = *replayed_seq;
+               *replayed_seq = 0;
+       }
+
+       if (zilog->zl_destroy_txg == txg) {
+               blkptr_t blk = zh->zh_log;
+
+               ASSERT(list_head(&zilog->zl_lwb_list) == NULL);
+
+               bzero(zh, sizeof (zil_header_t));
+               bzero(zilog->zl_replayed_seq, sizeof (zilog->zl_replayed_seq));
+
+               if (zilog->zl_keep_first) {
+                       /*
+                        * If this block was part of log chain that couldn't
+                        * be claimed because a device was missing during
+                        * zil_claim(), but that device later returns,
+                        * then this block could erroneously appear valid.
+                        * To guard against this, assign a new GUID to the new
+                        * log chain so it doesn't matter what blk points to.
+                        */
+                       zil_init_log_chain(zilog, &blk);
+                       zh->zh_log = blk;
+               }
+       }
+
+       while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) {
+               zh->zh_log = lwb->lwb_blk;
+               if (lwb->lwb_buf != NULL || lwb->lwb_max_txg > txg)
+                       break;
+
+               ASSERT(lwb->lwb_zio == NULL);
+
+               list_remove(&zilog->zl_lwb_list, lwb);
+               zio_free_zil(spa, txg, &lwb->lwb_blk);
+               kmem_cache_free(zil_lwb_cache, lwb);
+
+               /*
+                * If we don't have anything left in the lwb list then
+                * we've had an allocation failure and we need to zero
+                * out the zil_header blkptr so that we don't end
+                * up freeing the same block twice.
+                */
+               if (list_head(&zilog->zl_lwb_list) == NULL)
+                       BP_ZERO(&zh->zh_log);
+       }
+
+       /*
+        * Remove fastwrite on any blocks that have been pre-allocated for
+        * the next commit. This prevents fastwrite counter pollution by
+        * unused, long-lived LWBs.
+        */
+       for (; lwb != NULL; lwb = list_next(&zilog->zl_lwb_list, lwb)) {
+               if (lwb->lwb_fastwrite && !lwb->lwb_zio) {
+                       metaslab_fastwrite_unmark(zilog->zl_spa, &lwb->lwb_blk);
+                       lwb->lwb_fastwrite = 0;
+               }
+       }
+
+       mutex_exit(&zilog->zl_lock);
+}
+
+void
+zil_init(void)
+{
+       zil_lwb_cache = kmem_cache_create("zil_lwb_cache",
+           sizeof (struct lwb), 0, NULL, NULL, NULL, NULL, NULL, 0);
+
+       zil_ksp = kstat_create("zfs", 0, "zil", "misc",
+           KSTAT_TYPE_NAMED, sizeof (zil_stats) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+
+       if (zil_ksp != NULL) {
+               zil_ksp->ks_data = &zil_stats;
+               kstat_install(zil_ksp);
+       }
+}
+
+void
+zil_fini(void)
+{
+       kmem_cache_destroy(zil_lwb_cache);
+
+       if (zil_ksp != NULL) {
+               kstat_delete(zil_ksp);
+               zil_ksp = NULL;
+       }
+}
+
+void
+zil_set_sync(zilog_t *zilog, uint64_t sync)
+{
+       zilog->zl_sync = sync;
+}
+
+void
+zil_set_logbias(zilog_t *zilog, uint64_t logbias)
+{
+       zilog->zl_logbias = logbias;
+}
+
+zilog_t *
+zil_alloc(objset_t *os, zil_header_t *zh_phys)
+{
+       zilog_t *zilog;
+       int i;
+
+       zilog = kmem_zalloc(sizeof (zilog_t), KM_SLEEP);
+
+       zilog->zl_header = zh_phys;
+       zilog->zl_os = os;
+       zilog->zl_spa = dmu_objset_spa(os);
+       zilog->zl_dmu_pool = dmu_objset_pool(os);
+       zilog->zl_destroy_txg = TXG_INITIAL - 1;
+       zilog->zl_logbias = dmu_objset_logbias(os);
+       zilog->zl_sync = dmu_objset_syncprop(os);
+       zilog->zl_next_batch = 1;
+
+       mutex_init(&zilog->zl_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               mutex_init(&zilog->zl_itxg[i].itxg_lock, NULL,
+                   MUTEX_DEFAULT, NULL);
+       }
+
+       list_create(&zilog->zl_lwb_list, sizeof (lwb_t),
+           offsetof(lwb_t, lwb_node));
+
+       list_create(&zilog->zl_itx_commit_list, sizeof (itx_t),
+           offsetof(itx_t, itx_node));
+
+       mutex_init(&zilog->zl_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       avl_create(&zilog->zl_vdev_tree, zil_vdev_compare,
+           sizeof (zil_vdev_node_t), offsetof(zil_vdev_node_t, zv_node));
+
+       cv_init(&zilog->zl_cv_writer, NULL, CV_DEFAULT, NULL);
+       cv_init(&zilog->zl_cv_suspend, NULL, CV_DEFAULT, NULL);
+       cv_init(&zilog->zl_cv_batch[0], NULL, CV_DEFAULT, NULL);
+       cv_init(&zilog->zl_cv_batch[1], NULL, CV_DEFAULT, NULL);
+
+       return (zilog);
+}
+
+void
+zil_free(zilog_t *zilog)
+{
+       int i;
+
+       zilog->zl_stop_sync = 1;
+
+       ASSERT0(zilog->zl_suspend);
+       ASSERT0(zilog->zl_suspending);
+
+       ASSERT(list_is_empty(&zilog->zl_lwb_list));
+       list_destroy(&zilog->zl_lwb_list);
+
+       avl_destroy(&zilog->zl_vdev_tree);
+       mutex_destroy(&zilog->zl_vdev_lock);
+
+       ASSERT(list_is_empty(&zilog->zl_itx_commit_list));
+       list_destroy(&zilog->zl_itx_commit_list);
+
+       for (i = 0; i < TXG_SIZE; i++) {
+               /*
+                * It's possible for an itx to be generated that doesn't dirty
+                * a txg (e.g. ztest TX_TRUNCATE). So there's no zil_clean()
+                * callback to remove the entry. We remove those here.
+                *
+                * Also free up the ziltest itxs.
+                */
+               if (zilog->zl_itxg[i].itxg_itxs)
+                       zil_itxg_clean(zilog->zl_itxg[i].itxg_itxs);
+               mutex_destroy(&zilog->zl_itxg[i].itxg_lock);
+       }
+
+       mutex_destroy(&zilog->zl_lock);
+
+       cv_destroy(&zilog->zl_cv_writer);
+       cv_destroy(&zilog->zl_cv_suspend);
+       cv_destroy(&zilog->zl_cv_batch[0]);
+       cv_destroy(&zilog->zl_cv_batch[1]);
+
+       kmem_free(zilog, sizeof (zilog_t));
+}
+
+/*
+ * Open an intent log.
+ */
+zilog_t *
+zil_open(objset_t *os, zil_get_data_t *get_data)
+{
+       zilog_t *zilog = dmu_objset_zil(os);
+
+       ASSERT(zilog->zl_clean_taskq == NULL);
+       ASSERT(zilog->zl_get_data == NULL);
+       ASSERT(list_is_empty(&zilog->zl_lwb_list));
+
+       zilog->zl_get_data = get_data;
+       zilog->zl_clean_taskq = taskq_create("zil_clean", 1, defclsyspri,
+           2, 2, TASKQ_PREPOPULATE);
+
+       return (zilog);
+}
+
+/*
+ * Close an intent log.
+ */
+void
+zil_close(zilog_t *zilog)
+{
+       lwb_t *lwb;
+       uint64_t txg = 0;
+
+       zil_commit(zilog, 0); /* commit all itx */
+
+       /*
+        * The lwb_max_txg for the stubby lwb will reflect the last activity
+        * for the zil.  After a txg_wait_synced() on the txg we know all the
+        * callbacks have occurred that may clean the zil.  Only then can we
+        * destroy the zl_clean_taskq.
+        */
+       mutex_enter(&zilog->zl_lock);
+       lwb = list_tail(&zilog->zl_lwb_list);
+       if (lwb != NULL)
+               txg = lwb->lwb_max_txg;
+       mutex_exit(&zilog->zl_lock);
+       if (txg)
+               txg_wait_synced(zilog->zl_dmu_pool, txg);
+       ASSERT(!zilog_is_dirty(zilog));
+
+       taskq_destroy(zilog->zl_clean_taskq);
+       zilog->zl_clean_taskq = NULL;
+       zilog->zl_get_data = NULL;
+
+       /*
+        * We should have only one LWB left on the list; remove it now.
+        */
+       mutex_enter(&zilog->zl_lock);
+       lwb = list_head(&zilog->zl_lwb_list);
+       if (lwb != NULL) {
+               ASSERT(lwb == list_tail(&zilog->zl_lwb_list));
+               ASSERT(lwb->lwb_zio == NULL);
+               if (lwb->lwb_fastwrite)
+                       metaslab_fastwrite_unmark(zilog->zl_spa, &lwb->lwb_blk);
+               list_remove(&zilog->zl_lwb_list, lwb);
+               zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
+               kmem_cache_free(zil_lwb_cache, lwb);
+       }
+       mutex_exit(&zilog->zl_lock);
+}
+
+static char *suspend_tag = "zil suspending";
+
+/*
+ * Suspend an intent log.  While in suspended mode, we still honor
+ * synchronous semantics, but we rely on txg_wait_synced() to do it.
+ * On old version pools, we suspend the log briefly when taking a
+ * snapshot so that it will have an empty intent log.
+ *
+ * Long holds are not really intended to be used the way we do here --
+ * held for such a short time.  A concurrent caller of dsl_dataset_long_held()
+ * could fail.  Therefore we take pains to only put a long hold if it is
+ * actually necessary.  Fortunately, it will only be necessary if the
+ * objset is currently mounted (or the ZVOL equivalent).  In that case it
+ * will already have a long hold, so we are not really making things any worse.
+ *
+ * Ideally, we would locate the existing long-holder (i.e. the zfsvfs_t or
+ * zvol_state_t), and use their mechanism to prevent their hold from being
+ * dropped (e.g. VFS_HOLD()).  However, that would be even more pain for
+ * very little gain.
+ *
+ * if cookiep == NULL, this does both the suspend & resume.
+ * Otherwise, it returns with the dataset "long held", and the cookie
+ * should be passed into zil_resume().
+ */
+int
+zil_suspend(const char *osname, void **cookiep)
+{
+       objset_t *os;
+       zilog_t *zilog;
+       const zil_header_t *zh;
+       int error;
+
+       error = dmu_objset_hold(osname, suspend_tag, &os);
+       if (error != 0)
+               return (error);
+       zilog = dmu_objset_zil(os);
+
+       mutex_enter(&zilog->zl_lock);
+       zh = zilog->zl_header;
+
+       if (zh->zh_flags & ZIL_REPLAY_NEEDED) {         /* unplayed log */
+               mutex_exit(&zilog->zl_lock);
+               dmu_objset_rele(os, suspend_tag);
+               return (SET_ERROR(EBUSY));
+       }
+
+       /*
+        * Don't put a long hold in the cases where we can avoid it.  This
+        * is when there is no cookie so we are doing a suspend & resume
+        * (i.e. called from zil_vdev_offline()), and there's nothing to do
+        * for the suspend because it's already suspended, or there's no ZIL.
+        */
+       if (cookiep == NULL && !zilog->zl_suspending &&
+           (zilog->zl_suspend > 0 || BP_IS_HOLE(&zh->zh_log))) {
+               mutex_exit(&zilog->zl_lock);
+               dmu_objset_rele(os, suspend_tag);
+               return (0);
+       }
+
+       dsl_dataset_long_hold(dmu_objset_ds(os), suspend_tag);
+       dsl_pool_rele(dmu_objset_pool(os), suspend_tag);
+
+       zilog->zl_suspend++;
+
+       if (zilog->zl_suspend > 1) {
+               /*
+                * Someone else is already suspending it.
+                * Just wait for them to finish.
+                */
+
+               while (zilog->zl_suspending)
+                       cv_wait(&zilog->zl_cv_suspend, &zilog->zl_lock);
+               mutex_exit(&zilog->zl_lock);
+
+               if (cookiep == NULL)
+                       zil_resume(os);
+               else
+                       *cookiep = os;
+               return (0);
+       }
+
+       /*
+        * If there is no pointer to an on-disk block, this ZIL must not
+        * be active (e.g. filesystem not mounted), so there's nothing
+        * to clean up.
+        */
+       if (BP_IS_HOLE(&zh->zh_log)) {
+               ASSERT(cookiep != NULL); /* fast path already handled */
+
+               *cookiep = os;
+               mutex_exit(&zilog->zl_lock);
+               return (0);
+       }
+
+       zilog->zl_suspending = B_TRUE;
+       mutex_exit(&zilog->zl_lock);
+
+       zil_commit(zilog, 0);
+
+       zil_destroy(zilog, B_FALSE);
+
+       mutex_enter(&zilog->zl_lock);
+       zilog->zl_suspending = B_FALSE;
+       cv_broadcast(&zilog->zl_cv_suspend);
+       mutex_exit(&zilog->zl_lock);
+
+       if (cookiep == NULL)
+               zil_resume(os);
+       else
+               *cookiep = os;
+       return (0);
+}
+
+void
+zil_resume(void *cookie)
+{
+       objset_t *os = cookie;
+       zilog_t *zilog = dmu_objset_zil(os);
+
+       mutex_enter(&zilog->zl_lock);
+       ASSERT(zilog->zl_suspend != 0);
+       zilog->zl_suspend--;
+       mutex_exit(&zilog->zl_lock);
+       dsl_dataset_long_rele(dmu_objset_ds(os), suspend_tag);
+       dsl_dataset_rele(dmu_objset_ds(os), suspend_tag);
+}
+
+typedef struct zil_replay_arg {
+       zil_replay_func_t *zr_replay;
+       void            *zr_arg;
+       boolean_t       zr_byteswap;
+       char            *zr_lr;
+} zil_replay_arg_t;
+
+static int
+zil_replay_error(zilog_t *zilog, lr_t *lr, int error)
+{
+       char name[MAXNAMELEN];
+
+       zilog->zl_replaying_seq--;      /* didn't actually replay this one */
+
+       dmu_objset_name(zilog->zl_os, name);
+
+       cmn_err(CE_WARN, "ZFS replay transaction error %d, "
+           "dataset %s, seq 0x%llx, txtype %llu %s\n", error, name,
+           (u_longlong_t)lr->lrc_seq,
+           (u_longlong_t)(lr->lrc_txtype & ~TX_CI),
+           (lr->lrc_txtype & TX_CI) ? "CI" : "");
+
+       return (error);
+}
+
+static int
+zil_replay_log_record(zilog_t *zilog, lr_t *lr, void *zra, uint64_t claim_txg)
+{
+       zil_replay_arg_t *zr = zra;
+       const zil_header_t *zh = zilog->zl_header;
+       uint64_t reclen = lr->lrc_reclen;
+       uint64_t txtype = lr->lrc_txtype;
+       int error = 0;
+
+       zilog->zl_replaying_seq = lr->lrc_seq;
+
+       if (lr->lrc_seq <= zh->zh_replay_seq)   /* already replayed */
+               return (0);
+
+       if (lr->lrc_txg < claim_txg)            /* already committed */
+               return (0);
+
+       /* Strip case-insensitive bit, still present in log record */
+       txtype &= ~TX_CI;
+
+       if (txtype == 0 || txtype >= TX_MAX_TYPE)
+               return (zil_replay_error(zilog, lr, EINVAL));
+
+       /*
+        * If this record type can be logged out of order, the object
+        * (lr_foid) may no longer exist.  That's legitimate, not an error.
+        */
+       if (TX_OOO(txtype)) {
+               error = dmu_object_info(zilog->zl_os,
+                   ((lr_ooo_t *)lr)->lr_foid, NULL);
+               if (error == ENOENT || error == EEXIST)
+                       return (0);
+       }
+
+       /*
+        * Make a copy of the data so we can revise and extend it.
+        */
+       bcopy(lr, zr->zr_lr, reclen);
+
+       /*
+        * If this is a TX_WRITE with a blkptr, suck in the data.
+        */
+       if (txtype == TX_WRITE && reclen == sizeof (lr_write_t)) {
+               error = zil_read_log_data(zilog, (lr_write_t *)lr,
+                   zr->zr_lr + reclen);
+               if (error != 0)
+                       return (zil_replay_error(zilog, lr, error));
+       }
+
+       /*
+        * The log block containing this lr may have been byteswapped
+        * so that we can easily examine common fields like lrc_txtype.
+        * However, the log is a mix of different record types, and only the
+        * replay vectors know how to byteswap their records.  Therefore, if
+        * the lr was byteswapped, undo it before invoking the replay vector.
+        */
+       if (zr->zr_byteswap)
+               byteswap_uint64_array(zr->zr_lr, reclen);
+
+       /*
+        * We must now do two things atomically: replay this log record,
+        * and update the log header sequence number to reflect the fact that
+        * we did so. At the end of each replay function the sequence number
+        * is updated if we are in replay mode.
+        */
+       error = zr->zr_replay[txtype](zr->zr_arg, zr->zr_lr, zr->zr_byteswap);
+       if (error != 0) {
+               /*
+                * The DMU's dnode layer doesn't see removes until the txg
+                * commits, so a subsequent claim can spuriously fail with
+                * EEXIST. So if we receive any error we try syncing out
+                * any removes then retry the transaction.  Note that we
+                * specify B_FALSE for byteswap now, so we don't do it twice.
+                */
+               txg_wait_synced(spa_get_dsl(zilog->zl_spa), 0);
+               error = zr->zr_replay[txtype](zr->zr_arg, zr->zr_lr, B_FALSE);
+               if (error != 0)
+                       return (zil_replay_error(zilog, lr, error));
+       }
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+zil_incr_blks(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
+{
+       zilog->zl_replay_blks++;
+
+       return (0);
+}
+
+/*
+ * If this dataset has a non-empty intent log, replay it and destroy it.
+ */
+void
+zil_replay(objset_t *os, void *arg, zil_replay_func_t replay_func[TX_MAX_TYPE])
+{
+       zilog_t *zilog = dmu_objset_zil(os);
+       const zil_header_t *zh = zilog->zl_header;
+       zil_replay_arg_t zr;
+
+       if ((zh->zh_flags & ZIL_REPLAY_NEEDED) == 0) {
+               zil_destroy(zilog, B_TRUE);
+               return;
+       }
+
+       zr.zr_replay = replay_func;
+       zr.zr_arg = arg;
+       zr.zr_byteswap = BP_SHOULD_BYTESWAP(&zh->zh_log);
+       zr.zr_lr = vmem_alloc(2 * SPA_MAXBLOCKSIZE, KM_SLEEP);
+
+       /*
+        * Wait for in-progress removes to sync before starting replay.
+        */
+       txg_wait_synced(zilog->zl_dmu_pool, 0);
+
+       zilog->zl_replay = B_TRUE;
+       zilog->zl_replay_time = ddi_get_lbolt();
+       ASSERT(zilog->zl_replay_blks == 0);
+       (void) zil_parse(zilog, zil_incr_blks, zil_replay_log_record, &zr,
+           zh->zh_claim_txg);
+       vmem_free(zr.zr_lr, 2 * SPA_MAXBLOCKSIZE);
+
+       zil_destroy(zilog, B_FALSE);
+       txg_wait_synced(zilog->zl_dmu_pool, zilog->zl_destroy_txg);
+       zilog->zl_replay = B_FALSE;
+}
+
+boolean_t
+zil_replaying(zilog_t *zilog, dmu_tx_t *tx)
+{
+       if (zilog->zl_sync == ZFS_SYNC_DISABLED)
+               return (B_TRUE);
+
+       if (zilog->zl_replay) {
+               dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
+               zilog->zl_replayed_seq[dmu_tx_get_txg(tx) & TXG_MASK] =
+                   zilog->zl_replaying_seq;
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/* ARGSUSED */
+int
+zil_vdev_offline(const char *osname, void *arg)
+{
+       int error;
+
+       error = zil_suspend(osname, NULL);
+       if (error != 0)
+               return (SET_ERROR(EEXIST));
+       return (0);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zil_alloc);
+EXPORT_SYMBOL(zil_free);
+EXPORT_SYMBOL(zil_open);
+EXPORT_SYMBOL(zil_close);
+EXPORT_SYMBOL(zil_replay);
+EXPORT_SYMBOL(zil_replaying);
+EXPORT_SYMBOL(zil_destroy);
+EXPORT_SYMBOL(zil_destroy_sync);
+EXPORT_SYMBOL(zil_itx_create);
+EXPORT_SYMBOL(zil_itx_destroy);
+EXPORT_SYMBOL(zil_itx_assign);
+EXPORT_SYMBOL(zil_commit);
+EXPORT_SYMBOL(zil_vdev_offline);
+EXPORT_SYMBOL(zil_claim);
+EXPORT_SYMBOL(zil_check_log_chain);
+EXPORT_SYMBOL(zil_sync);
+EXPORT_SYMBOL(zil_clean);
+EXPORT_SYMBOL(zil_suspend);
+EXPORT_SYMBOL(zil_resume);
+EXPORT_SYMBOL(zil_add_block);
+EXPORT_SYMBOL(zil_bp_tree_add);
+EXPORT_SYMBOL(zil_set_sync);
+EXPORT_SYMBOL(zil_set_logbias);
+
+module_param(zil_replay_disable, int, 0644);
+MODULE_PARM_DESC(zil_replay_disable, "Disable intent logging replay");
+
+module_param(zfs_nocacheflush, int, 0644);
+MODULE_PARM_DESC(zfs_nocacheflush, "Disable cache flushes");
+
+module_param(zil_slog_limit, ulong, 0644);
+MODULE_PARM_DESC(zil_slog_limit, "Max commit bytes to separate log device");
+#endif
diff --git a/zfs/module/zfs/zio.c b/zfs/module/zfs/zio.c
new file mode 100644 (file)
index 0000000..2bc88c5
--- /dev/null
@@ -0,0 +1,3513 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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) 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/sysmacros.h>
+#include <sys/zfs_context.h>
+#include <sys/fm/fs/zfs.h>
+#include <sys/spa.h>
+#include <sys/txg.h>
+#include <sys/spa_impl.h>
+#include <sys/vdev_impl.h>
+#include <sys/zio_impl.h>
+#include <sys/zio_compress.h>
+#include <sys/zio_checksum.h>
+#include <sys/dmu_objset.h>
+#include <sys/arc.h>
+#include <sys/ddt.h>
+#include <sys/blkptr.h>
+#include <sys/zfeature.h>
+
+/*
+ * ==========================================================================
+ * I/O type descriptions
+ * ==========================================================================
+ */
+const char *zio_type_name[ZIO_TYPES] = {
+       "z_null", "z_rd", "z_wr", "z_fr", "z_cl", "z_ioctl"
+};
+
+/*
+ * ==========================================================================
+ * I/O kmem caches
+ * ==========================================================================
+ */
+kmem_cache_t *zio_cache;
+kmem_cache_t *zio_link_cache;
+kmem_cache_t *zio_buf_cache[SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT];
+kmem_cache_t *zio_data_buf_cache[SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT];
+int zio_delay_max = ZIO_DELAY_MAX;
+
+#define        ZIO_PIPELINE_CONTINUE           0x100
+#define        ZIO_PIPELINE_STOP               0x101
+
+/*
+ * 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.
+ * Care should be taken when changing these values as they directly impact
+ * spa_sync() performance. Tuning these values may introduce subtle performance
+ * pathologies and should only be done in the context of performance analysis.
+ * These tunables will eventually be removed and replaced with #defines once
+ * enough analysis has been done to determine optimal values.
+ *
+ * The 'zfs_sync_pass_deferred_free' pass must be greater than 1 to ensure that
+ * regular blocks are not deferred.
+ */
+int zfs_sync_pass_deferred_free = 2; /* defer frees starting in this pass */
+int zfs_sync_pass_dont_compress = 5; /* don't compress starting in this pass */
+int zfs_sync_pass_rewrite = 2; /* rewrite new bps starting in this pass */
+
+/*
+ * An allocating zio is one that either currently has the DVA allocate
+ * stage set or will have it later in its lifetime.
+ */
+#define        IO_IS_ALLOCATING(zio) ((zio)->io_orig_pipeline & ZIO_STAGE_DVA_ALLOCATE)
+
+int zio_requeue_io_start_cut_in_line = 1;
+
+#ifdef ZFS_DEBUG
+int zio_buf_debug_limit = 16384;
+#else
+int zio_buf_debug_limit = 0;
+#endif
+
+static inline void __zio_execute(zio_t *zio);
+
+void
+zio_init(void)
+{
+       size_t c;
+       vmem_t *data_alloc_arena = NULL;
+
+       zio_cache = kmem_cache_create("zio_cache",
+           sizeof (zio_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+       zio_link_cache = kmem_cache_create("zio_link_cache",
+           sizeof (zio_link_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+
+       /*
+        * For small buffers, we want a cache for each multiple of
+        * SPA_MINBLOCKSIZE.  For larger buffers, we want a cache
+        * for each quarter-power of 2.
+        */
+       for (c = 0; c < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; c++) {
+               size_t size = (c + 1) << SPA_MINBLOCKSHIFT;
+               size_t p2 = size;
+               size_t align = 0;
+               size_t cflags = (size > zio_buf_debug_limit) ? KMC_NODEBUG : 0;
+
+#ifdef _ILP32
+               /*
+                * Cache size limited to 1M on 32-bit platforms until ARC
+                * buffers no longer require virtual address space.
+                */
+               if (size > zfs_max_recordsize)
+                       break;
+#endif
+
+               while (!ISP2(p2))
+                       p2 &= p2 - 1;
+
+#ifndef _KERNEL
+               /*
+                * If we are using watchpoints, put each buffer on its own page,
+                * to eliminate the performance overhead of trapping to the
+                * kernel when modifying a non-watched buffer that shares the
+                * page with a watched buffer.
+                */
+               if (arc_watch && !IS_P2ALIGNED(size, PAGESIZE))
+                       continue;
+#endif
+               if (size <= 4 * SPA_MINBLOCKSIZE) {
+                       align = SPA_MINBLOCKSIZE;
+               } else if (IS_P2ALIGNED(size, p2 >> 2)) {
+                       align = MIN(p2 >> 2, PAGESIZE);
+               }
+
+               if (align != 0) {
+                       char name[36];
+                       (void) sprintf(name, "zio_buf_%lu", (ulong_t)size);
+                       zio_buf_cache[c] = kmem_cache_create(name, size,
+                           align, NULL, NULL, NULL, NULL, NULL, cflags);
+
+                       (void) sprintf(name, "zio_data_buf_%lu", (ulong_t)size);
+                       zio_data_buf_cache[c] = kmem_cache_create(name, size,
+                           align, NULL, NULL, NULL, NULL,
+                           data_alloc_arena, cflags);
+               }
+       }
+
+       while (--c != 0) {
+               ASSERT(zio_buf_cache[c] != NULL);
+               if (zio_buf_cache[c - 1] == NULL)
+                       zio_buf_cache[c - 1] = zio_buf_cache[c];
+
+               ASSERT(zio_data_buf_cache[c] != NULL);
+               if (zio_data_buf_cache[c - 1] == NULL)
+                       zio_data_buf_cache[c - 1] = zio_data_buf_cache[c];
+       }
+
+       zio_inject_init();
+
+       lz4_init();
+}
+
+void
+zio_fini(void)
+{
+       size_t c;
+       kmem_cache_t *last_cache = NULL;
+       kmem_cache_t *last_data_cache = NULL;
+
+       for (c = 0; c < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; c++) {
+#ifdef _ILP32
+               /*
+                * Cache size limited to 1M on 32-bit platforms until ARC
+                * buffers no longer require virtual address space.
+                */
+               if (((c + 1) << SPA_MINBLOCKSHIFT) > zfs_max_recordsize)
+                       break;
+#endif
+               if (zio_buf_cache[c] != last_cache) {
+                       last_cache = zio_buf_cache[c];
+                       kmem_cache_destroy(zio_buf_cache[c]);
+               }
+               zio_buf_cache[c] = NULL;
+
+               if (zio_data_buf_cache[c] != last_data_cache) {
+                       last_data_cache = zio_data_buf_cache[c];
+                       kmem_cache_destroy(zio_data_buf_cache[c]);
+               }
+               zio_data_buf_cache[c] = NULL;
+       }
+
+       kmem_cache_destroy(zio_link_cache);
+       kmem_cache_destroy(zio_cache);
+
+       zio_inject_fini();
+
+       lz4_fini();
+}
+
+/*
+ * ==========================================================================
+ * Allocate and free I/O buffers
+ * ==========================================================================
+ */
+
+/*
+ * Use zio_buf_alloc to allocate ZFS metadata.  This data will appear in a
+ * crashdump if the kernel panics, so use it judiciously.  Obviously, it's
+ * useful to inspect ZFS metadata, but if possible, we should avoid keeping
+ * excess / transient data in-core during a crashdump.
+ */
+void *
+zio_buf_alloc(size_t size)
+{
+       size_t c = (size - 1) >> SPA_MINBLOCKSHIFT;
+
+       VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
+
+       return (kmem_cache_alloc(zio_buf_cache[c], KM_PUSHPAGE));
+}
+
+/*
+ * Use zio_data_buf_alloc to allocate data.  The data will not appear in a
+ * crashdump if the kernel panics.  This exists so that we will limit the amount
+ * of ZFS data that shows up in a kernel crashdump.  (Thus reducing the amount
+ * of kernel heap dumped to disk when the kernel panics)
+ */
+void *
+zio_data_buf_alloc(size_t size)
+{
+       size_t c = (size - 1) >> SPA_MINBLOCKSHIFT;
+
+       VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
+
+       return (kmem_cache_alloc(zio_data_buf_cache[c], KM_PUSHPAGE));
+}
+
+/*
+ * Use zio_buf_alloc_flags when specific allocation flags are needed.  e.g.
+ * passing KM_NOSLEEP when it is acceptable for an allocation to fail.
+ */
+void *
+zio_buf_alloc_flags(size_t size, int flags)
+{
+       size_t c = (size - 1) >> SPA_MINBLOCKSHIFT;
+
+       VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
+
+       return (kmem_cache_alloc(zio_buf_cache[c], flags));
+}
+
+void
+zio_buf_free(void *buf, size_t size)
+{
+       size_t c = (size - 1) >> SPA_MINBLOCKSHIFT;
+
+       VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
+
+       kmem_cache_free(zio_buf_cache[c], buf);
+}
+
+void
+zio_data_buf_free(void *buf, size_t size)
+{
+       size_t c = (size - 1) >> SPA_MINBLOCKSHIFT;
+
+       VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
+
+       kmem_cache_free(zio_data_buf_cache[c], buf);
+}
+
+/*
+ * ==========================================================================
+ * Push and pop I/O transform buffers
+ * ==========================================================================
+ */
+static void
+zio_push_transform(zio_t *zio, void *data, uint64_t size, uint64_t bufsize,
+       zio_transform_func_t *transform)
+{
+       zio_transform_t *zt = kmem_alloc(sizeof (zio_transform_t), KM_SLEEP);
+
+       zt->zt_orig_data = zio->io_data;
+       zt->zt_orig_size = zio->io_size;
+       zt->zt_bufsize = bufsize;
+       zt->zt_transform = transform;
+
+       zt->zt_next = zio->io_transform_stack;
+       zio->io_transform_stack = zt;
+
+       zio->io_data = data;
+       zio->io_size = size;
+}
+
+static void
+zio_pop_transforms(zio_t *zio)
+{
+       zio_transform_t *zt;
+
+       while ((zt = zio->io_transform_stack) != NULL) {
+               if (zt->zt_transform != NULL)
+                       zt->zt_transform(zio,
+                           zt->zt_orig_data, zt->zt_orig_size);
+
+               if (zt->zt_bufsize != 0)
+                       zio_buf_free(zio->io_data, zt->zt_bufsize);
+
+               zio->io_data = zt->zt_orig_data;
+               zio->io_size = zt->zt_orig_size;
+               zio->io_transform_stack = zt->zt_next;
+
+               kmem_free(zt, sizeof (zio_transform_t));
+       }
+}
+
+/*
+ * ==========================================================================
+ * I/O transform callbacks for subblocks and decompression
+ * ==========================================================================
+ */
+static void
+zio_subblock(zio_t *zio, void *data, uint64_t size)
+{
+       ASSERT(zio->io_size > size);
+
+       if (zio->io_type == ZIO_TYPE_READ)
+               bcopy(zio->io_data, data, size);
+}
+
+static void
+zio_decompress(zio_t *zio, void *data, uint64_t size)
+{
+       if (zio->io_error == 0 &&
+           zio_decompress_data(BP_GET_COMPRESS(zio->io_bp),
+           zio->io_data, data, zio->io_size, size) != 0)
+               zio->io_error = SET_ERROR(EIO);
+}
+
+/*
+ * ==========================================================================
+ * 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_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)
+               return (NULL);
+
+       ASSERT(zl->zl_child == cio);
+       return (zl->zl_parent);
+}
+
+zio_t *
+zio_walk_children(zio_t *pio)
+{
+       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)
+               return (NULL);
+
+       ASSERT(zl->zl_parent == pio);
+       return (zl->zl_child);
+}
+
+zio_t *
+zio_unique_parent(zio_t *cio)
+{
+       zio_t *pio = zio_walk_parents(cio);
+
+       VERIFY(zio_walk_parents(cio) == NULL);
+       return (pio);
+}
+
+void
+zio_add_child(zio_t *pio, zio_t *cio)
+{
+       zio_link_t *zl = kmem_cache_alloc(zio_link_cache, KM_SLEEP);
+       int w;
+
+       /*
+        * Logical I/Os can have logical, gang, or vdev children.
+        * Gang I/Os can have gang or vdev children.
+        * Vdev I/Os can only have vdev children.
+        * The following ASSERT captures all of these constraints.
+        */
+       ASSERT(cio->io_child_type <= pio->io_child_type);
+
+       zl->zl_parent = pio;
+       zl->zl_child = cio;
+
+       mutex_enter(&cio->io_lock);
+       mutex_enter(&pio->io_lock);
+
+       ASSERT(pio->io_state[ZIO_WAIT_DONE] == 0);
+
+       for (w = 0; w < ZIO_WAIT_TYPES; w++)
+               pio->io_children[cio->io_child_type][w] += !cio->io_state[w];
+
+       list_insert_head(&pio->io_child_list, zl);
+       list_insert_head(&cio->io_parent_list, zl);
+
+       pio->io_child_count++;
+       cio->io_parent_count++;
+
+       mutex_exit(&pio->io_lock);
+       mutex_exit(&cio->io_lock);
+}
+
+static void
+zio_remove_child(zio_t *pio, zio_t *cio, zio_link_t *zl)
+{
+       ASSERT(zl->zl_parent == pio);
+       ASSERT(zl->zl_child == cio);
+
+       mutex_enter(&cio->io_lock);
+       mutex_enter(&pio->io_lock);
+
+       list_remove(&pio->io_child_list, zl);
+       list_remove(&cio->io_parent_list, zl);
+
+       pio->io_child_count--;
+       cio->io_parent_count--;
+
+       mutex_exit(&pio->io_lock);
+       mutex_exit(&cio->io_lock);
+
+       kmem_cache_free(zio_link_cache, zl);
+}
+
+static boolean_t
+zio_wait_for_children(zio_t *zio, enum zio_child child, enum zio_wait_type wait)
+{
+       uint64_t *countp = &zio->io_children[child][wait];
+       boolean_t waiting = B_FALSE;
+
+       mutex_enter(&zio->io_lock);
+       ASSERT(zio->io_stall == NULL);
+       if (*countp != 0) {
+               zio->io_stage >>= 1;
+               zio->io_stall = countp;
+               waiting = B_TRUE;
+       }
+       mutex_exit(&zio->io_lock);
+
+       return (waiting);
+}
+
+__attribute__((always_inline))
+static inline void
+zio_notify_parent(zio_t *pio, zio_t *zio, enum zio_wait_type wait)
+{
+       uint64_t *countp = &pio->io_children[zio->io_child_type][wait];
+       int *errorp = &pio->io_child_error[zio->io_child_type];
+
+       mutex_enter(&pio->io_lock);
+       if (zio->io_error && !(zio->io_flags & ZIO_FLAG_DONT_PROPAGATE))
+               *errorp = zio_worst_error(*errorp, zio->io_error);
+       pio->io_reexecute |= zio->io_reexecute;
+       ASSERT3U(*countp, >, 0);
+
+       (*countp)--;
+
+       if (*countp == 0 && pio->io_stall == countp) {
+               pio->io_stall = NULL;
+               mutex_exit(&pio->io_lock);
+               __zio_execute(pio);
+       } else {
+               mutex_exit(&pio->io_lock);
+       }
+}
+
+static void
+zio_inherit_child_errors(zio_t *zio, enum zio_child c)
+{
+       if (zio->io_child_error[c] != 0 && zio->io_error == 0)
+               zio->io_error = zio->io_child_error[c];
+}
+
+/*
+ * ==========================================================================
+ * Create the various types of I/O (read, write, free, etc)
+ * ==========================================================================
+ */
+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)
+{
+       zio_t *zio;
+
+       ASSERT3U(size, <=, SPA_MAXBLOCKSIZE);
+       ASSERT(P2PHASE(size, 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);
+
+       zio = kmem_cache_alloc(zio_cache, KM_SLEEP);
+       bzero(zio, sizeof (zio_t));
+
+       mutex_init(&zio->io_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&zio->io_cv, NULL, CV_DEFAULT, NULL);
+
+       list_create(&zio->io_parent_list, sizeof (zio_link_t),
+           offsetof(zio_link_t, zl_parent_node));
+       list_create(&zio->io_child_list, sizeof (zio_link_t),
+           offsetof(zio_link_t, zl_child_node));
+
+       if (vd != NULL)
+               zio->io_child_type = ZIO_CHILD_VDEV;
+       else if (flags & ZIO_FLAG_GANG_CHILD)
+               zio->io_child_type = ZIO_CHILD_GANG;
+       else if (flags & ZIO_FLAG_DDT_CHILD)
+               zio->io_child_type = ZIO_CHILD_DDT;
+       else
+               zio->io_child_type = ZIO_CHILD_LOGICAL;
+
+       if (bp != NULL) {
+               zio->io_bp = (blkptr_t *)bp;
+               zio->io_bp_copy = *bp;
+               zio->io_bp_orig = *bp;
+               if (type != ZIO_TYPE_WRITE ||
+                   zio->io_child_type == ZIO_CHILD_DDT)
+                       zio->io_bp = &zio->io_bp_copy;  /* so caller can free */
+               if (zio->io_child_type == ZIO_CHILD_LOGICAL)
+                       zio->io_logical = zio;
+               if (zio->io_child_type > ZIO_CHILD_GANG && BP_IS_GANG(bp))
+                       pipeline |= ZIO_GANG_STAGES;
+       }
+
+       zio->io_spa = spa;
+       zio->io_txg = txg;
+       zio->io_done = done;
+       zio->io_private = private;
+       zio->io_type = type;
+       zio->io_priority = priority;
+       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_flags = zio->io_flags = flags;
+       zio->io_orig_stage = zio->io_stage = stage;
+       zio->io_orig_pipeline = zio->io_pipeline = pipeline;
+
+       zio->io_state[ZIO_WAIT_READY] = (stage >= ZIO_STAGE_READY);
+       zio->io_state[ZIO_WAIT_DONE] = (stage >= ZIO_STAGE_DONE);
+
+       if (zb != NULL)
+               zio->io_bookmark = *zb;
+
+       if (pio != NULL) {
+               if (zio->io_logical == NULL)
+                       zio->io_logical = pio->io_logical;
+               if (zio->io_child_type == ZIO_CHILD_GANG)
+                       zio->io_gang_leader = pio->io_gang_leader;
+               zio_add_child(pio, zio);
+       }
+
+       taskq_init_ent(&zio->io_tqent);
+
+       return (zio);
+}
+
+static void
+zio_destroy(zio_t *zio)
+{
+       list_destroy(&zio->io_parent_list);
+       list_destroy(&zio->io_child_list);
+       mutex_destroy(&zio->io_lock);
+       cv_destroy(&zio->io_cv);
+       kmem_cache_free(zio_cache, zio);
+}
+
+zio_t *
+zio_null(zio_t *pio, spa_t *spa, vdev_t *vd, zio_done_func_t *done,
+    void *private, enum zio_flag flags)
+{
+       zio_t *zio;
+
+       zio = zio_create(pio, spa, 0, NULL, NULL, 0, done, private,
+           ZIO_TYPE_NULL, ZIO_PRIORITY_NOW, flags, vd, 0, NULL,
+           ZIO_STAGE_OPEN, ZIO_INTERLOCK_PIPELINE);
+
+       return (zio);
+}
+
+zio_t *
+zio_root(spa_t *spa, zio_done_func_t *done, void *private, enum zio_flag flags)
+{
+       return (zio_null(NULL, spa, NULL, done, private, flags));
+}
+
+void
+zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp)
+{
+       int i;
+
+       if (!DMU_OT_IS_VALID(BP_GET_TYPE(bp))) {
+               zfs_panic_recover("blkptr at %p has invalid TYPE %llu",
+                   bp, (longlong_t)BP_GET_TYPE(bp));
+       }
+       if (BP_GET_CHECKSUM(bp) >= ZIO_CHECKSUM_FUNCTIONS ||
+           BP_GET_CHECKSUM(bp) <= ZIO_CHECKSUM_ON) {
+               zfs_panic_recover("blkptr at %p has invalid CHECKSUM %llu",
+                   bp, (longlong_t)BP_GET_CHECKSUM(bp));
+       }
+       if (BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_FUNCTIONS ||
+           BP_GET_COMPRESS(bp) <= ZIO_COMPRESS_ON) {
+               zfs_panic_recover("blkptr at %p has invalid COMPRESS %llu",
+                   bp, (longlong_t)BP_GET_COMPRESS(bp));
+       }
+       if (BP_GET_LSIZE(bp) > SPA_MAXBLOCKSIZE) {
+               zfs_panic_recover("blkptr at %p has invalid LSIZE %llu",
+                   bp, (longlong_t)BP_GET_LSIZE(bp));
+       }
+       if (BP_GET_PSIZE(bp) > SPA_MAXBLOCKSIZE) {
+               zfs_panic_recover("blkptr at %p has invalid PSIZE %llu",
+                   bp, (longlong_t)BP_GET_PSIZE(bp));
+       }
+
+       if (BP_IS_EMBEDDED(bp)) {
+               if (BPE_GET_ETYPE(bp) > NUM_BP_EMBEDDED_TYPES) {
+                       zfs_panic_recover("blkptr at %p has invalid ETYPE %llu",
+                           bp, (longlong_t)BPE_GET_ETYPE(bp));
+               }
+       }
+
+       /*
+        * Pool-specific checks.
+        *
+        * Note: it would be nice to verify that the blk_birth and
+        * BP_PHYSICAL_BIRTH() are not too large.  However, spa_freeze()
+        * allows the birth time of log blocks (and dmu_sync()-ed blocks
+        * that are in the log) to be arbitrarily large.
+        */
+       for (i = 0; i < BP_GET_NDVAS(bp); i++) {
+               uint64_t vdevid = DVA_GET_VDEV(&bp->blk_dva[i]);
+               vdev_t *vd;
+               uint64_t offset, asize;
+               if (vdevid >= spa->spa_root_vdev->vdev_children) {
+                       zfs_panic_recover("blkptr at %p DVA %u has invalid "
+                           "VDEV %llu",
+                           bp, i, (longlong_t)vdevid);
+               }
+               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);
+               }
+               if (vd->vdev_ops == &vdev_hole_ops) {
+                       zfs_panic_recover("blkptr at %p DVA %u has hole "
+                           "VDEV %llu",
+                           bp, i, (longlong_t)vdevid);
+
+               }
+               if (vd->vdev_ops == &vdev_missing_ops) {
+                       /*
+                        * "missing" vdevs are valid during import, but we
+                        * don't have their detailed info (e.g. asize), so
+                        * we can't perform any more checks on them.
+                        */
+                       continue;
+               }
+               offset = DVA_GET_OFFSET(&bp->blk_dva[i]);
+               asize = DVA_GET_ASIZE(&bp->blk_dva[i]);
+               if (BP_IS_GANG(bp))
+                       asize = vdev_psize_to_asize(vd, SPA_GANGBLOCKSIZE);
+               if (offset + asize > vd->vdev_asize) {
+                       zfs_panic_recover("blkptr at %p DVA %u has invalid "
+                           "OFFSET %llu",
+                           bp, i, (longlong_t)offset);
+               }
+       }
+}
+
+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,
+    zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb)
+{
+       zio_t *zio;
+
+       zfs_blkptr_verify(spa, bp);
+
+       zio = zio_create(pio, spa, BP_PHYSICAL_BIRTH(bp), bp,
+           data, 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);
+
+       return (zio);
+}
+
+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)
+{
+       zio_t *zio;
+
+       ASSERT(zp->zp_checksum >= ZIO_CHECKSUM_OFF &&
+           zp->zp_checksum < ZIO_CHECKSUM_FUNCTIONS &&
+           zp->zp_compress >= ZIO_COMPRESS_OFF &&
+           zp->zp_compress < ZIO_COMPRESS_FUNCTIONS &&
+           DMU_OT_IS_VALID(zp->zp_type) &&
+           zp->zp_level < 32 &&
+           zp->zp_copies > 0 &&
+           zp->zp_copies <= spa_max_replication(spa));
+
+       zio = zio_create(pio, spa, txg, bp, data, size, 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_physdone = physdone;
+       zio->io_prop = *zp;
+
+       /*
+        * Data can be NULL if we are going to call zio_write_override() to
+        * provide the already-allocated BP.  But we may need the data to
+        * verify a dedup hit (if requested).  In this case, don't try to
+        * dedup (just take the already-allocated BP verbatim).
+        */
+       if (data == NULL && zio->io_prop.zp_dedup_verify) {
+               zio->io_prop.zp_dedup = zio->io_prop.zp_dedup_verify = B_FALSE;
+       }
+
+       return (zio);
+}
+
+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,
+    zio_priority_t priority, enum zio_flag flags, zbookmark_phys_t *zb)
+{
+       zio_t *zio;
+
+       zio = zio_create(pio, spa, txg, bp, data, size, done, private,
+           ZIO_TYPE_WRITE, priority, flags, NULL, 0, zb,
+           ZIO_STAGE_OPEN, ZIO_REWRITE_PIPELINE);
+
+       return (zio);
+}
+
+void
+zio_write_override(zio_t *zio, blkptr_t *bp, int copies, boolean_t nopwrite)
+{
+       ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+       ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+       ASSERT(zio->io_stage == ZIO_STAGE_OPEN);
+       ASSERT(zio->io_txg == spa_syncing_txg(zio->io_spa));
+
+       /*
+        * We must reset the io_prop to match the values that existed
+        * when the bp was first written by dmu_sync() keeping in mind
+        * that nopwrite and dedup are mutually exclusive.
+        */
+       zio->io_prop.zp_dedup = nopwrite ? B_FALSE : zio->io_prop.zp_dedup;
+       zio->io_prop.zp_nopwrite = nopwrite;
+       zio->io_prop.zp_copies = copies;
+       zio->io_bp_override = bp;
+}
+
+void
+zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp)
+{
+
+       /*
+        * The check for EMBEDDED is a performance optimization.  We
+        * process the free here (by ignoring it) rather than
+        * putting it on the list and then processing it in zio_free_sync().
+        */
+       if (BP_IS_EMBEDDED(bp))
+               return;
+       metaslab_check_free(spa, bp);
+
+       /*
+        * Frees that are for the currently-syncing txg, are not going to be
+        * deferred, and which will not need to do a read (i.e. not GANG or
+        * DEDUP), can be processed immediately.  Otherwise, put them on the
+        * in-memory list for later processing.
+        */
+       if (BP_IS_GANG(bp) || BP_GET_DEDUP(bp) ||
+           txg != spa->spa_syncing_txg ||
+           spa_sync_pass(spa) >= zfs_sync_pass_deferred_free) {
+               bplist_append(&spa->spa_free_bplist[txg & TXG_MASK], bp);
+       } else {
+               VERIFY0(zio_wait(zio_free_sync(NULL, spa, txg, bp, 0)));
+       }
+}
+
+zio_t *
+zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
+    enum zio_flag flags)
+{
+       zio_t *zio;
+       enum zio_stage stage = ZIO_FREE_PIPELINE;
+
+       ASSERT(!BP_IS_HOLE(bp));
+       ASSERT(spa_syncing_txg(spa) == txg);
+       ASSERT(spa_sync_pass(spa) < zfs_sync_pass_deferred_free);
+
+       if (BP_IS_EMBEDDED(bp))
+               return (zio_null(pio, spa, NULL, NULL, NULL, 0));
+
+       metaslab_check_free(spa, bp);
+       arc_freed(spa, bp);
+
+       /*
+        * GANG and DEDUP blocks can induce a read (for the gang block header,
+        * or the DDT), so issue them asynchronously so that this thread is
+        * not tied up.
+        */
+       if (BP_IS_GANG(bp) || BP_GET_DEDUP(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);
+
+       return (zio);
+}
+
+zio_t *
+zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
+    zio_done_func_t *done, void *private, enum zio_flag flags)
+{
+       zio_t *zio;
+
+       dprintf_bp(bp, "claiming in txg %llu", txg);
+
+       if (BP_IS_EMBEDDED(bp))
+               return (zio_null(pio, spa, NULL, NULL, NULL, 0));
+
+       /*
+        * A claim is an allocation of a specific block.  Claims are needed
+        * to support immediate writes in the intent log.  The issue is that
+        * immediate writes contain committed data, but in a txg that was
+        * *not* committed.  Upon opening the pool after an unclean shutdown,
+        * the intent log claims all blocks that contain immediate write data
+        * so that the SPA knows they're in use.
+        *
+        * All claims *must* be resolved in the first txg -- before the SPA
+        * starts allocating blocks -- so that nothing is allocated twice.
+        * If txg == 0 we just verify that the block is claimable.
+        */
+       ASSERT3U(spa->spa_uberblock.ub_rootbp.blk_birth, <, spa_first_txg(spa));
+       ASSERT(txg == spa_first_txg(spa) || txg == 0);
+       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);
+
+       return (zio);
+}
+
+zio_t *
+zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd,
+    zio_done_func_t *done, void *private, enum zio_flag flags)
+{
+       zio_t *zio;
+       int c;
+
+       if (vd->vdev_children == 0) {
+               zio = zio_create(pio, spa, 0, NULL, NULL, 0, done, private,
+                   ZIO_TYPE_IOCTL, ZIO_PRIORITY_NOW, flags, vd, 0, NULL,
+                   ZIO_STAGE_OPEN, ZIO_IOCTL_PIPELINE);
+
+               zio->io_cmd = cmd;
+       } else {
+               zio = zio_null(pio, spa, NULL, NULL, NULL, flags);
+
+               for (c = 0; c < vd->vdev_children; c++)
+                       zio_nowait(zio_ioctl(zio, spa, vd->vdev_child[c], cmd,
+                           done, private, flags));
+       }
+
+       return (zio);
+}
+
+zio_t *
+zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size,
+    void *data, int checksum, zio_done_func_t *done, void *private,
+    zio_priority_t priority, enum zio_flag flags, boolean_t labels)
+{
+       zio_t *zio;
+
+       ASSERT(vd->vdev_children == 0);
+       ASSERT(!labels || offset + size <= VDEV_LABEL_START_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->io_prop.zp_checksum = checksum;
+
+       return (zio);
+}
+
+zio_t *
+zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size,
+    void *data, int checksum, zio_done_func_t *done, void *private,
+    zio_priority_t priority, enum zio_flag flags, boolean_t labels)
+{
+       zio_t *zio;
+
+       ASSERT(vd->vdev_children == 0);
+       ASSERT(!labels || offset + size <= VDEV_LABEL_START_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->io_prop.zp_checksum = checksum;
+
+       if (zio_checksum_table[checksum].ci_eck) {
+               /*
+                * zec checksums are necessarily destructive -- they modify
+                * the end of the write buffer to hold the verifier/checksum.
+                * Therefore, we must make a local copy in case the data is
+                * being written to multiple places in parallel.
+                */
+               void *wbuf = zio_buf_alloc(size);
+               bcopy(data, wbuf, size);
+               zio_push_transform(zio, wbuf, size, size, NULL);
+       }
+
+       return (zio);
+}
+
+/*
+ * Create a child I/O to do some work for us.
+ */
+zio_t *
+zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset,
+       void *data, uint64_t size, int type, zio_priority_t priority,
+       enum zio_flag flags, zio_done_func_t *done, void *private)
+{
+       enum zio_stage pipeline = ZIO_VDEV_CHILD_PIPELINE;
+       zio_t *zio;
+
+       ASSERT(vd->vdev_parent ==
+           (pio->io_vd ? pio->io_vd : pio->io_spa->spa_root_vdev));
+
+       if (type == ZIO_TYPE_READ && bp != NULL) {
+               /*
+                * If we have the bp, then the child should perform the
+                * checksum and the parent need not.  This pushes error
+                * detection as close to the leaves as possible and
+                * eliminates redundant checksums in the interior nodes.
+                */
+               pipeline |= ZIO_STAGE_CHECKSUM_VERIFY;
+               pio->io_pipeline &= ~ZIO_STAGE_CHECKSUM_VERIFY;
+       }
+
+       if (vd->vdev_children == 0)
+               offset += VDEV_LABEL_START_SIZE;
+
+       flags |= ZIO_VDEV_CHILD_FLAGS(pio) | ZIO_FLAG_DONT_PROPAGATE;
+
+       /*
+        * If we've decided to do a repair, the write is not speculative --
+        * even if the original read was.
+        */
+       if (flags & ZIO_FLAG_IO_REPAIR)
+               flags &= ~ZIO_FLAG_SPECULATIVE;
+
+       zio = zio_create(pio, pio->io_spa, pio->io_txg, bp, data, size,
+           done, private, type, priority, flags, vd, offset, &pio->io_bookmark,
+           ZIO_STAGE_VDEV_IO_START >> 1, pipeline);
+
+       zio->io_physdone = pio->io_physdone;
+       if (vd->vdev_ops->vdev_op_leaf && zio->io_logical != NULL)
+               zio->io_logical->io_phys_children++;
+
+       return (zio);
+}
+
+zio_t *
+zio_vdev_delegated_io(vdev_t *vd, uint64_t offset, void *data, uint64_t size,
+       int type, zio_priority_t priority, enum zio_flag flags,
+       zio_done_func_t *done, void *private)
+{
+       zio_t *zio;
+
+       ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+       zio = zio_create(NULL, vd->vdev_spa, 0, NULL,
+           data, 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);
+
+       return (zio);
+}
+
+void
+zio_flush(zio_t *zio, vdev_t *vd)
+{
+       zio_nowait(zio_ioctl(zio, zio->io_spa, vd, DKIOCFLUSHWRITECACHE,
+           NULL, NULL,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY));
+}
+
+void
+zio_shrink(zio_t *zio, uint64_t size)
+{
+       ASSERT(zio->io_executor == NULL);
+       ASSERT(zio->io_orig_size == zio->io_size);
+       ASSERT(size <= zio->io_size);
+
+       /*
+        * We don't shrink for raidz because of problems with the
+        * reconstruction when reading back less than the block 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;
+}
+
+/*
+ * ==========================================================================
+ * Prepare to read and write logical blocks
+ * ==========================================================================
+ */
+
+static int
+zio_read_bp_init(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+
+       if (BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF &&
+           zio->io_child_type == ZIO_CHILD_LOGICAL &&
+           !(zio->io_flags & ZIO_FLAG_RAW)) {
+               uint64_t psize =
+                   BP_IS_EMBEDDED(bp) ? BPE_GET_PSIZE(bp) : BP_GET_PSIZE(bp);
+               void *cbuf = zio_buf_alloc(psize);
+
+               zio_push_transform(zio, cbuf, psize, psize, zio_decompress);
+       }
+
+       if (BP_IS_EMBEDDED(bp) && BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA) {
+               zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+               decode_embedded_bp_compressed(bp, zio->io_data);
+       } else {
+               ASSERT(!BP_IS_EMBEDDED(bp));
+       }
+
+       if (!DMU_OT_IS_METADATA(BP_GET_TYPE(bp)) && BP_GET_LEVEL(bp) == 0)
+               zio->io_flags |= ZIO_FLAG_DONT_CACHE;
+
+       if (BP_GET_TYPE(bp) == DMU_OT_DDT_ZAP)
+               zio->io_flags |= ZIO_FLAG_DONT_CACHE;
+
+       if (BP_GET_DEDUP(bp) && zio->io_child_type == ZIO_CHILD_LOGICAL)
+               zio->io_pipeline = ZIO_DDT_READ_PIPELINE;
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+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);
+
+       ASSERT(zio->io_child_type != ZIO_CHILD_DDT);
+
+       if (zio->io_bp_override) {
+               ASSERT(bp->blk_birth != zio->io_txg);
+               ASSERT(BP_GET_DEDUP(zio->io_bp_override) == 0);
+
+               *bp = *zio->io_bp_override;
+               zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+
+               if (BP_IS_EMBEDDED(bp))
+                       return (ZIO_PIPELINE_CONTINUE);
+
+               /*
+                * If we've been overridden and nopwrite is set then
+                * set the flag accordingly to indicate that a nopwrite
+                * has already occurred.
+                */
+               if (!BP_IS_HOLE(bp) && zp->zp_nopwrite) {
+                       ASSERT(!zp->zp_dedup);
+                       zio->io_flags |= ZIO_FLAG_NOPWRITE;
+                       return (ZIO_PIPELINE_CONTINUE);
+               }
+
+               ASSERT(!zp->zp_nopwrite);
+
+               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);
+
+               if (BP_GET_CHECKSUM(bp) == zp->zp_checksum) {
+                       BP_SET_DEDUP(bp, 1);
+                       zio->io_pipeline |= ZIO_STAGE_DDT_WRITE;
+                       return (ZIO_PIPELINE_CONTINUE);
+               }
+       }
+
+       if (!BP_IS_HOLE(bp) && bp->blk_birth == zio->io_txg) {
+               /*
+                * We're rewriting an existing block, which means we're
+                * working on behalf of spa_sync().  For spa_sync() to
+                * converge, it must eventually be the case that we don't
+                * have to allocate new blocks.  But compression changes
+                * the blocksize, which forces a reallocate, and makes
+                * convergence take longer.  Therefore, after the first
+                * few passes, stop compressing to ensure convergence.
+                */
+               pass = spa_sync_pass(spa);
+
+               ASSERT(zio->io_txg == spa_syncing_txg(spa));
+               ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+               ASSERT(!BP_GET_DEDUP(bp));
+
+               if (pass >= zfs_sync_pass_dont_compress)
+                       compress = ZIO_COMPRESS_OFF;
+
+               /* Make sure someone doesn't change their mind on overwrites */
+               ASSERT(BP_IS_EMBEDDED(bp) || MIN(zp->zp_copies + BP_IS_GANG(bp),
+                   spa_max_replication(spa)) == BP_GET_NDVAS(bp));
+       }
+
+       if (compress != ZIO_COMPRESS_OFF) {
+               void *cbuf = zio_buf_alloc(lsize);
+               psize = zio_compress_data(compress, zio->io_data, cbuf, lsize);
+               if (psize == 0 || psize == lsize) {
+                       compress = ZIO_COMPRESS_OFF;
+                       zio_buf_free(cbuf, lsize);
+               } else if (!zp->zp_dedup && psize <= BPE_PAYLOAD_SIZE &&
+                   zp->zp_level == 0 && !DMU_OT_HAS_FILL(zp->zp_type) &&
+                   spa_feature_is_enabled(spa, SPA_FEATURE_EMBEDDED_DATA)) {
+                       encode_embedded_bp_compressed(bp,
+                           cbuf, compress, lsize, psize);
+                       BPE_SET_ETYPE(bp, BP_EMBEDDED_TYPE_DATA);
+                       BP_SET_TYPE(bp, zio->io_prop.zp_type);
+                       BP_SET_LEVEL(bp, zio->io_prop.zp_level);
+                       zio_buf_free(cbuf, lsize);
+                       bp->blk_birth = zio->io_txg;
+                       zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+                       ASSERT(spa_feature_is_active(spa,
+                           SPA_FEATURE_EMBEDDED_DATA));
+                       return (ZIO_PIPELINE_CONTINUE);
+               } else {
+                       /*
+                        * Round up compressed size up to the ashift
+                        * of the smallest-ashift device, and zero the tail.
+                        * This ensures that the compressed size of the BP
+                        * (and thus compressratio property) are correct,
+                        * in that we charge for the padding used to fill out
+                        * the last sector.
+                        */
+                       size_t rounded;
+
+                       ASSERT3U(spa->spa_min_ashift, >=, SPA_MINBLOCKSHIFT);
+
+                       rounded = (size_t)P2ROUNDUP(psize,
+                           1ULL << spa->spa_min_ashift);
+                       if (rounded >= lsize) {
+                               compress = ZIO_COMPRESS_OFF;
+                               zio_buf_free(cbuf, lsize);
+                               psize = lsize;
+                       } else {
+                               bzero((char *)cbuf + psize, rounded - psize);
+                               psize = rounded;
+                               zio_push_transform(zio, cbuf,
+                                   psize, lsize, NULL);
+                       }
+               }
+       }
+
+       /*
+        * The final pass of spa_sync() must be all rewrites, but the first
+        * few passes offer a trade-off: allocating blocks defers convergence,
+        * but newly allocated blocks are sequential, so they can be written
+        * to disk faster.  Therefore, we allow the first few passes of
+        * spa_sync() to allocate new blocks, but force rewrites after that.
+        * There should only be a handful of blocks after pass 1 in any case.
+        */
+       if (!BP_IS_HOLE(bp) && bp->blk_birth == zio->io_txg &&
+           BP_GET_PSIZE(bp) == psize &&
+           pass >= zfs_sync_pass_rewrite) {
+               enum zio_stage gang_stages = zio->io_pipeline & ZIO_GANG_STAGES;
+               ASSERT(psize != 0);
+               zio->io_pipeline = ZIO_REWRITE_PIPELINE | gang_stages;
+               zio->io_flags |= ZIO_FLAG_IO_REWRITE;
+       } else {
+               BP_ZERO(bp);
+               zio->io_pipeline = ZIO_WRITE_PIPELINE;
+       }
+
+       if (psize == 0) {
+               if (zio->io_bp_orig.blk_birth != 0 &&
+                   spa_feature_is_active(spa, SPA_FEATURE_HOLE_BIRTH)) {
+                       BP_SET_LSIZE(bp, lsize);
+                       BP_SET_TYPE(bp, zp->zp_type);
+                       BP_SET_LEVEL(bp, zp->zp_level);
+                       BP_SET_BIRTH(bp, zio->io_txg, 0);
+               }
+               zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+       } else {
+               ASSERT(zp->zp_checksum != ZIO_CHECKSUM_GANG_HEADER);
+               BP_SET_LSIZE(bp, lsize);
+               BP_SET_TYPE(bp, zp->zp_type);
+               BP_SET_LEVEL(bp, zp->zp_level);
+               BP_SET_PSIZE(bp, psize);
+               BP_SET_COMPRESS(bp, compress);
+               BP_SET_CHECKSUM(bp, zp->zp_checksum);
+               BP_SET_DEDUP(bp, zp->zp_dedup);
+               BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
+               if (zp->zp_dedup) {
+                       ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+                       ASSERT(!(zio->io_flags & ZIO_FLAG_IO_REWRITE));
+                       zio->io_pipeline = ZIO_DDT_WRITE_PIPELINE;
+               }
+               if (zp->zp_nopwrite) {
+                       ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+                       ASSERT(!(zio->io_flags & ZIO_FLAG_IO_REWRITE));
+                       zio->io_pipeline |= ZIO_STAGE_NOP_WRITE;
+               }
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_free_bp_init(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+
+       if (zio->io_child_type == ZIO_CHILD_LOGICAL) {
+               if (BP_GET_DEDUP(bp))
+                       zio->io_pipeline = ZIO_DDT_FREE_PIPELINE;
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * ==========================================================================
+ * Execute the I/O pipeline
+ * ==========================================================================
+ */
+
+static void
+zio_taskq_dispatch(zio_t *zio, zio_taskq_type_t q, boolean_t cutinline)
+{
+       spa_t *spa = zio->io_spa;
+       zio_type_t t = zio->io_type;
+       int flags = (cutinline ? TQ_FRONT : 0);
+
+       /*
+        * If we're a config writer or a probe, the normal issue and
+        * interrupt threads may all be blocked waiting for the config lock.
+        * In this case, select the otherwise-unused taskq for ZIO_TYPE_NULL.
+        */
+       if (zio->io_flags & (ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_PROBE))
+               t = ZIO_TYPE_NULL;
+
+       /*
+        * A similar issue exists for the L2ARC write thread until L2ARC 2.0.
+        */
+       if (t == ZIO_TYPE_WRITE && zio->io_vd && zio->io_vd->vdev_aux)
+               t = ZIO_TYPE_NULL;
+
+       /*
+        * If this is a high priority I/O, then use the high priority taskq if
+        * available.
+        */
+       if (zio->io_priority == ZIO_PRIORITY_NOW &&
+           spa->spa_zio_taskq[t][q + 1].stqs_count != 0)
+               q++;
+
+       ASSERT3U(q, <, ZIO_TASKQ_TYPES);
+
+       /*
+        * NB: We are assuming that the zio can only be dispatched
+        * to a single taskq at a time.  It would be a grievous error
+        * to dispatch the zio to another taskq at the same time.
+        */
+       ASSERT(taskq_empty_ent(&zio->io_tqent));
+       spa_taskq_dispatch_ent(spa, t, q, (task_func_t *)zio_execute, zio,
+           flags, &zio->io_tqent);
+}
+
+static boolean_t
+zio_taskq_member(zio_t *zio, zio_taskq_type_t q)
+{
+       kthread_t *executor = zio->io_executor;
+       spa_t *spa = zio->io_spa;
+       zio_type_t t;
+
+       for (t = 0; t < ZIO_TYPES; t++) {
+               spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
+               uint_t i;
+               for (i = 0; i < tqs->stqs_count; i++) {
+                       if (taskq_member(tqs->stqs_taskq[i], executor))
+                               return (B_TRUE);
+               }
+       }
+
+       return (B_FALSE);
+}
+
+static int
+zio_issue_async(zio_t *zio)
+{
+       zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, B_FALSE);
+
+       return (ZIO_PIPELINE_STOP);
+}
+
+void
+zio_interrupt(zio_t *zio)
+{
+       zio_taskq_dispatch(zio, ZIO_TASKQ_INTERRUPT, B_FALSE);
+}
+
+/*
+ * Execute the I/O pipeline until one of the following occurs:
+ * (1) the I/O completes; (2) the pipeline stalls waiting for
+ * dependent child I/Os; (3) the I/O issues, so we're waiting
+ * for an I/O completion interrupt; (4) the I/O is delegated by
+ * vdev-level caching or aggregation; (5) the I/O is deferred
+ * due to vdev-level queueing; (6) the I/O is handed off to
+ * another thread.  In all cases, the pipeline stops whenever
+ * there's no CPU work; it never burns a thread in cv_wait_io().
+ *
+ * There's no locking on io_stage because there's no legitimate way
+ * for multiple threads to be attempting to process the same I/O.
+ */
+static zio_pipe_stage_t *zio_pipeline[];
+
+/*
+ * zio_execute() is a wrapper around the static function
+ * __zio_execute() so that we can force  __zio_execute() to be
+ * inlined.  This reduces stack overhead which is important
+ * because __zio_execute() is called recursively in several zio
+ * code paths.  zio_execute() itself cannot be inlined because
+ * it is externally visible.
+ */
+void
+zio_execute(zio_t *zio)
+{
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       __zio_execute(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;
+
+       while (zio->io_stage < ZIO_STAGE_DONE) {
+               enum zio_stage pipeline = zio->io_pipeline;
+               enum zio_stage stage = zio->io_stage;
+               int rv;
+
+               ASSERT(!MUTEX_HELD(&zio->io_lock));
+               ASSERT(ISP2(stage));
+               ASSERT(zio->io_stall == NULL);
+
+               do {
+                       stage <<= 1;
+               } while ((stage & pipeline) == 0);
+
+               ASSERT(stage <= ZIO_STAGE_DONE);
+
+               /*
+                * If we are in interrupt context and this pipeline stage
+                * will grab a config lock that is held across I/O,
+                * or may wait for an I/O that needs an interrupt thread
+                * to complete, issue async to avoid deadlock.
+                *
+                * For VDEV_IO_START, we cut in line so that the io will
+                * be sent to disk promptly.
+                */
+               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 the current context doesn't have large enough stacks
+                * the zio must be issued asynchronously to prevent overflow.
+                */
+               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;
+               rv = zio_pipeline[highbit64(stage) - 1](zio);
+
+               if (rv == ZIO_PIPELINE_STOP)
+                       return;
+
+               ASSERT(rv == ZIO_PIPELINE_CONTINUE);
+       }
+}
+
+
+/*
+ * ==========================================================================
+ * Initiate I/O, either sync or async
+ * ==========================================================================
+ */
+int
+zio_wait(zio_t *zio)
+{
+       int error;
+
+       ASSERT(zio->io_stage == ZIO_STAGE_OPEN);
+       ASSERT(zio->io_executor == NULL);
+
+       zio->io_waiter = curthread;
+
+       __zio_execute(zio);
+
+       mutex_enter(&zio->io_lock);
+       while (zio->io_executor != NULL)
+               cv_wait_io(&zio->io_cv, &zio->io_lock);
+       mutex_exit(&zio->io_lock);
+
+       error = zio->io_error;
+       zio_destroy(zio);
+
+       return (error);
+}
+
+void
+zio_nowait(zio_t *zio)
+{
+       ASSERT(zio->io_executor == NULL);
+
+       if (zio->io_child_type == ZIO_CHILD_LOGICAL &&
+           zio_unique_parent(zio) == NULL) {
+               zio_t *pio;
+
+               /*
+                * This is a logical async I/O with no parent to wait for it.
+                * We add it to the spa_async_root_zio "Godfather" I/O which
+                * will ensure they complete prior to unloading the pool.
+                */
+               spa_t *spa = zio->io_spa;
+               kpreempt_disable();
+               pio = spa->spa_async_zio_root[CPU_SEQID];
+               kpreempt_enable();
+
+               zio_add_child(pio, zio);
+       }
+
+       __zio_execute(zio);
+}
+
+/*
+ * ==========================================================================
+ * Reexecute or suspend/resume failed I/O
+ * ==========================================================================
+ */
+
+static void
+zio_reexecute(zio_t *pio)
+{
+       zio_t *cio, *cio_next;
+       int c, w;
+
+       ASSERT(pio->io_child_type == ZIO_CHILD_LOGICAL);
+       ASSERT(pio->io_orig_stage == ZIO_STAGE_OPEN);
+       ASSERT(pio->io_gang_leader == NULL);
+       ASSERT(pio->io_gang_tree == NULL);
+
+       pio->io_flags = pio->io_orig_flags;
+       pio->io_stage = pio->io_orig_stage;
+       pio->io_pipeline = pio->io_orig_pipeline;
+       pio->io_reexecute = 0;
+       pio->io_flags |= ZIO_FLAG_REEXECUTED;
+       pio->io_error = 0;
+       for (w = 0; w < ZIO_WAIT_TYPES; w++)
+               pio->io_state[w] = 0;
+       for (c = 0; c < ZIO_CHILD_TYPES; c++)
+               pio->io_child_error[c] = 0;
+
+       if (IO_IS_ALLOCATING(pio))
+               BP_ZERO(pio->io_bp);
+
+       /*
+        * As we reexecute pio's children, new children could be created.
+        * New children go to the head of pio's io_child_list, however,
+        * so we will (correctly) not reexecute them.  The key is that
+        * 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);
+               mutex_enter(&pio->io_lock);
+               for (w = 0; w < ZIO_WAIT_TYPES; w++)
+                       pio->io_children[cio->io_child_type][w]++;
+               mutex_exit(&pio->io_lock);
+               zio_reexecute(cio);
+       }
+
+       /*
+        * Now that all children have been reexecuted, execute the parent.
+        * 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))
+               __zio_execute(pio);
+}
+
+void
+zio_suspend(spa_t *spa, zio_t *zio)
+{
+       if (spa_get_failmode(spa) == ZIO_FAILURE_MODE_PANIC)
+               fm_panic("Pool '%s' has encountered an uncorrectable I/O "
+                   "failure and the failure mode property for this pool "
+                   "is set to panic.", spa_name(spa));
+
+       cmn_err(CE_WARN, "Pool '%s' has encountered an uncorrectable I/O "
+           "failure and has been suspended.\n", spa_name(spa));
+
+       zfs_ereport_post(FM_EREPORT_ZFS_IO_FAILURE, spa, NULL, NULL, 0, 0);
+
+       mutex_enter(&spa->spa_suspend_lock);
+
+       if (spa->spa_suspend_zio_root == NULL)
+               spa->spa_suspend_zio_root = zio_root(spa, NULL, NULL,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+                   ZIO_FLAG_GODFATHER);
+
+       spa->spa_suspended = B_TRUE;
+
+       if (zio != NULL) {
+               ASSERT(!(zio->io_flags & ZIO_FLAG_GODFATHER));
+               ASSERT(zio != spa->spa_suspend_zio_root);
+               ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+               ASSERT(zio_unique_parent(zio) == NULL);
+               ASSERT(zio->io_stage == ZIO_STAGE_DONE);
+               zio_add_child(spa->spa_suspend_zio_root, zio);
+       }
+
+       mutex_exit(&spa->spa_suspend_lock);
+}
+
+int
+zio_resume(spa_t *spa)
+{
+       zio_t *pio;
+
+       /*
+        * Reexecute all previously suspended i/o.
+        */
+       mutex_enter(&spa->spa_suspend_lock);
+       spa->spa_suspended = B_FALSE;
+       cv_broadcast(&spa->spa_suspend_cv);
+       pio = spa->spa_suspend_zio_root;
+       spa->spa_suspend_zio_root = NULL;
+       mutex_exit(&spa->spa_suspend_lock);
+
+       if (pio == NULL)
+               return (0);
+
+       zio_reexecute(pio);
+       return (zio_wait(pio));
+}
+
+void
+zio_resume_wait(spa_t *spa)
+{
+       mutex_enter(&spa->spa_suspend_lock);
+       while (spa_suspended(spa))
+               cv_wait(&spa->spa_suspend_cv, &spa->spa_suspend_lock);
+       mutex_exit(&spa->spa_suspend_lock);
+}
+
+/*
+ * ==========================================================================
+ * Gang blocks.
+ *
+ * A gang block is a collection of small blocks that looks to the DMU
+ * like one large block.  When zio_dva_allocate() cannot find a block
+ * of the requested size, due to either severe fragmentation or the pool
+ * being nearly full, it calls zio_write_gang_block() to construct the
+ * block from smaller fragments.
+ *
+ * A gang block consists of a gang header (zio_gbh_phys_t) and up to
+ * three (SPA_GBH_NBLKPTRS) gang members.  The gang header is just like
+ * an indirect block: it's an array of block pointers.  It consumes
+ * only one sector and hence is allocatable regardless of fragmentation.
+ * The gang header's bps point to its gang members, which hold the data.
+ *
+ * Gang blocks are self-checksumming, using the bp's <vdev, offset, txg>
+ * as the verifier to ensure uniqueness of the SHA256 checksum.
+ * Critically, the gang block bp's blk_cksum is the checksum of the data,
+ * not the gang header.  This ensures that data block signatures (needed for
+ * deduplication) are independent of how the block is physically stored.
+ *
+ * Gang blocks can be nested: a gang member may itself be a gang block.
+ * Thus every gang block is a tree in which root and all interior nodes are
+ * gang headers, and the leaves are normal blocks that contain user data.
+ * The root of the gang tree is called the gang leader.
+ *
+ * To perform any operation (read, rewrite, free, claim) on a gang block,
+ * zio_gang_assemble() first assembles the gang tree (minus data leaves)
+ * in the io_gang_tree field of the original logical i/o by recursively
+ * reading the gang leader and all gang headers below it.  This yields
+ * an in-core tree containing the contents of every gang header and the
+ * bps for every constituent of the gang block.
+ *
+ * With the gang tree now assembled, zio_gang_issue() just walks the gang tree
+ * and invokes a callback on each bp.  To free a gang block, zio_gang_issue()
+ * calls zio_free_gang() -- a trivial wrapper around zio_free() -- for each bp.
+ * zio_claim_gang() provides a similarly trivial wrapper for zio_claim().
+ * zio_read_gang() is a wrapper around zio_read() that omits reading gang
+ * headers, since we already have those in io_gang_tree.  zio_rewrite_gang()
+ * performs a zio_rewrite() of the data or, for gang headers, a zio_rewrite()
+ * of the gang header plus zio_checksum_compute() of the data to update the
+ * gang header's blk_cksum as described above.
+ *
+ * The two-phase assemble/issue model solves the problem of partial failure --
+ * what if you'd freed part of a gang block but then couldn't read the
+ * gang header for another part?  Assembling the entire gang tree first
+ * ensures that all the necessary gang header I/O has succeeded before
+ * starting the actual work of free, claim, or write.  Once the gang tree
+ * is assembled, free and claim are in-memory operations that cannot fail.
+ *
+ * In the event that a gang write fails, zio_dva_unallocate() walks the
+ * gang tree to immediately free (i.e. insert back into the space map)
+ * everything we've allocated.  This ensures that we don't get ENOSPC
+ * errors during repeated suspend/resume cycles due to a flaky device.
+ *
+ * Gang rewrites only happen during sync-to-convergence.  If we can't assemble
+ * the gang tree, we won't modify the block, so we can safely defer the free
+ * (knowing that the block is still intact).  If we *can* assemble the gang
+ * tree, then even if some of the rewrites fail, zio_dva_unallocate() will free
+ * each constituent bp and we can allocate a new block on the next sync pass.
+ *
+ * In all cases, the gang tree allows complete recovery from partial failure.
+ * ==========================================================================
+ */
+
+static zio_t *
+zio_read_gang(zio_t *pio, blkptr_t *bp, zio_gang_node_t *gn, void *data)
+{
+       if (gn != NULL)
+               return (pio);
+
+       return (zio_read(pio, pio->io_spa, bp, data, BP_GET_PSIZE(bp),
+           NULL, NULL, pio->io_priority, ZIO_GANG_CHILD_FLAGS(pio),
+           &pio->io_bookmark));
+}
+
+zio_t *
+zio_rewrite_gang(zio_t *pio, blkptr_t *bp, zio_gang_node_t *gn, void *data)
+{
+       zio_t *zio;
+
+       if (gn != NULL) {
+               zio = zio_rewrite(pio, pio->io_spa, pio->io_txg, bp,
+                   gn->gn_gbh, SPA_GANGBLOCKSIZE, NULL, NULL, pio->io_priority,
+                   ZIO_GANG_CHILD_FLAGS(pio), &pio->io_bookmark);
+               /*
+                * As we rewrite each gang header, the pipeline will compute
+                * a new gang block header checksum for it; but no one will
+                * compute a new data checksum, so we do that here.  The one
+                * exception is the gang leader: the pipeline already computed
+                * its data checksum because that stage precedes gang assembly.
+                * (Presently, nothing actually uses interior data checksums;
+                * this is just good hygiene.)
+                */
+               if (gn != pio->io_gang_leader->io_gang_tree) {
+                       zio_checksum_compute(zio, BP_GET_CHECKSUM(bp),
+                           data, BP_GET_PSIZE(bp));
+               }
+               /*
+                * If we are here to damage data for testing purposes,
+                * leave the GBH alone so that we can detect the damage.
+                */
+               if (pio->io_gang_leader->io_flags & ZIO_FLAG_INDUCE_DAMAGE)
+                       zio->io_pipeline &= ~ZIO_VDEV_IO_STAGES;
+       } else {
+               zio = zio_rewrite(pio, pio->io_spa, pio->io_txg, bp,
+                   data, BP_GET_PSIZE(bp), NULL, NULL, pio->io_priority,
+                   ZIO_GANG_CHILD_FLAGS(pio), &pio->io_bookmark);
+       }
+
+       return (zio);
+}
+
+/* ARGSUSED */
+zio_t *
+zio_free_gang(zio_t *pio, blkptr_t *bp, zio_gang_node_t *gn, void *data)
+{
+       return (zio_free_sync(pio, pio->io_spa, pio->io_txg, bp,
+           ZIO_GANG_CHILD_FLAGS(pio)));
+}
+
+/* ARGSUSED */
+zio_t *
+zio_claim_gang(zio_t *pio, blkptr_t *bp, zio_gang_node_t *gn, void *data)
+{
+       return (zio_claim(pio, pio->io_spa, pio->io_txg, bp,
+           NULL, NULL, ZIO_GANG_CHILD_FLAGS(pio)));
+}
+
+static zio_gang_issue_func_t *zio_gang_issue_func[ZIO_TYPES] = {
+       NULL,
+       zio_read_gang,
+       zio_rewrite_gang,
+       zio_free_gang,
+       zio_claim_gang,
+       NULL
+};
+
+static void zio_gang_tree_assemble_done(zio_t *zio);
+
+static zio_gang_node_t *
+zio_gang_node_alloc(zio_gang_node_t **gnpp)
+{
+       zio_gang_node_t *gn;
+
+       ASSERT(*gnpp == NULL);
+
+       gn = kmem_zalloc(sizeof (*gn), KM_SLEEP);
+       gn->gn_gbh = zio_buf_alloc(SPA_GANGBLOCKSIZE);
+       *gnpp = gn;
+
+       return (gn);
+}
+
+static void
+zio_gang_node_free(zio_gang_node_t **gnpp)
+{
+       zio_gang_node_t *gn = *gnpp;
+       int g;
+
+       for (g = 0; g < SPA_GBH_NBLKPTRS; g++)
+               ASSERT(gn->gn_child[g] == NULL);
+
+       zio_buf_free(gn->gn_gbh, SPA_GANGBLOCKSIZE);
+       kmem_free(gn, sizeof (*gn));
+       *gnpp = NULL;
+}
+
+static void
+zio_gang_tree_free(zio_gang_node_t **gnpp)
+{
+       zio_gang_node_t *gn = *gnpp;
+       int g;
+
+       if (gn == NULL)
+               return;
+
+       for (g = 0; g < SPA_GBH_NBLKPTRS; g++)
+               zio_gang_tree_free(&gn->gn_child[g]);
+
+       zio_gang_node_free(gnpp);
+}
+
+static void
+zio_gang_tree_assemble(zio_t *gio, blkptr_t *bp, zio_gang_node_t **gnpp)
+{
+       zio_gang_node_t *gn = zio_gang_node_alloc(gnpp);
+
+       ASSERT(gio->io_gang_leader == gio);
+       ASSERT(BP_IS_GANG(bp));
+
+       zio_nowait(zio_read(gio, gio->io_spa, bp, gn->gn_gbh,
+           SPA_GANGBLOCKSIZE, zio_gang_tree_assemble_done, gn,
+           gio->io_priority, ZIO_GANG_CHILD_FLAGS(gio), &gio->io_bookmark));
+}
+
+static void
+zio_gang_tree_assemble_done(zio_t *zio)
+{
+       zio_t *gio = zio->io_gang_leader;
+       zio_gang_node_t *gn = zio->io_private;
+       blkptr_t *bp = zio->io_bp;
+       int g;
+
+       ASSERT(gio == zio_unique_parent(zio));
+       ASSERT(zio->io_child_count == 0);
+
+       if (zio->io_error)
+               return;
+
+       if (BP_SHOULD_BYTESWAP(bp))
+               byteswap_uint64_array(zio->io_data, zio->io_size);
+
+       ASSERT(zio->io_data == gn->gn_gbh);
+       ASSERT(zio->io_size == SPA_GANGBLOCKSIZE);
+       ASSERT(gn->gn_gbh->zg_tail.zec_magic == ZEC_MAGIC);
+
+       for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+               blkptr_t *gbp = &gn->gn_gbh->zg_blkptr[g];
+               if (!BP_IS_GANG(gbp))
+                       continue;
+               zio_gang_tree_assemble(gio, gbp, &gn->gn_child[g]);
+       }
+}
+
+static void
+zio_gang_tree_issue(zio_t *pio, zio_gang_node_t *gn, blkptr_t *bp, void *data)
+{
+       zio_t *gio = pio->io_gang_leader;
+       zio_t *zio;
+       int g;
+
+       ASSERT(BP_IS_GANG(bp) == !!gn);
+       ASSERT(BP_GET_CHECKSUM(bp) == BP_GET_CHECKSUM(gio->io_bp));
+       ASSERT(BP_GET_LSIZE(bp) == BP_GET_PSIZE(bp) || gn == gio->io_gang_tree);
+
+       /*
+        * If you're a gang header, your data is in gn->gn_gbh.
+        * If you're a gang member, your data is in 'data' and gn == NULL.
+        */
+       zio = zio_gang_issue_func[gio->io_type](pio, bp, gn, data);
+
+       if (gn != NULL) {
+               ASSERT(gn->gn_gbh->zg_tail.zec_magic == ZEC_MAGIC);
+
+               for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+                       blkptr_t *gbp = &gn->gn_gbh->zg_blkptr[g];
+                       if (BP_IS_HOLE(gbp))
+                               continue;
+                       zio_gang_tree_issue(zio, gn->gn_child[g], gbp, data);
+                       data = (char *)data + BP_GET_PSIZE(gbp);
+               }
+       }
+
+       if (gn == gio->io_gang_tree)
+               ASSERT3P((char *)gio->io_data + gio->io_size, ==, data);
+
+       if (zio != pio)
+               zio_nowait(zio);
+}
+
+static int
+zio_gang_assemble(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+
+       ASSERT(BP_IS_GANG(bp) && zio->io_gang_leader == NULL);
+       ASSERT(zio->io_child_type > ZIO_CHILD_GANG);
+
+       zio->io_gang_leader = zio;
+
+       zio_gang_tree_assemble(zio, bp, &zio->io_gang_tree);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_gang_issue(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+
+       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE))
+               return (ZIO_PIPELINE_STOP);
+
+       ASSERT(BP_IS_GANG(bp) && zio->io_gang_leader == zio);
+       ASSERT(zio->io_child_type > ZIO_CHILD_GANG);
+
+       if (zio->io_child_error[ZIO_CHILD_GANG] == 0)
+               zio_gang_tree_issue(zio, zio->io_gang_tree, bp, zio->io_data);
+       else
+               zio_gang_tree_free(&zio->io_gang_tree);
+
+       zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static void
+zio_write_gang_member_ready(zio_t *zio)
+{
+       zio_t *pio = zio_unique_parent(zio);
+       dva_t *cdva = zio->io_bp->blk_dva;
+       dva_t *pdva = pio->io_bp->blk_dva;
+       uint64_t asize;
+       int d;
+       ASSERTV(zio_t *gio = zio->io_gang_leader);
+
+       if (BP_IS_HOLE(zio->io_bp))
+               return;
+
+       ASSERT(BP_IS_HOLE(&zio->io_bp_orig));
+
+       ASSERT(zio->io_child_type == ZIO_CHILD_GANG);
+       ASSERT3U(zio->io_prop.zp_copies, ==, gio->io_prop.zp_copies);
+       ASSERT3U(zio->io_prop.zp_copies, <=, BP_GET_NDVAS(zio->io_bp));
+       ASSERT3U(pio->io_prop.zp_copies, <=, BP_GET_NDVAS(pio->io_bp));
+       ASSERT3U(BP_GET_NDVAS(zio->io_bp), <=, BP_GET_NDVAS(pio->io_bp));
+
+       mutex_enter(&pio->io_lock);
+       for (d = 0; d < BP_GET_NDVAS(zio->io_bp); d++) {
+               ASSERT(DVA_GET_GANG(&pdva[d]));
+               asize = DVA_GET_ASIZE(&pdva[d]);
+               asize += DVA_GET_ASIZE(&cdva[d]);
+               DVA_SET_ASIZE(&pdva[d], asize);
+       }
+       mutex_exit(&pio->io_lock);
+}
+
+static int
+zio_write_gang_block(zio_t *pio)
+{
+       spa_t *spa = pio->io_spa;
+       blkptr_t *bp = pio->io_bp;
+       zio_t *gio = pio->io_gang_leader;
+       zio_t *zio;
+       zio_gang_node_t *gn, **gnpp;
+       zio_gbh_phys_t *gbh;
+       uint64_t txg = pio->io_txg;
+       uint64_t resid = pio->io_size;
+       uint64_t lsize;
+       int copies = gio->io_prop.zp_copies;
+       int gbh_copies = MIN(copies + 1, spa_max_replication(spa));
+       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);
+       if (error) {
+               pio->io_error = error;
+               return (ZIO_PIPELINE_CONTINUE);
+       }
+
+       if (pio == gio) {
+               gnpp = &gio->io_gang_tree;
+       } else {
+               gnpp = pio->io_private;
+               ASSERT(pio->io_ready == zio_write_gang_member_ready);
+       }
+
+       gn = zio_gang_node_alloc(gnpp);
+       gbh = gn->gn_gbh;
+       bzero(gbh, SPA_GANGBLOCKSIZE);
+
+       /*
+        * Create the gang header.
+        */
+       zio = zio_rewrite(pio, spa, txg, bp, gbh, SPA_GANGBLOCKSIZE, NULL, NULL,
+           pio->io_priority, ZIO_GANG_CHILD_FLAGS(pio), &pio->io_bookmark);
+
+       /*
+        * Create and nowait the gang children.
+        */
+       for (g = 0; resid != 0; resid -= lsize, g++) {
+               lsize = P2ROUNDUP(resid / (SPA_GBH_NBLKPTRS - g),
+                   SPA_MINBLOCKSIZE);
+               ASSERT(lsize >= SPA_MINBLOCKSIZE && lsize <= resid);
+
+               zp.zp_checksum = gio->io_prop.zp_checksum;
+               zp.zp_compress = ZIO_COMPRESS_OFF;
+               zp.zp_type = DMU_OT_NONE;
+               zp.zp_level = 0;
+               zp.zp_copies = gio->io_prop.zp_copies;
+               zp.zp_dedup = B_FALSE;
+               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));
+       }
+
+       /*
+        * Set pio's pipeline to just wait for zio to finish.
+        */
+       pio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+
+       /*
+        * We didn't allocate this bp, so make sure it doesn't get unmarked.
+        */
+       pio->io_flags &= ~ZIO_FLAG_FASTWRITE;
+
+       zio_nowait(zio);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * 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.
+ */
+static int
+zio_nop_write(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       blkptr_t *bp_orig = &zio->io_bp_orig;
+       zio_prop_t *zp = &zio->io_prop;
+
+       ASSERT(BP_GET_LEVEL(bp) == 0);
+       ASSERT(!(zio->io_flags & ZIO_FLAG_IO_REWRITE));
+       ASSERT(zp->zp_nopwrite);
+       ASSERT(!zp->zp_dedup);
+       ASSERT(zio->io_bp_override == NULL);
+       ASSERT(IO_IS_ALLOCATING(zio));
+
+       /*
+        * Check to see if the original bp and the new bp have matching
+        * characteristics (i.e. same checksum, compression algorithms, etc).
+        * If they don't then just continue with the pipeline which will
+        * allocate a new bp.
+        */
+       if (BP_IS_HOLE(bp_orig) ||
+           !zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_dedup ||
+           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) ||
+           zp->zp_copies != BP_GET_NDVAS(bp_orig))
+               return (ZIO_PIPELINE_CONTINUE);
+
+       /*
+        * If the checksums match then reset the pipeline so that we
+        * 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);
+               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);
+               ASSERT(bcmp(&bp->blk_prop, &bp_orig->blk_prop,
+                   sizeof (uint64_t)) == 0);
+
+               *bp = *bp_orig;
+               zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+               zio->io_flags |= ZIO_FLAG_NOPWRITE;
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * ==========================================================================
+ * Dedup
+ * ==========================================================================
+ */
+static void
+zio_ddt_child_read_done(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       ddt_entry_t *dde = zio->io_private;
+       ddt_phys_t *ddp;
+       zio_t *pio = zio_unique_parent(zio);
+
+       mutex_enter(&pio->io_lock);
+       ddp = ddt_phys_select(dde, bp);
+       if (zio->io_error == 0)
+               ddt_phys_clear(ddp);    /* this ddp doesn't need repair */
+       if (zio->io_error == 0 && dde->dde_repair_data == NULL)
+               dde->dde_repair_data = zio->io_data;
+       else
+               zio_buf_free(zio->io_data, zio->io_size);
+       mutex_exit(&pio->io_lock);
+}
+
+static int
+zio_ddt_read_start(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       int p;
+
+       ASSERT(BP_GET_DEDUP(bp));
+       ASSERT(BP_GET_PSIZE(bp) == zio->io_size);
+       ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+
+       if (zio->io_child_error[ZIO_CHILD_DDT]) {
+               ddt_t *ddt = ddt_select(zio->io_spa, bp);
+               ddt_entry_t *dde = ddt_repair_start(ddt, bp);
+               ddt_phys_t *ddp = dde->dde_phys;
+               ddt_phys_t *ddp_self = ddt_phys_select(dde, bp);
+               blkptr_t blk;
+
+               ASSERT(zio->io_vsd == NULL);
+               zio->io_vsd = dde;
+
+               if (ddp_self == NULL)
+                       return (ZIO_PIPELINE_CONTINUE);
+
+               for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+                       if (ddp->ddp_phys_birth == 0 || ddp == ddp_self)
+                               continue;
+                       ddt_bp_create(ddt->ddt_checksum, &dde->dde_key, ddp,
+                           &blk);
+                       zio_nowait(zio_read(zio, zio->io_spa, &blk,
+                           zio_buf_alloc(zio->io_size), zio->io_size,
+                           zio_ddt_child_read_done, dde, zio->io_priority,
+                           ZIO_DDT_CHILD_FLAGS(zio) | ZIO_FLAG_DONT_PROPAGATE,
+                           &zio->io_bookmark));
+               }
+               return (ZIO_PIPELINE_CONTINUE);
+       }
+
+       zio_nowait(zio_read(zio, zio->io_spa, bp,
+           zio->io_data, zio->io_size, NULL, NULL, zio->io_priority,
+           ZIO_DDT_CHILD_FLAGS(zio), &zio->io_bookmark));
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_ddt_read_done(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+
+       if (zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE))
+               return (ZIO_PIPELINE_STOP);
+
+       ASSERT(BP_GET_DEDUP(bp));
+       ASSERT(BP_GET_PSIZE(bp) == zio->io_size);
+       ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+
+       if (zio->io_child_error[ZIO_CHILD_DDT]) {
+               ddt_t *ddt = ddt_select(zio->io_spa, bp);
+               ddt_entry_t *dde = zio->io_vsd;
+               if (ddt == NULL) {
+                       ASSERT(spa_load_state(zio->io_spa) != SPA_LOAD_NONE);
+                       return (ZIO_PIPELINE_CONTINUE);
+               }
+               if (dde == NULL) {
+                       zio->io_stage = ZIO_STAGE_DDT_READ_START >> 1;
+                       zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, B_FALSE);
+                       return (ZIO_PIPELINE_STOP);
+               }
+               if (dde->dde_repair_data != NULL) {
+                       bcopy(dde->dde_repair_data, zio->io_data, zio->io_size);
+                       zio->io_child_error[ZIO_CHILD_DDT] = 0;
+               }
+               ddt_repair_done(ddt, dde);
+               zio->io_vsd = NULL;
+       }
+
+       ASSERT(zio->io_vsd == NULL);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static boolean_t
+zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
+{
+       spa_t *spa = zio->io_spa;
+       int p;
+
+       /*
+        * 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.
+        */
+       for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
+               zio_t *lio = dde->dde_lead_zio[p];
+
+               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);
+               }
+       }
+
+       for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
+               ddt_phys_t *ddp = &dde->dde_phys[p];
+
+               if (ddp->ddp_phys_birth != 0) {
+                       arc_buf_t *abuf = NULL;
+                       arc_flags_t aflags = ARC_FLAG_WAIT;
+                       blkptr_t blk = *zio->io_bp;
+                       int error;
+
+                       ddt_bp_fill(ddp, &blk, ddp->ddp_phys_birth);
+
+                       ddt_exit(ddt);
+
+                       error = arc_read(NULL, spa, &blk,
+                           arc_getbuf_func, &abuf, ZIO_PRIORITY_SYNC_READ,
+                           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
+                           &aflags, &zio->io_bookmark);
+
+                       if (error == 0) {
+                               if (arc_buf_size(abuf) != zio->io_orig_size ||
+                                   bcmp(abuf->b_data, zio->io_orig_data,
+                                   zio->io_orig_size) != 0)
+                                       error = SET_ERROR(EEXIST);
+                               VERIFY(arc_buf_remove_ref(abuf, &abuf));
+                       }
+
+                       ddt_enter(ddt);
+                       return (error != 0);
+               }
+       }
+
+       return (B_FALSE);
+}
+
+static void
+zio_ddt_child_write_ready(zio_t *zio)
+{
+       int p = zio->io_prop.zp_copies;
+       ddt_t *ddt = ddt_select(zio->io_spa, zio->io_bp);
+       ddt_entry_t *dde = zio->io_private;
+       ddt_phys_t *ddp = &dde->dde_phys[p];
+       zio_t *pio;
+
+       if (zio->io_error)
+               return;
+
+       ddt_enter(ddt);
+
+       ASSERT(dde->dde_lead_zio[p] == zio);
+
+       ddt_phys_fill(ddp, zio->io_bp);
+
+       while ((pio = zio_walk_parents(zio)) != NULL)
+               ddt_bp_fill(ddp, pio->io_bp, zio->io_txg);
+
+       ddt_exit(ddt);
+}
+
+static void
+zio_ddt_child_write_done(zio_t *zio)
+{
+       int p = zio->io_prop.zp_copies;
+       ddt_t *ddt = ddt_select(zio->io_spa, zio->io_bp);
+       ddt_entry_t *dde = zio->io_private;
+       ddt_phys_t *ddp = &dde->dde_phys[p];
+
+       ddt_enter(ddt);
+
+       ASSERT(ddp->ddp_refcnt == 0);
+       ASSERT(dde->dde_lead_zio[p] == zio);
+       dde->dde_lead_zio[p] = NULL;
+
+       if (zio->io_error == 0) {
+               while (zio_walk_parents(zio) != NULL)
+                       ddt_phys_addref(ddp);
+       } else {
+               ddt_phys_clear(ddp);
+       }
+
+       ddt_exit(ddt);
+}
+
+static void
+zio_ddt_ditto_write_done(zio_t *zio)
+{
+       int p = DDT_PHYS_DITTO;
+       blkptr_t *bp = zio->io_bp;
+       ddt_t *ddt = ddt_select(zio->io_spa, bp);
+       ddt_entry_t *dde = zio->io_private;
+       ddt_phys_t *ddp = &dde->dde_phys[p];
+       ddt_key_t *ddk = &dde->dde_key;
+       ASSERTV(zio_prop_t *zp = &zio->io_prop);
+
+       ddt_enter(ddt);
+
+       ASSERT(ddp->ddp_refcnt == 0);
+       ASSERT(dde->dde_lead_zio[p] == zio);
+       dde->dde_lead_zio[p] = NULL;
+
+       if (zio->io_error == 0) {
+               ASSERT(ZIO_CHECKSUM_EQUAL(bp->blk_cksum, ddk->ddk_cksum));
+               ASSERT(zp->zp_copies < SPA_DVAS_PER_BP);
+               ASSERT(zp->zp_copies == BP_GET_NDVAS(bp) - BP_IS_GANG(bp));
+               if (ddp->ddp_phys_birth != 0)
+                       ddt_phys_free(ddt, ddk, ddp, zio->io_txg);
+               ddt_phys_fill(ddp, bp);
+       }
+
+       ddt_exit(ddt);
+}
+
+static int
+zio_ddt_write(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       blkptr_t *bp = zio->io_bp;
+       uint64_t txg = zio->io_txg;
+       zio_prop_t *zp = &zio->io_prop;
+       int p = zp->zp_copies;
+       int ditto_copies;
+       zio_t *cio = NULL;
+       zio_t *dio = NULL;
+       ddt_t *ddt = ddt_select(spa, bp);
+       ddt_entry_t *dde;
+       ddt_phys_t *ddp;
+
+       ASSERT(BP_GET_DEDUP(bp));
+       ASSERT(BP_GET_CHECKSUM(bp) == zp->zp_checksum);
+       ASSERT(BP_IS_HOLE(bp) || zio->io_bp_override);
+
+       ddt_enter(ddt);
+       dde = ddt_lookup(ddt, bp, B_TRUE);
+       ddp = &dde->dde_phys[p];
+
+       if (zp->zp_dedup_verify && zio_ddt_collision(zio, ddt, dde)) {
+               /*
+                * If we're using a weak checksum, upgrade to a strong checksum
+                * and try again.  If we're already using a strong checksum,
+                * 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) {
+                       zp->zp_checksum = spa_dedup_checksum(spa);
+                       zio_pop_transforms(zio);
+                       zio->io_stage = ZIO_STAGE_OPEN;
+                       BP_ZERO(bp);
+               } else {
+                       zp->zp_dedup = B_FALSE;
+               }
+               zio->io_pipeline = ZIO_WRITE_PIPELINE;
+               ddt_exit(ddt);
+               return (ZIO_PIPELINE_CONTINUE);
+       }
+
+       ditto_copies = ddt_ditto_copies_needed(ddt, dde, ddp);
+       ASSERT(ditto_copies < SPA_DVAS_PER_BP);
+
+       if (ditto_copies > ddt_ditto_copies_present(dde) &&
+           dde->dde_lead_zio[DDT_PHYS_DITTO] == NULL) {
+               zio_prop_t czp = *zp;
+
+               czp.zp_copies = ditto_copies;
+
+               /*
+                * If we arrived here with an override bp, we won't have run
+                * the transform stack, so we won't have the data we need to
+                * generate a child i/o.  So, toss the override bp and restart.
+                * This is safe, because using the override bp is just an
+                * optimization; and it's rare, so the cost doesn't matter.
+                */
+               if (zio->io_bp_override) {
+                       zio_pop_transforms(zio);
+                       zio->io_stage = ZIO_STAGE_OPEN;
+                       zio->io_pipeline = ZIO_WRITE_PIPELINE;
+                       zio->io_bp_override = NULL;
+                       BP_ZERO(bp);
+                       ddt_exit(ddt);
+                       return (ZIO_PIPELINE_CONTINUE);
+               }
+
+               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_DDT_CHILD_FLAGS(zio), &zio->io_bookmark);
+
+               zio_push_transform(dio, zio->io_data, zio->io_size, 0, NULL);
+               dde->dde_lead_zio[DDT_PHYS_DITTO] = dio;
+       }
+
+       if (ddp->ddp_phys_birth != 0 || dde->dde_lead_zio[p] != NULL) {
+               if (ddp->ddp_phys_birth != 0)
+                       ddt_bp_fill(ddp, bp, txg);
+               if (dde->dde_lead_zio[p] != NULL)
+                       zio_add_child(zio, dde->dde_lead_zio[p]);
+               else
+                       ddt_phys_addref(ddp);
+       } else if (zio->io_bp_override) {
+               ASSERT(bp->blk_birth == txg);
+               ASSERT(BP_EQUAL(bp, zio->io_bp_override));
+               ddt_phys_fill(ddp, bp);
+               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_ddt_child_write_done, dde, zio->io_priority,
+                   ZIO_DDT_CHILD_FLAGS(zio), &zio->io_bookmark);
+
+               zio_push_transform(cio, zio->io_data, zio->io_size, 0, NULL);
+               dde->dde_lead_zio[p] = cio;
+       }
+
+       ddt_exit(ddt);
+
+       if (cio)
+               zio_nowait(cio);
+       if (dio)
+               zio_nowait(dio);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+ddt_entry_t *freedde; /* for debugging */
+
+static int
+zio_ddt_free(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       blkptr_t *bp = zio->io_bp;
+       ddt_t *ddt = ddt_select(spa, bp);
+       ddt_entry_t *dde;
+       ddt_phys_t *ddp;
+
+       ASSERT(BP_GET_DEDUP(bp));
+       ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+
+       ddt_enter(ddt);
+       freedde = dde = ddt_lookup(ddt, bp, B_TRUE);
+       if (dde) {
+               ddp = ddt_phys_select(dde, bp);
+               if (ddp)
+                       ddt_phys_decref(ddp);
+       }
+       ddt_exit(ddt);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * ==========================================================================
+ * Allocate and free blocks
+ * ==========================================================================
+ */
+static int
+zio_dva_allocate(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       metaslab_class_t *mc = spa_normal_class(spa);
+       blkptr_t *bp = zio->io_bp;
+       int error;
+       int flags = 0;
+
+       if (zio->io_gang_leader == NULL) {
+               ASSERT(zio->io_child_type > ZIO_CHILD_GANG);
+               zio->io_gang_leader = zio;
+       }
+
+       ASSERT(BP_IS_HOLE(bp));
+       ASSERT0(BP_GET_NDVAS(bp));
+       ASSERT3U(zio->io_prop.zp_copies, >, 0);
+       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;
+       error = metaslab_alloc(spa, mc, zio->io_size, bp,
+           zio->io_prop.zp_copies, zio->io_txg, NULL, flags);
+
+       if (error) {
+               spa_dbgmsg(spa, "%s: metaslab allocation failure: zio %p, "
+                   "size %llu, error %d", spa_name(spa), zio, zio->io_size,
+                   error);
+               if (error == ENOSPC && zio->io_size > SPA_MINBLOCKSIZE)
+                       return (zio_write_gang_block(zio));
+               zio->io_error = error;
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_dva_free(zio_t *zio)
+{
+       metaslab_free(zio->io_spa, zio->io_bp, zio->io_txg, B_FALSE);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_dva_claim(zio_t *zio)
+{
+       int error;
+
+       error = metaslab_claim(zio->io_spa, zio->io_bp, zio->io_txg);
+       if (error)
+               zio->io_error = error;
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * Undo an allocation.  This is used by zio_done() when an I/O fails
+ * and we want to give back the block we just allocated.
+ * This handles both normal blocks and gang blocks.
+ */
+static void
+zio_dva_unallocate(zio_t *zio, zio_gang_node_t *gn, blkptr_t *bp)
+{
+       int g;
+
+       ASSERT(bp->blk_birth == zio->io_txg || BP_IS_HOLE(bp));
+       ASSERT(zio->io_bp_override == NULL);
+
+       if (!BP_IS_HOLE(bp))
+               metaslab_free(zio->io_spa, bp, bp->blk_birth, B_TRUE);
+
+       if (gn != NULL) {
+               for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+                       zio_dva_unallocate(zio, gn->gn_child[g],
+                           &gn->gn_gbh->zg_blkptr[g]);
+               }
+       }
+}
+
+/*
+ * Try to allocate an intent log block.  Return 0 on success, errno on failure.
+ */
+int
+zio_alloc_zil(spa_t *spa, uint64_t txg, blkptr_t *new_bp, uint64_t size,
+    boolean_t use_slog)
+{
+       int error = 1;
+
+       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);
+       }
+
+       if (error) {
+               error = metaslab_alloc(spa, spa_normal_class(spa), size,
+                   new_bp, 1, txg, NULL,
+                   METASLAB_FASTWRITE);
+       }
+
+       if (error == 0) {
+               BP_SET_LSIZE(new_bp, size);
+               BP_SET_PSIZE(new_bp, size);
+               BP_SET_COMPRESS(new_bp, ZIO_COMPRESS_OFF);
+               BP_SET_CHECKSUM(new_bp,
+                   spa_version(spa) >= SPA_VERSION_SLIM_ZIL
+                   ? ZIO_CHECKSUM_ZILOG2 : ZIO_CHECKSUM_ZILOG);
+               BP_SET_TYPE(new_bp, DMU_OT_INTENT_LOG);
+               BP_SET_LEVEL(new_bp, 0);
+               BP_SET_DEDUP(new_bp, 0);
+               BP_SET_BYTEORDER(new_bp, ZFS_HOST_BYTEORDER);
+       }
+
+       return (error);
+}
+
+/*
+ * Free an intent log block.
+ */
+void
+zio_free_zil(spa_t *spa, uint64_t txg, blkptr_t *bp)
+{
+       ASSERT(BP_GET_TYPE(bp) == DMU_OT_INTENT_LOG);
+       ASSERT(!BP_IS_GANG(bp));
+
+       zio_free(spa, txg, bp);
+}
+
+/*
+ * ==========================================================================
+ * Read and write to physical devices
+ * ==========================================================================
+ */
+
+
+/*
+ * Issue an I/O to the underlying vdev. Typically the issue pipeline
+ * stops after this stage and will resume upon I/O completion.
+ * However, there are instances where the vdev layer may need to
+ * continue the pipeline when an I/O was not issued. Since the I/O
+ * that was sent to the vdev layer might be different than the one
+ * currently active in the pipeline (see vdev_queue_io()), we explicitly
+ * force the underlying vdev layers to call either zio_execute() or
+ * zio_interrupt() to ensure that the pipeline continues with the correct I/O.
+ */
+static int
+zio_vdev_io_start(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       uint64_t align;
+       spa_t *spa = zio->io_spa;
+
+       ASSERT(zio->io_error == 0);
+       ASSERT(zio->io_child_error[ZIO_CHILD_VDEV] == 0);
+
+       if (vd == NULL) {
+               if (!(zio->io_flags & ZIO_FLAG_CONFIG_WRITER))
+                       spa_config_enter(spa, SCL_ZIO, zio, RW_READER);
+
+               /*
+                * The mirror_ops handle multiple DVAs in a single BP.
+                */
+               vdev_mirror_ops.vdev_op_io_start(zio);
+               return (ZIO_PIPELINE_STOP);
+       }
+
+       /*
+        * We keep track of time-sensitive I/Os so that the scan thread
+        * can quickly react to certain workloads.  In particular, we care
+        * about non-scrubbing, top-level reads and writes with the following
+        * characteristics:
+        *      - synchronous writes of user data to non-slog devices
+        *      - any reads of user data
+        * When these conditions are met, adjust the timestamp of spa_last_io
+        * which allows the scan thread to adjust its workload accordingly.
+        */
+       if (!(zio->io_flags & ZIO_FLAG_SCAN_THREAD) && zio->io_bp != NULL &&
+           vd == vd->vdev_top && !vd->vdev_islog &&
+           zio->io_bookmark.zb_objset != DMU_META_OBJSET &&
+           zio->io_txg != spa_syncing_txg(spa)) {
+               uint64_t old = spa->spa_last_io;
+               uint64_t new = ddi_get_lbolt64();
+               if (old != new)
+                       (void) atomic_cas_64(&spa->spa_last_io, old, new);
+       }
+
+       align = 1ULL << vd->vdev_top->vdev_ashift;
+
+       if (!(zio->io_flags & ZIO_FLAG_PHYSICAL) &&
+           P2PHASE(zio->io_size, align) != 0) {
+               /* Transform logical writes to be a full physical block size. */
+               uint64_t asize = P2ROUNDUP(zio->io_size, align);
+               char *abuf = zio_buf_alloc(asize);
+               ASSERT(vd == vd->vdev_top);
+               if (zio->io_type == ZIO_TYPE_WRITE) {
+                       bcopy(zio->io_data, abuf, zio->io_size);
+                       bzero(abuf + zio->io_size, asize - zio->io_size);
+               }
+               zio_push_transform(zio, abuf, asize, asize, zio_subblock);
+       }
+
+       /*
+        * If this is not a physical io, make sure that it is properly aligned
+        * before proceeding.
+        */
+       if (!(zio->io_flags & ZIO_FLAG_PHYSICAL)) {
+               ASSERT0(P2PHASE(zio->io_offset, align));
+               ASSERT0(P2PHASE(zio->io_size, align));
+       } else {
+               /*
+                * For physical writes, we allow 512b aligned writes and assume
+                * the device will perform a read-modify-write as necessary.
+                */
+               ASSERT0(P2PHASE(zio->io_offset, SPA_MINBLOCKSIZE));
+               ASSERT0(P2PHASE(zio->io_size, SPA_MINBLOCKSIZE));
+       }
+
+       VERIFY(zio->io_type != ZIO_TYPE_WRITE || spa_writeable(spa));
+
+       /*
+        * If this is a repair I/O, and there's no self-healing involved --
+        * that is, we're just resilvering what we expect to resilver --
+        * then don't do the I/O unless zio's txg is actually in vd's DTL.
+        * This prevents spurious resilvering with nested replication.
+        * For example, given a mirror of mirrors, (A+B)+(C+D), if only
+        * A is out of date, we'll read from C+D, then use the data to
+        * resilver A+B -- but we don't actually want to resilver B, just A.
+        * The top-level mirror has no way to know this, so instead we just
+        * discard unnecessary repairs as we work our way down the vdev tree.
+        * The same logic applies to any form of nested replication:
+        * ditto + mirror, RAID-Z + replacing, etc.  This covers them all.
+        */
+       if ((zio->io_flags & ZIO_FLAG_IO_REPAIR) &&
+           !(zio->io_flags & ZIO_FLAG_SELF_HEAL) &&
+           zio->io_txg != 0 && /* not a delegated i/o */
+           !vdev_dtl_contains(vd, DTL_PARTIAL, zio->io_txg, 1)) {
+               ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+               zio_vdev_io_bypass(zio);
+               return (ZIO_PIPELINE_CONTINUE);
+       }
+
+       if (vd->vdev_ops->vdev_op_leaf &&
+           (zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE)) {
+
+               if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio))
+                       return (ZIO_PIPELINE_CONTINUE);
+
+               if ((zio = vdev_queue_io(zio)) == NULL)
+                       return (ZIO_PIPELINE_STOP);
+
+               if (!vdev_accessible(vd, zio)) {
+                       zio->io_error = SET_ERROR(ENXIO);
+                       zio_interrupt(zio);
+                       return (ZIO_PIPELINE_STOP);
+               }
+       }
+
+       vd->vdev_ops->vdev_op_io_start(zio);
+       return (ZIO_PIPELINE_STOP);
+}
+
+static int
+zio_vdev_io_done(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       vdev_ops_t *ops = vd ? vd->vdev_ops : &vdev_mirror_ops;
+       boolean_t unexpected_error = B_FALSE;
+
+       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE))
+               return (ZIO_PIPELINE_STOP);
+
+       ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE);
+
+       if (vd != NULL && vd->vdev_ops->vdev_op_leaf) {
+
+               vdev_queue_io_done(zio);
+
+               if (zio->io_type == ZIO_TYPE_WRITE)
+                       vdev_cache_write(zio);
+
+               if (zio_injection_enabled && zio->io_error == 0)
+                       zio->io_error = zio_handle_device_injection(vd,
+                           zio, EIO);
+
+               if (zio_injection_enabled && zio->io_error == 0)
+                       zio->io_error = zio_handle_label_injection(zio, EIO);
+
+               if (zio->io_error) {
+                       if (!vdev_accessible(vd, zio)) {
+                               zio->io_error = SET_ERROR(ENXIO);
+                       } else {
+                               unexpected_error = B_TRUE;
+                       }
+               }
+       }
+
+       ops->vdev_op_io_done(zio);
+
+       if (unexpected_error)
+               VERIFY(vdev_probe(vd, zio) == NULL);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * For non-raidz ZIOs, we can just copy aside the bad data read from the
+ * disk, and use that to finish the checksum ereport later.
+ */
+static void
+zio_vsd_default_cksum_finish(zio_cksum_report_t *zcr,
+    const void *good_buf)
+{
+       /* no processing needed */
+       zfs_ereport_finish_checksum(zcr, good_buf, zcr->zcr_cbdata, B_FALSE);
+}
+
+/*ARGSUSED*/
+void
+zio_vsd_default_cksum_report(zio_t *zio, zio_cksum_report_t *zcr, void *ignored)
+{
+       void *buf = zio_buf_alloc(zio->io_size);
+
+       bcopy(zio->io_data, buf, zio->io_size);
+
+       zcr->zcr_cbinfo = zio->io_size;
+       zcr->zcr_cbdata = buf;
+       zcr->zcr_finish = zio_vsd_default_cksum_finish;
+       zcr->zcr_free = zio_buf_free;
+}
+
+static int
+zio_vdev_io_assess(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+
+       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE))
+               return (ZIO_PIPELINE_STOP);
+
+       if (vd == NULL && !(zio->io_flags & ZIO_FLAG_CONFIG_WRITER))
+               spa_config_exit(zio->io_spa, SCL_ZIO, zio);
+
+       if (zio->io_vsd != NULL) {
+               zio->io_vsd_ops->vsd_free(zio);
+               zio->io_vsd = NULL;
+       }
+
+       if (zio_injection_enabled && zio->io_error == 0)
+               zio->io_error = zio_handle_fault_injection(zio, EIO);
+
+       /*
+        * If the I/O failed, determine whether we should attempt to retry it.
+        *
+        * On retry, we cut in line in the issue queue, since we don't want
+        * compression/checksumming/etc. work to prevent our (cheap) IO reissue.
+        */
+       if (zio->io_error && vd == NULL &&
+           !(zio->io_flags & (ZIO_FLAG_DONT_RETRY | ZIO_FLAG_IO_RETRY))) {
+               ASSERT(!(zio->io_flags & ZIO_FLAG_DONT_QUEUE)); /* not a leaf */
+               ASSERT(!(zio->io_flags & ZIO_FLAG_IO_BYPASS));  /* not a leaf */
+               zio->io_error = 0;
+               zio->io_flags |= ZIO_FLAG_IO_RETRY |
+                   ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_AGGREGATE;
+               zio->io_stage = ZIO_STAGE_VDEV_IO_START >> 1;
+               zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE,
+                   zio_requeue_io_start_cut_in_line);
+               return (ZIO_PIPELINE_STOP);
+       }
+
+       /*
+        * If we got an error on a leaf device, convert it to ENXIO
+        * if the device is not accessible at all.
+        */
+       if (zio->io_error && vd != NULL && vd->vdev_ops->vdev_op_leaf &&
+           !vdev_accessible(vd, zio))
+               zio->io_error = SET_ERROR(ENXIO);
+
+       /*
+        * If we can't write to an interior vdev (mirror or RAID-Z),
+        * set vdev_cant_write so that we stop trying to allocate from it.
+        */
+       if (zio->io_error == ENXIO && zio->io_type == ZIO_TYPE_WRITE &&
+           vd != NULL && !vd->vdev_ops->vdev_op_leaf) {
+               vd->vdev_cant_write = B_TRUE;
+       }
+
+       if (zio->io_error)
+               zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+
+       if (vd != NULL && vd->vdev_ops->vdev_op_leaf &&
+           zio->io_physdone != NULL) {
+               ASSERT(!(zio->io_flags & ZIO_FLAG_DELEGATED));
+               ASSERT(zio->io_child_type == ZIO_CHILD_VDEV);
+               zio->io_physdone(zio->io_logical);
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+void
+zio_vdev_io_reissue(zio_t *zio)
+{
+       ASSERT(zio->io_stage == ZIO_STAGE_VDEV_IO_START);
+       ASSERT(zio->io_error == 0);
+
+       zio->io_stage >>= 1;
+}
+
+void
+zio_vdev_io_redone(zio_t *zio)
+{
+       ASSERT(zio->io_stage == ZIO_STAGE_VDEV_IO_DONE);
+
+       zio->io_stage >>= 1;
+}
+
+void
+zio_vdev_io_bypass(zio_t *zio)
+{
+       ASSERT(zio->io_stage == ZIO_STAGE_VDEV_IO_START);
+       ASSERT(zio->io_error == 0);
+
+       zio->io_flags |= ZIO_FLAG_IO_BYPASS;
+       zio->io_stage = ZIO_STAGE_VDEV_IO_ASSESS >> 1;
+}
+
+/*
+ * ==========================================================================
+ * Generate and verify checksums
+ * ==========================================================================
+ */
+static int
+zio_checksum_generate(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       enum zio_checksum checksum;
+
+       if (bp == NULL) {
+               /*
+                * This is zio_write_phys().
+                * We're either generating a label checksum, or none at all.
+                */
+               checksum = zio->io_prop.zp_checksum;
+
+               if (checksum == ZIO_CHECKSUM_OFF)
+                       return (ZIO_PIPELINE_CONTINUE);
+
+               ASSERT(checksum == ZIO_CHECKSUM_LABEL);
+       } else {
+               if (BP_IS_GANG(bp) && zio->io_child_type == ZIO_CHILD_GANG) {
+                       ASSERT(!IO_IS_ALLOCATING(zio));
+                       checksum = ZIO_CHECKSUM_GANG_HEADER;
+               } else {
+                       checksum = BP_GET_CHECKSUM(bp);
+               }
+       }
+
+       zio_checksum_compute(zio, checksum, zio->io_data, zio->io_size);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_checksum_verify(zio_t *zio)
+{
+       zio_bad_cksum_t info;
+       blkptr_t *bp = zio->io_bp;
+       int error;
+
+       ASSERT(zio->io_vd != NULL);
+
+       if (bp == NULL) {
+               /*
+                * This is zio_read_phys().
+                * We're either verifying a label checksum, or nothing at all.
+                */
+               if (zio->io_prop.zp_checksum == ZIO_CHECKSUM_OFF)
+                       return (ZIO_PIPELINE_CONTINUE);
+
+               ASSERT(zio->io_prop.zp_checksum == ZIO_CHECKSUM_LABEL);
+       }
+
+       if ((error = zio_checksum_error(zio, &info)) != 0) {
+               zio->io_error = error;
+               if (error == ECKSUM &&
+                   !(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+                       zfs_ereport_start_checksum(zio->io_spa,
+                           zio->io_vd, zio, zio->io_offset,
+                           zio->io_size, NULL, &info);
+               }
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+/*
+ * Called by RAID-Z to ensure we don't compute the checksum twice.
+ */
+void
+zio_checksum_verified(zio_t *zio)
+{
+       zio->io_pipeline &= ~ZIO_STAGE_CHECKSUM_VERIFY;
+}
+
+/*
+ * ==========================================================================
+ * Error rank.  Error are ranked in the order 0, ENXIO, ECKSUM, EIO, other.
+ * An error of 0 indicates success.  ENXIO indicates whole-device failure,
+ * which may be transient (e.g. unplugged) or permament.  ECKSUM and EIO
+ * indicate errors that are specific to one I/O, and most likely permanent.
+ * Any other error is presumed to be worse because we weren't expecting it.
+ * ==========================================================================
+ */
+int
+zio_worst_error(int e1, int e2)
+{
+       static int zio_error_rank[] = { 0, ENXIO, ECKSUM, EIO };
+       int r1, r2;
+
+       for (r1 = 0; r1 < sizeof (zio_error_rank) / sizeof (int); r1++)
+               if (e1 == zio_error_rank[r1])
+                       break;
+
+       for (r2 = 0; r2 < sizeof (zio_error_rank) / sizeof (int); r2++)
+               if (e2 == zio_error_rank[r2])
+                       break;
+
+       return (r1 > r2 ? e1 : e2);
+}
+
+/*
+ * ==========================================================================
+ * I/O completion
+ * ==========================================================================
+ */
+static int
+zio_ready(zio_t *zio)
+{
+       blkptr_t *bp = zio->io_bp;
+       zio_t *pio, *pio_next;
+
+       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
+           zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_READY))
+               return (ZIO_PIPELINE_STOP);
+
+       if (zio->io_ready) {
+               ASSERT(IO_IS_ALLOCATING(zio));
+               ASSERT(bp->blk_birth == zio->io_txg || BP_IS_HOLE(bp) ||
+                   (zio->io_flags & ZIO_FLAG_NOPWRITE));
+               ASSERT(zio->io_children[ZIO_CHILD_GANG][ZIO_WAIT_READY] == 0);
+
+               zio->io_ready(zio);
+       }
+
+       if (bp != NULL && bp != &zio->io_bp_copy)
+               zio->io_bp_copy = *bp;
+
+       if (zio->io_error)
+               zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
+
+       mutex_enter(&zio->io_lock);
+       zio->io_state[ZIO_WAIT_READY] = 1;
+       pio = zio_walk_parents(zio);
+       mutex_exit(&zio->io_lock);
+
+       /*
+        * As we notify zio's parents, new parents could be added.
+        * New parents go to the head of zio's io_parent_list, however,
+        * so we will (correctly) not notify them.  The remainder of zio's
+        * io_parent_list, from 'pio_next' onward, cannot change because
+        * 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);
+               zio_notify_parent(pio, zio, ZIO_WAIT_READY);
+       }
+
+       if (zio->io_flags & ZIO_FLAG_NODATA) {
+               if (BP_IS_GANG(bp)) {
+                       zio->io_flags &= ~ZIO_FLAG_NODATA;
+               } else {
+                       ASSERT((uintptr_t)zio->io_data < SPA_MAXBLOCKSIZE);
+                       zio->io_pipeline &= ~ZIO_VDEV_IO_STAGES;
+               }
+       }
+
+       if (zio_injection_enabled &&
+           zio->io_spa->spa_syncing_txg == zio->io_txg)
+               zio_handle_ignored_writes(zio);
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_done(zio_t *zio)
+{
+       zio_t *pio, *pio_next;
+       int c, w;
+
+       /*
+        * If our children haven't all completed,
+        * wait for them and then repeat this pipeline stage.
+        */
+       if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE) ||
+           zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE) ||
+           zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE) ||
+           zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_DONE))
+               return (ZIO_PIPELINE_STOP);
+
+       for (c = 0; c < ZIO_CHILD_TYPES; c++)
+               for (w = 0; w < ZIO_WAIT_TYPES; w++)
+                       ASSERT(zio->io_children[c][w] == 0);
+
+       if (zio->io_bp != NULL && !BP_IS_EMBEDDED(zio->io_bp)) {
+               ASSERT(zio->io_bp->blk_pad[0] == 0);
+               ASSERT(zio->io_bp->blk_pad[1] == 0);
+               ASSERT(bcmp(zio->io_bp, &zio->io_bp_copy,
+                   sizeof (blkptr_t)) == 0 ||
+                   (zio->io_bp == zio_unique_parent(zio)->io_bp));
+               if (zio->io_type == ZIO_TYPE_WRITE && !BP_IS_HOLE(zio->io_bp) &&
+                   zio->io_bp_override == NULL &&
+                   !(zio->io_flags & ZIO_FLAG_IO_REPAIR)) {
+                       ASSERT(!BP_SHOULD_BYTESWAP(zio->io_bp));
+                       ASSERT3U(zio->io_prop.zp_copies, <=,
+                           BP_GET_NDVAS(zio->io_bp));
+                       ASSERT(BP_COUNT_GANG(zio->io_bp) == 0 ||
+                           (BP_COUNT_GANG(zio->io_bp) ==
+                           BP_GET_NDVAS(zio->io_bp)));
+               }
+               if (zio->io_flags & ZIO_FLAG_NOPWRITE)
+                       VERIFY(BP_EQUAL(zio->io_bp, &zio->io_bp_orig));
+       }
+
+       /*
+        * If there were child vdev/gang/ddt errors, they apply to us now.
+        */
+       zio_inherit_child_errors(zio, ZIO_CHILD_VDEV);
+       zio_inherit_child_errors(zio, ZIO_CHILD_GANG);
+       zio_inherit_child_errors(zio, ZIO_CHILD_DDT);
+
+       /*
+        * If the I/O on the transformed data was successful, generate any
+        * checksum reports now while we still have the transformed data.
+        */
+       if (zio->io_error == 0) {
+               while (zio->io_cksum_report != NULL) {
+                       zio_cksum_report_t *zcr = zio->io_cksum_report;
+                       uint64_t align = zcr->zcr_align;
+                       uint64_t asize = P2ROUNDUP(zio->io_size, align);
+                       char *abuf = zio->io_data;
+
+                       if (asize != zio->io_size) {
+                               abuf = zio_buf_alloc(asize);
+                               bcopy(zio->io_data, abuf, zio->io_size);
+                               bzero(abuf+zio->io_size, asize-zio->io_size);
+                       }
+
+                       zio->io_cksum_report = zcr->zcr_next;
+                       zcr->zcr_next = NULL;
+                       zcr->zcr_finish(zcr, abuf);
+                       zfs_ereport_free_checksum(zcr);
+
+                       if (asize != zio->io_size)
+                               zio_buf_free(abuf, asize);
+               }
+       }
+
+       zio_pop_transforms(zio);        /* note: may set zio->io_error */
+
+       vdev_stat_update(zio, zio->io_size);
+
+       /*
+        * If this I/O is attached to a particular vdev is slow, exceeding
+        * 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_vd != NULL && !vdev_is_dead(zio->io_vd))
+                       zfs_ereport_post(FM_EREPORT_ZFS_DELAY, zio->io_spa,
+                           zio->io_vd, zio, 0, 0);
+       }
+
+       if (zio->io_error) {
+               /*
+                * If this I/O is attached to a particular vdev,
+                * generate an error message describing the I/O failure
+                * at the block level.  We ignore these errors if the
+                * device is currently unavailable.
+                */
+               if (zio->io_error != ECKSUM && zio->io_vd != NULL &&
+                       !vdev_is_dead(zio->io_vd))
+                       zfs_ereport_post(FM_EREPORT_ZFS_IO, zio->io_spa,
+                                               zio->io_vd, zio, 0, 0);
+
+               if ((zio->io_error == EIO || !(zio->io_flags &
+                   (ZIO_FLAG_SPECULATIVE | ZIO_FLAG_DONT_PROPAGATE))) &&
+                   zio == zio->io_logical) {
+                       /*
+                        * For logical I/O requests, tell the SPA to log the
+                        * error and generate a logical data ereport.
+                        */
+                       spa_log_error(zio->io_spa, zio);
+                       zfs_ereport_post(FM_EREPORT_ZFS_DATA, zio->io_spa,
+                           NULL, zio, 0, 0);
+               }
+       }
+
+       if (zio->io_error && zio == zio->io_logical) {
+               /*
+                * Determine whether zio should be reexecuted.  This will
+                * propagate all the way to the root via zio_notify_parent().
+                */
+               ASSERT(zio->io_vd == NULL && zio->io_bp != NULL);
+               ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+
+               if (IO_IS_ALLOCATING(zio) &&
+                   !(zio->io_flags & ZIO_FLAG_CANFAIL)) {
+                       if (zio->io_error != ENOSPC)
+                               zio->io_reexecute |= ZIO_REEXECUTE_NOW;
+                       else
+                               zio->io_reexecute |= ZIO_REEXECUTE_SUSPEND;
+               }
+
+               if ((zio->io_type == ZIO_TYPE_READ ||
+                   zio->io_type == ZIO_TYPE_FREE) &&
+                   !(zio->io_flags & ZIO_FLAG_SCAN_THREAD) &&
+                   zio->io_error == ENXIO &&
+                   spa_load_state(zio->io_spa) == SPA_LOAD_NONE &&
+                   spa_get_failmode(zio->io_spa) != ZIO_FAILURE_MODE_CONTINUE)
+                       zio->io_reexecute |= ZIO_REEXECUTE_SUSPEND;
+
+               if (!(zio->io_flags & ZIO_FLAG_CANFAIL) && !zio->io_reexecute)
+                       zio->io_reexecute |= ZIO_REEXECUTE_SUSPEND;
+
+               /*
+                * Here is a possibly good place to attempt to do
+                * either combinatorial reconstruction or error correction
+                * based on checksums.  It also might be a good place
+                * to send out preliminary ereports before we suspend
+                * processing.
+                */
+       }
+
+       /*
+        * If there were logical child errors, they apply to us now.
+        * We defer this until now to avoid conflating logical child
+        * errors with errors that happened to the zio itself when
+        * updating vdev stats and reporting FMA events above.
+        */
+       zio_inherit_child_errors(zio, ZIO_CHILD_LOGICAL);
+
+       if ((zio->io_error || zio->io_reexecute) &&
+           IO_IS_ALLOCATING(zio) && zio->io_gang_leader == zio &&
+           !(zio->io_flags & (ZIO_FLAG_IO_REWRITE | ZIO_FLAG_NOPWRITE)))
+               zio_dva_unallocate(zio, zio->io_gang_tree, zio->io_bp);
+
+       zio_gang_tree_free(&zio->io_gang_tree);
+
+       /*
+        * Godfather I/Os should never suspend.
+        */
+       if ((zio->io_flags & ZIO_FLAG_GODFATHER) &&
+           (zio->io_reexecute & ZIO_REEXECUTE_SUSPEND))
+               zio->io_reexecute = 0;
+
+       if (zio->io_reexecute) {
+               /*
+                * This is a logical I/O that wants to reexecute.
+                *
+                * Reexecute is top-down.  When an i/o fails, if it's not
+                * the root, it simply notifies its parent and sticks around.
+                * The parent, seeing that it still has children in zio_done(),
+                * does the same.  This percolates all the way up to the root.
+                * The root i/o will reexecute or suspend the entire tree.
+                *
+                * This approach ensures that zio_reexecute() honors
+                * all the original i/o dependency relationships, e.g.
+                * parents not executing until children are ready.
+                */
+               ASSERT(zio->io_child_type == ZIO_CHILD_LOGICAL);
+
+               zio->io_gang_leader = NULL;
+
+               mutex_enter(&zio->io_lock);
+               zio->io_state[ZIO_WAIT_DONE] = 1;
+               mutex_exit(&zio->io_lock);
+
+               /*
+                * "The Godfather" I/O monitors its children but is
+                * not a true parent to them. It will track them through
+                * the pipeline but severs its ties whenever they get into
+                * 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);
+
+                       if ((pio->io_flags & ZIO_FLAG_GODFATHER) &&
+                           (zio->io_reexecute & ZIO_REEXECUTE_SUSPEND)) {
+                               zio_remove_child(pio, zio, zl);
+                               zio_notify_parent(pio, zio, ZIO_WAIT_DONE);
+                       }
+               }
+
+               if ((pio = zio_unique_parent(zio)) != NULL) {
+                       /*
+                        * We're not a root i/o, so there's nothing to do
+                        * but notify our parent.  Don't propagate errors
+                        * upward since we haven't permanently failed yet.
+                        */
+                       ASSERT(!(zio->io_flags & ZIO_FLAG_GODFATHER));
+                       zio->io_flags |= ZIO_FLAG_DONT_PROPAGATE;
+                       zio_notify_parent(pio, zio, ZIO_WAIT_DONE);
+               } else if (zio->io_reexecute & ZIO_REEXECUTE_SUSPEND) {
+                       /*
+                        * We'd fail again if we reexecuted now, so suspend
+                        * until conditions improve (e.g. device comes online).
+                        */
+                       zio_suspend(zio->io_spa, zio);
+               } else {
+                       /*
+                        * Reexecution is potentially a huge amount of work.
+                        * Hand it off to the otherwise-unused claim taskq.
+                        */
+                       ASSERT(taskq_empty_ent(&zio->io_tqent));
+                       spa_taskq_dispatch_ent(zio->io_spa,
+                           ZIO_TYPE_CLAIM, ZIO_TASKQ_ISSUE,
+                           (task_func_t *)zio_reexecute, zio, 0,
+                           &zio->io_tqent);
+               }
+               return (ZIO_PIPELINE_STOP);
+       }
+
+       ASSERT(zio->io_child_count == 0);
+       ASSERT(zio->io_reexecute == 0);
+       ASSERT(zio->io_error == 0 || (zio->io_flags & ZIO_FLAG_CANFAIL));
+
+       /*
+        * Report any checksum errors, since the I/O is complete.
+        */
+       while (zio->io_cksum_report != NULL) {
+               zio_cksum_report_t *zcr = zio->io_cksum_report;
+               zio->io_cksum_report = zcr->zcr_next;
+               zcr->zcr_next = NULL;
+               zcr->zcr_finish(zcr, NULL);
+               zfs_ereport_free_checksum(zcr);
+       }
+
+       if (zio->io_flags & ZIO_FLAG_FASTWRITE && zio->io_bp &&
+           !BP_IS_HOLE(zio->io_bp) && !BP_IS_EMBEDDED(zio->io_bp) &&
+           !(zio->io_flags & ZIO_FLAG_NOPWRITE)) {
+               metaslab_fastwrite_unmark(zio->io_spa, zio->io_bp);
+       }
+
+       /*
+        * It is the responsibility of the done callback to ensure that this
+        * particular zio is no longer discoverable for adoption, and as
+        * such, cannot acquire any new parents.
+        */
+       if (zio->io_done)
+               zio->io_done(zio);
+
+       mutex_enter(&zio->io_lock);
+       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);
+               zio_notify_parent(pio, zio, ZIO_WAIT_DONE);
+       }
+
+       if (zio->io_waiter != NULL) {
+               mutex_enter(&zio->io_lock);
+               zio->io_executor = NULL;
+               cv_broadcast(&zio->io_cv);
+               mutex_exit(&zio->io_lock);
+       } else {
+               zio_destroy(zio);
+       }
+
+       return (ZIO_PIPELINE_STOP);
+}
+
+/*
+ * ==========================================================================
+ * I/O pipeline definition
+ * ==========================================================================
+ */
+static zio_pipe_stage_t *zio_pipeline[] = {
+       NULL,
+       zio_read_bp_init,
+       zio_free_bp_init,
+       zio_issue_async,
+       zio_write_bp_init,
+       zio_checksum_generate,
+       zio_nop_write,
+       zio_ddt_read_start,
+       zio_ddt_read_done,
+       zio_ddt_write,
+       zio_ddt_free,
+       zio_gang_assemble,
+       zio_gang_issue,
+       zio_dva_allocate,
+       zio_dva_free,
+       zio_dva_claim,
+       zio_ready,
+       zio_vdev_io_start,
+       zio_vdev_io_done,
+       zio_vdev_io_assess,
+       zio_checksum_verify,
+       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));
+
+       zb2thisobj = zb2->zb_object ? zb2->zb_object :
+           zb2->zb_blkid << (DNODE_BLOCK_SHIFT - DNODE_SHIFT);
+
+       if (zb1->zb_object == DMU_META_DNODE_OBJECT) {
+               uint64_t nextobj = zb1nextL0 *
+                   (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT) >> DNODE_SHIFT;
+               return (nextobj <= zb2thisobj);
+       }
+
+       if (zb1->zb_object < zb2thisobj)
+               return (B_TRUE);
+       if (zb1->zb_object > zb2thisobj)
+               return (B_FALSE);
+       if (zb2->zb_object == DMU_META_DNODE_OBJECT)
+               return (B_FALSE);
+       return (zb1nextL0 <= zb2->zb_blkid);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zio_type_name);
+EXPORT_SYMBOL(zio_buf_alloc);
+EXPORT_SYMBOL(zio_data_buf_alloc);
+EXPORT_SYMBOL(zio_buf_alloc_flags);
+EXPORT_SYMBOL(zio_buf_free);
+EXPORT_SYMBOL(zio_data_buf_free);
+
+module_param(zio_delay_max, int, 0644);
+MODULE_PARM_DESC(zio_delay_max, "Max zio millisec delay before posting event");
+
+module_param(zio_requeue_io_start_cut_in_line, int, 0644);
+MODULE_PARM_DESC(zio_requeue_io_start_cut_in_line, "Prioritize requeued I/O");
+
+module_param(zfs_sync_pass_deferred_free, int, 0644);
+MODULE_PARM_DESC(zfs_sync_pass_deferred_free,
+       "Defer frees starting in this pass");
+
+module_param(zfs_sync_pass_dont_compress, int, 0644);
+MODULE_PARM_DESC(zfs_sync_pass_dont_compress,
+       "Don't compress starting in this pass");
+
+module_param(zfs_sync_pass_rewrite, int, 0644);
+MODULE_PARM_DESC(zfs_sync_pass_rewrite,
+       "Rewrite new bps starting in this pass");
+#endif
diff --git a/zfs/module/zfs/zio_checksum.c b/zfs/module/zfs/zio_checksum.c
new file mode 100644 (file)
index 0000000..3a5c73a
--- /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 (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/zio.h>
+#include <sys/zio_checksum.h>
+#include <sys/zil.h>
+#include <zfs_fletcher.h>
+
+/*
+ * Checksum vectors.
+ *
+ * In the SPA, everything is checksummed.  We support checksum vectors
+ * for three distinct reasons:
+ *
+ *   1. Different kinds of data need different levels of protection.
+ *     For SPA metadata, we always want a very strong checksum.
+ *     For user data, we let users make the trade-off between speed
+ *     and checksum strength.
+ *
+ *   2. Cryptographic hash and MAC algorithms are an area of active research.
+ *     It is likely that in future hash functions will be at least as strong
+ *     as current best-of-breed, and may be substantially faster as well.
+ *     We want the ability to take advantage of these new hashes as soon as
+ *     they become available.
+ *
+ *   3. If someone develops hardware that can compute a strong hash quickly,
+ *     we want the ability to take advantage of that hardware.
+ *
+ * Of course, we don't want a checksum upgrade to invalidate existing
+ * data, so we store the checksum *function* in eight bits of the bp.
+ * This gives us room for up to 256 different checksum functions.
+ *
+ * When writing a block, we always checksum it with the latest-and-greatest
+ * 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).
+ */
+
+/*ARGSUSED*/
+static void
+zio_checksum_off(const void *buf, uint64_t size, 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"},
+};
+
+enum zio_checksum
+zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
+{
+       ASSERT(child < ZIO_CHECKSUM_FUNCTIONS);
+       ASSERT(parent < ZIO_CHECKSUM_FUNCTIONS);
+       ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
+
+       if (child == ZIO_CHECKSUM_INHERIT)
+               return (parent);
+
+       if (child == ZIO_CHECKSUM_ON)
+               return (ZIO_CHECKSUM_ON_VALUE);
+
+       return (child);
+}
+
+enum zio_checksum
+zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child,
+    enum zio_checksum parent)
+{
+       ASSERT((child & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
+       ASSERT((parent & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
+       ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
+
+       if (child == ZIO_CHECKSUM_INHERIT)
+               return (parent);
+
+       if (child == ZIO_CHECKSUM_ON)
+               return (spa_dedup_checksum(spa));
+
+       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 ||
+           (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF);
+
+       return (child);
+}
+
+/*
+ * Set the external verifier for a gang block based on <vdev, offset, txg>,
+ * a tuple which is guaranteed to be unique for the life of the pool.
+ */
+static void
+zio_checksum_gang_verifier(zio_cksum_t *zcp, blkptr_t *bp)
+{
+       const dva_t *dva = BP_IDENTITY(bp);
+       uint64_t txg = BP_PHYSICAL_BIRTH(bp);
+
+       ASSERT(BP_IS_GANG(bp));
+
+       ZIO_SET_CHECKSUM(zcp, DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), txg, 0);
+}
+
+/*
+ * Set the external verifier for a label block based on its offset.
+ * The vdev is implicit, and the txg is unknowable at pool open time --
+ * hence the logic in vdev_uberblock_load() to find the most recent copy.
+ */
+static void
+zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
+{
+       ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
+}
+
+/*
+ * Generate the checksum.
+ */
+void
+zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
+       void *data, uint64_t size)
+{
+       blkptr_t *bp = zio->io_bp;
+       uint64_t offset = zio->io_offset;
+       zio_checksum_info_t *ci = &zio_checksum_table[checksum];
+       zio_cksum_t cksum;
+
+       ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS);
+       ASSERT(ci->ci_func[0] != NULL);
+
+       if (ci->ci_eck) {
+               zio_eck_t *eck;
+
+               if (checksum == ZIO_CHECKSUM_ZILOG2) {
+                       zil_chain_t *zilc = data;
+
+                       size = P2ROUNDUP_TYPED(zilc->zc_nused, ZIL_MIN_BLKSZ,
+                           uint64_t);
+                       eck = &zilc->zc_eck;
+               } else {
+                       eck = (zio_eck_t *)((char *)data + size) - 1;
+               }
+               if (checksum == ZIO_CHECKSUM_GANG_HEADER)
+                       zio_checksum_gang_verifier(&eck->zec_cksum, bp);
+               else if (checksum == ZIO_CHECKSUM_LABEL)
+                       zio_checksum_label_verifier(&eck->zec_cksum, offset);
+               else
+                       bp->blk_cksum = eck->zec_cksum;
+               eck->zec_magic = ZEC_MAGIC;
+               ci->ci_func[0](data, size, &cksum);
+               eck->zec_cksum = cksum;
+       } else {
+               ci->ci_func[0](data, size, &bp->blk_cksum);
+       }
+}
+
+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 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;
+
+       if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
+               return (SET_ERROR(EINVAL));
+
+       if (ci->ci_eck) {
+               zio_eck_t *eck;
+
+               if (checksum == ZIO_CHECKSUM_ZILOG2) {
+                       zil_chain_t *zilc = data;
+                       uint64_t nused;
+
+                       eck = &zilc->zc_eck;
+                       if (eck->zec_magic == ZEC_MAGIC)
+                               nused = zilc->zc_nused;
+                       else if (eck->zec_magic == BSWAP_64(ZEC_MAGIC))
+                               nused = BSWAP_64(zilc->zc_nused);
+                       else
+                               return (SET_ERROR(ECKSUM));
+
+                       if (nused > size)
+                               return (SET_ERROR(ECKSUM));
+
+                       size = P2ROUNDUP_TYPED(nused, ZIL_MIN_BLKSZ, uint64_t);
+               } else {
+                       eck = (zio_eck_t *)((char *)data + size) - 1;
+               }
+
+               if (checksum == ZIO_CHECKSUM_GANG_HEADER)
+                       zio_checksum_gang_verifier(&verifier, bp);
+               else if (checksum == ZIO_CHECKSUM_LABEL)
+                       zio_checksum_label_verifier(&verifier, offset);
+               else
+                       verifier = bp->blk_cksum;
+
+               byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC));
+
+               if (byteswap)
+                       byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
+
+               expected_cksum = eck->zec_cksum;
+               eck->zec_cksum = verifier;
+               ci->ci_func[byteswap](data, size, &actual_cksum);
+               eck->zec_cksum = expected_cksum;
+
+               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);
+       }
+
+       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 &&
+           (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) {
+
+               info->zbc_injected = 1;
+               return (error);
+       }
+
+       return (0);
+}
diff --git a/zfs/module/zfs/zio_compress.c b/zfs/module/zfs/zio_compress.c
new file mode 100644 (file)
index 0000000..6b8d6c3
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: 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 Saso Kiselkov. All rights reserved.
+ */
+
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/compress.h>
+#include <sys/spa.h>
+#include <sys/zfeature.h>
+#include <sys/zio.h>
+#include <sys/zio_compress.h>
+
+/*
+ * Compression vectors.
+ */
+
+zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = {
+       {NULL,                  NULL,                   0,      "inherit"},
+       {NULL,                  NULL,                   0,      "on"},
+       {NULL,                  NULL,                   0,      "uncompressed"},
+       {lzjb_compress,         lzjb_decompress,        0,      "lzjb"},
+       {NULL,                  NULL,                   0,      "empty"},
+       {gzip_compress,         gzip_decompress,        1,      "gzip-1"},
+       {gzip_compress,         gzip_decompress,        2,      "gzip-2"},
+       {gzip_compress,         gzip_decompress,        3,      "gzip-3"},
+       {gzip_compress,         gzip_decompress,        4,      "gzip-4"},
+       {gzip_compress,         gzip_decompress,        5,      "gzip-5"},
+       {gzip_compress,         gzip_decompress,        6,      "gzip-6"},
+       {gzip_compress,         gzip_decompress,        7,      "gzip-7"},
+       {gzip_compress,         gzip_decompress,        8,      "gzip-8"},
+       {gzip_compress,         gzip_decompress,        9,      "gzip-9"},
+       {zle_compress,          zle_decompress,         64,     "zle"},
+       {lz4_compress_zfs,      lz4_decompress_zfs,     0,      "lz4"},
+};
+
+enum zio_compress
+zio_compress_select(spa_t *spa, enum zio_compress child,
+    enum zio_compress parent)
+{
+       enum zio_compress result;
+
+       ASSERT(child < ZIO_COMPRESS_FUNCTIONS);
+       ASSERT(parent < ZIO_COMPRESS_FUNCTIONS);
+       ASSERT(parent != ZIO_COMPRESS_INHERIT);
+
+       result = child;
+       if (result == ZIO_COMPRESS_INHERIT)
+               result = parent;
+
+       if (result == ZIO_COMPRESS_ON) {
+               if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS))
+                       result = ZIO_COMPRESS_LZ4_ON_VALUE;
+               else
+                       result = ZIO_COMPRESS_LEGACY_ON_VALUE;
+       }
+
+       return (result);
+}
+
+size_t
+zio_compress_data(enum zio_compress c, void *src, void *dst, size_t s_len)
+{
+       uint64_t *word, *word_end;
+       size_t c_len, d_len;
+       zio_compress_info_t *ci = &zio_compress_table[c];
+
+       ASSERT((uint_t)c < ZIO_COMPRESS_FUNCTIONS);
+       ASSERT((uint_t)c == ZIO_COMPRESS_EMPTY || ci->ci_compress != NULL);
+
+       /*
+        * If the data is all zeroes, we don't even need to allocate
+        * a block for it.  We indicate this by returning zero size.
+        */
+       word_end = (uint64_t *)((char *)src + s_len);
+       for (word = src; word < word_end; word++)
+               if (*word != 0)
+                       break;
+
+       if (word == word_end)
+               return (0);
+
+       if (c == ZIO_COMPRESS_EMPTY)
+               return (s_len);
+
+       /* Compress at least 12.5% */
+       d_len = s_len - (s_len >> 3);
+       c_len = ci->ci_compress(src, dst, s_len, d_len, ci->ci_level);
+
+       if (c_len > d_len)
+               return (s_len);
+
+       ASSERT3U(c_len, <=, d_len);
+       return (c_len);
+}
+
+int
+zio_decompress_data(enum zio_compress c, void *src, void *dst,
+    size_t s_len, size_t d_len)
+{
+       zio_compress_info_t *ci = &zio_compress_table[c];
+
+       if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL)
+               return (SET_ERROR(EINVAL));
+
+       return (ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level));
+}
diff --git a/zfs/module/zfs/zio_inject.c b/zfs/module/zfs/zio_inject.c
new file mode 100644 (file)
index 0000000..40b507a
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * ZFS fault injection
+ *
+ * To handle fault injection, we keep track of a series of zinject_record_t
+ * structures which describe which logical block(s) should be injected with a
+ * fault.  These are kept in a global list.  Each record corresponds to a given
+ * spa_t and maintains a special hold on the spa_t so that it cannot be deleted
+ * or exported while the injection record exists.
+ *
+ * Device level injection is done using the 'zi_guid' field.  If this is set, it
+ * means that the error is destined for a particular device, not a piece of
+ * data.
+ *
+ * This is a rather poor data structure and algorithm, but we don't expect more
+ * than a few faults at any one time, so it should be sufficient for our needs.
+ */
+
+#include <sys/arc.h>
+#include <sys/zio_impl.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/vdev_impl.h>
+#include <sys/dmu_objset.h>
+#include <sys/fs/zfs.h>
+
+uint32_t zio_injection_enabled = 0;
+
+typedef struct inject_handler {
+       int                     zi_id;
+       spa_t                   *zi_spa;
+       zinject_record_t        zi_record;
+       list_node_t             zi_link;
+} inject_handler_t;
+
+static list_t inject_handlers;
+static krwlock_t inject_lock;
+static int inject_next_id = 1;
+
+/*
+ * Returns true if the given record matches the I/O in progress.
+ */
+static boolean_t
+zio_match_handler(zbookmark_phys_t *zb, uint64_t type,
+    zinject_record_t *record, int error)
+{
+       /*
+        * Check for a match against the MOS, which is based on type
+        */
+       if (zb->zb_objset == DMU_META_OBJSET &&
+           record->zi_objset == DMU_META_OBJSET &&
+           record->zi_object == DMU_META_DNODE_OBJECT) {
+               if (record->zi_type == DMU_OT_NONE ||
+                   type == record->zi_type)
+                       return (record->zi_freq == 0 ||
+                           spa_get_random(100) < record->zi_freq);
+               else
+                       return (B_FALSE);
+       }
+
+       /*
+        * Check for an exact match.
+        */
+       if (zb->zb_objset == record->zi_objset &&
+           zb->zb_object == record->zi_object &&
+           zb->zb_level == record->zi_level &&
+           zb->zb_blkid >= record->zi_start &&
+           zb->zb_blkid <= record->zi_end &&
+           error == record->zi_error)
+               return (record->zi_freq == 0 ||
+                   spa_get_random(100) < record->zi_freq);
+
+       return (B_FALSE);
+}
+
+/*
+ * Panic the system when a config change happens in the function
+ * specified by tag.
+ */
+void
+zio_handle_panic_injection(spa_t *spa, char *tag, uint64_t type)
+{
+       inject_handler_t *handler;
+
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler)) {
+
+               if (spa != handler->zi_spa)
+                       continue;
+
+               if (handler->zi_record.zi_type == type &&
+                   strcmp(tag, handler->zi_record.zi_func) == 0)
+                       panic("Panic requested in function %s\n", tag);
+       }
+
+       rw_exit(&inject_lock);
+}
+
+/*
+ * Determine if the I/O in question should return failure.  Returns the errno
+ * to be returned to the caller.
+ */
+int
+zio_handle_fault_injection(zio_t *zio, int error)
+{
+       int ret = 0;
+       inject_handler_t *handler;
+
+       /*
+        * Ignore I/O not associated with any logical data.
+        */
+       if (zio->io_logical == NULL)
+               return (0);
+
+       /*
+        * Currently, we only support fault injection on reads.
+        */
+       if (zio->io_type != ZIO_TYPE_READ)
+               return (0);
+
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler)) {
+
+               if (zio->io_spa != handler->zi_spa ||
+                   handler->zi_record.zi_cmd != ZINJECT_DATA_FAULT)
+                       continue;
+
+               /* If this handler matches, return EIO */
+               if (zio_match_handler(&zio->io_logical->io_bookmark,
+                   zio->io_bp ? BP_GET_TYPE(zio->io_bp) : DMU_OT_NONE,
+                   &handler->zi_record, error)) {
+                       ret = error;
+                       break;
+               }
+       }
+
+       rw_exit(&inject_lock);
+
+       return (ret);
+}
+
+/*
+ * Determine if the zio is part of a label update and has an injection
+ * handler associated with that portion of the label. Currently, we
+ * allow error injection in either the nvlist or the uberblock region of
+ * of the vdev label.
+ */
+int
+zio_handle_label_injection(zio_t *zio, int error)
+{
+       inject_handler_t *handler;
+       vdev_t *vd = zio->io_vd;
+       uint64_t offset = zio->io_offset;
+       int label;
+       int ret = 0;
+
+       if (offset >= VDEV_LABEL_START_SIZE &&
+           offset < vd->vdev_psize - VDEV_LABEL_END_SIZE)
+               return (0);
+
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler)) {
+               uint64_t start = handler->zi_record.zi_start;
+               uint64_t end = handler->zi_record.zi_end;
+
+               if (handler->zi_record.zi_cmd != ZINJECT_LABEL_FAULT)
+                       continue;
+
+               /*
+                * The injection region is the relative offsets within a
+                * vdev label. We must determine the label which is being
+                * updated and adjust our region accordingly.
+                */
+               label = vdev_label_number(vd->vdev_psize, offset);
+               start = vdev_label_offset(vd->vdev_psize, label, start);
+               end = vdev_label_offset(vd->vdev_psize, label, end);
+
+               if (zio->io_vd->vdev_guid == handler->zi_record.zi_guid &&
+                   (offset >= start && offset <= end)) {
+                       ret = error;
+                       break;
+               }
+       }
+       rw_exit(&inject_lock);
+       return (ret);
+}
+
+
+int
+zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error)
+{
+       inject_handler_t *handler;
+       int ret = 0;
+
+       /*
+        * We skip over faults in the labels unless it's during
+        * device open (i.e. zio == NULL).
+        */
+       if (zio != NULL) {
+               uint64_t offset = zio->io_offset;
+
+               if (offset < VDEV_LABEL_START_SIZE ||
+                   offset >= vd->vdev_psize - VDEV_LABEL_END_SIZE)
+                       return (0);
+       }
+
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler)) {
+
+               if (handler->zi_record.zi_cmd != ZINJECT_DEVICE_FAULT)
+                       continue;
+
+               if (vd->vdev_guid == handler->zi_record.zi_guid) {
+                       if (handler->zi_record.zi_failfast &&
+                           (zio == NULL || (zio->io_flags &
+                           (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD)))) {
+                               continue;
+                       }
+
+                       /* Handle type specific I/O failures */
+                       if (zio != NULL &&
+                           handler->zi_record.zi_iotype != ZIO_TYPES &&
+                           handler->zi_record.zi_iotype != zio->io_type)
+                               continue;
+
+                       if (handler->zi_record.zi_error == error) {
+                               /*
+                                * For a failed open, pretend like the device
+                                * has gone away.
+                                */
+                               if (error == ENXIO)
+                                       vd->vdev_stat.vs_aux =
+                                           VDEV_AUX_OPEN_FAILED;
+
+                               /*
+                                * Treat these errors as if they had been
+                                * retried so that all the appropriate stats
+                                * and FMA events are generated.
+                                */
+                               if (!handler->zi_record.zi_failfast &&
+                                   zio != NULL)
+                                       zio->io_flags |= ZIO_FLAG_IO_RETRY;
+
+                               ret = error;
+                               break;
+                       }
+                       if (handler->zi_record.zi_error == ENXIO) {
+                               ret = SET_ERROR(EIO);
+                               break;
+                       }
+               }
+       }
+
+       rw_exit(&inject_lock);
+
+       return (ret);
+}
+
+/*
+ * Simulate hardware that ignores cache flushes.  For requested number
+ * of seconds nix the actual writing to disk.
+ */
+void
+zio_handle_ignored_writes(zio_t *zio)
+{
+       inject_handler_t *handler;
+
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler)) {
+
+               /* Ignore errors not destined for this pool */
+               if (zio->io_spa != handler->zi_spa ||
+                   handler->zi_record.zi_cmd != ZINJECT_IGNORED_WRITES)
+                       continue;
+
+               /*
+                * Positive duration implies # of seconds, negative
+                * a number of txgs
+                */
+               if (handler->zi_record.zi_timer == 0) {
+                       if (handler->zi_record.zi_duration > 0)
+                               handler->zi_record.zi_timer = ddi_get_lbolt64();
+                       else
+                               handler->zi_record.zi_timer = zio->io_txg;
+               }
+
+               /* Have a "problem" writing 60% of the time */
+               if (spa_get_random(100) < 60)
+                       zio->io_pipeline &= ~ZIO_VDEV_IO_STAGES;
+               break;
+       }
+
+       rw_exit(&inject_lock);
+}
+
+void
+spa_handle_ignored_writes(spa_t *spa)
+{
+       inject_handler_t *handler;
+
+       if (zio_injection_enabled == 0)
+               return;
+
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler)) {
+
+               if (spa != handler->zi_spa ||
+                   handler->zi_record.zi_cmd != ZINJECT_IGNORED_WRITES)
+                       continue;
+
+               if (handler->zi_record.zi_duration > 0) {
+                       VERIFY(handler->zi_record.zi_timer == 0 ||
+                           ddi_time_after64(
+                           (int64_t)handler->zi_record.zi_timer +
+                           handler->zi_record.zi_duration * hz,
+                           ddi_get_lbolt64()));
+               } else {
+                       /* duration is negative so the subtraction here adds */
+                       VERIFY(handler->zi_record.zi_timer == 0 ||
+                           handler->zi_record.zi_timer -
+                           handler->zi_record.zi_duration >=
+                           spa_syncing_txg(spa));
+               }
+       }
+
+       rw_exit(&inject_lock);
+}
+
+uint64_t
+zio_handle_io_delay(zio_t *zio)
+{
+       vdev_t *vd = zio->io_vd;
+       inject_handler_t *handler;
+       uint64_t seconds = 0;
+
+       if (zio_injection_enabled == 0)
+               return (0);
+
+       rw_enter(&inject_lock, RW_READER);
+
+       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;
+               }
+
+       }
+       rw_exit(&inject_lock);
+       return (seconds);
+}
+
+/*
+ * Create a new handler for the given record.  We add it to the list, adding
+ * a reference to the spa_t in the process.  We increment zio_injection_enabled,
+ * which is the switch to trigger all fault injection.
+ */
+int
+zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record)
+{
+       inject_handler_t *handler;
+       int error;
+       spa_t *spa;
+
+       /*
+        * If this is pool-wide metadata, make sure we unload the corresponding
+        * spa_t, so that the next attempt to load it will trigger the fault.
+        * We call spa_reset() to unload the pool appropriately.
+        */
+       if (flags & ZINJECT_UNLOAD_SPA)
+               if ((error = spa_reset(name)) != 0)
+                       return (error);
+
+       if (!(flags & ZINJECT_NULL)) {
+               /*
+                * spa_inject_ref() will add an injection reference, which will
+                * prevent the pool from being removed from the namespace while
+                * still allowing it to be unloaded.
+                */
+               if ((spa = spa_inject_addref(name)) == NULL)
+                       return (SET_ERROR(ENOENT));
+
+               handler = kmem_alloc(sizeof (inject_handler_t), KM_SLEEP);
+
+               rw_enter(&inject_lock, RW_WRITER);
+
+               *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);
+
+               rw_exit(&inject_lock);
+       }
+
+       /*
+        * Flush the ARC, so that any attempts to read this data will end up
+        * going to the ZIO layer.  Note that this is a little overkill, but
+        * we don't have the necessary ARC interfaces to do anything else, and
+        * fault injection isn't a performance critical path.
+        */
+       if (flags & ZINJECT_FLUSH_ARC)
+               /*
+                * We must use FALSE to ensure arc_flush returns, since
+                * we're not preventing concurrent ARC insertions.
+                */
+               arc_flush(NULL, FALSE);
+
+       return (0);
+}
+
+/*
+ * Returns the next record with an ID greater than that supplied to the
+ * function.  Used to iterate over all handlers in the system.
+ */
+int
+zio_inject_list_next(int *id, char *name, size_t buflen,
+    zinject_record_t *record)
+{
+       inject_handler_t *handler;
+       int ret;
+
+       mutex_enter(&spa_namespace_lock);
+       rw_enter(&inject_lock, RW_READER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler))
+               if (handler->zi_id > *id)
+                       break;
+
+       if (handler) {
+               *record = handler->zi_record;
+               *id = handler->zi_id;
+               (void) strncpy(name, spa_name(handler->zi_spa), buflen);
+               ret = 0;
+       } else {
+               ret = SET_ERROR(ENOENT);
+       }
+
+       rw_exit(&inject_lock);
+       mutex_exit(&spa_namespace_lock);
+
+       return (ret);
+}
+
+/*
+ * Clear the fault handler with the given identifier, or return ENOENT if none
+ * exists.
+ */
+int
+zio_clear_fault(int id)
+{
+       inject_handler_t *handler;
+
+       rw_enter(&inject_lock, RW_WRITER);
+
+       for (handler = list_head(&inject_handlers); handler != NULL;
+           handler = list_next(&inject_handlers, handler))
+               if (handler->zi_id == id)
+                       break;
+
+       if (handler == NULL) {
+               rw_exit(&inject_lock);
+               return (SET_ERROR(ENOENT));
+       }
+
+       list_remove(&inject_handlers, handler);
+       rw_exit(&inject_lock);
+
+       spa_inject_delref(handler->zi_spa);
+       kmem_free(handler, sizeof (inject_handler_t));
+       atomic_add_32(&zio_injection_enabled, -1);
+
+       return (0);
+}
+
+void
+zio_inject_init(void)
+{
+       rw_init(&inject_lock, NULL, RW_DEFAULT, NULL);
+       list_create(&inject_handlers, sizeof (inject_handler_t),
+           offsetof(inject_handler_t, zi_link));
+}
+
+void
+zio_inject_fini(void)
+{
+       list_destroy(&inject_handlers);
+       rw_destroy(&inject_lock);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zio_injection_enabled);
+EXPORT_SYMBOL(zio_inject_fault);
+EXPORT_SYMBOL(zio_inject_list_next);
+EXPORT_SYMBOL(zio_clear_fault);
+EXPORT_SYMBOL(zio_handle_fault_injection);
+EXPORT_SYMBOL(zio_handle_device_injection);
+EXPORT_SYMBOL(zio_handle_label_injection);
+#endif
diff --git a/zfs/module/zfs/zle.c b/zfs/module/zfs/zle.c
new file mode 100644 (file)
index 0000000..13c5673
--- /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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Zero-length encoding.  This is a fast and simple algorithm to eliminate
+ * runs of zeroes.  Each chunk of compressed data begins with a length byte, b.
+ * If b < n (where n is the compression parameter) then the next b + 1 bytes
+ * are literal values.  If b >= n then the next (256 - b + 1) bytes are zero.
+ */
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+size_t
+zle_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+       uchar_t *src = s_start;
+       uchar_t *dst = d_start;
+       uchar_t *s_end = src + s_len;
+       uchar_t *d_end = dst + d_len;
+
+       while (src < s_end && dst < d_end - 1) {
+               uchar_t *first = src;
+               uchar_t *len = dst++;
+               if (src[0] == 0) {
+                       uchar_t *last = src + (256 - n);
+                       while (src < MIN(last, s_end) && src[0] == 0)
+                               src++;
+                       *len = src - first - 1 + n;
+               } else {
+                       uchar_t *last = src + n;
+                       if (d_end - dst < n)
+                               break;
+                       while (src < MIN(last, s_end) - 1 && (src[0] | src[1]))
+                               *dst++ = *src++;
+                       if (src[0])
+                               *dst++ = *src++;
+                       *len = src - first - 1;
+               }
+       }
+       return (src == s_end ? dst - (uchar_t *)d_start : s_len);
+}
+
+int
+zle_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+       uchar_t *src = s_start;
+       uchar_t *dst = d_start;
+       uchar_t *s_end = src + s_len;
+       uchar_t *d_end = dst + d_len;
+
+       while (src < s_end && dst < d_end) {
+               int len = 1 + *src++;
+               if (len <= n) {
+                       while (len-- != 0)
+                               *dst++ = *src++;
+               } else {
+                       len -= n;
+                       while (len-- != 0)
+                               *dst++ = 0;
+               }
+       }
+       return (dst == d_end ? 0 : -1);
+}
diff --git a/zfs/module/zfs/zpl_ctldir.c b/zfs/module/zfs/zpl_ctldir.c
new file mode 100644 (file)
index 0000000..d691f67
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * LLNL-CODE-403049.
+ * Rewritten for Linux by:
+ *   Rohan Puri <rohan.puri15@gmail.com>
+ *   Brian Behlendorf <behlendorf1@llnl.gov>
+ */
+
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zpl.h>
+
+/*
+ * Common open routine.  Disallow any write access.
+ */
+/* ARGSUSED */
+static int
+zpl_common_open(struct inode *ip, struct file *filp)
+{
+       if (filp->f_mode & FMODE_WRITE)
+               return (-EACCES);
+
+       return (generic_file_open(ip, filp));
+}
+
+/*
+ * Get root directory contents.
+ */
+static int
+zpl_root_iterate(struct file *filp, struct dir_context *ctx)
+{
+       zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
+       int error = 0;
+
+       ZFS_ENTER(zsb);
+
+       if (!dir_emit_dots(filp, ctx))
+               goto out;
+
+       if (ctx->pos == 2) {
+               if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, strlen(ZFS_SNAPDIR_NAME),
+                   ZFSCTL_INO_SNAPDIR, DT_DIR))
+                       goto out;
+
+               ctx->pos++;
+       }
+
+       if (ctx->pos == 3) {
+               if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, strlen(ZFS_SHAREDIR_NAME),
+                   ZFSCTL_INO_SHARES, DT_DIR))
+                       goto out;
+
+               ctx->pos++;
+       }
+out:
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED)
+static int
+zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
+       int error;
+
+       error = zpl_root_iterate(filp, &ctx);
+       filp->f_pos = ctx.pos;
+
+       return (error);
+}
+#endif /* HAVE_VFS_ITERATE */
+
+/*
+ * Get root directory attributes.
+ */
+/* ARGSUSED */
+static int
+zpl_root_getattr(struct vfsmount *mnt, struct dentry *dentry,
+    struct kstat *stat)
+{
+       int error;
+
+       error = simple_getattr(mnt, dentry, stat);
+       stat->atime = CURRENT_TIME;
+
+       return (error);
+}
+
+static struct dentry *
+#ifdef HAVE_LOOKUP_NAMEIDATA
+zpl_root_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
+#else
+zpl_root_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
+#endif
+{
+       cred_t *cr = CRED();
+       struct inode *ip;
+       int error;
+
+       crhold(cr);
+       error = -zfsctl_root_lookup(dip, dname(dentry), &ip, 0, cr, NULL, NULL);
+       ASSERT3S(error, <=, 0);
+       crfree(cr);
+
+       if (error) {
+               if (error == -ENOENT)
+                       return (d_splice_alias(NULL, dentry));
+               else
+                       return (ERR_PTR(error));
+       }
+
+       return (d_splice_alias(ip, dentry));
+}
+
+/*
+ * The '.zfs' control directory file and inode operations.
+ */
+const struct file_operations zpl_fops_root = {
+       .open           = zpl_common_open,
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+#ifdef HAVE_VFS_ITERATE_SHARED
+       .iterate_shared = zpl_root_iterate,
+#elif defined(HAVE_VFS_ITERATE)
+       .iterate        = zpl_root_iterate,
+#else
+       .readdir        = zpl_root_readdir,
+#endif
+};
+
+const struct inode_operations zpl_ops_root = {
+       .lookup         = zpl_root_lookup,
+       .getattr        = zpl_root_getattr,
+};
+
+#ifdef HAVE_AUTOMOUNT
+static struct vfsmount *
+zpl_snapdir_automount(struct path *path)
+{
+       int error;
+
+       error = -zfsctl_snapshot_mount(path, 0);
+       if (error)
+               return (ERR_PTR(error));
+
+       /*
+        * Rather than returning the new vfsmount for the snapshot we must
+        * return NULL to indicate a mount collision.  This is done because
+        * the user space mount calls do_add_mount() which adds the vfsmount
+        * to the name space.  If we returned the new mount here it would be
+        * added again to the vfsmount list resulting in list corruption.
+        */
+       return (NULL);
+}
+#endif /* HAVE_AUTOMOUNT */
+
+/*
+ * Negative dentries must always be revalidated so newly created snapshots
+ * can be detected and automounted.  Normal dentries should be kept because
+ * as of the 3.18 kernel revaliding the mountpoint dentry will result in
+ * the snapshot being immediately unmounted.
+ */
+static int
+#ifdef HAVE_D_REVALIDATE_NAMEIDATA
+zpl_snapdir_revalidate(struct dentry *dentry, struct nameidata *i)
+#else
+zpl_snapdir_revalidate(struct dentry *dentry, unsigned int flags)
+#endif
+{
+       return (!!dentry->d_inode);
+}
+
+dentry_operations_t zpl_dops_snapdirs = {
+/*
+ * Auto mounting of snapshots is only supported for 2.6.37 and
+ * newer kernels.  Prior to this kernel the ops->follow_link()
+ * callback was used as a hack to trigger the mount.  The
+ * resulting vfsmount was then explicitly grafted in to the
+ * name space.  While it might be possible to add compatibility
+ * code to accomplish this it would require considerable care.
+ */
+#ifdef HAVE_AUTOMOUNT
+       .d_automount    = zpl_snapdir_automount,
+#endif /* HAVE_AUTOMOUNT */
+       .d_revalidate   = zpl_snapdir_revalidate,
+};
+
+static struct dentry *
+#ifdef HAVE_LOOKUP_NAMEIDATA
+zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
+    struct nameidata *nd)
+#else
+zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
+    unsigned int flags)
+#endif
+
+{
+       fstrans_cookie_t cookie;
+       cred_t *cr = CRED();
+       struct inode *ip = NULL;
+       int error;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfsctl_snapdir_lookup(dip, dname(dentry), &ip,
+           0, cr, NULL, NULL);
+       ASSERT3S(error, <=, 0);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       if (error && error != -ENOENT)
+               return (ERR_PTR(error));
+
+       ASSERT(error == 0 || ip == NULL);
+       d_clear_d_op(dentry);
+       d_set_d_op(dentry, &zpl_dops_snapdirs);
+#ifdef HAVE_AUTOMOUNT
+       dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+#endif
+
+       return (d_splice_alias(ip, dentry));
+}
+
+static int
+zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
+{
+       zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
+       fstrans_cookie_t cookie;
+       char snapname[MAXNAMELEN];
+       boolean_t case_conflict;
+       uint64_t id, pos;
+       int error = 0;
+
+       ZFS_ENTER(zsb);
+       cookie = spl_fstrans_mark();
+
+       if (!dir_emit_dots(filp, ctx))
+               goto out;
+
+       pos = ctx->pos;
+       while (error == 0) {
+               dsl_pool_config_enter(dmu_objset_pool(zsb->z_os), FTAG);
+               error = -dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN,
+                   snapname, &id, &pos, &case_conflict);
+               dsl_pool_config_exit(dmu_objset_pool(zsb->z_os), FTAG);
+               if (error)
+                       goto out;
+
+               if (!dir_emit(ctx, snapname, strlen(snapname),
+                   ZFSCTL_INO_SHARES - id, DT_DIR))
+                       goto out;
+
+               ctx->pos = pos;
+       }
+out:
+       spl_fstrans_unmark(cookie);
+       ZFS_EXIT(zsb);
+
+       if (error == -ENOENT)
+               return (0);
+
+       return (error);
+}
+
+#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED)
+static int
+zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
+       int error;
+
+       error = zpl_snapdir_iterate(filp, &ctx);
+       filp->f_pos = ctx.pos;
+
+       return (error);
+}
+#endif /* HAVE_VFS_ITERATE */
+
+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);
+       ASSERT3S(error, <=, 0);
+       crfree(cr);
+
+       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)
+{
+       cred_t *cr = CRED();
+       int error;
+
+       crhold(cr);
+       error = -zfsctl_snapdir_remove(dip, dname(dentry), cr, 0);
+       ASSERT3S(error, <=, 0);
+       crfree(cr);
+
+       return (error);
+}
+
+static int
+zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode)
+{
+       cred_t *cr = CRED();
+       vattr_t *vap;
+       struct inode *ip;
+       int error;
+
+       crhold(cr);
+       vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+       zpl_vap_init(vap, dip, mode | S_IFDIR, cr);
+
+       error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0);
+       if (error == 0) {
+               d_clear_d_op(dentry);
+               d_set_d_op(dentry, &zpl_dops_snapdirs);
+               d_instantiate(dentry, ip);
+       }
+
+       kmem_free(vap, sizeof (vattr_t));
+       ASSERT3S(error, <=, 0);
+       crfree(cr);
+
+       return (error);
+}
+
+/*
+ * Get snapshot directory attributes.
+ */
+/* ARGSUSED */
+static int
+zpl_snapdir_getattr(struct vfsmount *mnt, struct dentry *dentry,
+    struct kstat *stat)
+{
+       zfs_sb_t *zsb = ITOZSB(dentry->d_inode);
+       int error;
+
+       ZFS_ENTER(zsb);
+       error = simple_getattr(mnt, dentry, stat);
+       stat->nlink = stat->size = 2;
+       stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zsb->z_os);
+       stat->atime = CURRENT_TIME;
+       ZFS_EXIT(zsb);
+
+       return (error);
+}
+
+/*
+ * The '.zfs/snapshot' directory file operations.  These mainly control
+ * generating the list of available snapshots when doing an 'ls' in the
+ * directory.  See zpl_snapdir_readdir().
+ */
+const struct file_operations zpl_fops_snapdir = {
+       .open           = zpl_common_open,
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+#ifdef HAVE_VFS_ITERATE_SHARED
+       .iterate_shared = zpl_snapdir_iterate,
+#elif defined(HAVE_VFS_ITERATE)
+       .iterate        = zpl_snapdir_iterate,
+#else
+       .readdir        = zpl_snapdir_readdir,
+#endif
+
+};
+
+/*
+ * The '.zfs/snapshot' directory inode operations.  These mainly control
+ * creating an inode for a snapshot directory and initializing the needed
+ * infrastructure to automount the snapshot.  See zpl_snapdir_lookup().
+ */
+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,
+};
+
+static struct dentry *
+#ifdef HAVE_LOOKUP_NAMEIDATA
+zpl_shares_lookup(struct inode *dip, struct dentry *dentry,
+    struct nameidata *nd)
+#else
+zpl_shares_lookup(struct inode *dip, struct dentry *dentry,
+    unsigned int flags)
+#endif
+{
+       fstrans_cookie_t cookie;
+       cred_t *cr = CRED();
+       struct inode *ip = NULL;
+       int error;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfsctl_shares_lookup(dip, dname(dentry), &ip,
+           0, cr, NULL, NULL);
+       ASSERT3S(error, <=, 0);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       if (error) {
+               if (error == -ENOENT)
+                       return (d_splice_alias(NULL, dentry));
+               else
+                       return (ERR_PTR(error));
+       }
+
+       return (d_splice_alias(ip, dentry));
+}
+
+static int
+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);
+       znode_t *dzp;
+       int error = 0;
+
+       ZFS_ENTER(zsb);
+       cookie = spl_fstrans_mark();
+
+       if (zsb->z_shares_dir == 0) {
+               dir_emit_dots(filp, ctx);
+               goto out;
+       }
+
+       error = -zfs_zget(zsb, zsb->z_shares_dir, &dzp);
+       if (error)
+               goto out;
+
+       crhold(cr);
+       error = -zfs_readdir(ZTOI(dzp), ctx, cr);
+       crfree(cr);
+
+       iput(ZTOI(dzp));
+out:
+       spl_fstrans_unmark(cookie);
+       ZFS_EXIT(zsb);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED)
+static int
+zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
+       int error;
+
+       error = zpl_shares_iterate(filp, &ctx);
+       filp->f_pos = ctx.pos;
+
+       return (error);
+}
+#endif /* HAVE_VFS_ITERATE */
+
+/* ARGSUSED */
+static int
+zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,
+    struct kstat *stat)
+{
+       struct inode *ip = dentry->d_inode;
+       zfs_sb_t *zsb = ITOZSB(ip);
+       znode_t *dzp;
+       int error;
+
+       ZFS_ENTER(zsb);
+
+       if (zsb->z_shares_dir == 0) {
+               error = simple_getattr(mnt, dentry, stat);
+               stat->nlink = stat->size = 2;
+               stat->atime = CURRENT_TIME;
+               ZFS_EXIT(zsb);
+               return (error);
+       }
+
+       error = -zfs_zget(zsb, zsb->z_shares_dir, &dzp);
+       if (error == 0) {
+               error = -zfs_getattr_fast(ZTOI(dzp), stat);
+               iput(ZTOI(dzp));
+       }
+
+       ZFS_EXIT(zsb);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+/*
+ * The '.zfs/shares' directory file operations.
+ */
+const struct file_operations zpl_fops_shares = {
+       .open           = zpl_common_open,
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+#ifdef HAVE_VFS_ITERATE_SHARED
+       .iterate_shared = zpl_shares_iterate,
+#elif defined(HAVE_VFS_ITERATE)
+       .iterate        = zpl_shares_iterate,
+#else
+       .readdir        = zpl_shares_readdir,
+#endif
+
+};
+
+/*
+ * The '.zfs/shares' directory inode operations.
+ */
+const struct inode_operations zpl_ops_shares = {
+       .lookup         = zpl_shares_lookup,
+       .getattr        = zpl_shares_getattr,
+};
diff --git a/zfs/module/zfs/zpl_export.c b/zfs/module/zfs/zpl_export.c
new file mode 100644 (file)
index 0000000..6f051a0
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Gunnar Beutner
+ * Copyright (c) 2012 Cyril Plisko. All rights reserved.
+ */
+
+
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zpl.h>
+
+
+static int
+#ifdef HAVE_ENCODE_FH_WITH_INODE
+zpl_encode_fh(struct inode *ip, __u32 *fh, int *max_len, struct inode *parent)
+{
+#else
+zpl_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, int connectable)
+{
+       struct inode *ip = dentry->d_inode;
+#endif /* HAVE_ENCODE_FH_WITH_INODE */
+       fstrans_cookie_t cookie;
+       fid_t *fid = (fid_t *)fh;
+       int len_bytes, rc;
+
+       len_bytes = *max_len * sizeof (__u32);
+
+       if (len_bytes < offsetof(fid_t, fid_data))
+               return (255);
+
+       fid->fid_len = len_bytes - offsetof(fid_t, fid_data);
+       cookie = spl_fstrans_mark();
+
+       if (zfsctl_is_node(ip))
+               rc = zfsctl_fid(ip, fid);
+       else
+               rc = zfs_fid(ip, fid);
+
+       spl_fstrans_unmark(cookie);
+       len_bytes = offsetof(fid_t, fid_data) + fid->fid_len;
+       *max_len = roundup(len_bytes, sizeof (__u32)) / sizeof (__u32);
+
+       return (rc == 0 ? FILEID_INO32_GEN : 255);
+}
+
+static struct dentry *
+zpl_dentry_obtain_alias(struct inode *ip)
+{
+       struct dentry *result;
+
+#ifdef HAVE_D_OBTAIN_ALIAS
+       result = d_obtain_alias(ip);
+#else
+       result = d_alloc_anon(ip);
+
+       if (result == NULL) {
+               iput(ip);
+               result = ERR_PTR(-ENOMEM);
+       }
+#endif /* HAVE_D_OBTAIN_ALIAS */
+
+       return (result);
+}
+
+static struct dentry *
+zpl_fh_to_dentry(struct super_block *sb, struct fid *fh,
+    int fh_len, int fh_type)
+{
+       fid_t *fid = (fid_t *)fh;
+       fstrans_cookie_t cookie;
+       struct inode *ip;
+       int len_bytes, rc;
+
+       len_bytes = fh_len * sizeof (__u32);
+
+       if (fh_type != FILEID_INO32_GEN ||
+           len_bytes < offsetof(fid_t, fid_data) ||
+           len_bytes < offsetof(fid_t, fid_data) + fid->fid_len)
+               return (ERR_PTR(-EINVAL));
+
+       cookie = spl_fstrans_mark();
+       rc = zfs_vget(sb, &ip, fid);
+       spl_fstrans_unmark(cookie);
+
+       if (rc) {
+               /*
+                * If we see ENOENT it might mean that an NFSv4 * client
+                * is using a cached inode value in a file handle and
+                * that the sought after file has had its inode changed
+                * by a third party.  So change the error to ESTALE
+                * which will trigger a full lookup by the client and
+                * will find the new filename/inode pair if it still
+                * exists.
+                */
+               if (rc == ENOENT)
+                       rc = ESTALE;
+
+               return (ERR_PTR(-rc));
+       }
+
+       ASSERT((ip != NULL) && !IS_ERR(ip));
+
+       return (zpl_dentry_obtain_alias(ip));
+}
+
+static struct dentry *
+zpl_get_parent(struct dentry *child)
+{
+       cred_t *cr = CRED();
+       fstrans_cookie_t cookie;
+       struct inode *ip;
+       int error;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_lookup(child->d_inode, "..", &ip, 0, cr, NULL, NULL);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       if (error)
+               return (ERR_PTR(error));
+
+       return (zpl_dentry_obtain_alias(ip));
+}
+
+#ifdef HAVE_COMMIT_METADATA
+static int
+zpl_commit_metadata(struct inode *inode)
+{
+       cred_t *cr = CRED();
+       fstrans_cookie_t cookie;
+       int error;
+
+       if (zfsctl_is_node(inode))
+               return (0);
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_fsync(inode, 0, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+#endif /* HAVE_COMMIT_METADATA */
+
+const struct export_operations zpl_export_operations = {
+       .encode_fh              = zpl_encode_fh,
+       .fh_to_dentry           = zpl_fh_to_dentry,
+       .get_parent             = zpl_get_parent,
+#ifdef HAVE_COMMIT_METADATA
+       .commit_metadata        = zpl_commit_metadata,
+#endif /* HAVE_COMMIT_METADATA */
+};
diff --git a/zfs/module/zfs/zpl_file.c b/zfs/module/zfs/zpl_file.c
new file mode 100644 (file)
index 0000000..19e8a62
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, Lawrence Livermore National Security, LLC.
+ * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+#include <sys/dmu_objset.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zpl.h>
+
+
+static int
+zpl_open(struct inode *ip, struct file *filp)
+{
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+
+       error = generic_file_open(ip, filp);
+       if (error)
+               return (error);
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_open(ip, filp->f_mode, filp->f_flags, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_release(struct inode *ip, struct file *filp)
+{
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       if (ITOZ(ip)->z_atime_dirty)
+               zfs_mark_inode_dirty(ip);
+
+       crhold(cr);
+       error = -zfs_close(ip, filp->f_flags, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+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);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#if !defined(HAVE_VFS_ITERATE) && !defined(HAVE_VFS_ITERATE_SHARED)
+static int
+zpl_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
+       int error;
+
+       error = zpl_iterate(filp, &ctx);
+       filp->f_pos = ctx.pos;
+
+       return (error);
+}
+#endif /* HAVE_VFS_ITERATE */
+
+#if defined(HAVE_FSYNC_WITH_DENTRY)
+/*
+ * Linux 2.6.x - 2.6.34 API,
+ * Through 2.6.34 the nfsd kernel server would pass a NULL 'file struct *'
+ * to the fops->fsync() hook.  For this reason, we must be careful not to
+ * use filp unconditionally.
+ */
+static int
+zpl_fsync(struct file *filp, struct dentry *dentry, int datasync)
+{
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_fsync(dentry->d_inode, datasync, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#ifdef HAVE_FILE_AIO_FSYNC
+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));
+}
+#endif
+
+#elif defined(HAVE_FSYNC_WITHOUT_DENTRY)
+/*
+ * Linux 2.6.35 - 3.0 API,
+ * As of 2.6.35 the dentry argument to the fops->fsync() hook was deemed
+ * redundant.  The dentry is still accessible via filp->f_path.dentry,
+ * and we are guaranteed that filp will never be NULL.
+ */
+static int
+zpl_fsync(struct file *filp, int datasync)
+{
+       struct inode *inode = filp->f_mapping->host;
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_fsync(inode, datasync, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#ifdef HAVE_FILE_AIO_FSYNC
+static int
+zpl_aio_fsync(struct kiocb *kiocb, int datasync)
+{
+       return (zpl_fsync(kiocb->ki_filp, datasync));
+}
+#endif
+
+#elif defined(HAVE_FSYNC_RANGE)
+/*
+ * Linux 3.1 - 3.x API,
+ * As of 3.1 the responsibility to call filemap_write_and_wait_range() has
+ * been pushed down in to the .fsync() vfs hook.  Additionally, the i_mutex
+ * lock is no longer held by the caller, for zfs we don't require the lock
+ * to be held so we don't acquire it.
+ */
+static int
+zpl_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
+{
+       struct inode *inode = filp->f_mapping->host;
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+
+       error = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (error)
+               return (error);
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_fsync(inode, datasync, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#ifdef HAVE_FILE_AIO_FSYNC
+static int
+zpl_aio_fsync(struct kiocb *kiocb, int datasync)
+{
+       return (zpl_fsync(kiocb->ki_filp, kiocb->ki_pos, -1, datasync));
+}
+#endif
+
+#else
+#error "Unsupported fops->fsync() implementation"
+#endif
+
+static ssize_t
+zpl_read_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
+    unsigned long nr_segs, loff_t *ppos, uio_seg_t segment, int flags,
+    cred_t *cr, size_t skip)
+{
+       ssize_t read;
+       uio_t uio;
+       int error;
+       fstrans_cookie_t cookie;
+
+       uio.uio_iov = iovp;
+       uio.uio_skip = skip;
+       uio.uio_resid = count;
+       uio.uio_iovcnt = nr_segs;
+       uio.uio_loffset = *ppos;
+       uio.uio_limit = MAXOFFSET_T;
+       uio.uio_segflg = segment;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_read(ip, &uio, flags, cr);
+       spl_fstrans_unmark(cookie);
+       if (error < 0)
+               return (error);
+
+       read = count - uio.uio_resid;
+       *ppos += read;
+       task_io_account_read(read);
+
+       return (read);
+}
+
+inline ssize_t
+zpl_read_common(struct inode *ip, const char *buf, size_t len, loff_t *ppos,
+    uio_seg_t segment, int flags, cred_t *cr)
+{
+       struct iovec iov;
+
+       iov.iov_base = (void *)buf;
+       iov.iov_len = len;
+
+       return (zpl_read_common_iovec(ip, &iov, len, 1, ppos, segment,
+           flags, cr, 0));
+}
+
+static ssize_t
+zpl_iter_read_common(struct kiocb *kiocb, const struct iovec *iovp,
+    unsigned long nr_segs, size_t count, uio_seg_t seg, size_t skip)
+{
+       cred_t *cr = CRED();
+       struct file *filp = kiocb->ki_filp;
+       ssize_t read;
+
+       crhold(cr);
+       read = zpl_read_common_iovec(filp->f_mapping->host, iovp, count,
+           nr_segs, &kiocb->ki_pos, seg, filp->f_flags, cr, skip);
+       crfree(cr);
+
+       file_accessed(filp);
+       return (read);
+}
+
+#if defined(HAVE_VFS_RW_ITERATE)
+static ssize_t
+zpl_iter_read(struct kiocb *kiocb, struct iov_iter *to)
+{
+       ssize_t ret;
+       uio_seg_t seg = UIO_USERSPACE;
+       if (to->type & ITER_KVEC)
+               seg = UIO_SYSSPACE;
+       if (to->type & ITER_BVEC)
+               seg = UIO_BVEC;
+       ret = zpl_iter_read_common(kiocb, to->iov, to->nr_segs,
+           iov_iter_count(to), seg, to->iov_offset);
+       if (ret > 0)
+               iov_iter_advance(to, ret);
+       return (ret);
+}
+#else
+static ssize_t
+zpl_aio_read(struct kiocb *kiocb, const struct iovec *iovp,
+    unsigned long nr_segs, loff_t pos)
+{
+       ssize_t ret;
+       size_t count;
+
+       ret = generic_segment_checks(iovp, &nr_segs, &count, VERIFY_WRITE);
+       if (ret)
+               return (ret);
+
+       return (zpl_iter_read_common(kiocb, iovp, nr_segs, count,
+           UIO_USERSPACE, 0));
+}
+#endif /* HAVE_VFS_RW_ITERATE */
+
+static ssize_t
+zpl_write_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
+    unsigned long nr_segs, loff_t *ppos, uio_seg_t segment, int flags,
+    cred_t *cr, size_t skip)
+{
+       ssize_t wrote;
+       uio_t uio;
+       int error;
+       fstrans_cookie_t cookie;
+
+       if (flags & O_APPEND)
+               *ppos = i_size_read(ip);
+
+       uio.uio_iov = iovp;
+       uio.uio_skip = skip;
+       uio.uio_resid = count;
+       uio.uio_iovcnt = nr_segs;
+       uio.uio_loffset = *ppos;
+       uio.uio_limit = MAXOFFSET_T;
+       uio.uio_segflg = segment;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_write(ip, &uio, flags, cr);
+       spl_fstrans_unmark(cookie);
+       if (error < 0)
+               return (error);
+
+       wrote = count - uio.uio_resid;
+       *ppos += wrote;
+       task_io_account_write(wrote);
+
+       return (wrote);
+}
+
+inline ssize_t
+zpl_write_common(struct inode *ip, const char *buf, size_t len, loff_t *ppos,
+    uio_seg_t segment, int flags, cred_t *cr)
+{
+       struct iovec iov;
+
+       iov.iov_base = (void *)buf;
+       iov.iov_len = len;
+
+       return (zpl_write_common_iovec(ip, &iov, len, 1, ppos, segment,
+           flags, cr, 0));
+}
+
+static ssize_t
+zpl_iter_write_common(struct kiocb *kiocb, const struct iovec *iovp,
+    unsigned long nr_segs, size_t count, uio_seg_t seg, size_t skip)
+{
+       cred_t *cr = CRED();
+       struct file *filp = kiocb->ki_filp;
+       ssize_t wrote;
+
+       crhold(cr);
+       wrote = zpl_write_common_iovec(filp->f_mapping->host, iovp, count,
+           nr_segs, &kiocb->ki_pos, seg, filp->f_flags, cr, skip);
+       crfree(cr);
+
+       return (wrote);
+}
+
+#if defined(HAVE_VFS_RW_ITERATE)
+static ssize_t
+zpl_iter_write(struct kiocb *kiocb, struct iov_iter *from)
+{
+       size_t count;
+       ssize_t ret;
+       uio_seg_t seg = UIO_USERSPACE;
+
+#ifndef HAVE_GENERIC_WRITE_CHECKS_KIOCB
+       struct file *file = kiocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *ip = mapping->host;
+       int isblk = S_ISBLK(ip->i_mode);
+
+       count = iov_iter_count(from);
+       ret = generic_write_checks(file, &kiocb->ki_pos, &count, isblk);
+       if (ret)
+               return (ret);
+#else
+       /*
+        * XXX - ideally this check should be in the same lock region with
+        * write operations, so that there's no TOCTTOU race when doing
+        * append and someone else grow the file.
+        */
+       ret = generic_write_checks(kiocb, from);
+       if (ret <= 0)
+               return (ret);
+       count = ret;
+#endif
+
+       if (from->type & ITER_KVEC)
+               seg = UIO_SYSSPACE;
+       if (from->type & ITER_BVEC)
+               seg = UIO_BVEC;
+
+       ret = zpl_iter_write_common(kiocb, from->iov, from->nr_segs,
+           count, seg, from->iov_offset);
+       if (ret > 0)
+               iov_iter_advance(from, ret);
+
+       return (ret);
+}
+#else
+static ssize_t
+zpl_aio_write(struct kiocb *kiocb, const struct iovec *iovp,
+    unsigned long nr_segs, loff_t pos)
+{
+       struct file *file = kiocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *ip = mapping->host;
+       int isblk = S_ISBLK(ip->i_mode);
+       size_t count;
+       ssize_t ret;
+
+       ret = generic_segment_checks(iovp, &nr_segs, &count, VERIFY_READ);
+       if (ret)
+               return (ret);
+
+       ret = generic_write_checks(file, &pos, &count, isblk);
+       if (ret)
+               return (ret);
+
+       return (zpl_iter_write_common(kiocb, iovp, nr_segs, count,
+           UIO_USERSPACE, 0));
+}
+#endif /* HAVE_VFS_RW_ITERATE */
+
+static loff_t
+zpl_llseek(struct file *filp, loff_t offset, int whence)
+{
+#if defined(SEEK_HOLE) && defined(SEEK_DATA)
+       fstrans_cookie_t cookie;
+
+       if (whence == SEEK_DATA || whence == SEEK_HOLE) {
+               struct inode *ip = filp->f_mapping->host;
+               loff_t maxbytes = ip->i_sb->s_maxbytes;
+               loff_t error;
+
+               spl_inode_lock_shared(ip);
+               cookie = spl_fstrans_mark();
+               error = -zfs_holey(ip, whence, &offset);
+               spl_fstrans_unmark(cookie);
+               if (error == 0)
+                       error = lseek_execute(filp, ip, offset, maxbytes);
+               spl_inode_unlock_shared(ip);
+
+               return (error);
+       }
+#endif /* SEEK_HOLE && SEEK_DATA */
+
+       return (generic_file_llseek(filp, offset, whence));
+}
+
+/*
+ * It's worth taking a moment to describe how mmap is implemented
+ * for zfs because it differs considerably from other Linux filesystems.
+ * However, this issue is handled the same way under OpenSolaris.
+ *
+ * The issue is that by design zfs bypasses the Linux page cache and
+ * leaves all caching up to the ARC.  This has been shown to work
+ * well for the common read(2)/write(2) case.  However, mmap(2)
+ * is problem because it relies on being tightly integrated with the
+ * page cache.  To handle this we cache mmap'ed files twice, once in
+ * the ARC and a second time in the page cache.  The code is careful
+ * to keep both copies synchronized.
+ *
+ * When a file with an mmap'ed region is written to using write(2)
+ * both the data in the ARC and existing pages in the page cache
+ * are updated.  For a read(2) data will be read first from the page
+ * cache then the ARC if needed.  Neither a write(2) or read(2) will
+ * will ever result in new pages being added to the page cache.
+ *
+ * New pages are added to the page cache only via .readpage() which
+ * is called when the vfs needs to read a page off disk to back the
+ * virtual memory region.  These pages may be modified without
+ * notifying the ARC and will be written out periodically via
+ * .writepage().  This will occur due to either a sync or the usual
+ * page aging behavior.  Note because a read(2) of a mmap'ed file
+ * will always check the page cache first even when the ARC is out
+ * of date correct data will still be returned.
+ *
+ * While this implementation ensures correct behavior it does have
+ * have some drawbacks.  The most obvious of which is that it
+ * increases the required memory footprint when access mmap'ed
+ * files.  It also adds additional complexity to the code keeping
+ * both caches synchronized.
+ *
+ * Longer term it may be possible to cleanly resolve this wart by
+ * mapping page cache pages directly on to the ARC buffers.  The
+ * Linux address space operations are flexible enough to allow
+ * selection of which pages back a particular index.  The trick
+ * would be working out the details of which subsystem is in
+ * charge, the ARC, the page cache, or both.  It may also prove
+ * helpful to move the ARC buffers to a scatter-gather lists
+ * rather than a vmalloc'ed region.
+ */
+static int
+zpl_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct inode *ip = filp->f_mapping->host;
+       znode_t *zp = ITOZ(ip);
+       int error;
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_map(ip, vma->vm_pgoff, (caddr_t *)vma->vm_start,
+           (size_t)(vma->vm_end - vma->vm_start), vma->vm_flags);
+       spl_fstrans_unmark(cookie);
+       if (error)
+               return (error);
+
+       error = generic_file_mmap(filp, vma);
+       if (error)
+               return (error);
+
+       mutex_enter(&zp->z_lock);
+       zp->z_is_mapped = 1;
+       mutex_exit(&zp->z_lock);
+
+       return (error);
+}
+
+/*
+ * Populate a page with data for the Linux page cache.  This function is
+ * only used to support mmap(2).  There will be an identical copy of the
+ * data in the ARC which is kept up to date via .write() and .writepage().
+ *
+ * Current this function relies on zpl_read_common() and the O_DIRECT
+ * flag to read in a page.  This works but the more correct way is to
+ * update zfs_fillpage() to be Linux friendly and use that interface.
+ */
+static int
+zpl_readpage(struct file *filp, struct page *pp)
+{
+       struct inode *ip;
+       struct page *pl[1];
+       int error = 0;
+       fstrans_cookie_t cookie;
+
+       ASSERT(PageLocked(pp));
+       ip = pp->mapping->host;
+       pl[0] = pp;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_getpage(ip, pl, 1);
+       spl_fstrans_unmark(cookie);
+
+       if (error) {
+               SetPageError(pp);
+               ClearPageUptodate(pp);
+       } else {
+               ClearPageError(pp);
+               SetPageUptodate(pp);
+               flush_dcache_page(pp);
+       }
+
+       unlock_page(pp);
+       return (error);
+}
+
+/*
+ * Populate a set of pages with data for the Linux page cache.  This
+ * function will only be called for read ahead and never for demand
+ * paging.  For simplicity, the code relies on read_cache_pages() to
+ * correctly lock each page for IO and call zpl_readpage().
+ */
+static int
+zpl_readpages(struct file *filp, struct address_space *mapping,
+       struct list_head *pages, unsigned nr_pages)
+{
+       return (read_cache_pages(mapping, pages,
+           (filler_t *)zpl_readpage, filp));
+}
+
+int
+zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
+{
+       struct address_space *mapping = data;
+       fstrans_cookie_t cookie;
+
+       ASSERT(PageLocked(pp));
+       ASSERT(!PageWriteback(pp));
+
+       cookie = spl_fstrans_mark();
+       (void) zfs_putpage(mapping->host, pp, wbc);
+       spl_fstrans_unmark(cookie);
+
+       return (0);
+}
+
+static int
+zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
+{
+       znode_t         *zp = ITOZ(mapping->host);
+       zfs_sb_t        *zsb = ITOZSB(mapping->host);
+       enum writeback_sync_modes sync_mode;
+       int result;
+
+       ZFS_ENTER(zsb);
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               wbc->sync_mode = WB_SYNC_ALL;
+       ZFS_EXIT(zsb);
+       sync_mode = wbc->sync_mode;
+
+       /*
+        * We don't want to run write_cache_pages() in SYNC mode here, because
+        * that would make putpage() wait for a single page to be committed to
+        * disk every single time, resulting in atrocious performance. Instead
+        * we run it once in non-SYNC mode so that the ZIL gets all the data,
+        * and then we commit it all in one go.
+        */
+       wbc->sync_mode = WB_SYNC_NONE;
+       result = write_cache_pages(mapping, wbc, zpl_putpage, mapping);
+       if (sync_mode != wbc->sync_mode) {
+               ZFS_ENTER(zsb);
+               ZFS_VERIFY_ZP(zp);
+               if (zsb->z_log != NULL)
+                       zil_commit(zsb->z_log, zp->z_id);
+               ZFS_EXIT(zsb);
+
+               /*
+                * We need to call write_cache_pages() again (we can't just
+                * return after the commit) because the previous call in
+                * non-SYNC mode does not guarantee that we got all the dirty
+                * pages (see the implementation of write_cache_pages() for
+                * details). That being said, this is a no-op in most cases.
+                */
+               wbc->sync_mode = sync_mode;
+               result = write_cache_pages(mapping, wbc, zpl_putpage, mapping);
+       }
+       return (result);
+}
+
+/*
+ * Write out dirty pages to the ARC, this function is only required to
+ * support mmap(2).  Mapped pages may be dirtied by memory operations
+ * which never call .write().  These dirty pages are kept in sync with
+ * the ARC buffers via this hook.
+ */
+static int
+zpl_writepage(struct page *pp, struct writeback_control *wbc)
+{
+       if (ITOZSB(pp->mapping->host)->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               wbc->sync_mode = WB_SYNC_ALL;
+
+       return (zpl_putpage(pp, wbc, pp->mapping));
+}
+
+/*
+ * The only flag combination which matches the behavior of zfs_space()
+ * is FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE.  The FALLOC_FL_PUNCH_HOLE
+ * flag was introduced in the 2.6.38 kernel.
+ */
+#if defined(HAVE_FILE_FALLOCATE) || defined(HAVE_INODE_FALLOCATE)
+long
+zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
+{
+       int error = -EOPNOTSUPP;
+
+#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
+       cred_t *cr = CRED();
+       flock64_t bf;
+       loff_t olen;
+       fstrans_cookie_t cookie;
+
+       if (mode != (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+               return (error);
+
+       if (offset < 0 || len <= 0)
+               return (-EINVAL);
+
+       spl_inode_lock(ip);
+       olen = i_size_read(ip);
+
+       if (offset > olen) {
+               spl_inode_unlock(ip);
+               return (0);
+       }
+       if (offset + len > olen)
+               len = olen - offset;
+       bf.l_type = F_WRLCK;
+       bf.l_whence = 0;
+       bf.l_start = offset;
+       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);
+       spl_inode_unlock(ip);
+
+       crfree(cr);
+#endif /* defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE) */
+
+       ASSERT3S(error, <=, 0);
+       return (error);
+}
+#endif /* defined(HAVE_FILE_FALLOCATE) || defined(HAVE_INODE_FALLOCATE) */
+
+#ifdef HAVE_FILE_FALLOCATE
+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,
+           mode, offset, len);
+}
+#endif /* HAVE_FILE_FALLOCATE */
+
+/*
+ * Map zfs file z_pflags (xvattr_t) to linux file attributes. Only file
+ * attributes common to both Linux and Solaris are mapped.
+ */
+static int
+zpl_ioctl_getflags(struct file *filp, void __user *arg)
+{
+       struct inode *ip = file_inode(filp);
+       unsigned int ioctl_flags = 0;
+       uint64_t zfs_flags = ITOZ(ip)->z_pflags;
+       int error;
+
+       if (zfs_flags & ZFS_IMMUTABLE)
+               ioctl_flags |= FS_IMMUTABLE_FL;
+
+       if (zfs_flags & ZFS_APPENDONLY)
+               ioctl_flags |= FS_APPEND_FL;
+
+       if (zfs_flags & ZFS_NODUMP)
+               ioctl_flags |= FS_NODUMP_FL;
+
+       ioctl_flags &= FS_FL_USER_VISIBLE;
+
+       error = copy_to_user(arg, &ioctl_flags, sizeof (ioctl_flags));
+
+       return (error);
+}
+
+/*
+ * fchange() is a helper macro to detect if we have been asked to change a
+ * flag. This is ugly, but the requirement that we do this is a consequence of
+ * how the Linux file attribute interface was designed. Another consequence is
+ * that concurrent modification of files suffers from a TOCTOU race. Neither
+ * are things we can fix without modifying the kernel-userland interface, which
+ * is outside of our jurisdiction.
+ */
+
+#define        fchange(f0, f1, b0, b1) (!((f0) & (b0)) != !((f1) & (b1)))
+
+static int
+zpl_ioctl_setflags(struct file *filp, void __user *arg)
+{
+       struct inode    *ip = file_inode(filp);
+       uint64_t        zfs_flags = ITOZ(ip)->z_pflags;
+       unsigned int    ioctl_flags;
+       cred_t          *cr = CRED();
+       xvattr_t        xva;
+       xoptattr_t      *xoap;
+       int             error;
+       fstrans_cookie_t cookie;
+
+       if (copy_from_user(&ioctl_flags, arg, sizeof (ioctl_flags)))
+               return (-EFAULT);
+
+       if ((ioctl_flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL)))
+               return (-EOPNOTSUPP);
+
+       if ((ioctl_flags & ~(FS_FL_USER_MODIFIABLE)))
+               return (-EACCES);
+
+       if ((fchange(ioctl_flags, zfs_flags, FS_IMMUTABLE_FL, ZFS_IMMUTABLE) ||
+           fchange(ioctl_flags, zfs_flags, FS_APPEND_FL, ZFS_APPENDONLY)) &&
+           !capable(CAP_LINUX_IMMUTABLE))
+               return (-EACCES);
+
+       if (!zpl_inode_owner_or_capable(ip))
+               return (-EACCES);
+
+       xva_init(&xva);
+       xoap = xva_getxoptattr(&xva);
+
+       XVA_SET_REQ(&xva, XAT_IMMUTABLE);
+       if (ioctl_flags & FS_IMMUTABLE_FL)
+               xoap->xoa_immutable = B_TRUE;
+
+       XVA_SET_REQ(&xva, XAT_APPENDONLY);
+       if (ioctl_flags & FS_APPEND_FL)
+               xoap->xoa_appendonly = B_TRUE;
+
+       XVA_SET_REQ(&xva, XAT_NODUMP);
+       if (ioctl_flags & FS_NODUMP_FL)
+               xoap->xoa_nodump = B_TRUE;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_setattr(ip, (vattr_t *)&xva, 0, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       return (error);
+}
+
+static long
+zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case FS_IOC_GETFLAGS:
+               return (zpl_ioctl_getflags(filp, (void *)arg));
+       case FS_IOC_SETFLAGS:
+               return (zpl_ioctl_setflags(filp, (void *)arg));
+       default:
+               return (-ENOTTY);
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static long
+zpl_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case FS_IOC32_GETFLAGS:
+               cmd = FS_IOC_GETFLAGS;
+               break;
+       case FS_IOC32_SETFLAGS:
+               cmd = FS_IOC_SETFLAGS;
+               break;
+       default:
+               return (-ENOTTY);
+       }
+       return (zpl_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)));
+}
+#endif /* CONFIG_COMPAT */
+
+
+const struct address_space_operations zpl_address_space_operations = {
+       .readpages      = zpl_readpages,
+       .readpage       = zpl_readpage,
+       .writepage      = zpl_writepage,
+       .writepages     = zpl_writepages,
+};
+
+const struct file_operations zpl_file_operations = {
+       .open           = zpl_open,
+       .release        = zpl_release,
+       .llseek         = zpl_llseek,
+#ifdef HAVE_VFS_RW_ITERATE
+       .read_iter      = zpl_iter_read,
+       .write_iter     = zpl_iter_write,
+#else
+       .aio_read       = zpl_aio_read,
+       .aio_write      = zpl_aio_write,
+#endif
+       .mmap           = zpl_mmap,
+       .fsync          = zpl_fsync,
+#ifdef HAVE_FILE_AIO_FSYNC
+       .aio_fsync      = zpl_aio_fsync,
+#endif
+#ifdef HAVE_FILE_FALLOCATE
+       .fallocate      = zpl_fallocate,
+#endif /* HAVE_FILE_FALLOCATE */
+       .unlocked_ioctl = zpl_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = zpl_compat_ioctl,
+#endif
+};
+
+const struct file_operations zpl_dir_file_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+#ifdef HAVE_VFS_ITERATE_SHARED
+       .iterate_shared = zpl_iterate,
+#elif defined(HAVE_VFS_ITERATE)
+       .iterate        = zpl_iterate,
+#else
+       .readdir        = zpl_readdir,
+#endif
+       .fsync          = zpl_fsync,
+       .unlocked_ioctl = zpl_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = zpl_compat_ioctl,
+#endif
+};
diff --git a/zfs/module/zfs/zpl_inode.c b/zfs/module/zfs/zpl_inode.c
new file mode 100644 (file)
index 0000000..1714aa2
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, Lawrence Livermore National Security, LLC.
+ * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
+#include <sys/dmu_objset.h>
+#include <sys/vfs.h>
+#include <sys/zpl.h>
+#include <sys/file.h>
+
+
+static struct dentry *
+#ifdef HAVE_LOOKUP_NAMEIDATA
+zpl_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+#else
+zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+#endif
+{
+       cred_t *cr = CRED();
+       struct inode *ip;
+       int error;
+       fstrans_cookie_t cookie;
+       pathname_t *ppn = NULL;
+       pathname_t pn;
+       int zfs_flags = 0;
+       zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
+
+       if (dlen(dentry) > ZFS_MAXNAMELEN)
+               return (ERR_PTR(-ENAMETOOLONG));
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+
+       /* 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);
+               ppn = &pn;
+       }
+
+       error = -zfs_lookup(dir, dname(dentry), &ip, zfs_flags, cr, NULL, ppn);
+       spl_fstrans_unmark(cookie);
+       ASSERT3S(error, <=, 0);
+       crfree(cr);
+
+       spin_lock(&dentry->d_lock);
+       dentry->d_time = jiffies;
+#ifndef HAVE_S_D_OP
+       d_set_d_op(dentry, &zpl_dentry_operations);
+#endif /* HAVE_S_D_OP */
+       spin_unlock(&dentry->d_lock);
+
+       if (error) {
+               /*
+                * If we have a case sensitive fs, we do not want to
+                * insert negative entries, so return NULL for ENOENT.
+                * Fall through if the error is not ENOENT. Also free memory.
+                */
+               if (ppn) {
+                       kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+                       if (error == -ENOENT)
+                               return (NULL);
+               }
+
+               if (error == -ENOENT)
+                       return (d_splice_alias(NULL, dentry));
+               else
+                       return (ERR_PTR(error));
+       }
+
+       /*
+        * If we are case insensitive, call the correct function
+        * to install the name.
+        */
+       if (ppn) {
+               struct dentry *new_dentry;
+               struct qstr ci_name;
+
+               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);
+               }
+               kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+               return (new_dentry);
+       } else {
+               return (d_splice_alias(ip, dentry));
+       }
+}
+
+void
+zpl_vap_init(vattr_t *vap, struct inode *dir, zpl_umode_t mode, cred_t *cr)
+{
+       vap->va_mask = ATTR_MODE;
+       vap->va_mode = mode;
+       vap->va_uid = crgetfsuid(cr);
+
+       if (dir && dir->i_mode & S_ISGID) {
+               vap->va_gid = KGID_TO_SGID(dir->i_gid);
+               if (S_ISDIR(mode))
+                       vap->va_mode |= S_ISGID;
+       } else {
+               vap->va_gid = crgetfsgid(cr);
+       }
+}
+
+static int
+#ifdef HAVE_CREATE_NAMEIDATA
+zpl_create(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
+    struct nameidata *nd)
+#else
+zpl_create(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
+    bool flag)
+#endif
+{
+       cred_t *cr = CRED();
+       struct inode *ip;
+       vattr_t *vap;
+       int error;
+       fstrans_cookie_t cookie;
+
+       crhold(cr);
+       vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+       zpl_vap_init(vap, dir, mode, cr);
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_create(dir, dname(dentry), vap, 0, mode, &ip, cr, 0, NULL);
+       if (error == 0) {
+               d_instantiate(dentry, ip);
+
+               error = zpl_xattr_security_init(ip, dir, &dentry->d_name);
+               if (error == 0)
+                       error = zpl_init_acl(ip, dir);
+
+               if (error)
+                       (void) zfs_remove(dir, dname(dentry), cr);
+       }
+
+       spl_fstrans_unmark(cookie);
+       kmem_free(vap, sizeof (vattr_t));
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_mknod(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
+    dev_t rdev)
+{
+       cred_t *cr = CRED();
+       struct inode *ip;
+       vattr_t *vap;
+       int error;
+       fstrans_cookie_t cookie;
+
+       /*
+        * We currently expect Linux to supply rdev=0 for all sockets
+        * and fifos, but we want to know if this behavior ever changes.
+        */
+       if (S_ISSOCK(mode) || S_ISFIFO(mode))
+               ASSERT(rdev == 0);
+
+       crhold(cr);
+       vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+       zpl_vap_init(vap, dir, mode, cr);
+       vap->va_rdev = rdev;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_create(dir, dname(dentry), vap, 0, mode, &ip, cr, 0, NULL);
+       if (error == 0) {
+               d_instantiate(dentry, ip);
+
+               error = zpl_xattr_security_init(ip, dir, &dentry->d_name);
+               if (error == 0)
+                       error = zpl_init_acl(ip, dir);
+
+               if (error)
+                       (void) zfs_remove(dir, dname(dentry), cr);
+       }
+
+       spl_fstrans_unmark(cookie);
+       kmem_free(vap, sizeof (vattr_t));
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_unlink(struct inode *dir, struct dentry *dentry)
+{
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+       zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_remove(dir, dname(dentry), cr);
+
+       /*
+        * For a CI FS we must invalidate the dentry to prevent the
+        * creation of negative entries.
+        */
+       if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
+               d_invalidate(dentry);
+
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_mkdir(struct inode *dir, struct dentry *dentry, zpl_umode_t mode)
+{
+       cred_t *cr = CRED();
+       vattr_t *vap;
+       struct inode *ip;
+       int error;
+       fstrans_cookie_t cookie;
+
+       crhold(cr);
+       vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+       zpl_vap_init(vap, dir, mode | S_IFDIR, cr);
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_mkdir(dir, dname(dentry), vap, &ip, cr, 0, NULL);
+       if (error == 0) {
+               d_instantiate(dentry, ip);
+
+               error = zpl_xattr_security_init(ip, dir, &dentry->d_name);
+               if (error == 0)
+                       error = zpl_init_acl(ip, dir);
+
+               if (error)
+                       (void) zfs_rmdir(dir, dname(dentry), NULL, cr, 0);
+       }
+
+       spl_fstrans_unmark(cookie);
+       kmem_free(vap, sizeof (vattr_t));
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_rmdir(struct inode * dir, struct dentry *dentry)
+{
+       cred_t *cr = CRED();
+       int error;
+       fstrans_cookie_t cookie;
+       zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_rmdir(dir, dname(dentry), NULL, cr, 0);
+
+       /*
+        * For a CI FS we must invalidate the dentry to prevent the
+        * creation of negative entries.
+        */
+       if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
+               d_invalidate(dentry);
+
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+       int error;
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_getattr_fast(dentry->d_inode, stat);
+       spl_fstrans_unmark(cookie);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_setattr(struct dentry *dentry, struct iattr *ia)
+{
+       struct inode *ip = dentry->d_inode;
+       cred_t *cr = CRED();
+       vattr_t *vap;
+       int error;
+       fstrans_cookie_t cookie;
+
+       error = setattr_prepare(dentry, ia);
+       if (error)
+               return (error);
+
+       crhold(cr);
+       vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+       vap->va_mask = ia->ia_valid & ATTR_IATTR_MASK;
+       vap->va_mode = ia->ia_mode;
+       vap->va_uid = KUID_TO_SUID(ia->ia_uid);
+       vap->va_gid = KGID_TO_SGID(ia->ia_gid);
+       vap->va_size = ia->ia_size;
+       vap->va_atime = ia->ia_atime;
+       vap->va_mtime = ia->ia_mtime;
+       vap->va_ctime = ia->ia_ctime;
+
+       if (vap->va_mask & ATTR_ATIME)
+               ip->i_atime = ia->ia_atime;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_setattr(ip, vap, 0, cr);
+       if (!error && (ia->ia_valid & ATTR_MODE))
+               error = zpl_chmod_acl(ip);
+
+       spl_fstrans_unmark(cookie);
+       kmem_free(vap, sizeof (vattr_t));
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+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);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       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)
+{
+       cred_t *cr = CRED();
+       vattr_t *vap;
+       struct inode *ip;
+       int error;
+       fstrans_cookie_t cookie;
+
+       crhold(cr);
+       vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+       zpl_vap_init(vap, dir, S_IFLNK | S_IRWXUGO, cr);
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_symlink(dir, dname(dentry), vap, (char *)name, &ip, cr, 0);
+       if (error == 0) {
+               d_instantiate(dentry, ip);
+
+               error = zpl_xattr_security_init(ip, dir, &dentry->d_name);
+               if (error)
+                       (void) zfs_remove(dir, dname(dentry), cr);
+       }
+
+       spl_fstrans_unmark(cookie);
+       kmem_free(vap, sizeof (vattr_t));
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#if defined(HAVE_PUT_LINK_COOKIE)
+static void
+zpl_put_link(struct inode *unused, void *cookie)
+{
+       kmem_free(cookie, MAXPATHLEN);
+}
+#elif defined(HAVE_PUT_LINK_NAMEIDATA)
+static void
+zpl_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+       const char *link = nd_get_link(nd);
+
+       if (!IS_ERR(link))
+               kmem_free(link, MAXPATHLEN);
+}
+#elif defined(HAVE_PUT_LINK_DELAYED)
+static void
+zpl_put_link(void *ptr)
+{
+       kmem_free(ptr, MAXPATHLEN);
+}
+#endif
+
+static int
+zpl_get_link_common(struct dentry *dentry, struct inode *ip, char **link)
+{
+       fstrans_cookie_t cookie;
+       cred_t *cr = CRED();
+       struct iovec iov;
+       uio_t uio;
+       int error;
+
+       crhold(cr);
+       *link = NULL;
+       iov.iov_len = MAXPATHLEN;
+       iov.iov_base = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+       uio.uio_iov = &iov;
+       uio.uio_iovcnt = 1;
+       uio.uio_skip = 0;
+       uio.uio_resid = (MAXPATHLEN - 1);
+       uio.uio_segflg = UIO_SYSSPACE;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_readlink(ip, &uio, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       if (error)
+               kmem_free(iov.iov_base, MAXPATHLEN);
+       else
+               *link = iov.iov_base;
+
+       return (error);
+}
+
+#if defined(HAVE_GET_LINK_DELAYED)
+const char *
+zpl_get_link(struct dentry *dentry, struct inode *inode,
+    struct delayed_call *done)
+{
+       char *link = NULL;
+       int error;
+
+       if (!dentry)
+               return (ERR_PTR(-ECHILD));
+
+       error = zpl_get_link_common(dentry, inode, &link);
+       if (error)
+               return (ERR_PTR(error));
+
+       set_delayed_call(done, zpl_put_link, link);
+
+       return (link);
+}
+#elif defined(HAVE_GET_LINK_COOKIE)
+const char *
+zpl_get_link(struct dentry *dentry, struct inode *inode, void **cookie)
+{
+       char *link = NULL;
+       int error;
+
+       if (!dentry)
+               return (ERR_PTR(-ECHILD));
+
+       error = zpl_get_link_common(dentry, inode, &link);
+       if (error)
+               return (ERR_PTR(error));
+
+       return (*cookie = link);
+}
+#elif defined(HAVE_FOLLOW_LINK_COOKIE)
+const char *
+zpl_follow_link(struct dentry *dentry, void **cookie)
+{
+       char *link = NULL;
+       int error;
+
+       error = zpl_get_link_common(dentry, dentry->d_inode, &link);
+       if (error)
+               return (ERR_PTR(error));
+
+       return (*cookie = link);
+}
+#elif defined(HAVE_FOLLOW_LINK_NAMEIDATA)
+static void *
+zpl_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       char *link = NULL;
+       int error;
+
+       error = zpl_get_link_common(dentry, dentry->d_inode, &link);
+       if (error)
+               nd_set_link(nd, ERR_PTR(error));
+       else
+               nd_set_link(nd, link);
+
+       return (NULL);
+}
+#endif
+
+static int
+zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
+{
+       cred_t *cr = CRED();
+       struct inode *ip = old_dentry->d_inode;
+       int error;
+       fstrans_cookie_t cookie;
+
+       if (ip->i_nlink >= ZFS_LINK_MAX)
+               return (-EMLINK);
+
+       crhold(cr);
+       ip->i_ctime = CURRENT_TIME_SEC;
+       igrab(ip); /* Use ihold() if available */
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_link(dir, ip, dname(dentry), cr);
+       if (error) {
+               iput(ip);
+               goto out;
+       }
+
+       d_instantiate(dentry, ip);
+out:
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#ifdef HAVE_INODE_TRUNCATE_RANGE
+static void
+zpl_truncate_range(struct inode *ip, loff_t start, loff_t end)
+{
+       cred_t *cr = CRED();
+       flock64_t bf;
+       fstrans_cookie_t cookie;
+
+       ASSERT3S(start, <=, end);
+
+       /*
+        * zfs_freesp() will interpret (len == 0) as meaning "truncate until
+        * the end of the file". We don't want that.
+        */
+       if (start == end)
+               return;
+
+       crhold(cr);
+
+       bf.l_type = F_WRLCK;
+       bf.l_whence = 0;
+       bf.l_start = start;
+       bf.l_len = end - start;
+       bf.l_pid = 0;
+       cookie = spl_fstrans_mark();
+       zfs_space(ip, F_FREESP, &bf, FWRITE, start, cr);
+       spl_fstrans_unmark(cookie);
+
+       crfree(cr);
+}
+#endif /* HAVE_INODE_TRUNCATE_RANGE */
+
+#ifdef HAVE_INODE_FALLOCATE
+static long
+zpl_fallocate(struct inode *ip, int mode, loff_t offset, loff_t len)
+{
+       return (zpl_fallocate_common(ip, mode, offset, len));
+}
+#endif /* HAVE_INODE_FALLOCATE */
+
+static int
+#ifdef HAVE_D_REVALIDATE_NAMEIDATA
+zpl_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       unsigned int flags = (nd ? nd->flags : 0);
+#else
+zpl_revalidate(struct dentry *dentry, unsigned int flags)
+{
+#endif /* HAVE_D_REVALIDATE_NAMEIDATA */
+       zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
+       int error;
+
+       if (flags & LOOKUP_RCU)
+               return (-ECHILD);
+
+       /*
+        * Automounted snapshots rely on periodic dentry revalidation
+        * to defer snapshots from being automatically unmounted.
+        */
+       if (zsb->z_issnap) {
+               if (time_after(jiffies, zsb->z_snap_defer_time +
+                   MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
+                       zsb->z_snap_defer_time = jiffies;
+                       zfsctl_snapshot_unmount_delay(zsb->z_os->os_spa,
+                           dmu_objset_id(zsb->z_os), zfs_expire_snapshot);
+               }
+       }
+
+       /*
+        * After a rollback negative dentries created before the rollback
+        * time must be invalidated.  Otherwise they can obscure files which
+        * are only present in the rolled back dataset.
+        */
+       if (dentry->d_inode == NULL) {
+               spin_lock(&dentry->d_lock);
+               error = time_before(dentry->d_time, zsb->z_rollback_time);
+               spin_unlock(&dentry->d_lock);
+
+               if (error)
+                       return (0);
+       }
+
+       /*
+        * The dentry may reference a stale inode if a mounted file system
+        * was rolled back to a point in time where the object didn't exist.
+        */
+       if (dentry->d_inode && ITOZ(dentry->d_inode)->z_is_stale)
+               return (0);
+
+       return (1);
+}
+
+const struct inode_operations zpl_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,
+#ifdef HAVE_INODE_TRUNCATE_RANGE
+       .truncate_range = zpl_truncate_range,
+#endif /* HAVE_INODE_TRUNCATE_RANGE */
+#ifdef HAVE_INODE_FALLOCATE
+       .fallocate      = zpl_fallocate,
+#endif /* HAVE_INODE_FALLOCATE */
+#if defined(CONFIG_FS_POSIX_ACL)
+#if defined(HAVE_SET_ACL)
+       .set_acl        = zpl_set_acl,
+#endif
+#if defined(HAVE_GET_ACL)
+       .get_acl        = zpl_get_acl,
+#elif defined(HAVE_CHECK_ACL)
+       .check_acl      = zpl_check_acl,
+#elif defined(HAVE_PERMISSION)
+       .permission     = zpl_permission,
+#endif /* HAVE_GET_ACL | HAVE_CHECK_ACL | HAVE_PERMISSION */
+#endif /* CONFIG_FS_POSIX_ACL */
+};
+
+const struct inode_operations zpl_dir_inode_operations = {
+       .create         = zpl_create,
+       .lookup         = zpl_lookup,
+       .link           = zpl_link,
+       .unlink         = zpl_unlink,
+       .symlink        = zpl_symlink,
+       .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_SET_ACL)
+       .set_acl        = zpl_set_acl,
+#endif
+#if defined(HAVE_GET_ACL)
+       .get_acl        = zpl_get_acl,
+#elif defined(HAVE_CHECK_ACL)
+       .check_acl      = zpl_check_acl,
+#elif defined(HAVE_PERMISSION)
+       .permission     = zpl_permission,
+#endif /* HAVE_GET_ACL | HAVE_CHECK_ACL | HAVE_PERMISSION */
+#endif /* CONFIG_FS_POSIX_ACL */
+};
+
+const struct inode_operations zpl_symlink_inode_operations = {
+#ifdef HAVE_GENERIC_READLINK
+       .readlink       = generic_readlink,
+#endif
+#if defined(HAVE_GET_LINK_DELAYED) || defined(HAVE_GET_LINK_COOKIE)
+       .get_link       = zpl_get_link,
+#elif defined(HAVE_FOLLOW_LINK_COOKIE) || defined(HAVE_FOLLOW_LINK_NAMEIDATA)
+       .follow_link    = zpl_follow_link,
+#endif
+#if defined(HAVE_PUT_LINK_COOKIE) || defined(HAVE_PUT_LINK_NAMEIDATA)
+       .put_link       = zpl_put_link,
+#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_SET_ACL)
+       .set_acl        = zpl_set_acl,
+#endif
+#if defined(HAVE_GET_ACL)
+       .get_acl        = zpl_get_acl,
+#elif defined(HAVE_CHECK_ACL)
+       .check_acl      = zpl_check_acl,
+#elif defined(HAVE_PERMISSION)
+       .permission     = zpl_permission,
+#endif /* HAVE_GET_ACL | HAVE_CHECK_ACL | HAVE_PERMISSION */
+#endif /* CONFIG_FS_POSIX_ACL */
+};
+
+dentry_operations_t zpl_dentry_operations = {
+       .d_revalidate   = zpl_revalidate,
+};
diff --git a/zfs/module/zfs/zpl_super.c b/zfs/module/zfs/zpl_super.c
new file mode 100644 (file)
index 0000000..91c36c9
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, Lawrence Livermore National Security, LLC.
+ */
+
+
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zpl.h>
+
+
+static struct inode *
+zpl_inode_alloc(struct super_block *sb)
+{
+       struct inode *ip;
+
+       VERIFY3S(zfs_inode_alloc(sb, &ip), ==, 0);
+       ip->i_version = 1;
+
+       return (ip);
+}
+
+static void
+zpl_inode_destroy(struct inode *ip)
+{
+       ASSERT(atomic_read(&ip->i_count) == 0);
+       zfs_inode_destroy(ip);
+}
+
+/*
+ * Called from __mark_inode_dirty() to reflect that something in the
+ * inode has changed.  We use it to ensure the znode system attributes
+ * are always strictly update to date with respect to the inode.
+ */
+#ifdef HAVE_DIRTY_INODE_WITH_FLAGS
+static void
+zpl_dirty_inode(struct inode *ip, int flags)
+{
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       zfs_dirty_inode(ip, flags);
+       spl_fstrans_unmark(cookie);
+}
+#else
+static void
+zpl_dirty_inode(struct inode *ip)
+{
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       zfs_dirty_inode(ip, 0);
+       spl_fstrans_unmark(cookie);
+}
+#endif /* HAVE_DIRTY_INODE_WITH_FLAGS */
+
+/*
+ * When ->drop_inode() is called its return value indicates if the
+ * inode should be evicted from the inode cache.  If the inode is
+ * unhashed and has no links the default policy is to evict it
+ * immediately.
+ *
+ * Prior to 2.6.36 this eviction was accomplished by the vfs calling
+ * ->delete_inode().  It was ->delete_inode()'s responsibility to
+ * truncate the inode pages and call clear_inode().  The call to
+ * clear_inode() synchronously invalidates all the buffers and
+ * calls ->clear_inode().  It was ->clear_inode()'s responsibility
+ * to cleanup and filesystem specific data before freeing the inode.
+ *
+ * This elaborate mechanism was replaced by ->evict_inode() which
+ * does the job of both ->delete_inode() and ->clear_inode().  It
+ * will be called exactly once, and when it returns the inode must
+ * be in a state where it can simply be freed.i
+ *
+ * The ->evict_inode() callback must minimally truncate the inode pages,
+ * and call clear_inode().  For 2.6.35 and later kernels this will
+ * simply update the inode state, with the sync occurring before the
+ * truncate in evict().  For earlier kernels clear_inode() maps to
+ * end_writeback() which is responsible for completing all outstanding
+ * write back.  In either case, once this is done it is safe to cleanup
+ * any remaining inode specific data via zfs_inactive().
+ * remaining filesystem specific data.
+ */
+#ifdef HAVE_EVICT_INODE
+static void
+zpl_evict_inode(struct inode *ip)
+{
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       truncate_setsize(ip, 0);
+       clear_inode(ip);
+       zfs_inactive(ip);
+       spl_fstrans_unmark(cookie);
+}
+
+#else
+
+static void
+zpl_drop_inode(struct inode *ip)
+{
+       generic_delete_inode(ip);
+}
+
+static void
+zpl_clear_inode(struct inode *ip)
+{
+       fstrans_cookie_t cookie;
+
+       cookie = spl_fstrans_mark();
+       zfs_inactive(ip);
+       spl_fstrans_unmark(cookie);
+}
+
+static void
+zpl_inode_delete(struct inode *ip)
+{
+       truncate_setsize(ip, 0);
+       clear_inode(ip);
+}
+#endif /* HAVE_EVICT_INODE */
+
+static void
+zpl_put_super(struct super_block *sb)
+{
+       fstrans_cookie_t cookie;
+       int error;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_umount(sb);
+       spl_fstrans_unmark(cookie);
+       ASSERT3S(error, <=, 0);
+}
+
+static int
+zpl_sync_fs(struct super_block *sb, int wait)
+{
+       fstrans_cookie_t cookie;
+       cred_t *cr = CRED();
+       int error;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       error = -zfs_sync(sb, wait, cr);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_statfs(struct dentry *dentry, struct kstatfs *statp)
+{
+       fstrans_cookie_t cookie;
+       int error;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_statvfs(dentry, statp);
+       spl_fstrans_unmark(cookie);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+enum {
+       TOKEN_RO,
+       TOKEN_RW,
+       TOKEN_SETUID,
+       TOKEN_NOSETUID,
+       TOKEN_EXEC,
+       TOKEN_NOEXEC,
+       TOKEN_DEVICES,
+       TOKEN_NODEVICES,
+       TOKEN_DIRXATTR,
+       TOKEN_SAXATTR,
+       TOKEN_XATTR,
+       TOKEN_NOXATTR,
+       TOKEN_ATIME,
+       TOKEN_NOATIME,
+       TOKEN_RELATIME,
+       TOKEN_NORELATIME,
+       TOKEN_NBMAND,
+       TOKEN_NONBMAND,
+       TOKEN_MNTPOINT,
+       TOKEN_LAST,
+};
+
+static const match_table_t zpl_tokens = {
+       { TOKEN_RO,             MNTOPT_RO },
+       { TOKEN_RW,             MNTOPT_RW },
+       { TOKEN_SETUID,         MNTOPT_SETUID },
+       { TOKEN_NOSETUID,       MNTOPT_NOSETUID },
+       { TOKEN_EXEC,           MNTOPT_EXEC },
+       { TOKEN_NOEXEC,         MNTOPT_NOEXEC },
+       { TOKEN_DEVICES,        MNTOPT_DEVICES },
+       { TOKEN_NODEVICES,      MNTOPT_NODEVICES },
+       { TOKEN_DIRXATTR,       MNTOPT_DIRXATTR },
+       { TOKEN_SAXATTR,        MNTOPT_SAXATTR },
+       { TOKEN_XATTR,          MNTOPT_XATTR },
+       { TOKEN_NOXATTR,        MNTOPT_NOXATTR },
+       { TOKEN_ATIME,          MNTOPT_ATIME },
+       { TOKEN_NOATIME,        MNTOPT_NOATIME },
+       { TOKEN_RELATIME,       MNTOPT_RELATIME },
+       { TOKEN_NORELATIME,     MNTOPT_NORELATIME },
+       { TOKEN_NBMAND,         MNTOPT_NBMAND },
+       { TOKEN_NONBMAND,       MNTOPT_NONBMAND },
+       { TOKEN_MNTPOINT,       MNTOPT_MNTPOINT "=%s" },
+       { TOKEN_LAST,           NULL },
+};
+
+static int
+zpl_parse_option(char *option, int token, substring_t *args, zfs_mntopts_t *zmo)
+{
+       switch (token) {
+       case TOKEN_RO:
+               zmo->z_readonly = B_TRUE;
+               zmo->z_do_readonly = B_TRUE;
+               break;
+       case TOKEN_RW:
+               zmo->z_readonly = B_FALSE;
+               zmo->z_do_readonly = B_TRUE;
+               break;
+       case TOKEN_SETUID:
+               zmo->z_setuid = B_TRUE;
+               zmo->z_do_setuid = B_TRUE;
+               break;
+       case TOKEN_NOSETUID:
+               zmo->z_setuid = B_FALSE;
+               zmo->z_do_setuid = B_TRUE;
+               break;
+       case TOKEN_EXEC:
+               zmo->z_exec = B_TRUE;
+               zmo->z_do_exec = B_TRUE;
+               break;
+       case TOKEN_NOEXEC:
+               zmo->z_exec = B_FALSE;
+               zmo->z_do_exec = B_TRUE;
+               break;
+       case TOKEN_DEVICES:
+               zmo->z_devices = B_TRUE;
+               zmo->z_do_devices = B_TRUE;
+               break;
+       case TOKEN_NODEVICES:
+               zmo->z_devices = B_FALSE;
+               zmo->z_do_devices = B_TRUE;
+               break;
+       case TOKEN_DIRXATTR:
+               zmo->z_xattr = ZFS_XATTR_DIR;
+               zmo->z_do_xattr = B_TRUE;
+               break;
+       case TOKEN_SAXATTR:
+               zmo->z_xattr = ZFS_XATTR_SA;
+               zmo->z_do_xattr = B_TRUE;
+               break;
+       case TOKEN_XATTR:
+               zmo->z_xattr = ZFS_XATTR_DIR;
+               zmo->z_do_xattr = B_TRUE;
+               break;
+       case TOKEN_NOXATTR:
+               zmo->z_xattr = ZFS_XATTR_OFF;
+               zmo->z_do_xattr = B_TRUE;
+               break;
+       case TOKEN_ATIME:
+               zmo->z_atime = B_TRUE;
+               zmo->z_do_atime = B_TRUE;
+               break;
+       case TOKEN_NOATIME:
+               zmo->z_atime = B_FALSE;
+               zmo->z_do_atime = B_TRUE;
+               break;
+       case TOKEN_RELATIME:
+               zmo->z_relatime = B_TRUE;
+               zmo->z_do_relatime = B_TRUE;
+               break;
+       case TOKEN_NORELATIME:
+               zmo->z_relatime = B_FALSE;
+               zmo->z_do_relatime = B_TRUE;
+               break;
+       case TOKEN_NBMAND:
+               zmo->z_nbmand = B_TRUE;
+               zmo->z_do_nbmand = B_TRUE;
+               break;
+       case TOKEN_NONBMAND:
+               zmo->z_nbmand = B_FALSE;
+               zmo->z_do_nbmand = B_TRUE;
+               break;
+       case TOKEN_MNTPOINT:
+               zmo->z_mntpoint = match_strdup(&args[0]);
+               if (zmo->z_mntpoint == NULL)
+                       return (-ENOMEM);
+
+               break;
+       default:
+               break;
+       }
+
+       return (0);
+}
+
+/*
+ * Parse the mntopts string storing the results in provided zmo argument.
+ * If an error occurs the zmo argument will not be modified.  The caller
+ * needs to set isremount when recycling an existing zfs_mntopts_t.
+ */
+static int
+zpl_parse_options(char *osname, char *mntopts, zfs_mntopts_t *zmo,
+    boolean_t isremount)
+{
+       zfs_mntopts_t *tmp_zmo;
+       int error;
+
+       tmp_zmo = zfs_mntopts_alloc();
+       tmp_zmo->z_osname = strdup(osname);
+
+       if (mntopts) {
+               substring_t args[MAX_OPT_ARGS];
+               char *tmp_mntopts, *p, *t;
+               int token;
+
+               t = tmp_mntopts = strdup(mntopts);
+
+               while ((p = strsep(&t, ",")) != NULL) {
+                       if (!*p)
+                               continue;
+
+                       args[0].to = args[0].from = NULL;
+                       token = match_token(p, zpl_tokens, args);
+                       error = zpl_parse_option(p, token, args, tmp_zmo);
+                       if (error) {
+                               zfs_mntopts_free(tmp_zmo);
+                               strfree(tmp_mntopts);
+                               return (error);
+                       }
+               }
+
+               strfree(tmp_mntopts);
+       }
+
+       if (isremount == B_TRUE) {
+               if (zmo->z_osname)
+                       strfree(zmo->z_osname);
+
+               if (zmo->z_mntpoint)
+                       strfree(zmo->z_mntpoint);
+       } else {
+               ASSERT3P(zmo->z_osname, ==, NULL);
+               ASSERT3P(zmo->z_mntpoint, ==, NULL);
+       }
+
+       memcpy(zmo, tmp_zmo, sizeof (zfs_mntopts_t));
+       kmem_free(tmp_zmo, sizeof (zfs_mntopts_t));
+
+       return (0);
+}
+
+static int
+zpl_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+       zfs_sb_t *zsb = sb->s_fs_info;
+       fstrans_cookie_t cookie;
+       int error;
+
+       error = zpl_parse_options(zsb->z_mntopts->z_osname, data,
+           zsb->z_mntopts, B_TRUE);
+       if (error)
+               return (error);
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_remount(sb, flags, zsb->z_mntopts);
+       spl_fstrans_unmark(cookie);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+__zpl_show_options(struct seq_file *seq, zfs_sb_t *zsb)
+{
+       seq_printf(seq, ",%s", zsb->z_flags & ZSB_XATTR ? "xattr" : "noxattr");
+
+#ifdef CONFIG_FS_POSIX_ACL
+       switch (zsb->z_acl_type) {
+       case ZFS_ACLTYPE_POSIXACL:
+               seq_puts(seq, ",posixacl");
+               break;
+       default:
+               seq_puts(seq, ",noacl");
+               break;
+       }
+#endif /* CONFIG_FS_POSIX_ACL */
+
+       return (0);
+}
+
+#ifdef HAVE_SHOW_OPTIONS_WITH_DENTRY
+static int
+zpl_show_options(struct seq_file *seq, struct dentry *root)
+{
+       return (__zpl_show_options(seq, root->d_sb->s_fs_info));
+}
+#else
+static int
+zpl_show_options(struct seq_file *seq, struct vfsmount *vfsp)
+{
+       return (__zpl_show_options(seq, vfsp->mnt_sb->s_fs_info));
+}
+#endif /* HAVE_SHOW_OPTIONS_WITH_DENTRY */
+
+static int
+zpl_fill_super(struct super_block *sb, void *data, int silent)
+{
+       zfs_mntopts_t *zmo = (zfs_mntopts_t *)data;
+       fstrans_cookie_t cookie;
+       int error;
+
+       cookie = spl_fstrans_mark();
+       error = -zfs_domount(sb, zmo, silent);
+       spl_fstrans_unmark(cookie);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+#ifdef HAVE_MOUNT_NODEV
+static struct dentry *
+zpl_mount(struct file_system_type *fs_type, int flags,
+    const char *osname, void *data)
+{
+       zfs_mntopts_t *zmo = zfs_mntopts_alloc();
+       int error;
+
+       error = zpl_parse_options((char *)osname, (char *)data, zmo, B_FALSE);
+       if (error) {
+               zfs_mntopts_free(zmo);
+               return (ERR_PTR(error));
+       }
+
+       return (mount_nodev(fs_type, flags, zmo, zpl_fill_super));
+}
+#else
+static int
+zpl_get_sb(struct file_system_type *fs_type, int flags,
+    const char *osname, void *data, struct vfsmount *mnt)
+{
+       zfs_mntopts_t *zmo = zfs_mntopts_alloc();
+       int error;
+
+       error = zpl_parse_options((char *)osname, (char *)data, zmo, B_FALSE);
+       if (error) {
+               zfs_mntopts_free(zmo);
+               return (error);
+       }
+
+       return (get_sb_nodev(fs_type, flags, zmo, zpl_fill_super, mnt));
+}
+#endif /* HAVE_MOUNT_NODEV */
+
+static void
+zpl_kill_sb(struct super_block *sb)
+{
+       zfs_preumount(sb);
+       kill_anon_super(sb);
+
+#ifdef HAVE_S_INSTANCES_LIST_HEAD
+       sb->s_instances.next = &(zpl_fs_type.fs_supers);
+#endif /* HAVE_S_INSTANCES_LIST_HEAD */
+}
+
+void
+zpl_prune_sb(int64_t nr_to_scan, void *arg)
+{
+       struct super_block *sb = (struct super_block *)arg;
+       int objects = 0;
+
+       (void) -zfs_sb_prune(sb, nr_to_scan, &objects);
+}
+
+#ifdef HAVE_NR_CACHED_OBJECTS
+static int
+zpl_nr_cached_objects(struct super_block *sb)
+{
+       return (0);
+}
+#endif /* HAVE_NR_CACHED_OBJECTS */
+
+#ifdef HAVE_FREE_CACHED_OBJECTS
+static void
+zpl_free_cached_objects(struct super_block *sb, int nr_to_scan)
+{
+       /* noop */
+}
+#endif /* HAVE_FREE_CACHED_OBJECTS */
+
+const struct super_operations zpl_super_operations = {
+       .alloc_inode            = zpl_inode_alloc,
+       .destroy_inode          = zpl_inode_destroy,
+       .dirty_inode            = zpl_dirty_inode,
+       .write_inode            = NULL,
+#ifdef HAVE_EVICT_INODE
+       .evict_inode            = zpl_evict_inode,
+#else
+       .drop_inode             = zpl_drop_inode,
+       .clear_inode            = zpl_clear_inode,
+       .delete_inode           = zpl_inode_delete,
+#endif /* HAVE_EVICT_INODE */
+       .put_super              = zpl_put_super,
+       .sync_fs                = zpl_sync_fs,
+       .statfs                 = zpl_statfs,
+       .remount_fs             = zpl_remount_fs,
+       .show_options           = zpl_show_options,
+       .show_stats             = NULL,
+#ifdef HAVE_NR_CACHED_OBJECTS
+       .nr_cached_objects      = zpl_nr_cached_objects,
+#endif /* HAVE_NR_CACHED_OBJECTS */
+#ifdef HAVE_FREE_CACHED_OBJECTS
+       .free_cached_objects    = zpl_free_cached_objects,
+#endif /* HAVE_FREE_CACHED_OBJECTS */
+};
+
+struct file_system_type zpl_fs_type = {
+       .owner                  = THIS_MODULE,
+       .name                   = ZFS_DRIVER,
+#ifdef HAVE_MOUNT_NODEV
+       .mount                  = zpl_mount,
+#else
+       .get_sb                 = zpl_get_sb,
+#endif /* HAVE_MOUNT_NODEV */
+       .kill_sb                = zpl_kill_sb,
+};
diff --git a/zfs/module/zfs/zpl_xattr.c b/zfs/module/zfs/zpl_xattr.c
new file mode 100644 (file)
index 0000000..5896207
--- /dev/null
@@ -0,0 +1,1543 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, Lawrence Livermore National Security, LLC.
+ *
+ * Extended attributes (xattr) on Solaris are implemented as files
+ * which exist in a hidden xattr directory.  These extended attributes
+ * can be accessed using the attropen() system call which opens
+ * the extended attribute.  It can then be manipulated just like
+ * a standard file descriptor.  This has a couple advantages such
+ * as practically no size limit on the file, and the extended
+ * attributes permissions may differ from those of the parent file.
+ * This interface is really quite clever, but it's also completely
+ * different than what is supported on Linux.  It also comes with a
+ * steep performance penalty when accessing small xattrs because they
+ * are not stored with the parent file.
+ *
+ * Under Linux extended attributes are manipulated by the system
+ * calls getxattr(2), setxattr(2), and listxattr(2).  They consider
+ * extended attributes to be name/value pairs where the name is a
+ * NULL terminated string.  The name must also include one of the
+ * following namespace prefixes:
+ *
+ *   user     - No restrictions and is available to user applications.
+ *   trusted  - Restricted to kernel and root (CAP_SYS_ADMIN) use.
+ *   system   - Used for access control lists (system.nfs4_acl, etc).
+ *   security - Used by SELinux to store a files security context.
+ *
+ * The value under Linux to limited to 65536 bytes of binary data.
+ * In practice, individual xattrs tend to be much smaller than this
+ * and are typically less than 100 bytes.  A good example of this
+ * are the security.selinux xattrs which are less than 100 bytes and
+ * exist for every file when xattr labeling is enabled.
+ *
+ * The Linux xattr implemenation has been written to take advantage of
+ * this typical usage.  When the dataset property 'xattr=sa' is set,
+ * then xattrs will be preferentially stored as System Attributes (SA).
+ * This allows tiny xattrs (~100 bytes) to be stored with the dnode and
+ * up to 64k of xattrs to be stored in the spill block.  If additional
+ * xattr space is required, which is unlikely under Linux, they will
+ * be stored using the traditional directory approach.
+ *
+ * This optimization results in roughly a 3x performance improvement
+ * when accessing xattrs because it avoids the need to perform a seek
+ * for every xattr value.  When multiple xattrs are stored per-file
+ * the performance improvements are even greater because all of the
+ * xattrs stored in the spill block will be cached.
+ *
+ * However, by default SA based xattrs are disabled in the Linux port
+ * to maximize compatibility with other implementations.  If you do
+ * enable SA based xattrs then they will not be visible on platforms
+ * which do not support this feature.
+ *
+ * NOTE: One additional consequence of the xattr directory implementation
+ * is that when an extended attribute is manipulated an inode is created.
+ * This inode will exist in the Linux inode cache but there will be no
+ * associated entry in the dentry cache which references it.  This is
+ * safe but it may result in some confusion.  Enabling SA based xattrs
+ * largely avoids the issue except in the overflow case.
+ */
+
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zap.h>
+#include <sys/vfs.h>
+#include <sys/zpl.h>
+
+typedef struct xattr_filldir {
+       size_t size;
+       size_t offset;
+       char *buf;
+       struct dentry *dentry;
+} xattr_filldir_t;
+
+static const struct xattr_handler *zpl_xattr_handler(const char *);
+
+static int
+zpl_xattr_permission(xattr_filldir_t *xf, const char *name, int name_len)
+{
+       static const struct xattr_handler *handler;
+       struct dentry *d = xf->dentry;
+
+       handler = zpl_xattr_handler(name);
+       if (!handler)
+               return (0);
+
+       if (handler->list) {
+#if defined(HAVE_XATTR_LIST_SIMPLE)
+               if (!handler->list(d))
+                       return (0);
+#elif defined(HAVE_XATTR_LIST_DENTRY)
+               if (!handler->list(d, NULL, 0, name, name_len, 0))
+                       return (0);
+#elif defined(HAVE_XATTR_LIST_HANDLER)
+               if (!handler->list(handler, d, NULL, 0, name, name_len))
+                       return (0);
+#elif defined(HAVE_XATTR_LIST_INODE)
+               if (!handler->list(d->d_inode, NULL, 0, name, name_len))
+                       return (0);
+#endif
+       }
+
+       return (1);
+}
+
+/*
+ * Determine is a given xattr name should be visible and if so copy it
+ * in to the provided buffer (xf->buf).
+ */
+static int
+zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len)
+{
+       /* Check permissions using the per-namespace list xattr handler. */
+       if (!zpl_xattr_permission(xf, name, name_len))
+               return (0);
+
+       /* When xf->buf is NULL only calculate the required size. */
+       if (xf->buf) {
+               if (xf->offset + name_len + 1 > xf->size)
+                       return (-ERANGE);
+
+               memcpy(xf->buf + xf->offset, name, name_len);
+               xf->buf[xf->offset + name_len] = '\0';
+       }
+
+       xf->offset += (name_len + 1);
+
+       return (0);
+}
+
+/*
+ * Read as many directory entry names as will fit in to the provided buffer,
+ * or when no buffer is provided calculate the required buffer size.
+ */
+int
+zpl_xattr_readdir(struct inode *dxip, xattr_filldir_t *xf)
+{
+       zap_cursor_t zc;
+       zap_attribute_t zap;
+       int error;
+
+       zap_cursor_init(&zc, ITOZSB(dxip)->z_os, ITOZ(dxip)->z_id);
+
+       while ((error = -zap_cursor_retrieve(&zc, &zap)) == 0) {
+
+               if (zap.za_integer_length != 8 || zap.za_num_integers != 1) {
+                       error = -ENXIO;
+                       break;
+               }
+
+               error = zpl_xattr_filldir(xf, zap.za_name, strlen(zap.za_name));
+               if (error)
+                       break;
+
+               zap_cursor_advance(&zc);
+       }
+
+       zap_cursor_fini(&zc);
+
+       if (error == -ENOENT)
+               error = 0;
+
+       return (error);
+}
+
+static ssize_t
+zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
+{
+       struct inode *ip = xf->dentry->d_inode;
+       struct inode *dxip = NULL;
+       int error;
+
+       /* Lookup the xattr directory */
+       error = -zfs_lookup(ip, NULL, &dxip, LOOKUP_XATTR, cr, NULL, NULL);
+       if (error) {
+               if (error == -ENOENT)
+                       error = 0;
+
+               return (error);
+       }
+
+       error = zpl_xattr_readdir(dxip, xf);
+       iput(dxip);
+
+       return (error);
+}
+
+static ssize_t
+zpl_xattr_list_sa(xattr_filldir_t *xf)
+{
+       znode_t *zp = ITOZ(xf->dentry->d_inode);
+       nvpair_t *nvp = NULL;
+       int error = 0;
+
+       mutex_enter(&zp->z_lock);
+       if (zp->z_xattr_cached == NULL)
+               error = -zfs_sa_get_xattr(zp);
+       mutex_exit(&zp->z_lock);
+
+       if (error)
+               return (error);
+
+       ASSERT(zp->z_xattr_cached);
+
+       while ((nvp = nvlist_next_nvpair(zp->z_xattr_cached, nvp)) != NULL) {
+               ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY);
+
+               error = zpl_xattr_filldir(xf, nvpair_name(nvp),
+                   strlen(nvpair_name(nvp)));
+               if (error)
+                       return (error);
+       }
+
+       return (0);
+}
+
+ssize_t
+zpl_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
+{
+       znode_t *zp = ITOZ(dentry->d_inode);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       xattr_filldir_t xf = { buffer_size, 0, buffer, dentry };
+       cred_t *cr = CRED();
+       fstrans_cookie_t cookie;
+       int error = 0;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       rrm_enter_read(&(zsb)->z_teardown_lock, FTAG);
+       rw_enter(&zp->z_xattr_lock, RW_READER);
+
+       if (zsb->z_use_sa && zp->z_is_sa) {
+               error = zpl_xattr_list_sa(&xf);
+               if (error)
+                       goto out;
+       }
+
+       error = zpl_xattr_list_dir(&xf, cr);
+       if (error)
+               goto out;
+
+       error = xf.offset;
+out:
+
+       rw_exit(&zp->z_xattr_lock);
+       rrm_exit(&(zsb)->z_teardown_lock, FTAG);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       return (error);
+}
+
+static int
+zpl_xattr_get_dir(struct inode *ip, const char *name, void *value,
+    size_t size, cred_t *cr)
+{
+       struct inode *dxip = NULL;
+       struct inode *xip = NULL;
+       loff_t pos = 0;
+       int error;
+
+       /* Lookup the xattr directory */
+       error = -zfs_lookup(ip, NULL, &dxip, LOOKUP_XATTR, cr, NULL, NULL);
+       if (error)
+               goto out;
+
+       /* Lookup a specific xattr name in the directory */
+       error = -zfs_lookup(dxip, (char *)name, &xip, 0, cr, NULL, NULL);
+       if (error)
+               goto out;
+
+       if (!size) {
+               error = i_size_read(xip);
+               goto out;
+       }
+
+       if (size < i_size_read(xip)) {
+               error = -ERANGE;
+               goto out;
+       }
+
+       error = zpl_read_common(xip, value, size, &pos, UIO_SYSSPACE, 0, cr);
+out:
+       if (xip)
+               iput(xip);
+
+       if (dxip)
+               iput(dxip);
+
+       return (error);
+}
+
+static int
+zpl_xattr_get_sa(struct inode *ip, const char *name, void *value, size_t size)
+{
+       znode_t *zp = ITOZ(ip);
+       uchar_t *nv_value;
+       uint_t nv_size;
+       int error = 0;
+
+       ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
+
+       mutex_enter(&zp->z_lock);
+       if (zp->z_xattr_cached == NULL)
+               error = -zfs_sa_get_xattr(zp);
+       mutex_exit(&zp->z_lock);
+
+       if (error)
+               return (error);
+
+       ASSERT(zp->z_xattr_cached);
+       error = -nvlist_lookup_byte_array(zp->z_xattr_cached, name,
+           &nv_value, &nv_size);
+       if (error)
+               return (error);
+
+       if (!size)
+               return (nv_size);
+
+       if (size < nv_size)
+               return (-ERANGE);
+
+       memcpy(value, nv_value, nv_size);
+
+       return (nv_size);
+}
+
+static int
+__zpl_xattr_get(struct inode *ip, const char *name, void *value, size_t size,
+    cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       int error;
+
+       ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
+
+       if (zsb->z_use_sa && zp->z_is_sa) {
+               error = zpl_xattr_get_sa(ip, name, value, size);
+               if (error != -ENOENT)
+                       goto out;
+       }
+
+       error = zpl_xattr_get_dir(ip, name, value, size, cr);
+out:
+       if (error == -ENOENT)
+               error = -ENODATA;
+
+       return (error);
+}
+
+#define        XATTR_NOENT     0x0
+#define        XATTR_IN_SA     0x1
+#define        XATTR_IN_DIR    0x2
+/* check where the xattr resides */
+static int
+__zpl_xattr_where(struct inode *ip, const char *name, int *where, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       int error;
+
+       ASSERT(where);
+       ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
+
+       *where = XATTR_NOENT;
+       if (zsb->z_use_sa && zp->z_is_sa) {
+               error = zpl_xattr_get_sa(ip, name, NULL, 0);
+               if (error >= 0)
+                       *where |= XATTR_IN_SA;
+               else if (error != -ENOENT)
+                       return (error);
+       }
+
+       error = zpl_xattr_get_dir(ip, name, NULL, 0, cr);
+       if (error >= 0)
+               *where |= XATTR_IN_DIR;
+       else if (error != -ENOENT)
+               return (error);
+
+       if (*where == (XATTR_IN_SA|XATTR_IN_DIR))
+               cmn_err(CE_WARN, "ZFS: inode %p has xattr \"%s\""
+                   " in both SA and dir", ip, name);
+       if (*where == XATTR_NOENT)
+               error = -ENODATA;
+       else
+               error = 0;
+       return (error);
+}
+
+static int
+zpl_xattr_get(struct inode *ip, const char *name, void *value, size_t size)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       cred_t *cr = CRED();
+       fstrans_cookie_t cookie;
+       int error;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       rrm_enter_read(&(zsb)->z_teardown_lock, FTAG);
+       rw_enter(&zp->z_xattr_lock, RW_READER);
+       error = __zpl_xattr_get(ip, name, value, size, cr);
+       rw_exit(&zp->z_xattr_lock);
+       rrm_exit(&(zsb)->z_teardown_lock, FTAG);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+
+       return (error);
+}
+
+static int
+zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value,
+    size_t size, int flags, cred_t *cr)
+{
+       struct inode *dxip = NULL;
+       struct inode *xip = NULL;
+       vattr_t *vap = NULL;
+       ssize_t wrote;
+       int lookup_flags, error;
+       const int xattr_mode = S_IFREG | 0644;
+       loff_t pos = 0;
+
+       /*
+        * Lookup the xattr directory.  When we're adding an entry pass
+        * CREATE_XATTR_DIR to ensure the xattr directory is created.
+        * When removing an entry this flag is not passed to avoid
+        * unnecessarily creating a new xattr directory.
+        */
+       lookup_flags = LOOKUP_XATTR;
+       if (value != NULL)
+               lookup_flags |= CREATE_XATTR_DIR;
+
+       error = -zfs_lookup(ip, NULL, &dxip, lookup_flags, cr, NULL, NULL);
+       if (error)
+               goto out;
+
+       /* Lookup a specific xattr name in the directory */
+       error = -zfs_lookup(dxip, (char *)name, &xip, 0, cr, NULL, NULL);
+       if (error && (error != -ENOENT))
+               goto out;
+
+       error = 0;
+
+       /* Remove a specific name xattr when value is set to NULL. */
+       if (value == NULL) {
+               if (xip)
+                       error = -zfs_remove(dxip, (char *)name, cr);
+
+               goto out;
+       }
+
+       /* Lookup failed create a new xattr. */
+       if (xip == NULL) {
+               vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
+               vap->va_mode = xattr_mode;
+               vap->va_mask = ATTR_MODE;
+               vap->va_uid = crgetfsuid(cr);
+               vap->va_gid = crgetfsgid(cr);
+
+               error = -zfs_create(dxip, (char *)name, vap, 0, 0644, &xip,
+                   cr, 0, NULL);
+               if (error)
+                       goto out;
+       }
+
+       ASSERT(xip != NULL);
+
+       error = -zfs_freesp(ITOZ(xip), 0, 0, xattr_mode, TRUE);
+       if (error)
+               goto out;
+
+       wrote = zpl_write_common(xip, value, size, &pos, UIO_SYSSPACE, 0, cr);
+       if (wrote < 0)
+               error = wrote;
+
+out:
+       if (vap)
+               kmem_free(vap, sizeof (vattr_t));
+
+       if (xip)
+               iput(xip);
+
+       if (dxip)
+               iput(dxip);
+
+       if (error == -ENOENT)
+               error = -ENODATA;
+
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_xattr_set_sa(struct inode *ip, const char *name, const void *value,
+    size_t size, int flags, cred_t *cr)
+{
+       znode_t *zp = ITOZ(ip);
+       nvlist_t *nvl;
+       size_t sa_size;
+       int error = 0;
+
+       mutex_enter(&zp->z_lock);
+       if (zp->z_xattr_cached == NULL)
+               error = -zfs_sa_get_xattr(zp);
+       mutex_exit(&zp->z_lock);
+
+       if (error)
+               return (error);
+
+       ASSERT(zp->z_xattr_cached);
+       nvl = zp->z_xattr_cached;
+
+       if (value == NULL) {
+               error = -nvlist_remove(nvl, name, DATA_TYPE_BYTE_ARRAY);
+               if (error == -ENOENT)
+                       error = zpl_xattr_set_dir(ip, name, NULL, 0, flags, cr);
+       } else {
+               /* Limited to 32k to keep nvpair memory allocations small */
+               if (size > DXATTR_MAX_ENTRY_SIZE)
+                       return (-EFBIG);
+
+               /* Prevent the DXATTR SA from consuming the entire SA region */
+               error = -nvlist_size(nvl, &sa_size, NV_ENCODE_XDR);
+               if (error)
+                       return (error);
+
+               if (sa_size > DXATTR_MAX_SA_SIZE)
+                       return (-EFBIG);
+
+               error = -nvlist_add_byte_array(nvl, name,
+                   (uchar_t *)value, size);
+       }
+
+       /*
+        * Update the SA for additions, modifications, and removals. On
+        * error drop the inconsistent cached version of the nvlist, it
+        * will be reconstructed from the ARC when next accessed.
+        */
+       if (error == 0)
+               error = -zfs_sa_set_xattr(zp);
+
+       if (error) {
+               nvlist_free(nvl);
+               zp->z_xattr_cached = NULL;
+       }
+
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+static int
+zpl_xattr_set(struct inode *ip, const char *name, const void *value,
+    size_t size, int flags)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ZTOZSB(zp);
+       cred_t *cr = CRED();
+       fstrans_cookie_t cookie;
+       int where;
+       int error;
+
+       crhold(cr);
+       cookie = spl_fstrans_mark();
+       rrm_enter_read(&(zsb)->z_teardown_lock, FTAG);
+       rw_enter(&ITOZ(ip)->z_xattr_lock, RW_WRITER);
+
+       /*
+        * Before setting the xattr check to see if it already exists.
+        * This is done to ensure the following optional flags are honored.
+        *
+        *   XATTR_CREATE: fail if xattr already exists
+        *   XATTR_REPLACE: fail if xattr does not exist
+        *
+        * We also want to know if it resides in sa or dir, so we can make
+        * sure we don't end up with duplicate in both places.
+        */
+       error = __zpl_xattr_where(ip, name, &where, cr);
+       if (error < 0) {
+               if (error != -ENODATA)
+                       goto out;
+               if (flags & XATTR_REPLACE)
+                       goto out;
+
+               /* The xattr to be removed already doesn't exist */
+               error = 0;
+               if (value == NULL)
+                       goto out;
+       } else {
+               error = -EEXIST;
+               if (flags & XATTR_CREATE)
+                       goto out;
+       }
+
+       /* Preferentially store the xattr as a SA for better performance */
+       if (zsb->z_use_sa && zp->z_is_sa &&
+           (zsb->z_xattr_sa || (value == NULL && where & XATTR_IN_SA))) {
+               error = zpl_xattr_set_sa(ip, name, value, size, flags, cr);
+               if (error == 0) {
+                       /*
+                        * Successfully put into SA, we need to clear the one
+                        * in dir.
+                        */
+                       if (where & XATTR_IN_DIR)
+                               zpl_xattr_set_dir(ip, name, NULL, 0, 0, cr);
+                       goto out;
+               }
+       }
+
+       error = zpl_xattr_set_dir(ip, name, value, size, flags, cr);
+       /*
+        * Successfully put into dir, we need to clear the one in SA.
+        */
+       if (error == 0 && (where & XATTR_IN_SA))
+               zpl_xattr_set_sa(ip, name, NULL, 0, 0, cr);
+out:
+       rw_exit(&ITOZ(ip)->z_xattr_lock);
+       rrm_exit(&(zsb)->z_teardown_lock, FTAG);
+       spl_fstrans_unmark(cookie);
+       crfree(cr);
+       ASSERT3S(error, <=, 0);
+
+       return (error);
+}
+
+/*
+ * Extended user attributes
+ *
+ * "Extended user attributes may be assigned to files and directories for
+ * storing arbitrary additional information such as the mime type,
+ * character set or encoding of a file.  The access permissions for user
+ * attributes are defined by the file permission bits: read permission
+ * is required to retrieve the attribute value, and writer permission is
+ * required to change it.
+ *
+ * The file permission bits of regular files and directories are
+ * interpreted differently from the file permission bits of special
+ * files and symbolic links.  For regular files and directories the file
+ * permission bits define access to the file's contents, while for
+ * device special files they define access to the device described by
+ * the special file.  The file permissions of symbolic links are not
+ * used in access checks.  These differences would allow users to
+ * consume filesystem resources in a way not controllable by disk quotas
+ * for group or world writable special files and directories.
+ *
+ * For this reason, extended user attributes are allowed only for
+ * regular files and directories, and access to extended user attributes
+ * is restricted to the owner and to users with appropriate capabilities
+ * for directories with the sticky bit set (see the chmod(1) manual page
+ * for an explanation of the sticky bit)." - xattr(7)
+ *
+ * ZFS allows extended user attributes to be disabled administratively
+ * by setting the 'xattr=off' property on the dataset.
+ */
+static int
+__zpl_xattr_user_list(struct inode *ip, char *list, size_t list_size,
+    const char *name, size_t name_len)
+{
+       return (ITOZSB(ip)->z_flags & ZSB_XATTR);
+}
+ZPL_XATTR_LIST_WRAPPER(zpl_xattr_user_list);
+
+static int
+__zpl_xattr_user_get(struct inode *ip, const char *name,
+    void *value, size_t size)
+{
+       char *xattr_name;
+       int error;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") == 0)
+               return (-EINVAL);
+#endif
+       if (!(ITOZSB(ip)->z_flags & ZSB_XATTR))
+               return (-EOPNOTSUPP);
+
+       xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
+       error = zpl_xattr_get(ip, xattr_name, value, size);
+       strfree(xattr_name);
+
+       return (error);
+}
+ZPL_XATTR_GET_WRAPPER(zpl_xattr_user_get);
+
+static int
+__zpl_xattr_user_set(struct inode *ip, const char *name,
+    const void *value, size_t size, int flags)
+{
+       char *xattr_name;
+       int error;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") == 0)
+               return (-EINVAL);
+#endif
+       if (!(ITOZSB(ip)->z_flags & ZSB_XATTR))
+               return (-EOPNOTSUPP);
+
+       xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
+       error = zpl_xattr_set(ip, xattr_name, value, size, flags);
+       strfree(xattr_name);
+
+       return (error);
+}
+ZPL_XATTR_SET_WRAPPER(zpl_xattr_user_set);
+
+xattr_handler_t zpl_xattr_user_handler =
+{
+       .prefix = XATTR_USER_PREFIX,
+       .list   = zpl_xattr_user_list,
+       .get    = zpl_xattr_user_get,
+       .set    = zpl_xattr_user_set,
+};
+
+/*
+ * Trusted extended attributes
+ *
+ * "Trusted extended attributes are visible and accessible only to
+ * processes that have the CAP_SYS_ADMIN capability.  Attributes in this
+ * class are used to implement mechanisms in user space (i.e., outside
+ * the kernel) which keep information in extended attributes to which
+ * ordinary processes should not have access." - xattr(7)
+ */
+static int
+__zpl_xattr_trusted_list(struct inode *ip, char *list, size_t list_size,
+    const char *name, size_t name_len)
+{
+       return (capable(CAP_SYS_ADMIN));
+}
+ZPL_XATTR_LIST_WRAPPER(zpl_xattr_trusted_list);
+
+static int
+__zpl_xattr_trusted_get(struct inode *ip, const char *name,
+    void *value, size_t size)
+{
+       char *xattr_name;
+       int error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return (-EACCES);
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") == 0)
+               return (-EINVAL);
+#endif
+       xattr_name = kmem_asprintf("%s%s", XATTR_TRUSTED_PREFIX, name);
+       error = zpl_xattr_get(ip, xattr_name, value, size);
+       strfree(xattr_name);
+
+       return (error);
+}
+ZPL_XATTR_GET_WRAPPER(zpl_xattr_trusted_get);
+
+static int
+__zpl_xattr_trusted_set(struct inode *ip, const char *name,
+    const void *value, size_t size, int flags)
+{
+       char *xattr_name;
+       int error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return (-EACCES);
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") == 0)
+               return (-EINVAL);
+#endif
+       xattr_name = kmem_asprintf("%s%s", XATTR_TRUSTED_PREFIX, name);
+       error = zpl_xattr_set(ip, xattr_name, value, size, flags);
+       strfree(xattr_name);
+
+       return (error);
+}
+ZPL_XATTR_SET_WRAPPER(zpl_xattr_trusted_set);
+
+xattr_handler_t zpl_xattr_trusted_handler =
+{
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .list   = zpl_xattr_trusted_list,
+       .get    = zpl_xattr_trusted_get,
+       .set    = zpl_xattr_trusted_set,
+};
+
+/*
+ * Extended security attributes
+ *
+ * "The security attribute namespace is used by kernel security modules,
+ * such as Security Enhanced Linux, and also to implement file
+ * capabilities (see capabilities(7)).  Read and write access
+ * permissions to security attributes depend on the policy implemented
+ * for each security attribute by the security module.  When no security
+ * module is loaded, all processes have read access to extended security
+ * attributes, and write access is limited to processes that have the
+ * CAP_SYS_ADMIN capability." - xattr(7)
+ */
+static int
+__zpl_xattr_security_list(struct inode *ip, char *list, size_t list_size,
+    const char *name, size_t name_len)
+{
+       return (1);
+}
+ZPL_XATTR_LIST_WRAPPER(zpl_xattr_security_list);
+
+static int
+__zpl_xattr_security_get(struct inode *ip, const char *name,
+    void *value, size_t size)
+{
+       char *xattr_name;
+       int error;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") == 0)
+               return (-EINVAL);
+#endif
+       xattr_name = kmem_asprintf("%s%s", XATTR_SECURITY_PREFIX, name);
+       error = zpl_xattr_get(ip, xattr_name, value, size);
+       strfree(xattr_name);
+
+       return (error);
+}
+ZPL_XATTR_GET_WRAPPER(zpl_xattr_security_get);
+
+static int
+__zpl_xattr_security_set(struct inode *ip, const char *name,
+    const void *value, size_t size, int flags)
+{
+       char *xattr_name;
+       int error;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") == 0)
+               return (-EINVAL);
+#endif
+       xattr_name = kmem_asprintf("%s%s", XATTR_SECURITY_PREFIX, name);
+       error = zpl_xattr_set(ip, xattr_name, value, size, flags);
+       strfree(xattr_name);
+
+       return (error);
+}
+ZPL_XATTR_SET_WRAPPER(zpl_xattr_security_set);
+
+#ifdef HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY
+static int
+__zpl_xattr_security_init(struct inode *ip, const struct xattr *xattrs,
+    void *fs_info)
+{
+       const struct xattr *xattr;
+       int error = 0;
+
+       for (xattr = xattrs; xattr->name != NULL; xattr++) {
+               error = __zpl_xattr_security_set(ip,
+                   xattr->name, xattr->value, xattr->value_len, 0);
+
+               if (error < 0)
+                       break;
+       }
+
+       return (error);
+}
+
+int
+zpl_xattr_security_init(struct inode *ip, struct inode *dip,
+    const struct qstr *qstr)
+{
+       return security_inode_init_security(ip, dip, qstr,
+           &__zpl_xattr_security_init, NULL);
+}
+
+#else
+int
+zpl_xattr_security_init(struct inode *ip, struct inode *dip,
+    const struct qstr *qstr)
+{
+       int error;
+       size_t len;
+       void *value;
+       char *name;
+
+       error = zpl_security_inode_init_security(ip, dip, qstr,
+           &name, &value, &len);
+       if (error) {
+               if (error == -EOPNOTSUPP)
+                       return (0);
+
+               return (error);
+       }
+
+       error = __zpl_xattr_security_set(ip, name, value, len, 0);
+
+       kfree(name);
+       kfree(value);
+
+       return (error);
+}
+#endif /* HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY */
+
+/*
+ * Security xattr namespace handlers.
+ */
+xattr_handler_t zpl_xattr_security_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .list   = zpl_xattr_security_list,
+       .get    = zpl_xattr_security_get,
+       .set    = zpl_xattr_security_set,
+};
+
+/*
+ * Extended system attributes
+ *
+ * "Extended system attributes are used by the kernel to store system
+ * objects such as Access Control Lists.  Read and write access permissions
+ * to system attributes depend on the policy implemented for each system
+ * attribute implemented by filesystems in the kernel." - xattr(7)
+ */
+#ifdef CONFIG_FS_POSIX_ACL
+int
+zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type)
+{
+       struct super_block *sb = ITOZSB(ip)->z_sb;
+       char *name, *value = NULL;
+       int error = 0;
+       size_t size = 0;
+
+       if (S_ISLNK(ip->i_mode))
+               return (-EOPNOTSUPP);
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
+               if (acl) {
+                       zpl_equivmode_t mode = ip->i_mode;
+                       error = posix_acl_equiv_mode(acl, &mode);
+                       if (error < 0) {
+                               return (error);
+                       } else {
+                               /*
+                                * The mode bits will have been set by
+                                * ->zfs_setattr()->zfs_acl_chmod_setattr()
+                                * using the ZFS ACL conversion.  If they
+                                * differ from the Posix ACL conversion dirty
+                                * the inode to write the Posix mode bits.
+                                */
+                               if (ip->i_mode != mode) {
+                                       ip->i_mode = mode;
+                                       ip->i_ctime = current_fs_time(sb);
+                                       zfs_mark_inode_dirty(ip);
+                               }
+
+                               if (error == 0)
+                                       acl = NULL;
+                       }
+               }
+               break;
+
+       case ACL_TYPE_DEFAULT:
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
+               if (!S_ISDIR(ip->i_mode))
+                       return (acl ? -EACCES : 0);
+               break;
+
+       default:
+               return (-EINVAL);
+       }
+
+       if (acl) {
+               size = posix_acl_xattr_size(acl->a_count);
+               value = kmem_alloc(size, KM_SLEEP);
+
+               error = zpl_acl_to_xattr(acl, value, size);
+               if (error < 0) {
+                       kmem_free(value, size);
+                       return (error);
+               }
+       }
+
+       error = zpl_xattr_set(ip, name, value, size, 0);
+       if (value)
+               kmem_free(value, size);
+
+       if (!error) {
+               if (acl)
+                       zpl_set_cached_acl(ip, type, acl);
+               else
+                       zpl_forget_cached_acl(ip, type);
+       }
+
+       return (error);
+}
+
+struct posix_acl *
+zpl_get_acl(struct inode *ip, int type)
+{
+       struct posix_acl *acl;
+       void *value = NULL;
+       char *name;
+       int size;
+
+       /*
+        * As of Linux 3.14, the kernel get_acl will check this for us.
+        * Also as of Linux 4.7, comparing against ACL_NOT_CACHED is wrong
+        * as the kernel get_acl will set it to temporary sentinel value.
+        */
+#ifndef HAVE_KERNEL_GET_ACL_HANDLE_CACHE
+       acl = get_cached_acl(ip, type);
+       if (acl != ACL_NOT_CACHED)
+               return (acl);
+#endif
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = XATTR_NAME_POSIX_ACL_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               name = XATTR_NAME_POSIX_ACL_DEFAULT;
+               break;
+       default:
+               return (ERR_PTR(-EINVAL));
+       }
+
+       size = zpl_xattr_get(ip, name, NULL, 0);
+       if (size > 0) {
+               value = kmem_alloc(size, KM_SLEEP);
+               size = zpl_xattr_get(ip, name, value, size);
+       }
+
+       if (size > 0) {
+               acl = zpl_acl_from_xattr(value, size);
+       } else if (size == -ENODATA || size == -ENOSYS) {
+               acl = NULL;
+       } else {
+               acl = ERR_PTR(-EIO);
+       }
+
+       if (size > 0)
+               kmem_free(value, size);
+
+       /* As of Linux 4.7, the kernel get_acl will set this for us */
+#ifndef HAVE_KERNEL_GET_ACL_HANDLE_CACHE
+       if (!IS_ERR(acl))
+               zpl_set_cached_acl(ip, type, acl);
+#endif
+
+       return (acl);
+}
+
+#if !defined(HAVE_GET_ACL)
+static int
+__zpl_check_acl(struct inode *ip, int mask)
+{
+       struct posix_acl *acl;
+       int error;
+
+       acl = zpl_get_acl(ip, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl))
+               return (PTR_ERR(acl));
+
+       if (acl) {
+               error = posix_acl_permission(ip, acl, mask);
+               zpl_posix_acl_release(acl);
+               return (error);
+       }
+
+       return (-EAGAIN);
+}
+
+#if defined(HAVE_CHECK_ACL_WITH_FLAGS)
+int
+zpl_check_acl(struct inode *ip, int mask, unsigned int flags)
+{
+       return (__zpl_check_acl(ip, mask));
+}
+#elif defined(HAVE_CHECK_ACL)
+int
+zpl_check_acl(struct inode *ip, int mask)
+{
+       return (__zpl_check_acl(ip, mask));
+}
+#elif defined(HAVE_PERMISSION_WITH_NAMEIDATA)
+int
+zpl_permission(struct inode *ip, int mask, struct nameidata *nd)
+{
+       return (generic_permission(ip, mask, __zpl_check_acl));
+}
+#elif defined(HAVE_PERMISSION)
+int
+zpl_permission(struct inode *ip, int mask)
+{
+       return (generic_permission(ip, mask, __zpl_check_acl));
+}
+#endif /* HAVE_CHECK_ACL | HAVE_PERMISSION */
+#endif /* !HAVE_GET_ACL */
+
+int
+zpl_init_acl(struct inode *ip, struct inode *dir)
+{
+       struct posix_acl *acl = NULL;
+       int error = 0;
+
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (0);
+
+       if (!S_ISLNK(ip->i_mode)) {
+               if (ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) {
+                       acl = zpl_get_acl(dir, ACL_TYPE_DEFAULT);
+                       if (IS_ERR(acl))
+                               return (PTR_ERR(acl));
+               }
+
+               if (!acl) {
+                       ip->i_mode &= ~current_umask();
+                       ip->i_ctime = current_fs_time(ITOZSB(ip)->z_sb);
+                       zfs_mark_inode_dirty(ip);
+                       return (0);
+               }
+       }
+
+       if ((ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) && acl) {
+               umode_t mode;
+
+               if (S_ISDIR(ip->i_mode)) {
+                       error = zpl_set_acl(ip, acl, ACL_TYPE_DEFAULT);
+                       if (error)
+                               goto out;
+               }
+
+               mode = ip->i_mode;
+               error = __posix_acl_create(&acl, GFP_KERNEL, &mode);
+               if (error >= 0) {
+                       ip->i_mode = mode;
+                       zfs_mark_inode_dirty(ip);
+                       if (error > 0)
+                               error = zpl_set_acl(ip, acl, ACL_TYPE_ACCESS);
+               }
+       }
+out:
+       zpl_posix_acl_release(acl);
+
+       return (error);
+}
+
+int
+zpl_chmod_acl(struct inode *ip)
+{
+       struct posix_acl *acl;
+       int error;
+
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (0);
+
+       if (S_ISLNK(ip->i_mode))
+               return (-EOPNOTSUPP);
+
+       acl = zpl_get_acl(ip, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl) || !acl)
+               return (PTR_ERR(acl));
+
+       error = __posix_acl_chmod(&acl, GFP_KERNEL, ip->i_mode);
+       if (!error)
+               error = zpl_set_acl(ip, acl, ACL_TYPE_ACCESS);
+
+       zpl_posix_acl_release(acl);
+
+       return (error);
+}
+
+static int
+__zpl_xattr_acl_list_access(struct inode *ip, char *list, size_t list_size,
+    const char *name, size_t name_len)
+{
+       char *xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
+       size_t xattr_size = sizeof (XATTR_NAME_POSIX_ACL_ACCESS);
+
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (0);
+
+       if (list && xattr_size <= list_size)
+               memcpy(list, xattr_name, xattr_size);
+
+       return (xattr_size);
+}
+ZPL_XATTR_LIST_WRAPPER(zpl_xattr_acl_list_access);
+
+static int
+__zpl_xattr_acl_list_default(struct inode *ip, char *list, size_t list_size,
+    const char *name, size_t name_len)
+{
+       char *xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
+       size_t xattr_size = sizeof (XATTR_NAME_POSIX_ACL_DEFAULT);
+
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (0);
+
+       if (list && xattr_size <= list_size)
+               memcpy(list, xattr_name, xattr_size);
+
+       return (xattr_size);
+}
+ZPL_XATTR_LIST_WRAPPER(zpl_xattr_acl_list_default);
+
+static int
+__zpl_xattr_acl_get_access(struct inode *ip, const char *name,
+    void *buffer, size_t size)
+{
+       struct posix_acl *acl;
+       int type = ACL_TYPE_ACCESS;
+       int error;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") != 0)
+               return (-EINVAL);
+#endif
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (-EOPNOTSUPP);
+
+       acl = zpl_get_acl(ip, type);
+       if (IS_ERR(acl))
+               return (PTR_ERR(acl));
+       if (acl == NULL)
+               return (-ENODATA);
+
+       error = zpl_acl_to_xattr(acl, buffer, size);
+       zpl_posix_acl_release(acl);
+
+       return (error);
+}
+ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_access);
+
+static int
+__zpl_xattr_acl_get_default(struct inode *ip, const char *name,
+    void *buffer, size_t size)
+{
+       struct posix_acl *acl;
+       int type = ACL_TYPE_DEFAULT;
+       int error;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") != 0)
+               return (-EINVAL);
+#endif
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (-EOPNOTSUPP);
+
+       acl = zpl_get_acl(ip, type);
+       if (IS_ERR(acl))
+               return (PTR_ERR(acl));
+       if (acl == NULL)
+               return (-ENODATA);
+
+       error = zpl_acl_to_xattr(acl, buffer, size);
+       zpl_posix_acl_release(acl);
+
+       return (error);
+}
+ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_default);
+
+static int
+__zpl_xattr_acl_set_access(struct inode *ip, const char *name,
+    const void *value, size_t size, int flags)
+{
+       struct posix_acl *acl;
+       int type = ACL_TYPE_ACCESS;
+       int error = 0;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") != 0)
+               return (-EINVAL);
+#endif
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (-EOPNOTSUPP);
+
+       if (!zpl_inode_owner_or_capable(ip))
+               return (-EPERM);
+
+       if (value) {
+               acl = zpl_acl_from_xattr(value, size);
+               if (IS_ERR(acl))
+                       return (PTR_ERR(acl));
+               else if (acl) {
+                       error = zpl_posix_acl_valid(ip, acl);
+                       if (error) {
+                               zpl_posix_acl_release(acl);
+                               return (error);
+                       }
+               }
+       } else {
+               acl = NULL;
+       }
+
+       error = zpl_set_acl(ip, acl, type);
+       zpl_posix_acl_release(acl);
+
+       return (error);
+}
+ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_access);
+
+static int
+__zpl_xattr_acl_set_default(struct inode *ip, const char *name,
+    const void *value, size_t size, int flags)
+{
+       struct posix_acl *acl;
+       int type = ACL_TYPE_DEFAULT;
+       int error = 0;
+       /* xattr_resolve_name will do this for us if this is defined */
+#ifndef HAVE_XATTR_HANDLER_NAME
+       if (strcmp(name, "") != 0)
+               return (-EINVAL);
+#endif
+       if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+               return (-EOPNOTSUPP);
+
+       if (!zpl_inode_owner_or_capable(ip))
+               return (-EPERM);
+
+       if (value) {
+               acl = zpl_acl_from_xattr(value, size);
+               if (IS_ERR(acl))
+                       return (PTR_ERR(acl));
+               else if (acl) {
+                       error = zpl_posix_acl_valid(ip, acl);
+                       if (error) {
+                               zpl_posix_acl_release(acl);
+                               return (error);
+                       }
+               }
+       } else {
+               acl = NULL;
+       }
+
+       error = zpl_set_acl(ip, acl, type);
+       zpl_posix_acl_release(acl);
+
+       return (error);
+}
+ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_default);
+
+/*
+ * ACL access xattr namespace handlers.
+ *
+ * Use .name instead of .prefix when available. xattr_resolve_name will match
+ * whole name and reject anything that has .name only as prefix.
+ */
+xattr_handler_t zpl_xattr_acl_access_handler =
+{
+#ifdef HAVE_XATTR_HANDLER_NAME
+       .name   = XATTR_NAME_POSIX_ACL_ACCESS,
+#else
+       .prefix = XATTR_NAME_POSIX_ACL_ACCESS,
+#endif
+       .list   = zpl_xattr_acl_list_access,
+       .get    = zpl_xattr_acl_get_access,
+       .set    = zpl_xattr_acl_set_access,
+#if defined(HAVE_XATTR_LIST_SIMPLE) || \
+    defined(HAVE_XATTR_LIST_DENTRY) || \
+    defined(HAVE_XATTR_LIST_HANDLER)
+       .flags  = ACL_TYPE_ACCESS,
+#endif
+};
+
+/*
+ * ACL default xattr namespace handlers.
+ *
+ * Use .name instead of .prefix when available. xattr_resolve_name will match
+ * whole name and reject anything that has .name only as prefix.
+ */
+xattr_handler_t zpl_xattr_acl_default_handler =
+{
+#ifdef HAVE_XATTR_HANDLER_NAME
+       .name   = XATTR_NAME_POSIX_ACL_DEFAULT,
+#else
+       .prefix = XATTR_NAME_POSIX_ACL_DEFAULT,
+#endif
+       .list   = zpl_xattr_acl_list_default,
+       .get    = zpl_xattr_acl_get_default,
+       .set    = zpl_xattr_acl_set_default,
+#if defined(HAVE_XATTR_LIST_SIMPLE) || \
+    defined(HAVE_XATTR_LIST_DENTRY) || \
+    defined(HAVE_XATTR_LIST_HANDLER)
+       .flags  = ACL_TYPE_DEFAULT,
+#endif
+};
+
+#endif /* CONFIG_FS_POSIX_ACL */
+
+xattr_handler_t *zpl_xattr_handlers[] = {
+       &zpl_xattr_security_handler,
+       &zpl_xattr_trusted_handler,
+       &zpl_xattr_user_handler,
+#ifdef CONFIG_FS_POSIX_ACL
+       &zpl_xattr_acl_access_handler,
+       &zpl_xattr_acl_default_handler,
+#endif /* CONFIG_FS_POSIX_ACL */
+       NULL
+};
+
+static const struct xattr_handler *
+zpl_xattr_handler(const char *name)
+{
+       if (strncmp(name, XATTR_USER_PREFIX,
+           XATTR_USER_PREFIX_LEN) == 0)
+               return (&zpl_xattr_user_handler);
+
+       if (strncmp(name, XATTR_TRUSTED_PREFIX,
+           XATTR_TRUSTED_PREFIX_LEN) == 0)
+               return (&zpl_xattr_trusted_handler);
+
+       if (strncmp(name, XATTR_SECURITY_PREFIX,
+           XATTR_SECURITY_PREFIX_LEN) == 0)
+               return (&zpl_xattr_security_handler);
+
+#ifdef CONFIG_FS_POSIX_ACL
+       if (strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
+           sizeof (XATTR_NAME_POSIX_ACL_ACCESS)) == 0)
+               return (&zpl_xattr_acl_access_handler);
+
+       if (strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
+           sizeof (XATTR_NAME_POSIX_ACL_DEFAULT)) == 0)
+               return (&zpl_xattr_acl_default_handler);
+#endif /* CONFIG_FS_POSIX_ACL */
+
+       return (NULL);
+}
+
+#if !defined(HAVE_POSIX_ACL_RELEASE) || defined(HAVE_POSIX_ACL_RELEASE_GPL_ONLY)
+struct acl_rel_struct {
+       struct acl_rel_struct *next;
+       struct posix_acl *acl;
+       clock_t time;
+};
+
+#define        ACL_REL_GRACE   (60*HZ)
+#define        ACL_REL_WINDOW  (1*HZ)
+#define        ACL_REL_SCHED   (ACL_REL_GRACE+ACL_REL_WINDOW)
+
+/*
+ * Lockless multi-producer single-consumer fifo list.
+ * Nodes are added to tail and removed from head. Tail pointer is our
+ * synchronization point. It always points to the next pointer of the last
+ * node, or head if list is empty.
+ */
+static struct acl_rel_struct *acl_rel_head = NULL;
+static struct acl_rel_struct **acl_rel_tail = &acl_rel_head;
+
+static void
+zpl_posix_acl_free(void *arg)
+{
+       struct acl_rel_struct *freelist = NULL;
+       struct acl_rel_struct *a;
+       clock_t new_time;
+       boolean_t refire = B_FALSE;
+
+       ASSERT3P(acl_rel_head, !=, NULL);
+       while (acl_rel_head) {
+               a = acl_rel_head;
+               if (ddi_get_lbolt() - a->time >= ACL_REL_GRACE) {
+                       /*
+                        * If a is the last node we need to reset tail, but we
+                        * need to use cmpxchg to make sure it is still the
+                        * last node.
+                        */
+                       if (acl_rel_tail == &a->next) {
+                               acl_rel_head = NULL;
+                               if (cmpxchg(&acl_rel_tail, &a->next,
+                                   &acl_rel_head) == &a->next) {
+                                       ASSERT3P(a->next, ==, NULL);
+                                       a->next = freelist;
+                                       freelist = a;
+                                       break;
+                               }
+                       }
+                       /*
+                        * a is not last node, make sure next pointer is set
+                        * by the adder and advance the head.
+                        */
+                       while (ACCESS_ONCE(a->next) == NULL)
+                               cpu_relax();
+                       acl_rel_head = a->next;
+                       a->next = freelist;
+                       freelist = a;
+               } else {
+                       /*
+                        * a is still in grace period. We are responsible to
+                        * reschedule the free task, since adder will only do
+                        * so if list is empty.
+                        */
+                       new_time = a->time + ACL_REL_SCHED;
+                       refire = B_TRUE;
+                       break;
+               }
+       }
+
+       if (refire)
+               taskq_dispatch_delay(system_taskq, zpl_posix_acl_free, NULL,
+                   TQ_SLEEP, new_time);
+
+       while (freelist) {
+               a = freelist;
+               freelist = a->next;
+               kfree(a->acl);
+               kmem_free(a, sizeof (struct acl_rel_struct));
+       }
+}
+
+void
+zpl_posix_acl_release_impl(struct posix_acl *acl)
+{
+       struct acl_rel_struct *a, **prev;
+
+       a = kmem_alloc(sizeof (struct acl_rel_struct), KM_SLEEP);
+       a->next = NULL;
+       a->acl = acl;
+       a->time = ddi_get_lbolt();
+       /* atomically points tail to us and get the previous tail */
+       prev = xchg(&acl_rel_tail, &a->next);
+       ASSERT3P(*prev, ==, NULL);
+       *prev = a;
+       /* if it was empty before, schedule the free task */
+       if (prev == &acl_rel_head)
+               taskq_dispatch_delay(system_taskq, zpl_posix_acl_free, NULL,
+                   TQ_SLEEP, ddi_get_lbolt() + ACL_REL_SCHED);
+}
+#endif
diff --git a/zfs/module/zfs/zrlock.c b/zfs/module/zfs/zrlock.c
new file mode 100644 (file)
index 0000000..52f9ee8
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 (c) 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * A Zero Reference Lock (ZRL) is a reference count that can lock out new
+ * references only when the count is zero and only without waiting if the count
+ * is not already zero. It is similar to a read-write lock in that it allows
+ * multiple readers and only a single writer, but it does not allow a writer to
+ * block while waiting for readers to exit, and therefore the question of
+ * reader/writer priority is moot (no WRWANT bit). Since the equivalent of
+ * rw_enter(&lock, RW_WRITER) is disallowed and only tryenter() is allowed, it
+ * is perfectly safe for the same reader to acquire the same lock multiple
+ * times. The fact that a ZRL is reentrant for readers (through multiple calls
+ * to zrl_add()) makes it convenient for determining whether something is
+ * actively referenced without the fuss of flagging lock ownership across
+ * function calls.
+ */
+#include <sys/zrlock.h>
+#include <sys/trace_zrlock.h>
+
+/*
+ * A ZRL can be locked only while there are zero references, so ZRL_LOCKED is
+ * treated as zero references.
+ */
+#define        ZRL_LOCKED      -1
+#define        ZRL_DESTROYED   -2
+
+void
+zrl_init(zrlock_t *zrl)
+{
+       mutex_init(&zrl->zr_mtx, NULL, MUTEX_DEFAULT, NULL);
+       zrl->zr_refcount = 0;
+       cv_init(&zrl->zr_cv, NULL, CV_DEFAULT, NULL);
+#ifdef ZFS_DEBUG
+       zrl->zr_owner = NULL;
+       zrl->zr_caller = NULL;
+#endif
+}
+
+void
+zrl_destroy(zrlock_t *zrl)
+{
+       ASSERT0(zrl->zr_refcount);
+
+       mutex_destroy(&zrl->zr_mtx);
+       zrl->zr_refcount = ZRL_DESTROYED;
+       cv_destroy(&zrl->zr_cv);
+}
+
+void
+#ifdef ZFS_DEBUG
+zrl_add_debug(zrlock_t *zrl, const char *zc)
+#else
+zrl_add(zrlock_t *zrl)
+#endif
+{
+       uint32_t n = (uint32_t)zrl->zr_refcount;
+
+       while (n != ZRL_LOCKED) {
+               uint32_t cas = atomic_cas_32(
+                   (uint32_t *)&zrl->zr_refcount, n, n + 1);
+               if (cas == n) {
+                       ASSERT3S((int32_t)n, >=, 0);
+#ifdef ZFS_DEBUG
+                       if (zrl->zr_owner == curthread) {
+                               DTRACE_PROBE2(zrlock__reentry,
+                                   zrlock_t *, zrl, uint32_t, n);
+                       }
+                       zrl->zr_owner = curthread;
+                       zrl->zr_caller = zc;
+#endif
+                       return;
+               }
+               n = cas;
+       }
+
+       mutex_enter(&zrl->zr_mtx);
+       while (zrl->zr_refcount == ZRL_LOCKED) {
+               cv_wait(&zrl->zr_cv, &zrl->zr_mtx);
+       }
+       ASSERT3S(zrl->zr_refcount, >=, 0);
+       zrl->zr_refcount++;
+#ifdef ZFS_DEBUG
+       zrl->zr_owner = curthread;
+       zrl->zr_caller = zc;
+#endif
+       mutex_exit(&zrl->zr_mtx);
+}
+
+void
+zrl_remove(zrlock_t *zrl)
+{
+       uint32_t n;
+
+#ifdef ZFS_DEBUG
+       if (zrl->zr_owner == curthread) {
+               zrl->zr_owner = NULL;
+               zrl->zr_caller = NULL;
+       }
+#endif
+       n = atomic_dec_32_nv((uint32_t *)&zrl->zr_refcount);
+       ASSERT3S((int32_t)n, >=, 0);
+}
+
+int
+zrl_tryenter(zrlock_t *zrl)
+{
+       uint32_t n = (uint32_t)zrl->zr_refcount;
+
+       if (n == 0) {
+               uint32_t cas = atomic_cas_32(
+                   (uint32_t *)&zrl->zr_refcount, 0, ZRL_LOCKED);
+               if (cas == 0) {
+#ifdef ZFS_DEBUG
+                       ASSERT3P(zrl->zr_owner, ==, NULL);
+                       zrl->zr_owner = curthread;
+#endif
+                       return (1);
+               }
+       }
+
+       ASSERT3S((int32_t)n, >, ZRL_DESTROYED);
+
+       return (0);
+}
+
+void
+zrl_exit(zrlock_t *zrl)
+{
+       ASSERT3S(zrl->zr_refcount, ==, ZRL_LOCKED);
+
+       mutex_enter(&zrl->zr_mtx);
+#ifdef ZFS_DEBUG
+       ASSERT3P(zrl->zr_owner, ==, curthread);
+       zrl->zr_owner = NULL;
+       membar_producer();      /* make sure the owner store happens first */
+#endif
+       zrl->zr_refcount = 0;
+       cv_broadcast(&zrl->zr_cv);
+       mutex_exit(&zrl->zr_mtx);
+}
+
+int
+zrl_refcount(zrlock_t *zrl)
+{
+       int n;
+
+       ASSERT3S(zrl->zr_refcount, >, ZRL_DESTROYED);
+
+       n = (int)zrl->zr_refcount;
+       return (n <= 0 ? 0 : n);
+}
+
+int
+zrl_is_zero(zrlock_t *zrl)
+{
+       ASSERT3S(zrl->zr_refcount, >, ZRL_DESTROYED);
+
+       return (zrl->zr_refcount <= 0);
+}
+
+int
+zrl_is_locked(zrlock_t *zrl)
+{
+       ASSERT3S(zrl->zr_refcount, >, ZRL_DESTROYED);
+
+       return (zrl->zr_refcount == ZRL_LOCKED);
+}
+
+#ifdef ZFS_DEBUG
+kthread_t *
+zrl_owner(zrlock_t *zrl)
+{
+       return (zrl->zr_owner);
+}
+#endif
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+
+#ifdef ZFS_DEBUG
+EXPORT_SYMBOL(zrl_add_debug);
+#else
+EXPORT_SYMBOL(zrl_add);
+#endif
+EXPORT_SYMBOL(zrl_remove);
+
+#endif
diff --git a/zfs/module/zfs/zvol.c b/zfs/module/zfs/zvol.c
new file mode 100644 (file)
index 0000000..0bb68f9
--- /dev/null
@@ -0,0 +1,1925 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * Rewritten for Linux by Brian Behlendorf <behlendorf1@llnl.gov>.
+ * LLNL-CODE-403049.
+ *
+ * ZFS volume emulation driver.
+ *
+ * Makes a DMU object look like a volume of arbitrary size, up to 2^64 bytes.
+ * Volumes are accessed through the symbolic links named:
+ *
+ * /dev/<pool_name>/<dataset_name>
+ *
+ * Volumes are persistent through reboot and module load.  No user command
+ * needs to be run before opening and using a device.
+ *
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+#include <sys/dbuf.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_dir.h>
+#include <sys/zap.h>
+#include <sys/zfeature.h>
+#include <sys/zil_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/zio.h>
+#include <sys/zfs_rlock.h>
+#include <sys/zfs_znode.h>
+#include <sys/spa_impl.h>
+#include <sys/zvol.h>
+#include <linux/blkdev_compat.h>
+
+unsigned int zvol_inhibit_dev = 0;
+unsigned int zvol_major = ZVOL_MAJOR;
+unsigned int zvol_prefetch_bytes = (128 * 1024);
+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";
+
+/*
+ * The in-core state of each volume.
+ */
+typedef struct zvol_state {
+       char                    zv_name[MAXNAMELEN];    /* name */
+       uint64_t                zv_volsize;             /* advertised space */
+       uint64_t                zv_volblocksize;        /* volume block size */
+       objset_t                *zv_objset;     /* objset handle */
+       uint32_t                zv_flags;       /* ZVOL_* flags */
+       uint32_t                zv_open_count;  /* open counts */
+       uint32_t                zv_changed;     /* disk changed */
+       zilog_t                 *zv_zilog;      /* ZIL handle */
+       zfs_rlock_t             zv_range_lock;  /* range lock */
+       dmu_buf_t               *zv_dbuf;       /* bonus handle */
+       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;
+
+typedef enum {
+       ZVOL_ASYNC_CREATE_MINORS,
+       ZVOL_ASYNC_REMOVE_MINORS,
+       ZVOL_ASYNC_RENAME_MINORS,
+       ZVOL_ASYNC_SET_SNAPDEV,
+       ZVOL_ASYNC_MAX
+} zvol_async_op_t;
+
+typedef struct {
+       zvol_async_op_t op;
+       char pool[MAXNAMELEN];
+       char name1[MAXNAMELEN];
+       char name2[MAXNAMELEN];
+       zprop_source_t source;
+       uint64_t snapdev;
+} zvol_task_t;
+
+#define        ZVOL_RDONLY     0x1
+
+/*
+ * Find the next available range of ZVOL_MINORS minor numbers.  The
+ * zvol_state_list is kept in ascending minor order so we simply need
+ * to scan the list for the first gap in the sequence.  This allows us
+ * to recycle minor number as devices are created and removed.
+ */
+static int
+zvol_find_minor(unsigned *minor)
+{
+       zvol_state_t *zv;
+
+       *minor = 0;
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+       for (zv = list_head(&zvol_state_list); zv != NULL;
+           zv = list_next(&zvol_state_list, zv), *minor += ZVOL_MINORS) {
+               if (MINOR(zv->zv_dev) != MINOR(*minor))
+                       break;
+       }
+
+       /* All minors are in use */
+       if (*minor >= (1 << MINORBITS))
+               return (SET_ERROR(ENXIO));
+
+       return (0);
+}
+
+/*
+ * Find a zvol_state_t given the full major+minor dev_t.
+ */
+static zvol_state_t *
+zvol_find_by_dev(dev_t dev)
+{
+       zvol_state_t *zv;
+
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+       for (zv = list_head(&zvol_state_list); zv != NULL;
+           zv = list_next(&zvol_state_list, zv)) {
+               if (zv->zv_dev == dev)
+                       return (zv);
+       }
+
+       return (NULL);
+}
+
+/*
+ * Find a zvol_state_t given the name provided at zvol_alloc() time.
+ */
+static zvol_state_t *
+zvol_find_by_name(const char *name)
+{
+       zvol_state_t *zv;
+
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+       for (zv = list_head(&zvol_state_list); zv != NULL;
+           zv = list_next(&zvol_state_list, zv)) {
+               if (strncmp(zv->zv_name, name, MAXNAMELEN) == 0)
+                       return (zv);
+       }
+
+       return (NULL);
+}
+
+
+/*
+ * Given a path, return TRUE if path is a ZVOL.
+ */
+boolean_t
+zvol_is_zvol(const char *device)
+{
+       struct block_device *bdev;
+       unsigned int major;
+
+       bdev = vdev_lookup_bdev(device);
+       if (IS_ERR(bdev))
+               return (B_FALSE);
+
+       major = MAJOR(bdev->bd_dev);
+       bdput(bdev);
+
+       if (major == zvol_major)
+               return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+/*
+ * ZFS_IOC_CREATE callback handles dmu zvol and zap object creation.
+ */
+void
+zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
+{
+       zfs_creat_t *zct = arg;
+       nvlist_t *nvprops = zct->zct_props;
+       int error;
+       uint64_t volblocksize, volsize;
+
+       VERIFY(nvlist_lookup_uint64(nvprops,
+           zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) == 0);
+       if (nvlist_lookup_uint64(nvprops,
+           zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0)
+               volblocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
+
+       /*
+        * These properties must be removed from the list so the generic
+        * property setting step won't apply to them.
+        */
+       VERIFY(nvlist_remove_all(nvprops,
+           zfs_prop_to_name(ZFS_PROP_VOLSIZE)) == 0);
+       (void) nvlist_remove_all(nvprops,
+           zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE));
+
+       error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, volblocksize,
+           DMU_OT_NONE, 0, tx);
+       ASSERT(error == 0);
+
+       error = zap_create_claim(os, ZVOL_ZAP_OBJ, DMU_OT_ZVOL_PROP,
+           DMU_OT_NONE, 0, tx);
+       ASSERT(error == 0);
+
+       error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize, tx);
+       ASSERT(error == 0);
+}
+
+/*
+ * ZFS_IOC_OBJSET_STATS entry point.
+ */
+int
+zvol_get_stats(objset_t *os, nvlist_t *nv)
+{
+       int error;
+       dmu_object_info_t *doi;
+       uint64_t val;
+
+       error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val);
+       if (error)
+               return (SET_ERROR(error));
+
+       dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val);
+       doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
+       error = dmu_object_info(os, ZVOL_OBJ, doi);
+
+       if (error == 0) {
+               dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLBLOCKSIZE,
+                   doi->doi_data_block_size);
+       }
+
+       kmem_free(doi, sizeof (dmu_object_info_t));
+
+       return (SET_ERROR(error));
+}
+
+static void
+zvol_size_changed(zvol_state_t *zv, uint64_t volsize)
+{
+       struct block_device *bdev;
+
+       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);
+}
+
+/*
+ * Sanity check volume size.
+ */
+int
+zvol_check_volsize(uint64_t volsize, uint64_t blocksize)
+{
+       if (volsize == 0)
+               return (SET_ERROR(EINVAL));
+
+       if (volsize % blocksize != 0)
+               return (SET_ERROR(EINVAL));
+
+#ifdef _ILP32
+       if (volsize - 1 > MAXOFFSET_T)
+               return (SET_ERROR(EOVERFLOW));
+#endif
+       return (0);
+}
+
+/*
+ * Ensure the zap is flushed then inform the VFS of the capacity change.
+ */
+static int
+zvol_update_volsize(uint64_t volsize, objset_t *os)
+{
+       dmu_tx_t *tx;
+       int error;
+
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+               return (SET_ERROR(error));
+       }
+
+       error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1,
+           &volsize, tx);
+       dmu_tx_commit(tx);
+
+       if (error == 0)
+               error = dmu_free_long_range(os,
+                   ZVOL_OBJ, volsize, DMU_OBJECT_END);
+
+       return (error);
+}
+
+static int
+zvol_update_live_volsize(zvol_state_t *zv, uint64_t volsize)
+{
+       zvol_size_changed(zv, volsize);
+
+       /*
+        * We should post a event here describing the expansion.  However,
+        * the zfs_ereport_post() interface doesn't nicely support posting
+        * events for zvols, it assumes events relate to vdevs or zios.
+        */
+
+       return (0);
+}
+
+/*
+ * Set ZFS_PROP_VOLSIZE set entry point.
+ */
+int
+zvol_set_volsize(const char *name, uint64_t volsize)
+{
+       zvol_state_t *zv = NULL;
+       objset_t *os = NULL;
+       int error;
+       dmu_object_info_t *doi;
+       uint64_t readonly;
+       boolean_t owned = B_FALSE;
+
+       error = dsl_prop_get_integer(name,
+           zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL);
+       if (error != 0)
+               return (SET_ERROR(error));
+       if (readonly)
+               return (SET_ERROR(EROFS));
+
+       mutex_enter(&zvol_state_lock);
+       zv = zvol_find_by_name(name);
+
+       if (zv == NULL || zv->zv_objset == NULL) {
+               if ((error = dmu_objset_own(name, DMU_OST_ZVOL, B_FALSE,
+                   FTAG, &os)) != 0) {
+                       mutex_exit(&zvol_state_lock);
+                       return (SET_ERROR(error));
+               }
+               owned = B_TRUE;
+               if (zv != NULL)
+                       zv->zv_objset = os;
+       } else {
+               os = zv->zv_objset;
+       }
+
+       doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
+
+       if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) ||
+           (error = zvol_check_volsize(volsize, doi->doi_data_block_size)))
+               goto out;
+
+       error = zvol_update_volsize(volsize, os);
+       kmem_free(doi, sizeof (dmu_object_info_t));
+
+       if (error == 0 && zv != NULL)
+               error = zvol_update_live_volsize(zv, volsize);
+out:
+       if (owned) {
+               dmu_objset_disown(os, FTAG);
+               if (zv != NULL)
+                       zv->zv_objset = NULL;
+       }
+       mutex_exit(&zvol_state_lock);
+       return (error);
+}
+
+/*
+ * Sanity check volume block size.
+ */
+int
+zvol_check_volblocksize(const char *name, uint64_t volblocksize)
+{
+       /* Record sizes above 128k need the feature to be enabled */
+       if (volblocksize > SPA_OLD_MAXBLOCKSIZE) {
+               spa_t *spa;
+               int error;
+
+               if ((error = spa_open(name, &spa, FTAG)) != 0)
+                       return (error);
+
+               if (!spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_BLOCKS)) {
+                       spa_close(spa, FTAG);
+                       return (SET_ERROR(ENOTSUP));
+               }
+
+               /*
+                * We don't allow setting the property above 1MB,
+                * unless the tunable has been changed.
+                */
+               if (volblocksize > zfs_max_recordsize)
+                       return (SET_ERROR(EDOM));
+
+               spa_close(spa, FTAG);
+       }
+
+       if (volblocksize < SPA_MINBLOCKSIZE ||
+           volblocksize > SPA_MAXBLOCKSIZE ||
+           !ISP2(volblocksize))
+               return (SET_ERROR(EDOM));
+
+       return (0);
+}
+
+/*
+ * Set ZFS_PROP_VOLBLOCKSIZE set entry point.
+ */
+int
+zvol_set_volblocksize(const char *name, uint64_t volblocksize)
+{
+       zvol_state_t *zv;
+       dmu_tx_t *tx;
+       int error;
+
+       mutex_enter(&zvol_state_lock);
+
+       zv = zvol_find_by_name(name);
+       if (zv == NULL) {
+               error = SET_ERROR(ENXIO);
+               goto out;
+       }
+
+       if (zv->zv_flags & ZVOL_RDONLY) {
+               error = SET_ERROR(EROFS);
+               goto out;
+       }
+
+       tx = dmu_tx_create(zv->zv_objset);
+       dmu_tx_hold_bonus(tx, ZVOL_OBJ);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+       } else {
+               error = dmu_object_set_blocksize(zv->zv_objset, ZVOL_OBJ,
+                   volblocksize, 0, tx);
+               if (error == ENOTSUP)
+                       error = SET_ERROR(EBUSY);
+               dmu_tx_commit(tx);
+               if (error == 0)
+                       zv->zv_volblocksize = volblocksize;
+       }
+out:
+       mutex_exit(&zvol_state_lock);
+
+       return (SET_ERROR(error));
+}
+
+/*
+ * Replay a TX_WRITE ZIL transaction that didn't get committed
+ * after a system failure
+ */
+static int
+zvol_replay_write(zvol_state_t *zv, lr_write_t *lr, boolean_t byteswap)
+{
+       objset_t *os = zv->zv_objset;
+       char *data = (char *)(lr + 1);  /* data follows lr_write_t */
+       uint64_t off = lr->lr_offset;
+       uint64_t len = lr->lr_length;
+       dmu_tx_t *tx;
+       int error;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_write(tx, ZVOL_OBJ, off, len);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error) {
+               dmu_tx_abort(tx);
+       } else {
+               dmu_write(os, ZVOL_OBJ, off, len, data, tx);
+               dmu_tx_commit(tx);
+       }
+
+       return (SET_ERROR(error));
+}
+
+static int
+zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap)
+{
+       return (SET_ERROR(ENOTSUP));
+}
+
+/*
+ * Callback vectors for replaying records.
+ * Only TX_WRITE is needed for zvol.
+ */
+zil_replay_func_t zvol_replay_vector[TX_MAX_TYPE] = {
+       (zil_replay_func_t)zvol_replay_err,     /* no such transaction type */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_CREATE */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_MKDIR */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_MKXATTR */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_SYMLINK */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_REMOVE */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_RMDIR */
+       (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_err,     /* TX_SETATTR */
+       (zil_replay_func_t)zvol_replay_err,     /* TX_ACL */
+};
+
+/*
+ * zvol_log_write() handles synchronous writes using TX_WRITE ZIL transactions.
+ *
+ * We store data in the log buffers if it's small enough.
+ * Otherwise we will later flush the data out via dmu_sync().
+ */
+ssize_t zvol_immediate_write_sz = 32768;
+
+static void
+zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, uint64_t offset,
+    uint64_t size, int sync)
+{
+       uint32_t blocksize = zv->zv_volblocksize;
+       zilog_t *zilog = zv->zv_zilog;
+       boolean_t slogging;
+       ssize_t immediate_write_sz;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       immediate_write_sz = (zilog->zl_logbias == ZFS_LOGBIAS_THROUGHPUT)
+               ? 0 : zvol_immediate_write_sz;
+       slogging = spa_has_slogs(zilog->zl_spa) &&
+               (zilog->zl_logbias == ZFS_LOGBIAS_LATENCY);
+
+       while (size) {
+               itx_t *itx;
+               lr_write_t *lr;
+               ssize_t len;
+               itx_wr_state_t write_state;
+
+               /*
+                * Unlike zfs_log_write() we can be called with
+                * up to DMU_MAX_ACCESS/2 (5MB) writes.
+                */
+               if (blocksize > immediate_write_sz && !slogging &&
+                   size >= blocksize && offset % blocksize == 0) {
+                       write_state = WR_INDIRECT; /* uses dmu_sync */
+                       len = blocksize;
+               } else if (sync) {
+                       write_state = WR_COPIED;
+                       len = MIN(ZIL_MAX_LOG_DATA, size);
+               } else {
+                       write_state = WR_NEED_COPY;
+                       len = MIN(ZIL_MAX_LOG_DATA, size);
+               }
+
+               itx = zil_itx_create(TX_WRITE, sizeof (*lr) +
+                   (write_state == WR_COPIED ? len : 0));
+               lr = (lr_write_t *)&itx->itx_lr;
+               if (write_state == WR_COPIED && dmu_read(zv->zv_objset,
+                   ZVOL_OBJ, offset, len, lr+1, DMU_READ_NO_PREFETCH) != 0) {
+                       zil_itx_destroy(itx);
+                       itx = zil_itx_create(TX_WRITE, sizeof (*lr));
+                       lr = (lr_write_t *)&itx->itx_lr;
+                       write_state = WR_NEED_COPY;
+               }
+
+               itx->itx_wr_state = write_state;
+               if (write_state == WR_NEED_COPY)
+                       itx->itx_sod += len;
+               lr->lr_foid = ZVOL_OBJ;
+               lr->lr_offset = offset;
+               lr->lr_length = len;
+               lr->lr_blkoff = 0;
+               BP_ZERO(&lr->lr_blkptr);
+
+               itx->itx_private = zv;
+               itx->itx_sync = sync;
+
+               (void) zil_itx_assign(zilog, itx, tx);
+
+               offset += len;
+               size -= len;
+       }
+}
+
+static int
+zvol_write(struct bio *bio)
+{
+       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;
+       rl_t *rl;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       if (bio_is_flush(bio))
+               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+
+       /*
+        * Some requests are just for flush and nothing else.
+        */
+       if (size == 0)
+               goto out;
+
+       rl = zfs_range_lock(&zv->zv_range_lock, offset, size, RL_WRITER);
+
+       tx = dmu_tx_create(zv->zv_objset);
+       dmu_tx_hold_write(tx, ZVOL_OBJ, offset, size);
+
+       /* 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;
+       }
+
+       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)));
+
+       dmu_tx_commit(tx);
+       zfs_range_unlock(rl);
+
+       if ((bio_is_fua(bio)) ||
+           zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)
+               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+
+out:
+       return (error);
+}
+
+static int
+zvol_discard(struct bio *bio)
+{
+       zvol_state_t *zv = bio->bi_bdev->bd_disk->private_data;
+       uint64_t start = BIO_BI_SECTOR(bio) << 9;
+       uint64_t size = BIO_BI_SIZE(bio);
+       uint64_t end = start + size;
+       int error;
+       rl_t *rl;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       if (end > zv->zv_volsize)
+               return (SET_ERROR(EIO));
+
+       /*
+        * Align the request to volume block boundaries when a secure erase is
+        * not required.  This will prevent dnode_free_range() from zeroing out
+        * the unaligned parts which is slow (read-modify-write) and useless
+        * since we are not freeing any space by doing so.
+        */
+       if (!bio_is_secure_erase(bio)) {
+               start = P2ROUNDUP(start, zv->zv_volblocksize);
+               end = P2ALIGN(end, zv->zv_volblocksize);
+               size = end - start;
+       }
+
+       if (start >= end)
+               return (0);
+
+       rl = zfs_range_lock(&zv->zv_range_lock, start, size, RL_WRITER);
+
+       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_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;
+       rl_t *rl;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       if (len == 0)
+               return (0);
+
+       rl = zfs_range_lock(&zv->zv_range_lock, offset, len, RL_READER);
+
+       error = dmu_read_bio(zv->zv_objset, ZVOL_OBJ, bio);
+
+       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)
+{
+       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)) {
+               printk(KERN_INFO
+                   "%s: bad access: block=%llu, count=%lu\n",
+                   zv->zv_disk->disk_name,
+                   (long long unsigned)offset,
+                   (long unsigned)sectors);
+               error = SET_ERROR(EIO);
+               goto out1;
+       }
+
+       generic_start_io_acct(rw, sectors, &zv->zv_disk->part0);
+
+       if (rw == WRITE) {
+               if (unlikely(zv->zv_flags & ZVOL_RDONLY)) {
+                       error = SET_ERROR(EROFS);
+                       goto out2;
+               }
+
+               if (bio_is_discard(bio) || bio_is_secure_erase(bio)) {
+                       error = zvol_discard(bio);
+                       goto out2;
+               }
+
+               error = zvol_write(bio);
+       } else
+               error = zvol_read(bio);
+
+out2:
+       generic_end_io_acct(rw, &zv->zv_disk->part0, start);
+out1:
+       BIO_END_IO(bio, -error);
+       spl_fstrans_unmark(cookie);
+#ifdef HAVE_MAKE_REQUEST_FN_RET_INT
+       return (0);
+#elif defined(HAVE_MAKE_REQUEST_FN_RET_QC)
+       return (BLK_QC_T_NONE);
+#endif
+}
+
+static void
+zvol_get_done(zgd_t *zgd, int error)
+{
+       if (zgd->zgd_db)
+               dmu_buf_rele(zgd->zgd_db, zgd);
+
+       zfs_range_unlock(zgd->zgd_rl);
+
+       if (error == 0 && zgd->zgd_bp)
+               zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
+
+       kmem_free(zgd, sizeof (zgd_t));
+}
+
+/*
+ * Get data to generate a TX_WRITE intent log record.
+ */
+static int
+zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
+{
+       zvol_state_t *zv = arg;
+       objset_t *os = zv->zv_objset;
+       uint64_t object = ZVOL_OBJ;
+       uint64_t offset = lr->lr_offset;
+       uint64_t size = lr->lr_length;
+       blkptr_t *bp = &lr->lr_blkptr;
+       dmu_buf_t *db;
+       zgd_t *zgd;
+       int error;
+
+       ASSERT(zio != NULL);
+       ASSERT(size != 0);
+
+       zgd = (zgd_t *)kmem_zalloc(sizeof (zgd_t), KM_SLEEP);
+       zgd->zgd_zilog = zv->zv_zilog;
+       zgd->zgd_rl = zfs_range_lock(&zv->zv_range_lock, offset, size,
+           RL_READER);
+
+       /*
+        * Write records come in two flavors: immediate and indirect.
+        * For small writes it's cheaper to store the data with the
+        * log record (immediate); for large writes it's cheaper to
+        * sync the data and get a pointer to it (indirect) so that
+        * we don't have to write the data twice.
+        */
+       if (buf != NULL) { /* immediate write */
+               error = dmu_read(os, object, offset, size, buf,
+                   DMU_READ_NO_PREFETCH);
+       } else {
+               size = zv->zv_volblocksize;
+               offset = P2ALIGN_TYPED(offset, size, uint64_t);
+               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 = &lr->lr_blkptr;
+
+                       ASSERT(db != NULL);
+                       ASSERT(db->db_offset == offset);
+                       ASSERT(db->db_size == size);
+
+                       error = dmu_sync(zio, lr->lr_common.lrc_txg,
+                           zvol_get_done, zgd);
+
+                       if (error == 0)
+                               return (0);
+               }
+       }
+
+       zvol_get_done(zgd, error);
+
+       return (SET_ERROR(error));
+}
+
+/*
+ * The zvol_state_t's are inserted in increasing MINOR(dev_t) order.
+ */
+static void
+zvol_insert(zvol_state_t *zv_insert)
+{
+       zvol_state_t *zv = NULL;
+
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+       ASSERT3U(MINOR(zv_insert->zv_dev) & ZVOL_MINOR_MASK, ==, 0);
+       for (zv = list_head(&zvol_state_list); zv != NULL;
+           zv = list_next(&zvol_state_list, zv)) {
+               if (MINOR(zv->zv_dev) > MINOR(zv_insert->zv_dev))
+                       break;
+       }
+
+       list_insert_before(&zvol_state_list, zv, zv_insert);
+}
+
+/*
+ * Simply remove the zvol from to list of zvols.
+ */
+static void
+zvol_remove(zvol_state_t *zv_remove)
+{
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+       list_remove(&zvol_state_list, zv_remove);
+}
+
+static int
+zvol_first_open(zvol_state_t *zv)
+{
+       objset_t *os;
+       uint64_t volsize;
+       int error;
+       uint64_t ro;
+
+       /* lie and say we're read-only */
+       error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os);
+       if (error)
+               return (SET_ERROR(-error));
+
+       zv->zv_objset = os;
+
+       error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
+       if (error)
+               goto out_owned;
+
+       error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
+       if (error)
+               goto out_owned;
+
+       error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf);
+       if (error)
+               goto out_owned;
+
+       set_capacity(zv->zv_disk, volsize >> 9);
+       zv->zv_volsize = volsize;
+       zv->zv_zilog = zil_open(os, zvol_get_data);
+
+       if (ro || dmu_objset_is_snapshot(os) ||
+           !spa_writeable(dmu_objset_spa(os))) {
+               set_disk_ro(zv->zv_disk, 1);
+               zv->zv_flags |= ZVOL_RDONLY;
+       } else {
+               set_disk_ro(zv->zv_disk, 0);
+               zv->zv_flags &= ~ZVOL_RDONLY;
+       }
+
+out_owned:
+       if (error) {
+               dmu_objset_disown(os, zvol_tag);
+               zv->zv_objset = NULL;
+       }
+
+       return (SET_ERROR(-error));
+}
+
+static void
+zvol_last_close(zvol_state_t *zv)
+{
+       zil_close(zv->zv_zilog);
+       zv->zv_zilog = NULL;
+
+       dmu_buf_rele(zv->zv_dbuf, zvol_tag);
+       zv->zv_dbuf = NULL;
+
+       /*
+        * Evict cached data
+        */
+       if (dsl_dataset_is_dirty(dmu_objset_ds(zv->zv_objset)) &&
+           !(zv->zv_flags & ZVOL_RDONLY))
+               txg_wait_synced(dmu_objset_pool(zv->zv_objset), 0);
+       (void) dmu_objset_evict_dbufs(zv->zv_objset);
+
+       dmu_objset_disown(zv->zv_objset, zvol_tag);
+       zv->zv_objset = NULL;
+}
+
+static int
+zvol_open(struct block_device *bdev, fmode_t flag)
+{
+       zvol_state_t *zv;
+       int error = 0, drop_mutex = 0;
+
+       /*
+        * If the caller is already holding the mutex do not take it
+        * again, this will happen as part of zvol_create_minor_impl().
+        * Once add_disk() is called the device is live and the kernel
+        * will attempt to open it to read the partition information.
+        */
+       if (!mutex_owned(&zvol_state_lock)) {
+               mutex_enter(&zvol_state_lock);
+               drop_mutex = 1;
+       }
+
+       /*
+        * Obtain a copy of private_data under the lock to make sure
+        * that either the result of zvol_freeg() setting
+        * bdev->bd_disk->private_data to NULL is observed, or zvol_free()
+        * is not called on this zv because of the positive zv_open_count.
+        */
+       zv = bdev->bd_disk->private_data;
+       if (zv == NULL) {
+               error = -ENXIO;
+               goto out_mutex;
+       }
+
+       if (zv->zv_open_count == 0) {
+               error = zvol_first_open(zv);
+               if (error)
+                       goto out_mutex;
+       }
+
+       if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
+               error = -EROFS;
+               goto out_open_count;
+       }
+
+       zv->zv_open_count++;
+
+       check_disk_change(bdev);
+
+out_open_count:
+       if (zv->zv_open_count == 0)
+               zvol_last_close(zv);
+
+out_mutex:
+       if (drop_mutex)
+               mutex_exit(&zvol_state_lock);
+
+       return (SET_ERROR(error));
+}
+
+#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
+static void
+#else
+static int
+#endif
+zvol_release(struct gendisk *disk, fmode_t mode)
+{
+       zvol_state_t *zv = disk->private_data;
+       int drop_mutex = 0;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       if (!mutex_owned(&zvol_state_lock)) {
+               mutex_enter(&zvol_state_lock);
+               drop_mutex = 1;
+       }
+
+       zv->zv_open_count--;
+       if (zv->zv_open_count == 0)
+               zvol_last_close(zv);
+
+       if (drop_mutex)
+               mutex_exit(&zvol_state_lock);
+
+#ifndef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
+       return (0);
+#endif
+}
+
+static int
+zvol_ioctl(struct block_device *bdev, fmode_t mode,
+    unsigned int cmd, unsigned long arg)
+{
+       zvol_state_t *zv = bdev->bd_disk->private_data;
+       int error = 0;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       switch (cmd) {
+       case BLKFLSBUF:
+               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+               break;
+       case BLKZNAME:
+               error = copy_to_user((void *)arg, zv->zv_name, MAXNAMELEN);
+               break;
+
+       default:
+               error = -ENOTTY;
+               break;
+
+       }
+
+       return (SET_ERROR(error));
+}
+
+#ifdef CONFIG_COMPAT
+static int
+zvol_compat_ioctl(struct block_device *bdev, fmode_t mode,
+    unsigned cmd, unsigned long arg)
+{
+       return (zvol_ioctl(bdev, mode, cmd, arg));
+}
+#else
+#define        zvol_compat_ioctl       NULL
+#endif
+
+static int zvol_media_changed(struct gendisk *disk)
+{
+       zvol_state_t *zv = disk->private_data;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       return (zv->zv_changed);
+}
+
+static int zvol_revalidate_disk(struct gendisk *disk)
+{
+       zvol_state_t *zv = disk->private_data;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       zv->zv_changed = 0;
+       set_capacity(zv->zv_disk, zv->zv_volsize >> 9);
+
+       return (0);
+}
+
+/*
+ * Provide a simple virtual geometry for legacy compatibility.  For devices
+ * smaller than 1 MiB a small head and sector count is used to allow very
+ * tiny devices.  For devices over 1 Mib a standard head and sector count
+ * is used to keep the cylinders count reasonable.
+ */
+static int
+zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+       zvol_state_t *zv = bdev->bd_disk->private_data;
+       sector_t sectors;
+
+       ASSERT(zv && zv->zv_open_count > 0);
+
+       sectors = get_capacity(zv->zv_disk);
+
+       if (sectors > 2048) {
+               geo->heads = 16;
+               geo->sectors = 63;
+       } else {
+               geo->heads = 2;
+               geo->sectors = 4;
+       }
+
+       geo->start = 0;
+       geo->cylinders = sectors / (geo->heads * geo->sectors);
+
+       return (0);
+}
+
+static struct kobject *
+zvol_probe(dev_t dev, int *part, void *arg)
+{
+       zvol_state_t *zv;
+       struct kobject *kobj;
+
+       mutex_enter(&zvol_state_lock);
+       zv = zvol_find_by_dev(dev);
+       kobj = zv ? get_disk(zv->zv_disk) : NULL;
+       mutex_exit(&zvol_state_lock);
+
+       return (kobj);
+}
+
+#ifdef HAVE_BDEV_BLOCK_DEVICE_OPERATIONS
+static struct block_device_operations zvol_ops = {
+       .open                   = zvol_open,
+       .release                = zvol_release,
+       .ioctl                  = zvol_ioctl,
+       .compat_ioctl           = zvol_compat_ioctl,
+       .media_changed          = zvol_media_changed,
+       .revalidate_disk        = zvol_revalidate_disk,
+       .getgeo                 = zvol_getgeo,
+       .owner                  = THIS_MODULE,
+};
+
+#else /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
+
+static int
+zvol_open_by_inode(struct inode *inode, struct file *file)
+{
+       return (zvol_open(inode->i_bdev, file->f_mode));
+}
+
+static int
+zvol_release_by_inode(struct inode *inode, struct file *file)
+{
+       return (zvol_release(inode->i_bdev->bd_disk, file->f_mode));
+}
+
+static int
+zvol_ioctl_by_inode(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+       if (file == NULL || inode == NULL)
+               return (SET_ERROR(-EINVAL));
+
+       return (zvol_ioctl(inode->i_bdev, file->f_mode, cmd, arg));
+}
+
+#ifdef CONFIG_COMPAT
+static long
+zvol_compat_ioctl_by_inode(struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+       if (file == NULL)
+               return (SET_ERROR(-EINVAL));
+
+       return (zvol_compat_ioctl(file->f_dentry->d_inode->i_bdev,
+           file->f_mode, cmd, arg));
+}
+#else
+#define        zvol_compat_ioctl_by_inode      NULL
+#endif
+
+static struct block_device_operations zvol_ops = {
+       .open                   = zvol_open_by_inode,
+       .release                = zvol_release_by_inode,
+       .ioctl                  = zvol_ioctl_by_inode,
+       .compat_ioctl           = zvol_compat_ioctl_by_inode,
+       .media_changed          = zvol_media_changed,
+       .revalidate_disk        = zvol_revalidate_disk,
+       .getgeo                 = zvol_getgeo,
+       .owner                  = THIS_MODULE,
+};
+#endif /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */
+
+/*
+ * Allocate memory for a new zvol_state_t and setup the required
+ * request queue and generic disk structures for the block device.
+ */
+static zvol_state_t *
+zvol_alloc(dev_t dev, const char *name)
+{
+       zvol_state_t *zv;
+
+       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);
+       if (zv->zv_queue == NULL)
+               goto out_kmem;
+
+       blk_queue_make_request(zv->zv_queue, zvol_request);
+       blk_queue_set_write_cache(zv->zv_queue, B_TRUE, B_TRUE);
+
+       zv->zv_disk = alloc_disk(ZVOL_MINORS);
+       if (zv->zv_disk == NULL)
+               goto out_queue;
+
+       zv->zv_queue->queuedata = zv;
+       zv->zv_dev = dev;
+       zv->zv_open_count = 0;
+       strlcpy(zv->zv_name, name, MAXNAMELEN);
+
+       zfs_rlock_init(&zv->zv_range_lock);
+
+       zv->zv_disk->major = zvol_major;
+       zv->zv_disk->first_minor = (dev & MINORMASK);
+       zv->zv_disk->fops = &zvol_ops;
+       zv->zv_disk->private_data = zv;
+       zv->zv_disk->queue = zv->zv_queue;
+       snprintf(zv->zv_disk->disk_name, DISK_NAME_LEN, "%s%d",
+           ZVOL_DEV_NAME, (dev & MINORMASK));
+
+       return (zv);
+
+out_queue:
+       blk_cleanup_queue(zv->zv_queue);
+out_kmem:
+       kmem_free(zv, sizeof (zvol_state_t));
+
+       return (NULL);
+}
+
+/*
+ * Cleanup then free a zvol_state_t which was created by zvol_alloc().
+ */
+static void
+zvol_free(zvol_state_t *zv)
+{
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+       ASSERT(zv->zv_open_count == 0);
+
+       zfs_rlock_destroy(&zv->zv_range_lock);
+
+       zv->zv_disk->private_data = NULL;
+
+       del_gendisk(zv->zv_disk);
+       blk_cleanup_queue(zv->zv_queue);
+       put_disk(zv->zv_disk);
+
+       kmem_free(zv, sizeof (zvol_state_t));
+}
+
+/*
+ * Create a block device minor node and setup the linkage between it
+ * and the specified volume.  Once this function returns the block
+ * device is live and ready for use.
+ */
+static int
+zvol_create_minor_impl(const char *name)
+{
+       zvol_state_t *zv;
+       objset_t *os;
+       dmu_object_info_t *doi;
+       uint64_t volsize;
+       uint64_t len;
+       unsigned minor = 0;
+       int error = 0;
+
+       mutex_enter(&zvol_state_lock);
+
+       zv = zvol_find_by_name(name);
+       if (zv) {
+               error = SET_ERROR(EEXIST);
+               goto out;
+       }
+
+       doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
+
+       error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
+       if (error)
+               goto out_doi;
+
+       error = dmu_object_info(os, ZVOL_OBJ, doi);
+       if (error)
+               goto out_dmu_objset_disown;
+
+       error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
+       if (error)
+               goto out_dmu_objset_disown;
+
+       error = zvol_find_minor(&minor);
+       if (error)
+               goto out_dmu_objset_disown;
+
+       zv = zvol_alloc(MKDEV(zvol_major, minor), name);
+       if (zv == NULL) {
+               error = SET_ERROR(EAGAIN);
+               goto out_dmu_objset_disown;
+       }
+
+       if (dmu_objset_is_snapshot(os))
+               zv->zv_flags |= ZVOL_RDONLY;
+
+       zv->zv_volblocksize = doi->doi_data_block_size;
+       zv->zv_volsize = volsize;
+       zv->zv_objset = os;
+
+       set_capacity(zv->zv_disk, zv->zv_volsize >> 9);
+
+       blk_queue_max_hw_sectors(zv->zv_queue, (DMU_MAX_ACCESS / 4) >> 9);
+       blk_queue_max_segments(zv->zv_queue, UINT16_MAX);
+       blk_queue_max_segment_size(zv->zv_queue, UINT_MAX);
+       blk_queue_physical_block_size(zv->zv_queue, zv->zv_volblocksize);
+       blk_queue_io_opt(zv->zv_queue, zv->zv_volblocksize);
+       blk_queue_max_discard_sectors(zv->zv_queue,
+           (zvol_max_discard_blocks * zv->zv_volblocksize) >> 9);
+       blk_queue_discard_granularity(zv->zv_queue, zv->zv_volblocksize);
+       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zv->zv_queue);
+#ifdef QUEUE_FLAG_NONROT
+       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zv->zv_queue);
+#endif
+#ifdef QUEUE_FLAG_ADD_RANDOM
+       queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, zv->zv_queue);
+#endif
+
+       if (spa_writeable(dmu_objset_spa(os))) {
+               if (zil_replay_disable)
+                       zil_destroy(dmu_objset_zil(os), B_FALSE);
+               else
+                       zil_replay(os, zv, zvol_replay_vector);
+       }
+
+       /*
+        * When udev detects the addition of the device it will immediately
+        * invoke blkid(8) to determine the type of content on the device.
+        * Prefetching the blocks commonly scanned by blkid(8) will speed
+        * up this process.
+        */
+       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);
+       }
+
+       zv->zv_objset = NULL;
+out_dmu_objset_disown:
+       dmu_objset_disown(os, zvol_tag);
+out_doi:
+       kmem_free(doi, sizeof (dmu_object_info_t));
+out:
+
+       if (error == 0) {
+               zvol_insert(zv);
+               /*
+                * Drop the lock to prevent deadlock with sys_open() ->
+                * zvol_open(), which first takes bd_disk->bd_mutex and then
+                * takes zvol_state_lock, whereas this code path first takes
+                * zvol_state_lock, and then takes bd_disk->bd_mutex.
+                */
+               mutex_exit(&zvol_state_lock);
+               add_disk(zv->zv_disk);
+       } else {
+               mutex_exit(&zvol_state_lock);
+       }
+
+       return (SET_ERROR(error));
+}
+
+/*
+ * Rename a block device minor mode for the specified volume.
+ */
+static void
+zvol_rename_minor(zvol_state_t *zv, const char *newname)
+{
+       int readonly = get_disk_ro(zv->zv_disk);
+
+       ASSERT(MUTEX_HELD(&zvol_state_lock));
+
+       strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
+
+       /*
+        * The block device's read-only state is briefly changed causing
+        * a KOBJ_CHANGE uevent to be issued.  This ensures udev detects
+        * the name change and fixes the symlinks.  This does not change
+        * ZVOL_RDONLY in zv->zv_flags so the actual read-only state never
+        * changes.  This would normally be done using kobject_uevent() but
+        * that is a GPL-only symbol which is why we need this workaround.
+        */
+       set_disk_ro(zv->zv_disk, !readonly);
+       set_disk_ro(zv->zv_disk, readonly);
+}
+
+
+/*
+ * Mask errors to continue dmu_objset_find() traversal
+ */
+static int
+zvol_create_snap_minor_cb(const char *dsname, void *arg)
+{
+       const char *name = (const char *)arg;
+
+       ASSERT0(MUTEX_HELD(&spa_namespace_lock));
+
+       /* skip the designated dataset */
+       if (name && strcmp(dsname, name) == 0)
+               return (0);
+
+       /* at this point, the dsname should name a snapshot */
+       if (strchr(dsname, '@') == 0) {
+               dprintf("zvol_create_snap_minor_cb(): "
+                       "%s is not a shapshot name\n", dsname);
+       } else {
+               (void) zvol_create_minor_impl(dsname);
+       }
+
+       return (0);
+}
+
+/*
+ * Mask errors to continue dmu_objset_find() traversal
+ */
+static int
+zvol_create_minors_cb(const char *dsname, void *arg)
+{
+       uint64_t snapdev;
+       int error;
+
+       ASSERT0(MUTEX_HELD(&spa_namespace_lock));
+
+       error = dsl_prop_get_integer(dsname, "snapdev", &snapdev, NULL);
+       if (error)
+               return (0);
+
+       /*
+        * Given the name and the 'snapdev' property, create device minor nodes
+        * with the linkages to zvols/snapshots as needed.
+        * If the name represents a zvol, create a minor node for the zvol, then
+        * check if its snapshots are 'visible', and if so, iterate over the
+        * snapshots and create device minor nodes for those.
+        */
+       if (strchr(dsname, '@') == 0) {
+               /* create minor for the 'dsname' explicitly */
+               error = zvol_create_minor_impl(dsname);
+               if ((error == 0 || error == EEXIST) &&
+                   (snapdev == ZFS_SNAPDEV_VISIBLE)) {
+                       fstrans_cookie_t cookie = spl_fstrans_mark();
+                       /*
+                        * traverse snapshots only, do not traverse children,
+                        * and skip the 'dsname'
+                        */
+                       error = dmu_objset_find((char *)dsname,
+                           zvol_create_snap_minor_cb, (void *)dsname,
+                           DS_FIND_SNAPSHOTS);
+                       spl_fstrans_unmark(cookie);
+               }
+       } else {
+               dprintf("zvol_create_minors_cb(): %s is not a zvol name\n",
+                       dsname);
+       }
+
+       return (0);
+}
+
+/*
+ * Create minors for the specified dataset, including children and snapshots.
+ * Pay attention to the 'snapdev' property and iterate over the snapshots
+ * only if they are 'visible'. This approach allows one to assure that the
+ * snapshot metadata is read from disk only if it is needed.
+ *
+ * The name can represent a dataset to be recursively scanned for zvols and
+ * their snapshots, or a single zvol snapshot. If the name represents a
+ * dataset, the scan is performed in two nested stages:
+ * - scan the dataset for zvols, and
+ * - for each zvol, create a minor node, then check if the zvol's snapshots
+ *   are 'visible', and only then iterate over the snapshots if needed
+ *
+ * If the name represents a snapshot, a check is perfromed if the snapshot is
+ * 'visible' (which also verifies that the parent is a zvol), and if so,
+ * a minor node for that snapshot is created.
+ */
+static int
+zvol_create_minors_impl(const char *name)
+{
+       int error = 0;
+       fstrans_cookie_t cookie;
+       char *atp, *parent;
+
+       if (zvol_inhibit_dev)
+               return (0);
+
+       parent = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+       (void) strlcpy(parent, name, MAXPATHLEN);
+
+       if ((atp = strrchr(parent, '@')) != NULL) {
+               uint64_t snapdev;
+
+               *atp = '\0';
+               error = dsl_prop_get_integer(parent, "snapdev",
+                   &snapdev, NULL);
+
+               if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE)
+                       error = zvol_create_minor_impl(name);
+       } else {
+               cookie = spl_fstrans_mark();
+               error = dmu_objset_find(parent, zvol_create_minors_cb,
+                   NULL, DS_FIND_CHILDREN);
+               spl_fstrans_unmark(cookie);
+       }
+
+       kmem_free(parent, MAXPATHLEN);
+
+       return (SET_ERROR(error));
+}
+
+/*
+ * Remove minors for specified dataset including children and snapshots.
+ */
+static void
+zvol_remove_minors_impl(const char *name)
+{
+       zvol_state_t *zv, *zv_next;
+       int namelen = ((name) ? strlen(name) : 0);
+
+       if (zvol_inhibit_dev)
+               return;
+
+       mutex_enter(&zvol_state_lock);
+
+       for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
+               zv_next = list_next(&zvol_state_list, zv);
+
+               if (name == NULL || strcmp(zv->zv_name, name) == 0 ||
+                   (strncmp(zv->zv_name, name, namelen) == 0 &&
+                   (zv->zv_name[namelen] == '/' ||
+                   zv->zv_name[namelen] == '@'))) {
+
+                       /* If in use, leave alone */
+                       if (zv->zv_open_count > 0)
+                               continue;
+
+                       zvol_remove(zv);
+                       zvol_free(zv);
+               }
+       }
+
+       mutex_exit(&zvol_state_lock);
+}
+
+/* Remove minor for this specific snapshot only */
+static void
+zvol_remove_minor_impl(const char *name)
+{
+       zvol_state_t *zv, *zv_next;
+
+       if (zvol_inhibit_dev)
+               return;
+
+       if (strchr(name, '@') == NULL)
+               return;
+
+       mutex_enter(&zvol_state_lock);
+
+       for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
+               zv_next = list_next(&zvol_state_list, zv);
+
+               if (strcmp(zv->zv_name, name) == 0) {
+                       /* If in use, leave alone */
+                       if (zv->zv_open_count > 0)
+                               continue;
+                       zvol_remove(zv);
+                       zvol_free(zv);
+                       break;
+               }
+       }
+
+       mutex_exit(&zvol_state_lock);
+}
+
+/*
+ * Rename minors for specified dataset including children and snapshots.
+ */
+static void
+zvol_rename_minors_impl(const char *oldname, const char *newname)
+{
+       zvol_state_t *zv, *zv_next;
+       int oldnamelen, newnamelen;
+       char *name;
+
+       if (zvol_inhibit_dev)
+               return;
+
+       oldnamelen = strlen(oldname);
+       newnamelen = strlen(newname);
+       name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+       mutex_enter(&zvol_state_lock);
+
+       for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
+               zv_next = list_next(&zvol_state_list, zv);
+
+               /* If in use, leave alone */
+               if (zv->zv_open_count > 0)
+                       continue;
+
+               if (strcmp(zv->zv_name, oldname) == 0) {
+                       zvol_rename_minor(zv, newname);
+               } else if (strncmp(zv->zv_name, oldname, oldnamelen) == 0 &&
+                   (zv->zv_name[oldnamelen] == '/' ||
+                   zv->zv_name[oldnamelen] == '@')) {
+                       snprintf(name, MAXNAMELEN, "%s%c%s", newname,
+                           zv->zv_name[oldnamelen],
+                           zv->zv_name + oldnamelen + 1);
+                       zvol_rename_minor(zv, name);
+               }
+       }
+
+       mutex_exit(&zvol_state_lock);
+
+       kmem_free(name, MAXNAMELEN);
+}
+
+typedef struct zvol_snapdev_cb_arg {
+       uint64_t snapdev;
+} zvol_snapdev_cb_arg_t;
+
+static int
+zvol_set_snapdev_cb(const char *dsname, void *param) {
+       zvol_snapdev_cb_arg_t *arg = param;
+
+       if (strchr(dsname, '@') == NULL)
+               return (0);
+
+       switch (arg->snapdev) {
+               case ZFS_SNAPDEV_VISIBLE:
+                       (void) zvol_create_minor_impl(dsname);
+                       break;
+               case ZFS_SNAPDEV_HIDDEN:
+                       (void) zvol_remove_minor_impl(dsname);
+                       break;
+       }
+
+       return (0);
+}
+
+static void
+zvol_set_snapdev_impl(char *name, uint64_t snapdev)
+{
+       zvol_snapdev_cb_arg_t arg = {snapdev};
+       fstrans_cookie_t cookie = spl_fstrans_mark();
+       /*
+        * The zvol_set_snapdev_sync() sets snapdev appropriately
+        * in the dataset hierarchy. Here, we only scan snapshots.
+        */
+       dmu_objset_find(name, zvol_set_snapdev_cb, &arg, DS_FIND_SNAPSHOTS);
+       spl_fstrans_unmark(cookie);
+}
+
+static zvol_task_t *
+zvol_task_alloc(zvol_async_op_t op, const char *name1, const char *name2,
+    uint64_t snapdev)
+{
+       zvol_task_t *task;
+       char *delim;
+
+       /* Never allow tasks on hidden names. */
+       if (name1[0] == '$')
+               return (NULL);
+
+       task = kmem_zalloc(sizeof (zvol_task_t), KM_SLEEP);
+       task->op = op;
+       task->snapdev = snapdev;
+       delim = strchr(name1, '/');
+       strlcpy(task->pool, name1, delim ? (delim - name1 + 1) : MAXNAMELEN);
+
+       strlcpy(task->name1, name1, MAXNAMELEN);
+       if (name2 != NULL)
+               strlcpy(task->name2, name2, MAXNAMELEN);
+
+       return (task);
+}
+
+static void
+zvol_task_free(zvol_task_t *task)
+{
+       kmem_free(task, sizeof (zvol_task_t));
+}
+
+/*
+ * The worker thread function performed asynchronously.
+ */
+static void
+zvol_task_cb(void *param)
+{
+       zvol_task_t *task = (zvol_task_t *)param;
+
+       switch (task->op) {
+       case ZVOL_ASYNC_CREATE_MINORS:
+               (void) zvol_create_minors_impl(task->name1);
+               break;
+       case ZVOL_ASYNC_REMOVE_MINORS:
+               zvol_remove_minors_impl(task->name1);
+               break;
+       case ZVOL_ASYNC_RENAME_MINORS:
+               zvol_rename_minors_impl(task->name1, task->name2);
+               break;
+       case ZVOL_ASYNC_SET_SNAPDEV:
+               zvol_set_snapdev_impl(task->name1, task->snapdev);
+               break;
+       default:
+               VERIFY(0);
+               break;
+       }
+
+       zvol_task_free(task);
+}
+
+typedef struct zvol_set_snapdev_arg {
+       const char *zsda_name;
+       uint64_t zsda_value;
+       zprop_source_t zsda_source;
+       dmu_tx_t *zsda_tx;
+} zvol_set_snapdev_arg_t;
+
+/*
+ * Sanity check the dataset for safe use by the sync task.  No additional
+ * conditions are imposed.
+ */
+static int
+zvol_set_snapdev_check(void *arg, dmu_tx_t *tx)
+{
+       zvol_set_snapdev_arg_t *zsda = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *dd;
+       int error;
+
+       error = dsl_dir_hold(dp, zsda->zsda_name, FTAG, &dd, NULL);
+       if (error != 0)
+               return (error);
+
+       dsl_dir_rele(dd, FTAG);
+
+       return (error);
+}
+
+static int
+zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
+{
+       zvol_set_snapdev_arg_t *zsda = arg;
+       char dsname[MAXNAMELEN];
+       zvol_task_t *task;
+
+       dsl_dataset_name(ds, dsname);
+       dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_SNAPDEV),
+           zsda->zsda_source, sizeof (zsda->zsda_value), 1,
+           &zsda->zsda_value, zsda->zsda_tx);
+
+       task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname,
+           NULL, zsda->zsda_value);
+       if (task == NULL)
+               return (0);
+
+       (void) taskq_dispatch(dp->dp_spa->spa_zvol_taskq, zvol_task_cb,
+               task, TQ_SLEEP);
+       return (0);
+}
+
+/*
+ * Traverse all child snapshot datasets and apply snapdev appropriately.
+ */
+static void
+zvol_set_snapdev_sync(void *arg, dmu_tx_t *tx)
+{
+       zvol_set_snapdev_arg_t *zsda = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       dsl_dir_t *dd;
+
+       VERIFY0(dsl_dir_hold(dp, zsda->zsda_name, FTAG, &dd, NULL));
+       zsda->zsda_tx = tx;
+
+       dmu_objset_find_dp(dp, dd->dd_object, zvol_set_snapdev_sync_cb,
+           zsda, DS_FIND_CHILDREN);
+
+       dsl_dir_rele(dd, FTAG);
+}
+
+int
+zvol_set_snapdev(const char *ddname, zprop_source_t source, uint64_t snapdev)
+{
+       zvol_set_snapdev_arg_t zsda;
+
+       zsda.zsda_name = ddname;
+       zsda.zsda_source = source;
+       zsda.zsda_value = snapdev;
+
+       return (dsl_sync_task(ddname, zvol_set_snapdev_check,
+           zvol_set_snapdev_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+void
+zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
+{
+       zvol_task_t *task;
+       taskqid_t id;
+
+       task = zvol_task_alloc(ZVOL_ASYNC_CREATE_MINORS, name, NULL, ~0ULL);
+       if (task == NULL)
+               return;
+
+       id = taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+       if ((async == B_FALSE) && (id != 0))
+               taskq_wait_id(spa->spa_zvol_taskq, id);
+}
+
+void
+zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
+{
+       zvol_task_t *task;
+       taskqid_t id;
+
+       task = zvol_task_alloc(ZVOL_ASYNC_REMOVE_MINORS, name, NULL, ~0ULL);
+       if (task == NULL)
+               return;
+
+       id = taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+       if ((async == B_FALSE) && (id != 0))
+               taskq_wait_id(spa->spa_zvol_taskq, id);
+}
+
+void
+zvol_rename_minors(spa_t *spa, const char *name1, const char *name2,
+    boolean_t async)
+{
+       zvol_task_t *task;
+       taskqid_t id;
+
+       task = zvol_task_alloc(ZVOL_ASYNC_RENAME_MINORS, name1, name2, ~0ULL);
+       if (task == NULL)
+               return;
+
+       id = taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+       if ((async == B_FALSE) && (id != 0))
+               taskq_wait_id(spa->spa_zvol_taskq, id);
+}
+
+int
+zvol_init(void)
+{
+       int error;
+
+       list_create(&zvol_state_list, sizeof (zvol_state_t),
+           offsetof(zvol_state_t, zv_next));
+       mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       error = register_blkdev(zvol_major, ZVOL_DRIVER);
+       if (error) {
+               printk(KERN_INFO "ZFS: register_blkdev() failed %d\n", error);
+               goto out;
+       }
+
+       blk_register_region(MKDEV(zvol_major, 0), 1UL << MINORBITS,
+           THIS_MODULE, zvol_probe, NULL, NULL);
+
+       return (0);
+
+out:
+       mutex_destroy(&zvol_state_lock);
+       list_destroy(&zvol_state_list);
+
+       return (SET_ERROR(error));
+}
+
+void
+zvol_fini(void)
+{
+       zvol_remove_minors_impl(NULL);
+
+       blk_unregister_region(MKDEV(zvol_major, 0), 1UL << MINORBITS);
+       unregister_blkdev(zvol_major, ZVOL_DRIVER);
+
+       list_destroy(&zvol_state_list);
+       mutex_destroy(&zvol_state_lock);
+}
+
+module_param(zvol_inhibit_dev, uint, 0644);
+MODULE_PARM_DESC(zvol_inhibit_dev, "Do not create zvol device nodes");
+
+module_param(zvol_major, uint, 0444);
+MODULE_PARM_DESC(zvol_major, "Major number for zvol device");
+
+module_param(zvol_max_discard_blocks, ulong, 0444);
+MODULE_PARM_DESC(zvol_max_discard_blocks, "Max number of blocks to discard");
+
+module_param(zvol_prefetch_bytes, uint, 0644);
+MODULE_PARM_DESC(zvol_prefetch_bytes, "Prefetch N bytes at zvol start+end");
diff --git a/zfs/module/zpios/Makefile.in b/zfs/module/zpios/Makefile.in
new file mode 100644 (file)
index 0000000..10a101d
--- /dev/null
@@ -0,0 +1,10 @@
+src = @abs_top_srcdir@/module/zpios
+obj = @abs_builddir@
+
+MODULE := zpios
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+$(MODULE)-objs += pios.o
diff --git a/zfs/module/zpios/pios.c b/zfs/module/zpios/pios.c
new file mode 100644 (file)
index 0000000..e3a85c1
--- /dev/null
@@ -0,0 +1,1325 @@
+/*
+ *  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/>.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dmu.h>
+#include <sys/txg.h>
+#include <sys/dsl_destroy.h>
+#include <linux/miscdevice.h>
+#include "zpios-internal.h"
+
+
+static char *zpios_tag = "zpios_tag";
+
+static int
+zpios_upcall(char *path, char *phase, run_args_t *run_args, int rc)
+{
+       /*
+        * This is stack heavy but it should be OK since we are only
+        * making the upcall between tests when the stack is shallow.
+        */
+       char id[16], chunk_size[16], region_size[16], thread_count[16];
+       char region_count[16], offset[16], region_noise[16], chunk_noise[16];
+       char thread_delay[16], flags[16], result[8];
+       char *argv[16], *envp[4];
+
+       if ((path == NULL) || (strlen(path) == 0))
+               return (-ENOENT);
+
+       snprintf(id, 15, "%d", run_args->id);
+       snprintf(chunk_size, 15, "%lu", (long unsigned)run_args->chunk_size);
+       snprintf(region_size, 15, "%lu", (long unsigned) run_args->region_size);
+       snprintf(thread_count, 15, "%u", run_args->thread_count);
+       snprintf(region_count, 15, "%u", run_args->region_count);
+       snprintf(offset, 15, "%lu", (long unsigned)run_args->offset);
+       snprintf(region_noise, 15, "%u", run_args->region_noise);
+       snprintf(chunk_noise, 15, "%u", run_args->chunk_noise);
+       snprintf(thread_delay, 15, "%u", run_args->thread_delay);
+       snprintf(flags, 15, "0x%x", run_args->flags);
+       snprintf(result, 7, "%d", rc);
+
+       /* Passing 15 args to registered pre/post upcall */
+       argv[0] = path;
+       argv[1] = phase;
+       argv[2] = strlen(run_args->log) ? run_args->log : "<none>";
+       argv[3] = id;
+       argv[4] = run_args->pool;
+       argv[5] = chunk_size;
+       argv[6] = region_size;
+       argv[7] = thread_count;
+       argv[8] = region_count;
+       argv[9] = offset;
+       argv[10] = region_noise;
+       argv[11] = chunk_noise;
+       argv[12] = thread_delay;
+       argv[13] = flags;
+       argv[14] = result;
+       argv[15] = NULL;
+
+       /* Passing environment for user space upcall */
+       envp[0] = "HOME=/";
+       envp[1] = "TERM=linux";
+       envp[2] = "PATH=/sbin:/usr/sbin:/bin:/usr/bin";
+       envp[3] = NULL;
+
+       return (call_usermodehelper(path, argv, envp, UMH_WAIT_PROC));
+}
+
+static int
+zpios_print(struct file *file, const char *format, ...)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+       va_list adx;
+       int rc;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       va_start(adx, format);
+       spin_lock(&info->info_lock);
+
+       /* Don't allow the kernel to start a write in the red zone */
+       if ((int)(info->info_head - info->info_buffer) >
+           (info->info_size - ZPIOS_INFO_BUFFER_REDZONE)) {
+               rc = -EOVERFLOW;
+       } else {
+               rc = vsprintf(info->info_head, format, adx);
+               if (rc >= 0)
+                       info->info_head += rc;
+       }
+
+       spin_unlock(&info->info_lock);
+       va_end(adx);
+
+       return (rc);
+}
+
+static uint64_t
+zpios_dmu_object_create(run_args_t *run_args, objset_t *os)
+{
+       struct dmu_tx *tx;
+       uint64_t obj = 0ULL;
+       int rc;
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, OBJ_SIZE);
+       rc = dmu_tx_assign(tx, TXG_WAIT);
+       if (rc) {
+               zpios_print(run_args->file,
+                   "dmu_tx_assign() failed: %d\n", rc);
+               dmu_tx_abort(tx);
+               return (obj);
+       }
+
+       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);
+       if (rc) {
+               zpios_print(run_args->file,
+                           "dmu_object_set_blocksize() failed: %d\n", rc);
+               dmu_tx_abort(tx);
+               return (obj);
+       }
+
+       dmu_tx_commit(tx);
+
+       return (obj);
+}
+
+static int
+zpios_dmu_object_free(run_args_t *run_args, objset_t *os, uint64_t obj)
+{
+       struct dmu_tx *tx;
+       int rc;
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END);
+       rc = dmu_tx_assign(tx, TXG_WAIT);
+       if (rc) {
+               zpios_print(run_args->file,
+                           "dmu_tx_assign() failed: %d\n", rc);
+               dmu_tx_abort(tx);
+               return (rc);
+       }
+
+       rc = dmu_object_free(os, obj, tx);
+       if (rc) {
+               zpios_print(run_args->file,
+                           "dmu_object_free() failed: %d\n", rc);
+               dmu_tx_abort(tx);
+               return (rc);
+       }
+
+       dmu_tx_commit(tx);
+
+       return (0);
+}
+
+static int
+zpios_dmu_setup(run_args_t *run_args)
+{
+       zpios_time_t *t = &(run_args->stats.cr_time);
+       objset_t *os;
+       char name[32];
+       uint64_t obj = 0ULL;
+       int i, rc = 0, rc2;
+
+       (void) zpios_upcall(run_args->pre, PHASE_PRE_CREATE, run_args, 0);
+       t->start = zpios_timespec_now();
+
+       (void) snprintf(name, 32, "%s/id_%d", run_args->pool, run_args->id);
+       rc = dmu_objset_create(name, DMU_OST_OTHER, 0, NULL, NULL);
+       if (rc) {
+               zpios_print(run_args->file, "Error dmu_objset_create(%s, ...) "
+                           "failed: %d\n", name, rc);
+               goto out;
+       }
+
+       rc = dmu_objset_own(name, DMU_OST_OTHER, 0, zpios_tag, &os);
+       if (rc) {
+               zpios_print(run_args->file, "Error dmu_objset_own(%s, ...) "
+                           "failed: %d\n", name, rc);
+               goto out_destroy;
+       }
+
+       if (!(run_args->flags & DMU_FPP)) {
+               obj = zpios_dmu_object_create(run_args, os);
+               if (obj == 0) {
+                       rc = -EBADF;
+                       zpios_print(run_args->file, "Error zpios_dmu_"
+                                   "object_create() failed, %d\n", rc);
+                       goto out_destroy;
+               }
+       }
+
+       for (i = 0; i < run_args->region_count; i++) {
+               zpios_region_t *region;
+
+               region = &run_args->regions[i];
+               mutex_init(&region->lock, NULL, MUTEX_DEFAULT, NULL);
+
+               if (run_args->flags & DMU_FPP) {
+                       /* File per process */
+                       region->obj.os  = os;
+                       region->obj.obj = zpios_dmu_object_create(run_args, os);
+                       ASSERT(region->obj.obj > 0); /* XXX - Handle this */
+                       region->wr_offset   = run_args->offset;
+                       region->rd_offset   = run_args->offset;
+                       region->init_offset = run_args->offset;
+                       region->max_offset  = run_args->offset +
+                           run_args->region_size;
+               } else {
+                       /* Single shared file */
+                       region->obj.os  = os;
+                       region->obj.obj = obj;
+                       region->wr_offset   = run_args->offset * i;
+                       region->rd_offset   = run_args->offset * i;
+                       region->init_offset = run_args->offset * i;
+                       region->max_offset  = run_args->offset *
+                           i + run_args->region_size;
+               }
+       }
+
+       run_args->os = os;
+out_destroy:
+       if (rc) {
+               rc2 = dsl_destroy_head(name);
+               if (rc2)
+                       zpios_print(run_args->file, "Error dsl_destroy_head"
+                                   "(%s, ...) failed: %d\n", name, rc2);
+       }
+out:
+       t->stop  = zpios_timespec_now();
+       t->delta = zpios_timespec_sub(t->stop, t->start);
+       (void) zpios_upcall(run_args->post, PHASE_POST_CREATE, run_args, rc);
+
+       return (rc);
+}
+
+static int
+zpios_setup_run(run_args_t **run_args, zpios_cmd_t *kcmd, struct file *file)
+{
+       run_args_t *ra;
+       int rc, size;
+
+       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);
+       strncpy(ra->pre, kcmd->cmd_pre, ZPIOS_PATH_SIZE - 1);
+       strncpy(ra->post, kcmd->cmd_post, ZPIOS_PATH_SIZE - 1);
+       strncpy(ra->log, kcmd->cmd_log, ZPIOS_PATH_SIZE - 1);
+       ra->id                  = kcmd->cmd_id;
+       ra->chunk_size          = kcmd->cmd_chunk_size;
+       ra->thread_count        = kcmd->cmd_thread_count;
+       ra->region_count        = kcmd->cmd_region_count;
+       ra->region_size         = kcmd->cmd_region_size;
+       ra->offset              = kcmd->cmd_offset;
+       ra->region_noise        = kcmd->cmd_region_noise;
+       ra->chunk_noise         = kcmd->cmd_chunk_noise;
+       ra->thread_delay        = kcmd->cmd_thread_delay;
+       ra->flags               = kcmd->cmd_flags;
+       ra->stats.wr_data       = 0;
+       ra->stats.wr_chunks     = 0;
+       ra->stats.rd_data       = 0;
+       ra->stats.rd_chunks     = 0;
+       ra->region_next         = 0;
+       ra->file                = file;
+       mutex_init(&ra->lock_work, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&ra->lock_ctl, NULL, MUTEX_DEFAULT, NULL);
+
+       (void) zpios_upcall(ra->pre, PHASE_PRE_RUN, ra, 0);
+
+       rc = zpios_dmu_setup(ra);
+       if (rc) {
+               mutex_destroy(&ra->lock_ctl);
+               mutex_destroy(&ra->lock_work);
+               vmem_free(ra, size);
+               *run_args = NULL;
+       }
+
+       return (rc);
+}
+
+static int
+zpios_get_work_item(run_args_t *run_args, dmu_obj_t *obj, __u64 *offset,
+                   __u32 *chunk_size, zpios_region_t **region, __u32 flags)
+{
+       int i, j, count = 0;
+       unsigned int random_int;
+
+       get_random_bytes(&random_int, sizeof (unsigned int));
+
+       mutex_enter(&run_args->lock_work);
+       i = run_args->region_next;
+
+       /*
+        * XXX: I don't much care for this chunk selection mechansim
+        * there's the potential to burn a lot of time here doing nothing
+        * useful while holding the global lock.  This could give some
+        * misleading performance results.  I'll fix it latter.
+        */
+       while (count < run_args->region_count) {
+               __u64 *rw_offset;
+               zpios_time_t *rw_time;
+
+               j = i % run_args->region_count;
+               *region = &(run_args->regions[j]);
+
+               if (flags & DMU_WRITE) {
+                       rw_offset = &((*region)->wr_offset);
+                       rw_time = &((*region)->stats.wr_time);
+               } else {
+                       rw_offset = &((*region)->rd_offset);
+                       rw_time = &((*region)->stats.rd_time);
+               }
+
+               /* test if region is fully written */
+               if (*rw_offset + *chunk_size > (*region)->max_offset) {
+                       i++;
+                       count++;
+
+                       if (unlikely(rw_time->stop.ts_sec == 0) &&
+                           unlikely(rw_time->stop.ts_nsec == 0))
+                               rw_time->stop = zpios_timespec_now();
+
+                       continue;
+               }
+
+               *offset = *rw_offset;
+               *obj = (*region)->obj;
+               *rw_offset += *chunk_size;
+
+               /* update ctl structure */
+               if (run_args->region_noise) {
+                       get_random_bytes(&random_int, sizeof (unsigned int));
+                       run_args->region_next +=
+                           random_int % run_args->region_noise;
+               } else {
+                       run_args->region_next++;
+               }
+
+               mutex_exit(&run_args->lock_work);
+               return (1);
+       }
+
+       /* nothing left to do */
+       mutex_exit(&run_args->lock_work);
+
+       return (0);
+}
+
+static void
+zpios_remove_objset(run_args_t *run_args)
+{
+       zpios_time_t *t = &(run_args->stats.rm_time);
+       zpios_region_t *region;
+       char name[32];
+       int rc = 0, i;
+
+       (void) zpios_upcall(run_args->pre, PHASE_PRE_REMOVE, run_args, 0);
+       t->start = zpios_timespec_now();
+
+       (void) snprintf(name, 32, "%s/id_%d", run_args->pool, run_args->id);
+
+       if (run_args->flags & DMU_REMOVE) {
+               if (run_args->flags & DMU_FPP) {
+                       for (i = 0; i < run_args->region_count; i++) {
+                               region = &run_args->regions[i];
+                               rc = zpios_dmu_object_free(run_args,
+                                   region->obj.os, region->obj.obj);
+                               if (rc)
+                                       zpios_print(run_args->file,
+                                           "Error removing object %d, %d\n",
+                                           (int)region->obj.obj, rc);
+                       }
+               } else {
+                       region = &run_args->regions[0];
+                       rc = zpios_dmu_object_free(run_args,
+                           region->obj.os, region->obj.obj);
+                       if (rc)
+                               zpios_print(run_args->file,
+                                   "Error removing object %d, %d\n",
+                                   (int)region->obj.obj, rc);
+               }
+       }
+
+       dmu_objset_disown(run_args->os, zpios_tag);
+
+       if (run_args->flags & DMU_REMOVE) {
+               rc = dsl_destroy_head(name);
+               if (rc)
+                       zpios_print(run_args->file, "Error dsl_destroy_head"
+                           "(%s, ...) failed: %d\n", name, rc);
+       }
+
+       t->stop  = zpios_timespec_now();
+       t->delta = zpios_timespec_sub(t->stop, t->start);
+       (void) zpios_upcall(run_args->post, PHASE_POST_REMOVE, run_args, rc);
+}
+
+static void
+zpios_cleanup_run(run_args_t *run_args)
+{
+       int i, size = 0;
+
+       if (run_args == NULL)
+               return;
+
+       if (run_args->threads != NULL) {
+               for (i = 0; i < run_args->thread_count; i++) {
+                       if (run_args->threads[i]) {
+                               mutex_destroy(&run_args->threads[i]->lock);
+                               kmem_free(run_args->threads[i],
+                                   sizeof (thread_data_t));
+                       }
+               }
+
+               kmem_free(run_args->threads,
+                   sizeof (thread_data_t *) * run_args->thread_count);
+       }
+
+       for (i = 0; i < run_args->region_count; i++)
+               mutex_destroy(&run_args->regions[i].lock);
+
+       mutex_destroy(&run_args->lock_work);
+       mutex_destroy(&run_args->lock_ctl);
+       size = run_args->region_count * sizeof (zpios_region_t);
+
+       vmem_free(run_args, sizeof (*run_args) + size);
+}
+
+static int
+zpios_dmu_write(run_args_t *run_args, objset_t *os, uint64_t object,
+               uint64_t offset, uint64_t size, const void *buf)
+{
+       struct dmu_tx *tx;
+       int rc, how = TXG_WAIT;
+//     int flags = 0;
+
+       if (run_args->flags & DMU_WRITE_NOWAIT)
+               how = TXG_NOWAIT;
+
+       while (1) {
+               tx = dmu_tx_create(os);
+               dmu_tx_hold_write(tx, object, offset, size);
+               rc = dmu_tx_assign(tx, how);
+
+               if (rc) {
+                       if (rc == ERESTART && how == TXG_NOWAIT) {
+                               dmu_tx_wait(tx);
+                               dmu_tx_abort(tx);
+                               continue;
+                       }
+                       zpios_print(run_args->file,
+                                   "Error in dmu_tx_assign(), %d", rc);
+                       dmu_tx_abort(tx);
+                       return (rc);
+               }
+               break;
+       }
+
+//     if (run_args->flags & DMU_WRITE_ZC)
+//             flags |= DMU_WRITE_ZEROCOPY;
+
+       dmu_write(os, object, offset, size, buf, tx);
+       dmu_tx_commit(tx);
+
+       return (0);
+}
+
+static int
+zpios_dmu_read(run_args_t *run_args, objset_t *os, uint64_t object,
+    uint64_t offset, uint64_t size, void *buf)
+{
+       int flags = 0;
+
+//     if (run_args->flags & DMU_READ_ZC)
+//             flags |= DMU_READ_ZEROCOPY;
+
+       if (run_args->flags & DMU_READ_NOPF)
+               flags |= DMU_READ_NO_PREFETCH;
+
+       return (dmu_read(os, object, offset, size, buf, flags));
+}
+
+static int
+zpios_thread_main(void *data)
+{
+       thread_data_t *thr = (thread_data_t *)data;
+       run_args_t *run_args = thr->run_args;
+       zpios_time_t t;
+       dmu_obj_t obj;
+       __u64 offset;
+       __u32 chunk_size;
+       zpios_region_t *region;
+       char *buf;
+       unsigned int random_int;
+       int chunk_noise = run_args->chunk_noise;
+       int chunk_noise_tmp = 0;
+       int thread_delay = run_args->thread_delay;
+       int thread_delay_tmp = 0;
+       int i, rc = 0;
+
+       if (chunk_noise) {
+               get_random_bytes(&random_int, sizeof (unsigned int));
+               chunk_noise_tmp = (random_int % (chunk_noise * 2))-chunk_noise;
+       }
+
+       /*
+        * It's OK to vmem_alloc() this memory because it will be copied
+        * in to the slab and pointers to the slab copy will be setup in
+        * the bio when the IO is submitted.  This of course is not ideal
+        * since we want a zero-copy IO path if possible.  It would be nice
+        * to have direct access to those slab entries.
+        */
+       chunk_size = run_args->chunk_size + chunk_noise_tmp;
+       buf = (char *)vmem_alloc(chunk_size, KM_SLEEP);
+       ASSERT(buf);
+
+       /* Trivial data verification pattern for now. */
+       if (run_args->flags & DMU_VERIFY)
+               memset(buf, 'z', chunk_size);
+
+       /* Write phase */
+       mutex_enter(&thr->lock);
+       thr->stats.wr_time.start = zpios_timespec_now();
+       mutex_exit(&thr->lock);
+
+       while (zpios_get_work_item(run_args, &obj, &offset,
+           &chunk_size, &region, DMU_WRITE)) {
+               if (thread_delay) {
+                       get_random_bytes(&random_int, sizeof (unsigned int));
+                       thread_delay_tmp = random_int % thread_delay;
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(thread_delay_tmp); /* In jiffies */
+               }
+
+               t.start = zpios_timespec_now();
+               rc = zpios_dmu_write(run_args, obj.os, obj.obj,
+                   offset, chunk_size, buf);
+               t.stop  = zpios_timespec_now();
+               t.delta = zpios_timespec_sub(t.stop, t.start);
+
+               if (rc) {
+                       zpios_print(run_args->file, "IO error while doing "
+                                   "dmu_write(): %d\n", rc);
+                       break;
+               }
+
+               mutex_enter(&thr->lock);
+               thr->stats.wr_data += chunk_size;
+               thr->stats.wr_chunks++;
+               thr->stats.wr_time.delta = zpios_timespec_add(
+                   thr->stats.wr_time.delta, t.delta);
+               mutex_exit(&thr->lock);
+
+               mutex_enter(&region->lock);
+               region->stats.wr_data += chunk_size;
+               region->stats.wr_chunks++;
+               region->stats.wr_time.delta = zpios_timespec_add(
+                   region->stats.wr_time.delta, t.delta);
+
+               /* First time region was accessed */
+               if (region->init_offset == offset)
+                       region->stats.wr_time.start = t.start;
+
+               mutex_exit(&region->lock);
+       }
+
+       mutex_enter(&run_args->lock_ctl);
+       run_args->threads_done++;
+       mutex_exit(&run_args->lock_ctl);
+
+       mutex_enter(&thr->lock);
+       thr->rc = rc;
+       thr->stats.wr_time.stop = zpios_timespec_now();
+       mutex_exit(&thr->lock);
+       wake_up(&run_args->waitq);
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule();
+
+       /* Check if we should exit */
+       mutex_enter(&thr->lock);
+       rc = thr->rc;
+       mutex_exit(&thr->lock);
+       if (rc)
+               goto out;
+
+       /* Read phase */
+       mutex_enter(&thr->lock);
+       thr->stats.rd_time.start = zpios_timespec_now();
+       mutex_exit(&thr->lock);
+
+       while (zpios_get_work_item(run_args, &obj, &offset,
+           &chunk_size, &region, DMU_READ)) {
+               if (thread_delay) {
+                       get_random_bytes(&random_int, sizeof (unsigned int));
+                       thread_delay_tmp = random_int % thread_delay;
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(thread_delay_tmp); /* In jiffies */
+               }
+
+               if (run_args->flags & DMU_VERIFY)
+                       memset(buf, 0, chunk_size);
+
+               t.start = zpios_timespec_now();
+               rc = zpios_dmu_read(run_args, obj.os, obj.obj,
+                                   offset, chunk_size, buf);
+               t.stop  = zpios_timespec_now();
+               t.delta = zpios_timespec_sub(t.stop, t.start);
+
+               if (rc) {
+                       zpios_print(run_args->file, "IO error while doing "
+                                   "dmu_read(): %d\n", rc);
+                       break;
+               }
+
+               /* Trivial data verification, expensive! */
+               if (run_args->flags & DMU_VERIFY) {
+                       for (i = 0; i < chunk_size; i++) {
+                               if (buf[i] != 'z') {
+                                       zpios_print(run_args->file,
+                                           "IO verify error: %d/%d/%d\n",
+                                           (int)obj.obj, (int)offset,
+                                           (int)chunk_size);
+                                       break;
+                               }
+                       }
+               }
+
+               mutex_enter(&thr->lock);
+               thr->stats.rd_data += chunk_size;
+               thr->stats.rd_chunks++;
+               thr->stats.rd_time.delta = zpios_timespec_add(
+                   thr->stats.rd_time.delta, t.delta);
+               mutex_exit(&thr->lock);
+
+               mutex_enter(&region->lock);
+               region->stats.rd_data += chunk_size;
+               region->stats.rd_chunks++;
+               region->stats.rd_time.delta = zpios_timespec_add(
+                   region->stats.rd_time.delta, t.delta);
+
+               /* First time region was accessed */
+               if (region->init_offset == offset)
+                       region->stats.rd_time.start = t.start;
+
+               mutex_exit(&region->lock);
+       }
+
+       mutex_enter(&run_args->lock_ctl);
+       run_args->threads_done++;
+       mutex_exit(&run_args->lock_ctl);
+
+       mutex_enter(&thr->lock);
+       thr->rc = rc;
+       thr->stats.rd_time.stop = zpios_timespec_now();
+       mutex_exit(&thr->lock);
+       wake_up(&run_args->waitq);
+
+out:
+       vmem_free(buf, chunk_size);
+       do_exit(0);
+
+       return (rc); /* Unreachable, due to do_exit() */
+}
+
+static int
+zpios_thread_done(run_args_t *run_args)
+{
+       ASSERT(run_args->threads_done <= run_args->thread_count);
+       return (run_args->threads_done == run_args->thread_count);
+}
+
+static int
+zpios_threads_run(run_args_t *run_args)
+{
+       struct task_struct *tsk, **tsks;
+       thread_data_t *thr = NULL;
+       zpios_time_t *tt = &(run_args->stats.total_time);
+       zpios_time_t *tw = &(run_args->stats.wr_time);
+       zpios_time_t *tr = &(run_args->stats.rd_time);
+       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;
+
+       /* 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;
+               thr->rc = 0;
+               mutex_init(&thr->lock, NULL, MUTEX_DEFAULT, NULL);
+               run_args->threads[i] = thr;
+
+               tsk = kthread_create(zpios_thread_main, (void *)thr,
+                   "%s/%d", "zpios_io", i);
+               if (IS_ERR(tsk)) {
+                       rc = -EINVAL;
+                       goto taskerr;
+               }
+
+               tsks[i] = tsk;
+       }
+
+       tt->start = zpios_timespec_now();
+
+       /* Wake up all threads for write phase */
+       (void) zpios_upcall(run_args->pre, PHASE_PRE_WRITE, run_args, 0);
+       for (i = 0; i < tc; i++)
+               wake_up_process(tsks[i]);
+
+       /* Wait for write phase to complete */
+       tw->start = zpios_timespec_now();
+       wait_event(run_args->waitq, zpios_thread_done(run_args));
+       tw->stop = zpios_timespec_now();
+       (void) zpios_upcall(run_args->post, PHASE_POST_WRITE, run_args, rc);
+
+       for (i = 0; i < tc; i++) {
+               thr = run_args->threads[i];
+
+               mutex_enter(&thr->lock);
+
+               if (!rc && thr->rc)
+                       rc = thr->rc;
+
+               run_args->stats.wr_data += thr->stats.wr_data;
+               run_args->stats.wr_chunks += thr->stats.wr_chunks;
+               mutex_exit(&thr->lock);
+       }
+
+       if (rc) {
+               /* Wake up all threads and tell them to exit */
+               for (i = 0; i < tc; i++) {
+                       mutex_enter(&thr->lock);
+                       thr->rc = rc;
+                       mutex_exit(&thr->lock);
+
+                       wake_up_process(tsks[i]);
+               }
+               goto out;
+       }
+
+       mutex_enter(&run_args->lock_ctl);
+       ASSERT(run_args->threads_done == run_args->thread_count);
+       run_args->threads_done = 0;
+       mutex_exit(&run_args->lock_ctl);
+
+       /* Wake up all threads for read phase */
+       (void) zpios_upcall(run_args->pre, PHASE_PRE_READ, run_args, 0);
+       for (i = 0; i < tc; i++)
+               wake_up_process(tsks[i]);
+
+       /* Wait for read phase to complete */
+       tr->start = zpios_timespec_now();
+       wait_event(run_args->waitq, zpios_thread_done(run_args));
+       tr->stop = zpios_timespec_now();
+       (void) zpios_upcall(run_args->post, PHASE_POST_READ, run_args, rc);
+
+       for (i = 0; i < tc; i++) {
+               thr = run_args->threads[i];
+
+               mutex_enter(&thr->lock);
+
+               if (!rc && thr->rc)
+                       rc = thr->rc;
+
+               run_args->stats.rd_data += thr->stats.rd_data;
+               run_args->stats.rd_chunks += thr->stats.rd_chunks;
+               mutex_exit(&thr->lock);
+       }
+out:
+       tt->stop  = zpios_timespec_now();
+       tt->delta = zpios_timespec_sub(tt->stop, tt->start);
+       tw->delta = zpios_timespec_sub(tw->stop, tw->start);
+       tr->delta = zpios_timespec_sub(tr->stop, tr->start);
+
+cleanup:
+       kmem_free(tsks, sizeof (struct task_struct *) * tc);
+cleanup2:
+       /* Returns first encountered thread error (if any) */
+       return (rc);
+
+taskerr:
+       /* Destroy all threads that were created successfully */
+       for (i = 0; i < tc; i++)
+               if (tsks[i] != NULL)
+                       (void) kthread_stop(tsks[i]);
+
+       goto cleanup;
+}
+
+static int
+zpios_do_one_run(struct file *file, zpios_cmd_t *kcmd,
+    int data_size, void *data)
+{
+       run_args_t *run_args = { 0 };
+       zpios_stats_t *stats = (zpios_stats_t *)data;
+       int i, n, m, size, rc;
+
+       if ((!kcmd->cmd_chunk_size) || (!kcmd->cmd_region_size) ||
+           (!kcmd->cmd_thread_count) || (!kcmd->cmd_region_count)) {
+               zpios_print(file, "Invalid chunk_size, region_size, "
+                   "thread_count, or region_count, %d\n", -EINVAL);
+               return (-EINVAL);
+       }
+
+       if (!(kcmd->cmd_flags & DMU_WRITE) ||
+           !(kcmd->cmd_flags & DMU_READ)) {
+               zpios_print(file, "Invalid flags, minimally DMU_WRITE "
+                   "and DMU_READ must be set, %d\n", -EINVAL);
+               return (-EINVAL);
+       }
+
+       if ((kcmd->cmd_flags & (DMU_WRITE_ZC | DMU_READ_ZC)) &&
+           (kcmd->cmd_flags & DMU_VERIFY)) {
+               zpios_print(file, "Invalid flags, DMU_*_ZC incompatible "
+                   "with DMU_VERIFY, used for performance analysis "
+                   "only, %d\n", -EINVAL);
+               return (-EINVAL);
+       }
+
+       /*
+        * Opaque data on return contains structs of the following form:
+        *
+        * zpios_stat_t stats[];
+        * stats[0]     = run_args->stats;
+        * stats[1-N]   = threads[N]->stats;
+        * stats[N+1-M] = regions[M]->stats;
+        *
+        * Where N is the number of threads, and M is the number of regions.
+        */
+       size = (sizeof (zpios_stats_t) +
+           (kcmd->cmd_thread_count * sizeof (zpios_stats_t)) +
+           (kcmd->cmd_region_count * sizeof (zpios_stats_t)));
+       if (data_size < size) {
+               zpios_print(file, "Invalid size, command data buffer "
+                   "size too small, (%d < %d)\n", data_size, size);
+               return (-ENOSPC);
+       }
+
+       rc = zpios_setup_run(&run_args, kcmd, file);
+       if (rc)
+               return (rc);
+
+       rc = zpios_threads_run(run_args);
+       zpios_remove_objset(run_args);
+       if (rc)
+               goto cleanup;
+
+       if (stats) {
+               n = 1;
+               m = 1 + kcmd->cmd_thread_count;
+               stats[0] = run_args->stats;
+
+               for (i = 0; i < kcmd->cmd_thread_count; i++)
+                       stats[n+i] = run_args->threads[i]->stats;
+
+               for (i = 0; i < kcmd->cmd_region_count; i++)
+                       stats[m+i] = run_args->regions[i].stats;
+       }
+
+cleanup:
+       zpios_cleanup_run(run_args);
+
+       (void) zpios_upcall(kcmd->cmd_post, PHASE_POST_RUN, run_args, 0);
+
+       return (rc);
+}
+
+static int
+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;
+
+       return (0);
+}
+
+static int
+zpios_release(struct inode *inode, struct file *file)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       vmem_free(info->info_buffer, ZPIOS_INFO_BUFFER_SIZE);
+       kmem_free(info, sizeof (*info));
+
+       return (0);
+}
+
+static int
+zpios_buffer_clear(struct file *file, zpios_cfg_t *kcfg, unsigned long arg)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       spin_lock(&info->info_lock);
+       memset(info->info_buffer, 0, info->info_size);
+       info->info_head = info->info_buffer;
+       spin_unlock(&info->info_lock);
+
+       return (0);
+}
+
+static int
+zpios_buffer_size(struct file *file, zpios_cfg_t *kcfg, unsigned long arg)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+       char *buf;
+       int min, size, rc = 0;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       spin_lock(&info->info_lock);
+       if (kcfg->cfg_arg1 > 0) {
+
+               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);
+               memset(buf, 0, size);
+               memcpy(buf, info->info_buffer, min);
+               vmem_free(info->info_buffer, info->info_size);
+               info->info_size = size;
+               info->info_buffer = buf;
+               info->info_head = info->info_buffer;
+       }
+
+       kcfg->cfg_rc1 = info->info_size;
+
+       if (copy_to_user((struct zpios_cfg_t __user *)arg,
+           kcfg, sizeof (*kcfg)))
+               rc = -EFAULT;
+out:
+       spin_unlock(&info->info_lock);
+
+       return (rc);
+}
+
+static int
+zpios_ioctl_cfg(struct file *file, unsigned long arg)
+{
+       zpios_cfg_t kcfg;
+       int rc = 0;
+
+       if (copy_from_user(&kcfg, (zpios_cfg_t *)arg, sizeof (kcfg)))
+               return (-EFAULT);
+
+       if (kcfg.cfg_magic != ZPIOS_CFG_MAGIC) {
+               zpios_print(file, "Bad config magic 0x%x != 0x%x\n",
+                   kcfg.cfg_magic, ZPIOS_CFG_MAGIC);
+               return (-EINVAL);
+       }
+
+       switch (kcfg.cfg_cmd) {
+               case ZPIOS_CFG_BUFFER_CLEAR:
+                       /*
+                        * cfg_arg1 - Unused
+                        * cfg_rc1  - Unused
+                        */
+                       rc = zpios_buffer_clear(file, &kcfg, arg);
+                       break;
+               case ZPIOS_CFG_BUFFER_SIZE:
+                       /*
+                        * cfg_arg1 - 0 - query size; >0 resize
+                        * cfg_rc1  - Set to current buffer size
+                        */
+                       rc = zpios_buffer_size(file, &kcfg, arg);
+                       break;
+               default:
+                       zpios_print(file, "Bad config command %d\n",
+                                   kcfg.cfg_cmd);
+                       rc = -EINVAL;
+                       break;
+       }
+
+       return (rc);
+}
+
+static int
+zpios_ioctl_cmd(struct file *file, unsigned long arg)
+{
+       zpios_cmd_t *kcmd;
+       void *data = NULL;
+       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) {
+               zpios_print(file, "Unable to copy command structure "
+                           "from user to kernel memory, %d\n", rc);
+               goto out_cmd;
+       }
+
+       if (kcmd->cmd_magic != ZPIOS_CMD_MAGIC) {
+               zpios_print(file, "Bad command magic 0x%x != 0x%x\n",
+                   kcmd->cmd_magic, ZPIOS_CFG_MAGIC);
+               rc = (-EINVAL);
+               goto out_cmd;
+       }
+
+       /* 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);
+               if (rc) {
+                       zpios_print(file, "Unable to copy data buffer "
+                                   "from user to kernel memory, %d\n", rc);
+                       goto out_data;
+               }
+       }
+
+       rc = zpios_do_one_run(file, kcmd, kcmd->cmd_data_size, data);
+
+       if (data != NULL) {
+               /* If the test failed do not print out the stats */
+               if (rc)
+                       goto out_data;
+
+               rc = copy_to_user((void *)(arg + offsetof(zpios_cmd_t,
+                   cmd_data_str)), data, kcmd->cmd_data_size);
+               if (rc) {
+                       zpios_print(file, "Unable to copy data buffer "
+                                   "from kernel to user memory, %d\n", rc);
+                       rc = -EFAULT;
+               }
+
+out_data:
+               vmem_free(data, kcmd->cmd_data_size);
+       }
+out_cmd:
+       kmem_free(kcmd, sizeof (zpios_cmd_t));
+
+       return (rc);
+}
+
+static long
+zpios_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int rc = 0;
+
+       /* Ignore tty ioctls */
+       if ((cmd & 0xffffff00) == ((int)'T') << 8)
+               return (-ENOTTY);
+
+       switch (cmd) {
+               case ZPIOS_CFG:
+                       rc = zpios_ioctl_cfg(file, arg);
+                       break;
+               case ZPIOS_CMD:
+                       rc = zpios_ioctl_cmd(file, arg);
+                       break;
+               default:
+                       zpios_print(file, "Bad ioctl command %d\n", cmd);
+                       rc = -EINVAL;
+                       break;
+       }
+
+       return (rc);
+}
+
+#ifdef CONFIG_COMPAT
+/* Compatibility handler for ioctls from 32-bit ELF binaries */
+static long
+zpios_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return (zpios_unlocked_ioctl(file, cmd, arg));
+}
+#endif /* CONFIG_COMPAT */
+
+/*
+ * I'm not sure why you would want to write in to this buffer from
+ * user space since its principle use is to pass test status info
+ * back to the user space, but I don't see any reason to prevent it.
+ */
+static ssize_t
+zpios_write(struct file *file, const char __user *buf,
+    size_t count, loff_t *ppos)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+       int rc = 0;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       spin_lock(&info->info_lock);
+
+       /* Write beyond EOF */
+       if (*ppos >= info->info_size) {
+               rc = -EFBIG;
+               goto out;
+       }
+
+       /* Resize count if beyond EOF */
+       if (*ppos + count > info->info_size)
+               count = info->info_size - *ppos;
+
+       if (copy_from_user(info->info_buffer, buf, count)) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       *ppos += count;
+       rc = count;
+out:
+       spin_unlock(&info->info_lock);
+       return (rc);
+}
+
+static ssize_t
+zpios_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+       int rc = 0;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       spin_lock(&info->info_lock);
+
+       /* Read beyond EOF */
+       if (*ppos >= info->info_size)
+               goto out;
+
+       /* Resize count if beyond EOF */
+       if (*ppos + count > info->info_size)
+               count = info->info_size - *ppos;
+
+       if (copy_to_user(buf, info->info_buffer + *ppos, count)) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       *ppos += count;
+       rc = count;
+out:
+       spin_unlock(&info->info_lock);
+       return (rc);
+}
+
+static loff_t zpios_seek(struct file *file, loff_t offset, int origin)
+{
+       zpios_info_t *info = (zpios_info_t *)file->private_data;
+       int rc = -EINVAL;
+
+       ASSERT(info);
+       ASSERT(info->info_buffer);
+
+       spin_lock(&info->info_lock);
+
+       switch (origin) {
+       case 0: /* SEEK_SET - No-op just do it */
+               break;
+       case 1: /* SEEK_CUR - Seek from current */
+               offset = file->f_pos + offset;
+               break;
+       case 2: /* SEEK_END - Seek from end */
+               offset = info->info_size + offset;
+               break;
+       }
+
+       if (offset >= 0) {
+               file->f_pos = offset;
+               file->f_version = 0;
+               rc = offset;
+       }
+
+       spin_unlock(&info->info_lock);
+
+       return (rc);
+}
+
+static struct file_operations zpios_fops = {
+       .owner          = THIS_MODULE,
+       .open           = zpios_open,
+       .release        = zpios_release,
+       .unlocked_ioctl = zpios_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = zpios_compat_ioctl,
+#endif
+       .read           = zpios_read,
+       .write          = zpios_write,
+       .llseek         = zpios_seek,
+};
+
+static struct miscdevice zpios_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = ZPIOS_NAME,
+       .fops           = &zpios_fops,
+};
+
+#ifdef DEBUG
+#define        ZFS_DEBUG_STR   " (DEBUG mode)"
+#else
+#define        ZFS_DEBUG_STR   ""
+#endif
+
+static int __init
+zpios_init(void)
+{
+       int error;
+
+       error = misc_register(&zpios_misc);
+       if (error) {
+               printk(KERN_INFO "ZPIOS: misc_register() failed %d\n", error);
+       } else {
+               printk(KERN_INFO "ZPIOS: Loaded module v%s-%s%s\n",
+                   ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR);
+       }
+
+       return (error);
+}
+
+static void __exit
+zpios_fini(void)
+{
+       misc_deregister(&zpios_misc);
+
+       printk(KERN_INFO "ZPIOS: Unloaded module v%s-%s%s\n",
+           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR);
+}
+
+module_init(zpios_init);
+module_exit(zpios_fini);
+
+MODULE_AUTHOR("LLNL / Sun");
+MODULE_DESCRIPTION("Kernel PIOS implementation");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
diff --git a/zfs/zfs.release.in b/zfs/zfs.release.in
new file mode 100644 (file)
index 0000000..8213079
--- /dev/null
@@ -0,0 +1 @@
+@ZFS_META_VERSION@-@ZFS_META_RELEASE@
diff --git a/zfs/zfs_config.h.in b/zfs/zfs_config.h.in
new file mode 100644 (file)
index 0000000..7b9a0e2
--- /dev/null
@@ -0,0 +1,527 @@
+/* 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
+
+/* lookup_bdev() wants 1 arg */
+#undef HAVE_1ARG_LOOKUP_BDEV
+
+/* submit_bio() wants 1 arg */
+#undef HAVE_1ARG_SUBMIT_BIO
+
+/* bdi_setup_and_register() wants 2 args */
+#undef HAVE_2ARGS_BDI_SETUP_AND_REGISTER
+
+/* lookup_bdev() wants 2 args */
+#undef HAVE_2ARGS_LOOKUP_BDEV
+
+/* 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
+
+/* bio_set_op_attrs is available */
+#undef HAVE_BIO_SET_OP_ATTRS
+
+/* 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
+
+/* BIO_RW_UNPLUG is available */
+#undef HAVE_BLK_QUEUE_HAVE_BIO_RW_UNPLUG
+
+/* struct blk_plug is available */
+#undef HAVE_BLK_QUEUE_HAVE_BLK_PLUG
+
+/* 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->aio_fsync() exists */
+#undef HAVE_FILE_AIO_FSYNC
+
+/* 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
+
+/* generic_readlink is global */
+#undef HAVE_GENERIC_READLINK
+
+/* generic_setxattr() exists */
+#undef HAVE_GENERIC_SETXATTR
+
+/* generic_write_checks() takes kiocb */
+#undef HAVE_GENERIC_WRITE_CHECKS_KIOCB
+
+/* 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
+
+/* kernel has large stacks */
+#undef HAVE_LARGE_STACKS
+
+/* 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
+
+/* 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
+
+/* iops->rename() wants flags */
+#undef HAVE_RENAME_WANTS_FLAGS
+
+/* 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_ERASE
+
+/* setattr_prepare() is available */
+#undef HAVE_SETATTR_PREPARE
+
+/* iops->set_acl() exists */
+#undef HAVE_SET_ACL
+
+/* posix_acl_release() is usable */
+#undef HAVE_SET_CACHED_ACL_USABLE
+
+/* 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