aboutsummaryrefslogtreecommitdiffstats
path: root/include/os/linux
diff options
context:
space:
mode:
authorMatt Macy <mmacy@FreeBSD.org>2020-08-24 22:48:19 +0000
committerMatt Macy <mmacy@FreeBSD.org>2020-08-24 22:48:19 +0000
commit3b0ce0e28db46d0403929aba45c682285e1ac217 (patch)
tree91721e6e5518bd0d8113dee535898f2225443411 /include/os/linux
downloadsrc-3b0ce0e28db46d0403929aba45c682285e1ac217.tar.gz
src-3b0ce0e28db46d0403929aba45c682285e1ac217.zip
Vendor import of openzfs master @ 184df27eef0abdc7ab2105b21257f753834b936bvendor/openzfs/2.0-rc0-g184df27
Sponsored by: iX Systems, Inc.
Notes
Notes: svn path=/vendor-sys/openzfs/dist/; revision=364736 svn path=/vendor-sys/openzfs/2.0-rc0-g184df27/; revision=364741; tag=vendor/openzfs/2.0-rc0-g184df27
Diffstat (limited to 'include/os/linux')
-rw-r--r--include/os/linux/Makefile.am1
-rw-r--r--include/os/linux/kernel/Makefile.am1
-rw-r--r--include/os/linux/kernel/linux/Makefile.am22
-rw-r--r--include/os/linux/kernel/linux/blkdev_compat.h506
-rw-r--r--include/os/linux/kernel/linux/compiler_compat.h35
-rw-r--r--include/os/linux/kernel/linux/dcache_compat.h64
-rw-r--r--include/os/linux/kernel/linux/kmap_compat.h43
-rw-r--r--include/os/linux/kernel/linux/mod_compat.h151
-rw-r--r--include/os/linux/kernel/linux/page_compat.h92
-rw-r--r--include/os/linux/kernel/linux/percpu_compat.h44
-rw-r--r--include/os/linux/kernel/linux/simd.h45
-rw-r--r--include/os/linux/kernel/linux/simd_aarch64.h54
-rw-r--r--include/os/linux/kernel/linux/simd_powerpc.h109
-rw-r--r--include/os/linux/kernel/linux/simd_x86.h646
-rw-r--r--include/os/linux/kernel/linux/utsname_compat.h29
-rw-r--r--include/os/linux/kernel/linux/vfs_compat.h439
-rw-r--r--include/os/linux/kernel/linux/xattr_compat.h184
-rw-r--r--include/os/linux/spl/Makefile.am1
-rw-r--r--include/os/linux/spl/rpc/Makefile.am7
-rw-r--r--include/os/linux/spl/rpc/xdr.h156
-rw-r--r--include/os/linux/spl/sys/Makefile.am64
-rw-r--r--include/os/linux/spl/sys/acl.h119
-rw-r--r--include/os/linux/spl/sys/atomic.h79
-rw-r--r--include/os/linux/spl/sys/byteorder.h87
-rw-r--r--include/os/linux/spl/sys/callb.h54
-rw-r--r--include/os/linux/spl/sys/callo.h52
-rw-r--r--include/os/linux/spl/sys/cmn_err.h42
-rw-r--r--include/os/linux/spl/sys/condvar.h113
-rw-r--r--include/os/linux/spl/sys/console.h31
-rw-r--r--include/os/linux/spl/sys/cred.h63
-rw-r--r--include/os/linux/spl/sys/ctype.h30
-rw-r--r--include/os/linux/spl/sys/debug.h169
-rw-r--r--include/os/linux/spl/sys/disp.h34
-rw-r--r--include/os/linux/spl/sys/dkio.h40
-rw-r--r--include/os/linux/spl/sys/errno.h57
-rw-r--r--include/os/linux/spl/sys/fcntl.h37
-rw-r--r--include/os/linux/spl/sys/file.h52
-rw-r--r--include/os/linux/spl/sys/inttypes.h28
-rw-r--r--include/os/linux/spl/sys/isa_defs.h254
-rw-r--r--include/os/linux/spl/sys/kmem.h211
-rw-r--r--include/os/linux/spl/sys/kmem_cache.h216
-rw-r--r--include/os/linux/spl/sys/kstat.h223
-rw-r--r--include/os/linux/spl/sys/list.h210
-rw-r--r--include/os/linux/spl/sys/mod_os.h28
-rw-r--r--include/os/linux/spl/sys/mutex.h185
-rw-r--r--include/os/linux/spl/sys/param.h36
-rw-r--r--include/os/linux/spl/sys/proc.h42
-rw-r--r--include/os/linux/spl/sys/processor.h32
-rw-r--r--include/os/linux/spl/sys/procfs_list.h72
-rw-r--r--include/os/linux/spl/sys/random.h40
-rw-r--r--include/os/linux/spl/sys/rwlock.h201
-rw-r--r--include/os/linux/spl/sys/shrinker.h110
-rw-r--r--include/os/linux/spl/sys/sid.h61
-rw-r--r--include/os/linux/spl/sys/signal.h55
-rw-r--r--include/os/linux/spl/sys/simd.h31
-rw-r--r--include/os/linux/spl/sys/stat.h30
-rw-r--r--include/os/linux/spl/sys/strings.h31
-rw-r--r--include/os/linux/spl/sys/sunddi.h58
-rw-r--r--include/os/linux/spl/sys/sysmacros.h206
-rw-r--r--include/os/linux/spl/sys/systeminfo.h36
-rw-r--r--include/os/linux/spl/sys/taskq.h164
-rw-r--r--include/os/linux/spl/sys/thread.h74
-rw-r--r--include/os/linux/spl/sys/time.h118
-rw-r--r--include/os/linux/spl/sys/timer.h86
-rw-r--r--include/os/linux/spl/sys/trace.h175
-rw-r--r--include/os/linux/spl/sys/trace_spl.h30
-rw-r--r--include/os/linux/spl/sys/trace_taskq.h89
-rw-r--r--include/os/linux/spl/sys/tsd.h46
-rw-r--r--include/os/linux/spl/sys/types.h58
-rw-r--r--include/os/linux/spl/sys/types32.h35
-rw-r--r--include/os/linux/spl/sys/uio.h144
-rw-r--r--include/os/linux/spl/sys/user.h42
-rw-r--r--include/os/linux/spl/sys/vfs.h51
-rw-r--r--include/os/linux/spl/sys/vmem.h102
-rw-r--r--include/os/linux/spl/sys/vmsystm.h103
-rw-r--r--include/os/linux/spl/sys/vnode.h107
-rw-r--r--include/os/linux/spl/sys/wait.h55
-rw-r--r--include/os/linux/spl/sys/zmod.h70
-rw-r--r--include/os/linux/spl/sys/zone.h36
-rw-r--r--include/os/linux/zfs/Makefile.am1
-rw-r--r--include/os/linux/zfs/sys/Makefile.am30
-rw-r--r--include/os/linux/zfs/sys/policy.h61
-rw-r--r--include/os/linux/zfs/sys/sha2.h151
-rw-r--r--include/os/linux/zfs/sys/trace_acl.h164
-rw-r--r--include/os/linux/zfs/sys/trace_arc.h419
-rw-r--r--include/os/linux/zfs/sys/trace_common.h112
-rw-r--r--include/os/linux/zfs/sys/trace_dbgmsg.h89
-rw-r--r--include/os/linux/zfs/sys/trace_dbuf.h169
-rw-r--r--include/os/linux/zfs/sys/trace_dmu.h136
-rw-r--r--include/os/linux/zfs/sys/trace_dnode.h129
-rw-r--r--include/os/linux/zfs/sys/trace_multilist.h89
-rw-r--r--include/os/linux/zfs/sys/trace_rrwlock.h31
-rw-r--r--include/os/linux/zfs/sys/trace_txg.h89
-rw-r--r--include/os/linux/zfs/sys/trace_vdev.h140
-rw-r--r--include/os/linux/zfs/sys/trace_zfs.h53
-rw-r--r--include/os/linux/zfs/sys/trace_zil.h229
-rw-r--r--include/os/linux/zfs/sys/trace_zio.h97
-rw-r--r--include/os/linux/zfs/sys/trace_zrlock.h94
-rw-r--r--include/os/linux/zfs/sys/zfs_context_os.h30
-rw-r--r--include/os/linux/zfs/sys/zfs_ctldir.h103
-rw-r--r--include/os/linux/zfs/sys/zfs_dir.h76
-rw-r--r--include/os/linux/zfs/sys/zfs_vfsops.h227
-rw-r--r--include/os/linux/zfs/sys/zfs_vnops.h91
-rw-r--r--include/os/linux/zfs/sys/zfs_znode_impl.h168
-rw-r--r--include/os/linux/zfs/sys/zpl.h183
105 files changed, 10894 insertions, 0 deletions
diff --git a/include/os/linux/Makefile.am b/include/os/linux/Makefile.am
new file mode 100644
index 000000000000..605a1fcb7506
--- /dev/null
+++ b/include/os/linux/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kernel spl zfs
diff --git a/include/os/linux/kernel/Makefile.am b/include/os/linux/kernel/Makefile.am
new file mode 100644
index 000000000000..08b2f5fc5c99
--- /dev/null
+++ b/include/os/linux/kernel/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = linux
diff --git a/include/os/linux/kernel/linux/Makefile.am b/include/os/linux/kernel/linux/Makefile.am
new file mode 100644
index 000000000000..6ff0df506d9c
--- /dev/null
+++ b/include/os/linux/kernel/linux/Makefile.am
@@ -0,0 +1,22 @@
+KERNEL_H = \
+ dcache_compat.h \
+ xattr_compat.h \
+ vfs_compat.h \
+ blkdev_compat.h \
+ utsname_compat.h \
+ kmap_compat.h \
+ percpu_compat.h \
+ simd.h \
+ simd_x86.h \
+ simd_aarch64.h \
+ simd_powerpc.h \
+ mod_compat.h \
+ page_compat.h \
+ compiler_compat.h
+
+if CONFIG_KERNEL
+if BUILD_LINUX
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/linux
+kernel_HEADERS = $(KERNEL_H)
+endif
+endif
diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h
new file mode 100644
index 000000000000..1cdc300a6f85
--- /dev/null
+++ b/include/os/linux/kernel/linux/blkdev_compat.h
@@ -0,0 +1,506 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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>
+#include <linux/backing-dev.h>
+#include <linux/hdreg.h>
+#include <linux/msdos_fs.h> /* for SECTOR_* */
+
+#ifndef HAVE_BLK_QUEUE_FLAG_SET
+static inline void
+blk_queue_flag_set(unsigned int flag, struct request_queue *q)
+{
+ queue_flag_set(flag, q);
+}
+#endif
+
+#ifndef HAVE_BLK_QUEUE_FLAG_CLEAR
+static inline void
+blk_queue_flag_clear(unsigned int flag, struct request_queue *q)
+{
+ queue_flag_clear(flag, q);
+}
+#endif
+
+/*
+ * 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.
+ */
+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)
+ if (wc)
+ blk_queue_flag_set(QUEUE_FLAG_WC, q);
+ else
+ blk_queue_flag_clear(QUEUE_FLAG_WC, q);
+ if (fua)
+ blk_queue_flag_set(QUEUE_FLAG_FUA, q);
+ else
+ blk_queue_flag_clear(QUEUE_FLAG_FUA, q);
+#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
+#error "Unsupported kernel"
+#endif
+}
+
+static inline void
+blk_queue_set_read_ahead(struct request_queue *q, unsigned long ra_pages)
+{
+#ifdef HAVE_BLK_QUEUE_BDI_DYNAMIC
+ q->backing_dev_info->ra_pages = ra_pages;
+#else
+ q->backing_dev_info.ra_pages = ra_pages;
+#endif
+}
+
+#if !defined(HAVE_GET_DISK_AND_MODULE)
+static inline struct kobject *
+get_disk_and_module(struct gendisk *disk)
+{
+ return (get_disk(disk));
+}
+#endif
+
+#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_BI_SKIP(bio) (bio)->bi_iter.bi_bvec_done
+#define bio_for_each_segment4(bv, bvp, b, i) \
+ bio_for_each_segment((bv), (b), (i))
+typedef struct bvec_iter bvec_iterator_t;
+#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_BI_SKIP(bio) (0)
+#define bio_for_each_segment4(bv, bvp, b, i) \
+ bio_for_each_segment((bvp), (b), (i))
+typedef int bvec_iterator_t;
+#endif
+
+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 */
+
+ *flags |= REQ_FAILFAST_MASK;
+}
+
+/*
+ * Maximum disk label length, it may be undefined for some kernels.
+ */
+#if !defined(DISK_NAME_LEN)
+#define DISK_NAME_LEN 32
+#endif /* DISK_NAME_LEN */
+
+#ifdef HAVE_BIO_BI_STATUS
+static inline int
+bi_status_to_errno(blk_status_t status)
+{
+ switch (status) {
+ case BLK_STS_OK:
+ return (0);
+ case BLK_STS_NOTSUPP:
+ return (EOPNOTSUPP);
+ case BLK_STS_TIMEOUT:
+ return (ETIMEDOUT);
+ case BLK_STS_NOSPC:
+ return (ENOSPC);
+ case BLK_STS_TRANSPORT:
+ return (ENOLINK);
+ case BLK_STS_TARGET:
+ return (EREMOTEIO);
+ case BLK_STS_NEXUS:
+ return (EBADE);
+ case BLK_STS_MEDIUM:
+ return (ENODATA);
+ case BLK_STS_PROTECTION:
+ return (EILSEQ);
+ case BLK_STS_RESOURCE:
+ return (ENOMEM);
+ case BLK_STS_AGAIN:
+ return (EAGAIN);
+ case BLK_STS_IOERR:
+ return (EIO);
+ default:
+ return (EIO);
+ }
+}
+
+static inline blk_status_t
+errno_to_bi_status(int error)
+{
+ switch (error) {
+ case 0:
+ return (BLK_STS_OK);
+ case EOPNOTSUPP:
+ return (BLK_STS_NOTSUPP);
+ case ETIMEDOUT:
+ return (BLK_STS_TIMEOUT);
+ case ENOSPC:
+ return (BLK_STS_NOSPC);
+ case ENOLINK:
+ return (BLK_STS_TRANSPORT);
+ case EREMOTEIO:
+ return (BLK_STS_TARGET);
+ case EBADE:
+ return (BLK_STS_NEXUS);
+ case ENODATA:
+ return (BLK_STS_MEDIUM);
+ case EILSEQ:
+ return (BLK_STS_PROTECTION);
+ case ENOMEM:
+ return (BLK_STS_RESOURCE);
+ case EAGAIN:
+ return (BLK_STS_AGAIN);
+ case EIO:
+ return (BLK_STS_IOERR);
+ default:
+ return (BLK_STS_IOERR);
+ }
+}
+#endif /* HAVE_BIO_BI_STATUS */
+
+/*
+ * 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
+#ifdef HAVE_BIO_BI_STATUS
+#define BIO_END_IO_ERROR(bio) bi_status_to_errno(bio->bi_status)
+#define BIO_END_IO_PROTO(fn, x, z) static void fn(struct bio *x)
+#define BIO_END_IO(bio, error) bio_set_bi_status(bio, error)
+static inline void
+bio_set_bi_status(struct bio *bio, int error)
+{
+ ASSERT3S(error, <=, 0);
+ bio->bi_status = errno_to_bi_status(-error);
+ bio_endio(bio);
+}
+#else
+#define BIO_END_IO_ERROR(bio) (-(bio->bi_error))
+#define BIO_END_IO_PROTO(fn, x, z) static void fn(struct bio *x)
+#define BIO_END_IO(bio, error) bio_set_bi_error(bio, error)
+static inline void
+bio_set_bi_error(struct bio *bio, int error)
+{
+ ASSERT3S(error, <=, 0);
+ bio->bi_error = error;
+ bio_endio(bio);
+}
+#endif /* HAVE_BIO_BI_STATUS */
+
+#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 */
+
+/*
+ * 4.1 - x.y.z API,
+ * 3.10.0 CentOS 7.x API,
+ * blkdev_reread_part()
+ *
+ * For older kernels trigger a re-reading of the partition table by calling
+ * check_disk_change() which calls flush_disk() to invalidate the device.
+ */
+#ifdef HAVE_BLKDEV_REREAD_PART
+#define vdev_bdev_reread_part(bdev) blkdev_reread_part(bdev)
+#else
+#define vdev_bdev_reread_part(bdev) check_disk_change(bdev)
+#endif /* HAVE_BLKDEV_REREAD_PART */
+
+/*
+ * 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
+#error "Unsupported kernel"
+#endif /* HAVE_2ARGS_LOOKUP_BDEV */
+#endif /* HAVE_1ARG_LOOKUP_BDEV */
+
+/*
+ * Kernels without bio_set_op_attrs use bi_rw for the bio flags.
+ */
+#if !defined(HAVE_BIO_SET_OP_ATTRS)
+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.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(HAVE_REQ_PREFLUSH) /* >= 4.10 */
+ bio_set_op_attrs(bio, 0, REQ_PREFLUSH);
+#elif defined(WRITE_FLUSH_FUA) /* >= 2.6.37 and <= 4.9 */
+ bio_set_op_attrs(bio, 0, WRITE_FLUSH_FUA);
+#else
+#error "Allowing the build will cause bio_set_flush requests to be ignored."
+#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
+ *
+ * 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.
+ *
+ */
+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(HAVE_REQ_PREFLUSH) && defined(HAVE_BIO_BI_OPF)
+ return (bio->bi_opf & REQ_PREFLUSH);
+#elif defined(HAVE_REQ_PREFLUSH) && !defined(HAVE_BIO_BI_OPF)
+ return (bio->bi_rw & REQ_PREFLUSH);
+#elif defined(HAVE_REQ_FLUSH)
+ return (bio->bi_rw & REQ_FLUSH);
+#else
+#error "Unsupported kernel"
+#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."
+#endif
+}
+
+/*
+ * 4.8 - 4.x API,
+ * REQ_OP_DISCARD
+ *
+ * 2.6.36 - 4.7 API,
+ * REQ_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.
+ */
+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_REQ_DISCARD)
+ return (bio->bi_rw & REQ_DISCARD);
+#else
+#error "Unsupported kernel"
+#endif
+}
+
+/*
+ * 4.8 - 4.x API,
+ * REQ_OP_SECURE_ERASE
+ *
+ * 2.6.36 - 4.7 API,
+ * REQ_SECURE
+ */
+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.
+ */
+static inline void
+blk_queue_discard_granularity(struct request_queue *q, unsigned int dg)
+{
+ q->limits.discard_granularity = dg;
+}
+
+/*
+ * 4.8 - 4.x API,
+ * blk_queue_secure_erase()
+ *
+ * 2.6.36 - 4.7 API,
+ * blk_queue_secdiscard()
+ */
+static inline int
+blk_queue_discard_secure(struct request_queue *q)
+{
+#if defined(HAVE_BLK_QUEUE_SECURE_ERASE)
+ return (blk_queue_secure_erase(q));
+#elif defined(HAVE_BLK_QUEUE_SECDISCARD)
+ return (blk_queue_secdiscard(q));
+#else
+ return (0);
+#endif
+}
+
+/*
+ * 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)
+
+static inline void
+blk_generic_start_io_acct(struct request_queue *q, int rw,
+ unsigned long sectors, struct hd_struct *part)
+{
+#if defined(HAVE_GENERIC_IO_ACCT_3ARG)
+ generic_start_io_acct(rw, sectors, part);
+#elif defined(HAVE_GENERIC_IO_ACCT_4ARG)
+ generic_start_io_acct(q, rw, sectors, part);
+#endif
+}
+
+static inline void
+blk_generic_end_io_acct(struct request_queue *q, int rw,
+ struct hd_struct *part, unsigned long start_time)
+{
+#if defined(HAVE_GENERIC_IO_ACCT_3ARG)
+ generic_end_io_acct(rw, part, start_time);
+#elif defined(HAVE_GENERIC_IO_ACCT_4ARG)
+ generic_end_io_acct(q, rw, part, start_time);
+#endif
+}
+
+#ifndef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS
+static inline struct request_queue *
+blk_generic_alloc_queue(make_request_fn make_request, int node_id)
+{
+#if defined(HAVE_BLK_ALLOC_QUEUE_REQUEST_FN)
+ return (blk_alloc_queue(make_request, node_id));
+#else
+ struct request_queue *q = blk_alloc_queue(GFP_KERNEL);
+ if (q != NULL)
+ blk_queue_make_request(q, make_request);
+
+ return (q);
+#endif
+}
+#endif /* !HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS */
+
+#endif /* _ZFS_BLKDEV_H */
diff --git a/include/os/linux/kernel/linux/compiler_compat.h b/include/os/linux/kernel/linux/compiler_compat.h
new file mode 100644
index 000000000000..921d32f246c5
--- /dev/null
+++ b/include/os/linux/kernel/linux/compiler_compat.h
@@ -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 (C) 2018 Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _ZFS_COMPILER_COMPAT_H
+#define _ZFS_COMPILER_COMPAT_H
+
+#include <linux/compiler.h>
+
+#if !defined(READ_ONCE)
+#define READ_ONCE(x) ACCESS_ONCE(x)
+#endif
+
+#endif /* _ZFS_COMPILER_COMPAT_H */
diff --git a/include/os/linux/kernel/linux/dcache_compat.h b/include/os/linux/kernel/linux/dcache_compat.h
new file mode 100644
index 000000000000..d0588a82e9ad
--- /dev/null
+++ b/include/os/linux/kernel/linux/dcache_compat.h
@@ -0,0 +1,64 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+typedef const struct dentry_operations dentry_operations_t;
+
+/*
+ * 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)
+{
+ dentry->d_op = NULL;
+ dentry->d_flags &= ~(
+ DCACHE_OP_HASH | DCACHE_OP_COMPARE |
+ DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE);
+}
+
+#endif /* _ZFS_DCACHE_H */
diff --git a/include/os/linux/kernel/linux/kmap_compat.h b/include/os/linux/kernel/linux/kmap_compat.h
new file mode 100644
index 000000000000..a7e63944ea16
--- /dev/null
+++ b/include/os/linux/kernel/linux/kmap_compat.h
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
+ */
+
+#ifndef _ZFS_KMAP_H
+#define _ZFS_KMAP_H
+
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+
+/* 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)
+
+/* 5.0 API change - no more 'type' argument for access_ok() */
+#ifdef HAVE_ACCESS_OK_TYPE
+#define zfs_access_ok(type, addr, size) access_ok(type, addr, size)
+#else
+#define zfs_access_ok(type, addr, size) access_ok(addr, size)
+#endif
+
+#endif /* _ZFS_KMAP_H */
diff --git a/include/os/linux/kernel/linux/mod_compat.h b/include/os/linux/kernel/linux/mod_compat.h
new file mode 100644
index 000000000000..4b83fe413334
--- /dev/null
+++ b/include/os/linux/kernel/linux/mod_compat.h
@@ -0,0 +1,151 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (C) 2016 Gvozden Neskovic <neskovic@gmail.com>.
+ */
+
+#ifndef _MOD_COMPAT_H
+#define _MOD_COMPAT_H
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Grsecurity kernel API change */
+#ifdef MODULE_PARAM_CALL_CONST
+typedef const struct kernel_param zfs_kernel_param_t;
+#else
+typedef struct kernel_param zfs_kernel_param_t;
+#endif
+
+#define ZMOD_RW 0644
+#define ZMOD_RD 0444
+
+/* BEGIN CSTYLED */
+#define INT int
+#define UINT uint
+#define ULONG ulong
+#define LONG long
+#define STRING charp
+/* END CSTYLED */
+
+enum scope_prefix_types {
+ zfs,
+ zfs_arc,
+ zfs_condense,
+ zfs_dbuf,
+ zfs_dbuf_cache,
+ zfs_deadman,
+ zfs_dedup,
+ zfs_l2arc,
+ zfs_livelist,
+ zfs_livelist_condense,
+ zfs_lua,
+ zfs_metaslab,
+ zfs_mg,
+ zfs_multihost,
+ zfs_prefetch,
+ zfs_reconstruct,
+ zfs_recv,
+ zfs_send,
+ zfs_spa,
+ zfs_trim,
+ zfs_txg,
+ zfs_vdev,
+ zfs_vdev_cache,
+ zfs_vdev_mirror,
+ zfs_zevent,
+ zfs_zio,
+ zfs_zil
+};
+
+/*
+ * Declare a module parameter / sysctl node
+ *
+ * "scope_prefix" the part of the the sysctl / sysfs tree the node resides under
+ * (currently a no-op on Linux)
+ * "name_prefix" the part of the variable name that will be excluded from the
+ * exported names on platforms with a hierarchical namespace
+ * "name" the part of the variable that will be exposed on platforms with a
+ * hierarchical namespace, or as name_prefix ## name on Linux
+ * "type" the variable type
+ * "perm" the permissions (read/write or read only)
+ * "desc" a brief description of the option
+ *
+ * Examples:
+ * ZFS_MODULE_PARAM(zfs_vdev_mirror, zfs_vdev_mirror_, rotating_inc, UINT,
+ * ZMOD_RW, "Rotating media load increment for non-seeking I/O's");
+ * on FreeBSD:
+ * vfs.zfs.vdev.mirror.rotating_inc
+ * on Linux:
+ * zfs_vdev_mirror_rotating_inc
+ *
+ * ZFS_MODULE_PARAM(zfs, , dmu_prefetch_max, UINT, ZMOD_RW,
+ * "Limit one prefetch call to this size");
+ * on FreeBSD:
+ * vfs.zfs.dmu_prefetch_max
+ * on Linux:
+ * dmu_prefetch_max
+ */
+/* BEGIN CSTYLED */
+#define ZFS_MODULE_PARAM(scope_prefix, name_prefix, name, type, perm, desc) \
+ CTASSERT_GLOBAL((sizeof (scope_prefix) == sizeof (enum scope_prefix_types))); \
+ module_param(name_prefix ## name, type, perm); \
+ MODULE_PARM_DESC(name_prefix ## name, desc)
+/* END CSTYLED */
+
+/*
+ * Declare a module parameter / sysctl node
+ *
+ * "scope_prefix" the part of the the sysctl / sysfs tree the node resides under
+ * (currently a no-op on Linux)
+ * "name_prefix" the part of the variable name that will be excluded from the
+ * exported names on platforms with a hierarchical namespace
+ * "name" the part of the variable that will be exposed on platforms with a
+ * hierarchical namespace, or as name_prefix ## name on Linux
+ * "setfunc" setter function
+ * "getfunc" getter function
+ * "perm" the permissions (read/write or read only)
+ * "desc" a brief description of the option
+ *
+ * Examples:
+ * ZFS_MODULE_PARAM_CALL(zfs_spa, spa_, slop_shift, param_set_slop_shift,
+ * param_get_int, ZMOD_RW, "Reserved free space in pool");
+ * on FreeBSD:
+ * vfs.zfs.spa_slop_shift
+ * on Linux:
+ * spa_slop_shift
+ */
+/* BEGIN CSTYLED */
+#define ZFS_MODULE_PARAM_CALL(scope_prefix, name_prefix, name, setfunc, getfunc, perm, desc) \
+ CTASSERT_GLOBAL((sizeof (scope_prefix) == sizeof (enum scope_prefix_types))); \
+ module_param_call(name_prefix ## name, setfunc, getfunc, &name_prefix ## name, perm); \
+ MODULE_PARM_DESC(name_prefix ## name, desc)
+/* END CSTYLED */
+
+#define ZFS_MODULE_PARAM_ARGS const char *buf, zfs_kernel_param_t *kp
+
+#define ZFS_MODULE_DESCRIPTION(s) MODULE_DESCRIPTION(s)
+#define ZFS_MODULE_AUTHOR(s) MODULE_AUTHOR(s)
+#define ZFS_MODULE_LICENSE(s) MODULE_LICENSE(s)
+#define ZFS_MODULE_VERSION(s) MODULE_VERSION(s)
+
+#endif /* _MOD_COMPAT_H */
diff --git a/include/os/linux/kernel/linux/page_compat.h b/include/os/linux/kernel/linux/page_compat.h
new file mode 100644
index 000000000000..8ad04f9bbfc6
--- /dev/null
+++ b/include/os/linux/kernel/linux/page_compat.h
@@ -0,0 +1,92 @@
+#ifndef _ZFS_PAGE_COMPAT_H
+#define _ZFS_PAGE_COMPAT_H
+
+/*
+ * We have various enum members moving between two separate enum types,
+ * and accessed by different functions at various times. Centralise the
+ * insanity.
+ *
+ * < v4.8: all enums in zone_stat_item, via global_page_state()
+ * v4.8: some enums moved to node_stat_item, global_node_page_state() introduced
+ * v4.13: some enums moved from zone_stat_item to node_state_item
+ * v4.14: global_page_state() rename to global_zone_page_state()
+ *
+ * The defines used here are created by config/kernel-global_page_state.m4
+ */
+
+/*
+ * Create our own accessor functions to follow the Linux API changes
+ */
+#if defined(ZFS_GLOBAL_ZONE_PAGE_STATE)
+
+/* global_zone_page_state() introduced */
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_FILE_PAGES)
+#define nr_file_pages() global_node_page_state(NR_FILE_PAGES)
+#else
+#define nr_file_pages() global_zone_page_state(NR_FILE_PAGES)
+#endif
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_ANON)
+#define nr_inactive_anon_pages() global_node_page_state(NR_INACTIVE_ANON)
+#else
+#define nr_inactive_anon_pages() global_zone_page_state(NR_INACTIVE_ANON)
+#endif
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_FILE)
+#define nr_inactive_file_pages() global_node_page_state(NR_INACTIVE_FILE)
+#else
+#define nr_inactive_file_pages() global_zone_page_state(NR_INACTIVE_FILE)
+#endif
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE_B)
+#define nr_slab_reclaimable_pages() \
+ global_node_page_state(NR_SLAB_RECLAIMABLE_B)
+#else
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE)
+#define nr_slab_reclaimable_pages() global_node_page_state(NR_SLAB_RECLAIMABLE)
+#else
+#define nr_slab_reclaimable_pages() global_zone_page_state(NR_SLAB_RECLAIMABLE)
+#endif
+#endif
+
+#elif defined(ZFS_GLOBAL_NODE_PAGE_STATE)
+
+/* global_node_page_state() introduced */
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_FILE_PAGES)
+#define nr_file_pages() global_node_page_state(NR_FILE_PAGES)
+#else
+#define nr_file_pages() global_page_state(NR_FILE_PAGES)
+#endif
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_ANON)
+#define nr_inactive_anon_pages() global_node_page_state(NR_INACTIVE_ANON)
+#else
+#define nr_inactive_anon_pages() global_page_state(NR_INACTIVE_ANON)
+#endif
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_INACTIVE_FILE)
+#define nr_inactive_file_pages() global_node_page_state(NR_INACTIVE_FILE)
+#else
+#define nr_inactive_file_pages() global_page_state(NR_INACTIVE_FILE)
+#endif
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE_B)
+#define nr_slab_reclaimable_pages() \
+ global_node_page_state(NR_SLAB_RECLAIMABLE_B)
+#else
+#if defined(ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE)
+#define nr_slab_reclaimable_pages() global_node_page_state(NR_SLAB_RECLAIMABLE)
+#else
+#define nr_slab_reclaimable_pages() global_page_state(NR_SLAB_RECLAIMABLE)
+#endif
+#endif
+
+#else
+
+/* global_page_state() only */
+#define nr_file_pages() global_page_state(NR_FILE_PAGES)
+#define nr_inactive_anon_pages() global_page_state(NR_INACTIVE_ANON)
+#define nr_inactive_file_pages() global_page_state(NR_INACTIVE_FILE)
+#ifdef ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE_B
+#define nr_slab_reclaimable_pages() global_page_state(NR_SLAB_RECLAIMABLE_B)
+#else
+#define nr_slab_reclaimable_pages() global_page_state(NR_SLAB_RECLAIMABLE)
+#endif /* ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE_B */
+
+#endif /* ZFS_GLOBAL_ZONE_PAGE_STATE */
+
+#endif /* _ZFS_PAGE_COMPAT_H */
diff --git a/include/os/linux/kernel/linux/percpu_compat.h b/include/os/linux/kernel/linux/percpu_compat.h
new file mode 100644
index 000000000000..e7a4242c466c
--- /dev/null
+++ b/include/os/linux/kernel/linux/percpu_compat.h
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2020 by Delphix. All rights reserved.
+ */
+
+#ifndef _ZFS_PERCPU_H
+#define _ZFS_PERCPU_H
+
+#include <linux/percpu_counter.h>
+
+/*
+ * 3.18 API change,
+ * percpu_counter_init() now must be passed a gfp mask which will be
+ * used for the dynamic allocation of the actual counter.
+ */
+#ifdef HAVE_PERCPU_COUNTER_INIT_WITH_GFP
+#define percpu_counter_init_common(counter, n, gfp) \
+ percpu_counter_init(counter, n, gfp)
+#else
+#define percpu_counter_init_common(counter, n, gfp) \
+ percpu_counter_init(counter, n)
+#endif
+
+#endif /* _ZFS_PERCPU_H */
diff --git a/include/os/linux/kernel/linux/simd.h b/include/os/linux/kernel/linux/simd.h
new file mode 100644
index 000000000000..4cde248e200c
--- /dev/null
+++ b/include/os/linux/kernel/linux/simd.h
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (C) 2019 Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _LINUX_SIMD_H
+#define _LINUX_SIMD_H
+
+#if defined(__x86)
+#include <linux/simd_x86.h>
+
+#elif defined(__aarch64__)
+#include <linux/simd_aarch64.h>
+
+#elif defined(__powerpc__)
+#include <linux/simd_powerpc.h>
+#else
+
+#define kfpu_allowed() 0
+#define kfpu_begin() do {} while (0)
+#define kfpu_end() do {} while (0)
+#define kfpu_init() 0
+#define kfpu_fini() ((void) 0)
+
+#endif
+#endif /* _LINUX_SIMD_H */
diff --git a/include/os/linux/kernel/linux/simd_aarch64.h b/include/os/linux/kernel/linux/simd_aarch64.h
new file mode 100644
index 000000000000..50937e97ced1
--- /dev/null
+++ b/include/os/linux/kernel/linux/simd_aarch64.h
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (C) 2016 Romain Dolbeau <romain@dolbeau.org>.
+ */
+
+/*
+ * USER API:
+ *
+ * Kernel fpu methods:
+ * kfpu_allowed()
+ * kfpu_begin()
+ * kfpu_end()
+ * kfpu_init()
+ * kfpu_fini()
+ */
+
+#ifndef _LINUX_SIMD_AARCH64_H
+#define _LINUX_SIMD_AARCH64_H
+
+#include <sys/isa_defs.h>
+
+#if defined(__aarch64__)
+
+#include <sys/types.h>
+#include <asm/neon.h>
+
+#define kfpu_allowed() 1
+#define kfpu_begin() kernel_neon_begin()
+#define kfpu_end() kernel_neon_end()
+#define kfpu_init() 0
+#define kfpu_fini() ((void) 0)
+
+#endif /* __aarch64__ */
+
+#endif /* _LINUX_SIMD_AARCH64_H */
diff --git a/include/os/linux/kernel/linux/simd_powerpc.h b/include/os/linux/kernel/linux/simd_powerpc.h
new file mode 100644
index 000000000000..108cef22f56f
--- /dev/null
+++ b/include/os/linux/kernel/linux/simd_powerpc.h
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (C) 2019 Romain Dolbeau
+ * <romain.dolbeau@european-processor-initiative.eu>
+ */
+
+/*
+ * USER API:
+ *
+ * Kernel fpu methods:
+ * kfpu_allowed()
+ * kfpu_begin()
+ * kfpu_end()
+ * kfpu_init()
+ * kfpu_fini()
+ *
+ * SIMD support:
+ *
+ * Following functions should be called to determine whether CPU feature
+ * is supported. All functions are usable in kernel and user space.
+ * If a SIMD algorithm is using more than one instruction set
+ * all relevant feature test functions should be called.
+ *
+ * Supported features:
+ * zfs_altivec_available()
+ */
+
+#ifndef _LINUX_SIMD_POWERPC_H
+#define _LINUX_SIMD_POWERPC_H
+
+/* only for __powerpc__ */
+#if defined(__powerpc__)
+
+#include <linux/preempt.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <asm/switch_to.h>
+#include <sys/types.h>
+#include <linux/version.h>
+
+#define kfpu_allowed() 1
+#define kfpu_begin() \
+ { \
+ preempt_disable(); \
+ enable_kernel_altivec(); \
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+#define kfpu_end() \
+ { \
+ disable_kernel_altivec(); \
+ preempt_enable(); \
+ }
+#else
+/* seems that before 4.5 no-one bothered disabling ... */
+#define kfpu_end() preempt_enable()
+#endif
+#define kfpu_init() 0
+#define kfpu_fini() ((void) 0)
+
+/*
+ * Check if AltiVec instruction set is available
+ */
+static inline boolean_t
+zfs_altivec_available(void)
+{
+ boolean_t res;
+ /* suggested by macallan at netbsd dot org */
+#if defined(__powerpc64__)
+ u64 msr;
+#else
+ u32 msr;
+#endif
+ kfpu_begin();
+ __asm volatile("mfmsr %0" : "=r"(msr));
+ /*
+ * 64 bits -> need to check bit 38
+ * Power ISA Version 3.0B
+ * p944
+ * 32 bits -> Need to check bit 6
+ * AltiVec Technology Programming Environments Manual
+ * p49 (2-9)
+ * They are the same, as ppc counts 'backward' ...
+ */
+ res = (msr & 0x2000000) != 0;
+ kfpu_end();
+ return (res);
+}
+#endif /* defined(__powerpc) */
+
+#endif /* _LINUX_SIMD_POWERPC_H */
diff --git a/include/os/linux/kernel/linux/simd_x86.h b/include/os/linux/kernel/linux/simd_x86.h
new file mode 100644
index 000000000000..cdd3286d2147
--- /dev/null
+++ b/include/os/linux/kernel/linux/simd_x86.h
@@ -0,0 +1,646 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (C) 2016 Gvozden Neskovic <neskovic@compeng.uni-frankfurt.de>.
+ */
+
+/*
+ * USER API:
+ *
+ * Kernel fpu methods:
+ * kfpu_allowed()
+ * kfpu_begin()
+ * kfpu_end()
+ * kfpu_init()
+ * kfpu_fini()
+ *
+ * SIMD support:
+ *
+ * Following functions should be called to determine whether CPU feature
+ * is supported. All functions are usable in kernel and user space.
+ * If a SIMD algorithm is using more than one instruction set
+ * all relevant feature test functions should be called.
+ *
+ * Supported features:
+ * zfs_sse_available()
+ * zfs_sse2_available()
+ * zfs_sse3_available()
+ * zfs_ssse3_available()
+ * zfs_sse4_1_available()
+ * zfs_sse4_2_available()
+ *
+ * zfs_avx_available()
+ * zfs_avx2_available()
+ *
+ * zfs_bmi1_available()
+ * zfs_bmi2_available()
+ *
+ * zfs_avx512f_available()
+ * zfs_avx512cd_available()
+ * zfs_avx512er_available()
+ * zfs_avx512pf_available()
+ * zfs_avx512bw_available()
+ * zfs_avx512dq_available()
+ * zfs_avx512vl_available()
+ * zfs_avx512ifma_available()
+ * zfs_avx512vbmi_available()
+ *
+ * NOTE(AVX-512VL): If using AVX-512 instructions with 128Bit registers
+ * also add zfs_avx512vl_available() to feature check.
+ */
+
+#ifndef _LINUX_SIMD_X86_H
+#define _LINUX_SIMD_X86_H
+
+/* only for __x86 */
+#if defined(__x86)
+
+#include <sys/types.h>
+#include <asm/cpufeature.h>
+
+/*
+ * Disable the WARN_ON_FPU() macro to prevent additional dependencies
+ * when providing the kfpu_* functions. Relevant warnings are included
+ * as appropriate and are unconditionally enabled.
+ */
+#if defined(CONFIG_X86_DEBUG_FPU) && !defined(KERNEL_EXPORTS_X86_FPU)
+#undef CONFIG_X86_DEBUG_FPU
+#endif
+
+#if defined(HAVE_KERNEL_FPU_API_HEADER)
+#include <asm/fpu/api.h>
+#include <asm/fpu/internal.h>
+#else
+#include <asm/i387.h>
+#include <asm/xcr.h>
+#endif
+
+/*
+ * The following cases are for kernels which export either the
+ * kernel_fpu_* or __kernel_fpu_* functions.
+ */
+#if defined(KERNEL_EXPORTS_X86_FPU)
+
+#define kfpu_allowed() 1
+#define kfpu_init() 0
+#define kfpu_fini() ((void) 0)
+
+#if defined(HAVE_UNDERSCORE_KERNEL_FPU)
+#define kfpu_begin() \
+{ \
+ preempt_disable(); \
+ __kernel_fpu_begin(); \
+}
+#define kfpu_end() \
+{ \
+ __kernel_fpu_end(); \
+ preempt_enable(); \
+}
+
+#elif defined(HAVE_KERNEL_FPU)
+#define kfpu_begin() kernel_fpu_begin()
+#define kfpu_end() kernel_fpu_end()
+
+#else
+/*
+ * This case is unreachable. When KERNEL_EXPORTS_X86_FPU is defined then
+ * either HAVE_UNDERSCORE_KERNEL_FPU or HAVE_KERNEL_FPU must be defined.
+ */
+#error "Unreachable kernel configuration"
+#endif
+
+#else /* defined(KERNEL_EXPORTS_X86_FPU) */
+
+/*
+ * When the kernel_fpu_* symbols are unavailable then provide our own
+ * versions which allow the FPU to be safely used.
+ */
+#if defined(HAVE_KERNEL_FPU_INTERNAL)
+
+#include <linux/mm.h>
+
+extern union fpregs_state **zfs_kfpu_fpregs;
+
+/*
+ * Initialize per-cpu variables to store FPU state.
+ */
+static inline void
+kfpu_fini(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ if (zfs_kfpu_fpregs[cpu] != NULL) {
+ free_pages((unsigned long)zfs_kfpu_fpregs[cpu],
+ get_order(sizeof (union fpregs_state)));
+ }
+ }
+
+ kfree(zfs_kfpu_fpregs);
+}
+
+static inline int
+kfpu_init(void)
+{
+ zfs_kfpu_fpregs = kzalloc(num_possible_cpus() *
+ sizeof (union fpregs_state *), GFP_KERNEL);
+ if (zfs_kfpu_fpregs == NULL)
+ return (-ENOMEM);
+
+ /*
+ * The fxsave and xsave operations require 16-/64-byte alignment of
+ * the target memory. Since kmalloc() provides no alignment
+ * guarantee instead use alloc_pages_node().
+ */
+ unsigned int order = get_order(sizeof (union fpregs_state));
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct page *page = alloc_pages_node(cpu_to_node(cpu),
+ GFP_KERNEL | __GFP_ZERO, order);
+ if (page == NULL) {
+ kfpu_fini();
+ return (-ENOMEM);
+ }
+
+ zfs_kfpu_fpregs[cpu] = page_address(page);
+ }
+
+ return (0);
+}
+
+#define kfpu_allowed() 1
+#define ex_handler_fprestore ex_handler_default
+
+/*
+ * FPU save and restore instructions.
+ */
+#define __asm __asm__ __volatile__
+#define kfpu_fxsave(addr) __asm("fxsave %0" : "=m" (*(addr)))
+#define kfpu_fxsaveq(addr) __asm("fxsaveq %0" : "=m" (*(addr)))
+#define kfpu_fnsave(addr) __asm("fnsave %0; fwait" : "=m" (*(addr)))
+#define kfpu_fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr)))
+#define kfpu_fxrstorq(addr) __asm("fxrstorq %0" : : "m" (*(addr)))
+#define kfpu_frstor(addr) __asm("frstor %0" : : "m" (*(addr)))
+#define kfpu_fxsr_clean(rval) __asm("fnclex; emms; fildl %P[addr]" \
+ : : [addr] "m" (rval));
+
+static inline void
+kfpu_save_xsave(struct xregs_state *addr, uint64_t mask)
+{
+ uint32_t low, hi;
+ int err;
+
+ low = mask;
+ hi = mask >> 32;
+ XSTATE_XSAVE(addr, low, hi, err);
+ WARN_ON_ONCE(err);
+}
+
+static inline void
+kfpu_save_fxsr(struct fxregs_state *addr)
+{
+ if (IS_ENABLED(CONFIG_X86_32))
+ kfpu_fxsave(addr);
+ else
+ kfpu_fxsaveq(addr);
+}
+
+static inline void
+kfpu_save_fsave(struct fregs_state *addr)
+{
+ kfpu_fnsave(addr);
+}
+
+static inline void
+kfpu_begin(void)
+{
+ /*
+ * Preemption and interrupts must be disabled for the critical
+ * region where the FPU state is being modified.
+ */
+ preempt_disable();
+ local_irq_disable();
+
+ /*
+ * The current FPU registers need to be preserved by kfpu_begin()
+ * and restored by kfpu_end(). They are stored in a dedicated
+ * per-cpu variable, not in the task struct, this allows any user
+ * FPU state to be correctly preserved and restored.
+ */
+ union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
+
+ if (static_cpu_has(X86_FEATURE_XSAVE)) {
+ kfpu_save_xsave(&state->xsave, ~0);
+ } else if (static_cpu_has(X86_FEATURE_FXSR)) {
+ kfpu_save_fxsr(&state->fxsave);
+ } else {
+ kfpu_save_fsave(&state->fsave);
+ }
+}
+
+static inline void
+kfpu_restore_xsave(struct xregs_state *addr, uint64_t mask)
+{
+ uint32_t low, hi;
+
+ low = mask;
+ hi = mask >> 32;
+ XSTATE_XRESTORE(addr, low, hi);
+}
+
+static inline void
+kfpu_restore_fxsr(struct fxregs_state *addr)
+{
+ /*
+ * On AuthenticAMD K7 and K8 processors the fxrstor instruction only
+ * restores the _x87 FOP, FIP, and FDP registers when an exception
+ * is pending. Clean the _x87 state to force the restore.
+ */
+ if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK)))
+ kfpu_fxsr_clean(addr);
+
+ if (IS_ENABLED(CONFIG_X86_32)) {
+ kfpu_fxrstor(addr);
+ } else {
+ kfpu_fxrstorq(addr);
+ }
+}
+
+static inline void
+kfpu_restore_fsave(struct fregs_state *addr)
+{
+ kfpu_frstor(addr);
+}
+
+static inline void
+kfpu_end(void)
+{
+ union fpregs_state *state = zfs_kfpu_fpregs[smp_processor_id()];
+
+ if (static_cpu_has(X86_FEATURE_XSAVE)) {
+ kfpu_restore_xsave(&state->xsave, ~0);
+ } else if (static_cpu_has(X86_FEATURE_FXSR)) {
+ kfpu_restore_fxsr(&state->fxsave);
+ } else {
+ kfpu_restore_fsave(&state->fsave);
+ }
+
+ local_irq_enable();
+ preempt_enable();
+}
+
+#else
+
+/*
+ * FPU support is unavailable.
+ */
+#define kfpu_allowed() 0
+#define kfpu_begin() do {} while (0)
+#define kfpu_end() do {} while (0)
+#define kfpu_init() 0
+#define kfpu_fini() ((void) 0)
+
+#endif /* defined(HAVE_KERNEL_FPU_INTERNAL) */
+#endif /* defined(KERNEL_EXPORTS_X86_FPU) */
+
+/*
+ * Linux kernel provides an interface for CPU feature testing.
+ */
+
+/*
+ * Detect register set support
+ */
+static inline boolean_t
+__simd_state_enabled(const uint64_t state)
+{
+ boolean_t has_osxsave;
+ uint64_t xcr0;
+
+#if defined(X86_FEATURE_OSXSAVE)
+ has_osxsave = !!boot_cpu_has(X86_FEATURE_OSXSAVE);
+#else
+ has_osxsave = B_FALSE;
+#endif
+ if (!has_osxsave)
+ return (B_FALSE);
+
+ xcr0 = xgetbv(0);
+ return ((xcr0 & state) == state);
+}
+
+#define _XSTATE_SSE_AVX (0x2 | 0x4)
+#define _XSTATE_AVX512 (0xE0 | _XSTATE_SSE_AVX)
+
+#define __ymm_enabled() __simd_state_enabled(_XSTATE_SSE_AVX)
+#define __zmm_enabled() __simd_state_enabled(_XSTATE_AVX512)
+
+/*
+ * Check if SSE instruction set is available
+ */
+static inline boolean_t
+zfs_sse_available(void)
+{
+ return (!!boot_cpu_has(X86_FEATURE_XMM));
+}
+
+/*
+ * Check if SSE2 instruction set is available
+ */
+static inline boolean_t
+zfs_sse2_available(void)
+{
+ return (!!boot_cpu_has(X86_FEATURE_XMM2));
+}
+
+/*
+ * Check if SSE3 instruction set is available
+ */
+static inline boolean_t
+zfs_sse3_available(void)
+{
+ return (!!boot_cpu_has(X86_FEATURE_XMM3));
+}
+
+/*
+ * Check if SSSE3 instruction set is available
+ */
+static inline boolean_t
+zfs_ssse3_available(void)
+{
+ return (!!boot_cpu_has(X86_FEATURE_SSSE3));
+}
+
+/*
+ * Check if SSE4.1 instruction set is available
+ */
+static inline boolean_t
+zfs_sse4_1_available(void)
+{
+ return (!!boot_cpu_has(X86_FEATURE_XMM4_1));
+}
+
+/*
+ * Check if SSE4.2 instruction set is available
+ */
+static inline boolean_t
+zfs_sse4_2_available(void)
+{
+ return (!!boot_cpu_has(X86_FEATURE_XMM4_2));
+}
+
+/*
+ * Check if AVX instruction set is available
+ */
+static inline boolean_t
+zfs_avx_available(void)
+{
+ return (boot_cpu_has(X86_FEATURE_AVX) && __ymm_enabled());
+}
+
+/*
+ * Check if AVX2 instruction set is available
+ */
+static inline boolean_t
+zfs_avx2_available(void)
+{
+ return (boot_cpu_has(X86_FEATURE_AVX2) && __ymm_enabled());
+}
+
+/*
+ * Check if BMI1 instruction set is available
+ */
+static inline boolean_t
+zfs_bmi1_available(void)
+{
+#if defined(X86_FEATURE_BMI1)
+ return (!!boot_cpu_has(X86_FEATURE_BMI1));
+#else
+ return (B_FALSE);
+#endif
+}
+
+/*
+ * Check if BMI2 instruction set is available
+ */
+static inline boolean_t
+zfs_bmi2_available(void)
+{
+#if defined(X86_FEATURE_BMI2)
+ return (!!boot_cpu_has(X86_FEATURE_BMI2));
+#else
+ return (B_FALSE);
+#endif
+}
+
+/*
+ * Check if AES instruction set is available
+ */
+static inline boolean_t
+zfs_aes_available(void)
+{
+#if defined(X86_FEATURE_AES)
+ return (!!boot_cpu_has(X86_FEATURE_AES));
+#else
+ return (B_FALSE);
+#endif
+}
+
+/*
+ * Check if PCLMULQDQ instruction set is available
+ */
+static inline boolean_t
+zfs_pclmulqdq_available(void)
+{
+#if defined(X86_FEATURE_PCLMULQDQ)
+ return (!!boot_cpu_has(X86_FEATURE_PCLMULQDQ));
+#else
+ return (B_FALSE);
+#endif
+}
+
+/*
+ * Check if MOVBE instruction is available
+ */
+static inline boolean_t
+zfs_movbe_available(void)
+{
+#if defined(X86_FEATURE_MOVBE)
+ return (!!boot_cpu_has(X86_FEATURE_MOVBE));
+#else
+ return (B_FALSE);
+#endif
+}
+
+/*
+ * AVX-512 family of instruction sets:
+ *
+ * AVX512F Foundation
+ * AVX512CD Conflict Detection Instructions
+ * AVX512ER Exponential and Reciprocal Instructions
+ * AVX512PF Prefetch Instructions
+ *
+ * AVX512BW Byte and Word Instructions
+ * AVX512DQ Double-word and Quadword Instructions
+ * AVX512VL Vector Length Extensions
+ *
+ * AVX512IFMA Integer Fused Multiply Add (Not supported by kernel 4.4)
+ * AVX512VBMI Vector Byte Manipulation Instructions
+ */
+
+/*
+ * Check if AVX512F instruction set is available
+ */
+static inline boolean_t
+zfs_avx512f_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512F)
+ has_avx512 = !!boot_cpu_has(X86_FEATURE_AVX512F);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512CD instruction set is available
+ */
+static inline boolean_t
+zfs_avx512cd_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512CD)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512CD);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512ER instruction set is available
+ */
+static inline boolean_t
+zfs_avx512er_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512ER)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512ER);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512PF instruction set is available
+ */
+static inline boolean_t
+zfs_avx512pf_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512PF)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512PF);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512BW instruction set is available
+ */
+static inline boolean_t
+zfs_avx512bw_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512BW)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512BW);
+#endif
+
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512DQ instruction set is available
+ */
+static inline boolean_t
+zfs_avx512dq_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512DQ)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512DQ);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512VL instruction set is available
+ */
+static inline boolean_t
+zfs_avx512vl_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512VL)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512VL);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512IFMA instruction set is available
+ */
+static inline boolean_t
+zfs_avx512ifma_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512IFMA)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512IFMA);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+/*
+ * Check if AVX512VBMI instruction set is available
+ */
+static inline boolean_t
+zfs_avx512vbmi_available(void)
+{
+ boolean_t has_avx512 = B_FALSE;
+
+#if defined(X86_FEATURE_AVX512VBMI)
+ has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+ boot_cpu_has(X86_FEATURE_AVX512VBMI);
+#endif
+ return (has_avx512 && __zmm_enabled());
+}
+
+#endif /* defined(__x86) */
+
+#endif /* _LINUX_SIMD_X86_H */
diff --git a/include/os/linux/kernel/linux/utsname_compat.h b/include/os/linux/kernel/linux/utsname_compat.h
new file mode 100644
index 000000000000..88da45cf504e
--- /dev/null
+++ b/include/os/linux/kernel/linux/utsname_compat.h
@@ -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/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h
new file mode 100644
index 000000000000..c35e80d31cd7
--- /dev/null
+++ b/include/os/linux/kernel/linux/vfs_compat.h
@@ -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 (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 <sys/cred.h>
+#include <linux/backing-dev.h>
+#include <linux/compat.h>
+
+/*
+ * 2.6.34 - 3.19, bdi_setup_and_register() takes 3 arguments.
+ * 4.0 - 4.11, bdi_setup_and_register() takes 2 arguments.
+ * 4.12 - x.y, super_setup_bdi_name() new interface.
+ */
+#if defined(HAVE_SUPER_SETUP_BDI_NAME)
+extern atomic_long_t zfs_bdi_seq;
+
+static inline int
+zpl_bdi_setup(struct super_block *sb, char *name)
+{
+ return super_setup_bdi_name(sb, "%.28s-%ld", name,
+ atomic_long_inc_return(&zfs_bdi_seq));
+}
+static inline void
+zpl_bdi_destroy(struct super_block *sb)
+{
+}
+#elif defined(HAVE_2ARGS_BDI_SETUP_AND_REGISTER)
+static inline int
+zpl_bdi_setup(struct super_block *sb, char *name)
+{
+ struct backing_dev_info *bdi;
+ int error;
+
+ bdi = kmem_zalloc(sizeof (struct backing_dev_info), KM_SLEEP);
+ error = bdi_setup_and_register(bdi, name);
+ if (error) {
+ kmem_free(bdi, sizeof (struct backing_dev_info));
+ return (error);
+ }
+
+ sb->s_bdi = bdi;
+
+ return (0);
+}
+static inline void
+zpl_bdi_destroy(struct super_block *sb)
+{
+ struct backing_dev_info *bdi = sb->s_bdi;
+
+ bdi_destroy(bdi);
+ kmem_free(bdi, sizeof (struct backing_dev_info));
+ sb->s_bdi = NULL;
+}
+#elif defined(HAVE_3ARGS_BDI_SETUP_AND_REGISTER)
+static inline int
+zpl_bdi_setup(struct super_block *sb, char *name)
+{
+ struct backing_dev_info *bdi;
+ int error;
+
+ bdi = kmem_zalloc(sizeof (struct backing_dev_info), KM_SLEEP);
+ error = bdi_setup_and_register(bdi, name, BDI_CAP_MAP_COPY);
+ if (error) {
+ kmem_free(sb->s_bdi, sizeof (struct backing_dev_info));
+ return (error);
+ }
+
+ sb->s_bdi = bdi;
+
+ return (0);
+}
+static inline void
+zpl_bdi_destroy(struct super_block *sb)
+{
+ struct backing_dev_info *bdi = sb->s_bdi;
+
+ bdi_destroy(bdi);
+ kmem_free(bdi, sizeof (struct backing_dev_info));
+ sb->s_bdi = NULL;
+}
+#else
+#error "Unsupported kernel"
+#endif
+
+/*
+ * 4.14 adds SB_* flag definitions, define them to MS_* equivalents
+ * if not set.
+ */
+#ifndef SB_RDONLY
+#define SB_RDONLY MS_RDONLY
+#endif
+
+#ifndef SB_SILENT
+#define SB_SILENT MS_SILENT
+#endif
+
+#ifndef SB_ACTIVE
+#define SB_ACTIVE MS_ACTIVE
+#endif
+
+#ifndef SB_POSIXACL
+#define SB_POSIXACL MS_POSIXACL
+#endif
+
+#ifndef SB_MANDLOCK
+#define SB_MANDLOCK MS_MANDLOCK
+#endif
+
+#ifndef SB_NOATIME
+#define SB_NOATIME MS_NOATIME
+#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 */
+
+#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;
+#ifdef HAVE_ACL_REFCOUNT
+ if (refcount_dec_and_test(&acl->a_refcount))
+ zpl_posix_acl_release_impl(acl);
+#else
+ if (atomic_dec_and_test(&acl->a_refcount))
+ zpl_posix_acl_release_impl(acl);
+#endif
+}
+#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 */
+
+/*
+ * 3.1 API change,
+ * posix_acl_chmod() was added as the preferred interface.
+ *
+ * 3.14 API change,
+ * posix_acl_chmod() was changed to __posix_acl_chmod()
+ */
+#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
+#error "Unsupported kernel"
+#endif /* HAVE_POSIX_ACL_CHMOD */
+#endif /* HAVE___POSIX_ACL_CHMOD */
+
+/*
+ * 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 */
+
+/*
+ * 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 */
+
+/*
+ * 4.1 API change
+ * struct access file->f_path.dentry was replaced by accessor function
+ * file_dentry(f)
+ */
+#ifndef HAVE_FILE_DENTRY
+static inline struct dentry *file_dentry(const struct file *f)
+{
+ return (f->f_path.dentry);
+}
+#endif /* HAVE_FILE_DENTRY */
+
+static inline uid_t zfs_uid_read_impl(struct inode *ip)
+{
+#ifdef HAVE_SUPER_USER_NS
+ return (from_kuid(ip->i_sb->s_user_ns, ip->i_uid));
+#else
+ return (from_kuid(kcred->user_ns, ip->i_uid));
+#endif
+}
+
+static inline uid_t zfs_uid_read(struct inode *ip)
+{
+ return (zfs_uid_read_impl(ip));
+}
+
+static inline gid_t zfs_gid_read_impl(struct inode *ip)
+{
+#ifdef HAVE_SUPER_USER_NS
+ return (from_kgid(ip->i_sb->s_user_ns, ip->i_gid));
+#else
+ return (from_kgid(kcred->user_ns, ip->i_gid));
+#endif
+}
+
+static inline gid_t zfs_gid_read(struct inode *ip)
+{
+ return (zfs_gid_read_impl(ip));
+}
+
+static inline void zfs_uid_write(struct inode *ip, uid_t uid)
+{
+#ifdef HAVE_SUPER_USER_NS
+ ip->i_uid = make_kuid(ip->i_sb->s_user_ns, uid);
+#else
+ ip->i_uid = make_kuid(kcred->user_ns, uid);
+#endif
+}
+
+static inline void zfs_gid_write(struct inode *ip, gid_t gid)
+{
+#ifdef HAVE_SUPER_USER_NS
+ ip->i_gid = make_kgid(ip->i_sb->s_user_ns, gid);
+#else
+ ip->i_gid = make_kgid(kcred->user_ns, gid);
+#endif
+}
+
+/*
+ * 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
+
+/*
+ * 4.11 API change
+ * These macros are defined by kernel 4.11. We define them so that the same
+ * code builds under kernels < 4.11 and >= 4.11. The macros are set to 0 so
+ * that it will create obvious failures if they are accidentally used when built
+ * against a kernel >= 4.11.
+ */
+
+#ifndef STATX_BASIC_STATS
+#define STATX_BASIC_STATS 0
+#endif
+
+#ifndef AT_STATX_SYNC_AS_STAT
+#define AT_STATX_SYNC_AS_STAT 0
+#endif
+
+/*
+ * 4.11 API change
+ * 4.11 takes struct path *, < 4.11 takes vfsmount *
+ */
+
+#ifdef HAVE_VFSMOUNT_IOPS_GETATTR
+#define ZPL_GETATTR_WRAPPER(func) \
+static int \
+func(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) \
+{ \
+ struct path path = { .mnt = mnt, .dentry = dentry }; \
+ return func##_impl(&path, stat, STATX_BASIC_STATS, \
+ AT_STATX_SYNC_AS_STAT); \
+}
+#elif defined(HAVE_PATH_IOPS_GETATTR)
+#define ZPL_GETATTR_WRAPPER(func) \
+static int \
+func(const struct path *path, struct kstat *stat, u32 request_mask, \
+ unsigned int query_flags) \
+{ \
+ return (func##_impl(path, stat, request_mask, query_flags)); \
+}
+#else
+#error
+#endif
+
+/*
+ * 4.9 API change
+ * Preferred interface to get the current FS time.
+ */
+#if !defined(HAVE_CURRENT_TIME)
+static inline struct timespec
+current_time(struct inode *ip)
+{
+ return (timespec_trunc(current_kernel_time(), ip->i_sb->s_time_gran));
+}
+#endif
+
+/*
+ * 4.16 API change
+ * Added iversion interface for managing inode version field.
+ */
+#ifdef HAVE_INODE_SET_IVERSION
+#include <linux/iversion.h>
+#else
+static inline void
+inode_set_iversion(struct inode *ip, u64 val)
+{
+ ip->i_version = val;
+}
+#endif
+
+/*
+ * Returns true when called in the context of a 32-bit system call.
+ */
+static inline int
+zpl_is_32bit_api(void)
+{
+#ifdef CONFIG_COMPAT
+#ifdef HAVE_IN_COMPAT_SYSCALL
+ return (in_compat_syscall());
+#else
+ return (is_compat_task());
+#endif
+#else
+ return (BITS_PER_LONG == 32);
+#endif
+}
+
+#endif /* _ZFS_VFS_H */
diff --git a/include/os/linux/kernel/linux/xattr_compat.h b/include/os/linux/kernel/linux/xattr_compat.h
new file mode 100644
index 000000000000..8348e99198af
--- /dev/null
+++ b/include/os/linux/kernel/linux/xattr_compat.h
@@ -0,0 +1,184 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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.
+ */
+typedef const struct xattr_handler xattr_handler_t;
+
+/*
+ * 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)); \
+}
+#else
+#error "Unsupported kernel"
+#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)); \
+}
+#else
+#error "Unsupported kernel"
+#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)); \
+}
+#else
+#error "Unsupported kernel"
+#endif
+
+/*
+ * 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).
+ */
+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));
+}
+
+#endif /* _ZFS_XATTR_H */
diff --git a/include/os/linux/spl/Makefile.am b/include/os/linux/spl/Makefile.am
new file mode 100644
index 000000000000..bd781c08f143
--- /dev/null
+++ b/include/os/linux/spl/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = rpc sys
diff --git a/include/os/linux/spl/rpc/Makefile.am b/include/os/linux/spl/rpc/Makefile.am
new file mode 100644
index 000000000000..13d804fce9b6
--- /dev/null
+++ b/include/os/linux/spl/rpc/Makefile.am
@@ -0,0 +1,7 @@
+KERNEL_H = \
+ xdr.h
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/spl/rpc
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/include/os/linux/spl/rpc/xdr.h b/include/os/linux/spl/rpc/xdr.h
new file mode 100644
index 000000000000..0b39b46cf6a2
--- /dev/null
+++ b/include/os/linux/spl/rpc/xdr.h
@@ -0,0 +1,156 @@
+/*
+ * 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>
+
+typedef int bool_t;
+
+/*
+ * XDR enums and types.
+ */
+enum xdr_op {
+ XDR_ENCODE,
+ XDR_DECODE
+};
+
+struct xdr_ops;
+
+typedef struct {
+ struct xdr_ops *x_ops; /* Let caller know xdrmem_create() succeeds */
+ 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);
+
+/* Currently not needed. If needed later, we'll add it to struct xdr_ops */
+#define xdr_destroy(xdrs) ((void) 0)
+
+#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/include/os/linux/spl/sys/Makefile.am b/include/os/linux/spl/sys/Makefile.am
new file mode 100644
index 000000000000..0fd4cd37a7ec
--- /dev/null
+++ b/include/os/linux/spl/sys/Makefile.am
@@ -0,0 +1,64 @@
+KERNEL_H = \
+ acl.h \
+ atomic.h \
+ byteorder.h \
+ callb.h \
+ callo.h \
+ cmn_err.h \
+ condvar.h \
+ console.h \
+ cred.h \
+ ctype.h \
+ debug.h \
+ disp.h \
+ dkio.h \
+ errno.h \
+ fcntl.h \
+ file.h \
+ inttypes.h \
+ isa_defs.h \
+ kmem_cache.h \
+ kmem.h \
+ kstat.h \
+ list.h \
+ mod_os.h \
+ mutex.h \
+ param.h \
+ processor.h \
+ proc.h \
+ procfs_list.h \
+ random.h \
+ rwlock.h \
+ shrinker.h \
+ sid.h \
+ signal.h \
+ simd.h \
+ stat.h \
+ strings.h \
+ sunddi.h \
+ sysmacros.h \
+ systeminfo.h \
+ taskq.h \
+ thread.h \
+ time.h \
+ timer.h \
+ trace.h \
+ trace_spl.h \
+ trace_taskq.h \
+ tsd.h \
+ types32.h \
+ types.h \
+ uio.h \
+ user.h \
+ vfs.h \
+ vmem.h \
+ vmsystm.h \
+ vnode.h \
+ wait.h \
+ zmod.h \
+ zone.h
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/spl/sys
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/include/os/linux/spl/sys/acl.h b/include/os/linux/spl/sys/acl.h
new file mode 100644
index 000000000000..9fc79c025caf
--- /dev/null
+++ b/include/os/linux/spl/sys/acl.h
@@ -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/>.
+ */
+
+#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)
+
+/* BEGIN CSTYLED */
+#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)
+/* END CSTYLED */
+
+#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/include/os/linux/spl/sys/atomic.h b/include/os/linux/spl/sys/atomic.h
new file mode 100644
index 000000000000..51b5479235ab
--- /dev/null
+++ b/include/os/linux/spl/sys/atomic.h
@@ -0,0 +1,79 @@
+/*
+ * 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>
+
+/*
+ * Map the atomic_* functions to the Linux counterparts. This relies on the
+ * fact that the atomic types are internally really a uint32 or uint64. If
+ * this were to change an alternate approach would be needed.
+ *
+ * N.B. Due to the limitations of the original API atomicity is not strictly
+ * preserved when using the 64-bit functions on a 32-bit system. In order
+ * to support this all consumers would need to be updated to use the Linux
+ * provided atomic_t and atomic64_t types.
+ */
+#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)
+
+#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/include/os/linux/spl/sys/byteorder.h b/include/os/linux/spl/sys/byteorder.h
new file mode 100644
index 000000000000..70847edbc8a9
--- /dev/null
+++ b/include/os/linux/spl/sys/byteorder.h
@@ -0,0 +1,87 @@
+/*
+ * 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>
+
+#if defined(__BIG_ENDIAN) && !defined(_ZFS_BIG_ENDIAN)
+#define _ZFS_BIG_ENDIAN
+#endif
+
+#if defined(__LITTLE_ENDIAN) && !defined(_ZFS_LITTLE_ENDIAN)
+#define _ZFS_LITTLE_ENDIAN
+#endif
+
+#include <sys/isa_defs.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))
+
+#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))
+
+#ifdef _ZFS_BIG_ENDIAN
+static __inline__ uint64_t
+htonll(uint64_t n)
+{
+ return (n);
+}
+
+static __inline__ uint64_t
+ntohll(uint64_t n)
+{
+ return (n);
+}
+#else
+static __inline__ uint64_t
+htonll(uint64_t n)
+{
+ return ((((uint64_t)htonl(n)) << 32) + htonl(n >> 32));
+}
+
+static __inline__ uint64_t
+ntohll(uint64_t n)
+{
+ return ((((uint64_t)ntohl(n)) << 32) + ntohl(n >> 32));
+}
+#endif
+
+#endif /* SPL_BYTEORDER_H */
diff --git a/include/os/linux/spl/sys/callb.h b/include/os/linux/spl/sys/callb.h
new file mode 100644
index 000000000000..f1826bfd353a
--- /dev/null
+++ b/include/os/linux/spl/sys/callb.h
@@ -0,0 +1,54 @@
+/*
+ * 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/include/os/linux/spl/sys/callo.h b/include/os/linux/spl/sys/callo.h
new file mode 100644
index 000000000000..c43ac92e7c32
--- /dev/null
+++ b/include/os/linux/spl/sys/callo.h
@@ -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/include/os/linux/spl/sys/cmn_err.h b/include/os/linux/spl/sys/cmn_err.h
new file mode 100644
index 000000000000..be57358b0a8a
--- /dev/null
+++ b/include/os/linux/spl/sys/cmn_err.h
@@ -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 <stdarg.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/include/os/linux/spl/sys/condvar.h b/include/os/linux/spl/sys/condvar.h
new file mode 100644
index 000000000000..22408824f85b
--- /dev/null
+++ b/include/os/linux/spl/sys/condvar.h
@@ -0,0 +1,113 @@
+/*
+ * 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 <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/callo.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+
+/*
+ * cv_timedwait() is similar to cv_wait() except that it additionally expects
+ * a timeout value specified in ticks. When woken by cv_signal() or
+ * cv_broadcast() it returns 1, otherwise when the timeout is reached -1 is
+ * returned.
+ *
+ * cv_timedwait_sig() behaves the same as cv_timedwait() but blocks
+ * interruptibly and can be woken by a signal (EINTR, ERESTART). When
+ * this occurs 0 is returned.
+ *
+ * cv_timedwait_io() and cv_timedwait_sig_io() are variants of cv_timedwait()
+ * and cv_timedwait_sig() which should be used when waiting for outstanding
+ * IO to complete. They are responsible for updating the iowait accounting
+ * when this is supported by the platform.
+ *
+ * cv_timedwait_hires() and cv_timedwait_sig_hires() are high resolution
+ * versions of cv_timedwait() and cv_timedwait_sig(). They expect the timeout
+ * to be specified as a hrtime_t allowing for timeouts of less than a tick.
+ *
+ * N.B. The return values differ slightly from the illumos implementation
+ * which returns the time remaining, instead of 1, when woken. They both
+ * return -1 on timeout. Consumers which need to know the time remaining
+ * are responsible for tracking it themselves.
+ */
+
+
+/*
+ * 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;
+ spl_wait_queue_head_t cv_event;
+ spl_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 int __cv_wait_io_sig(kcondvar_t *, kmutex_t *);
+extern int __cv_wait_sig(kcondvar_t *, kmutex_t *);
+extern int __cv_timedwait(kcondvar_t *, kmutex_t *, clock_t);
+extern int __cv_timedwait_io(kcondvar_t *, kmutex_t *, clock_t);
+extern int __cv_timedwait_sig(kcondvar_t *, kmutex_t *, clock_t);
+extern int cv_timedwait_hires(kcondvar_t *, kmutex_t *, hrtime_t,
+ hrtime_t res, int flag);
+extern int cv_timedwait_sig_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_io_sig(cvp, mp) __cv_wait_io_sig(cvp, mp)
+#define cv_wait_sig(cvp, mp) __cv_wait_sig(cvp, mp)
+#define cv_signal(cvp) __cv_signal(cvp)
+#define cv_broadcast(cvp) __cv_broadcast(cvp)
+
+/*
+ * NB: There is no way to reliably distinguish between having been signalled
+ * and having timed out on Linux. If the client code needs to reliably
+ * distinguish between the two it should use the hires variant.
+ */
+#define cv_timedwait(cvp, mp, t) __cv_timedwait(cvp, mp, t)
+#define cv_timedwait_io(cvp, mp, t) __cv_timedwait_io(cvp, mp, t)
+#define cv_timedwait_sig(cvp, mp, t) __cv_timedwait_sig(cvp, mp, t)
+
+#endif /* _SPL_CONDVAR_H */
diff --git a/include/os/linux/spl/sys/console.h b/include/os/linux/spl/sys/console.h
new file mode 100644
index 000000000000..33c8b3c6b4d7
--- /dev/null
+++ b/include/os/linux/spl/sys/console.h
@@ -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_CONSOLE_H
+#define _SPL_CONSOLE_H
+
+#define console_vprintf vprintk
+#define console_printf printk
+
+#endif /* _SPL_CONSOLE_H */
diff --git a/include/os/linux/spl/sys/cred.h b/include/os/linux/spl/sys/cred.h
new file mode 100644
index 000000000000..0b07c4369940
--- /dev/null
+++ b/include/os/linux/spl/sys/cred.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <linux/cred.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
+
+#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)
+
+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/include/os/linux/spl/sys/ctype.h b/include/os/linux/spl/sys/ctype.h
new file mode 100644
index 000000000000..18beb1daa5d9
--- /dev/null
+++ b/include/os/linux/spl/sys/ctype.h
@@ -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/include/os/linux/spl/sys/debug.h b/include/os/linux/spl/sys/debug.h
new file mode 100644
index 000000000000..e2dbd6804056
--- /dev/null
+++ b/include/os/linux/spl/sys/debug.h
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ * ASSERT3B() - Assert boolean X OP Y is true, if not panic.
+ * 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.
+ * VERIFY3B() - Verify boolean X OP Y 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.
+ */
+#define __printflike(a, b) __printf(a, b)
+
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((unused))
+#endif
+
+int spl_panic(const char *file, const char *func, int line,
+ const char *fmt, ...);
+void spl_dumpstack(void);
+
+/* BEGIN CSTYLED */
+#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 VERIFY3B(LEFT, OP, RIGHT) do { \
+ boolean_t _verify3_left = (boolean_t)(LEFT); \
+ boolean_t _verify3_right = (boolean_t)(RIGHT); \
+ if (!(_verify3_left OP _verify3_right)) \
+ spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+ "VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
+ "failed (%d " #OP " %d)\n", \
+ (boolean_t) (_verify3_left), \
+ (boolean_t) (_verify3_right)); \
+ } while (0)
+
+#define VERIFY3S(LEFT, OP, RIGHT) do { \
+ int64_t _verify3_left = (int64_t)(LEFT); \
+ int64_t _verify3_right = (int64_t)(RIGHT); \
+ if (!(_verify3_left OP _verify3_right)) \
+ spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+ "VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
+ "failed (%lld " #OP " %lld)\n", \
+ (long long) (_verify3_left), \
+ (long long) (_verify3_right)); \
+ } while (0)
+
+#define VERIFY3U(LEFT, OP, RIGHT) do { \
+ uint64_t _verify3_left = (uint64_t)(LEFT); \
+ uint64_t _verify3_right = (uint64_t)(RIGHT); \
+ if (!(_verify3_left OP _verify3_right)) \
+ spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+ "VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
+ "failed (%llu " #OP " %llu)\n", \
+ (unsigned long long) (_verify3_left), \
+ (unsigned long long) (_verify3_right)); \
+ } while (0)
+
+#define VERIFY3P(LEFT, OP, RIGHT) do { \
+ uintptr_t _verify3_left = (uintptr_t)(LEFT); \
+ uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
+ if (!(_verify3_left OP _verify3_right)) \
+ spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+ "VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
+ "failed (%px " #OP " %px)\n", \
+ (void *) (_verify3_left), \
+ (void *) (_verify3_right)); \
+ } while (0)
+
+#define VERIFY0(RIGHT) do { \
+ int64_t _verify3_left = (int64_t)(0); \
+ int64_t _verify3_right = (int64_t)(RIGHT); \
+ if (!(_verify3_left == _verify3_right)) \
+ spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+ "VERIFY3(0 == " #RIGHT ") " \
+ "failed (0 == %lld)\n", \
+ (long long) (_verify3_right)); \
+ } while (0)
+
+#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 ASSERT(x) ((void)0)
+#define ASSERT3B(x,y,z) ((void)0)
+#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 ASSERT3B VERIFY3B
+#define ASSERT3S VERIFY3S
+#define ASSERT3U VERIFY3U
+#define ASSERT3P VERIFY3P
+#define ASSERT0 VERIFY0
+#define ASSERT VERIFY
+#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 ")")))
+/* END CSTYLED */
+
+#endif /* NDEBUG */
+
+#endif /* SPL_DEBUG_H */
diff --git a/include/os/linux/spl/sys/disp.h b/include/os/linux/spl/sys/disp.h
new file mode 100644
index 000000000000..413b623c8145
--- /dev/null
+++ b/include/os/linux/spl/sys/disp.h
@@ -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/include/os/linux/spl/sys/dkio.h b/include/os/linux/spl/sys/dkio.h
new file mode 100644
index 000000000000..49f166a9c4aa
--- /dev/null
+++ b/include/os/linux/spl/sys/dkio.h
@@ -0,0 +1,40 @@
+/*
+ * 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
+
+#define DFL_SZ(num_exts) \
+ (sizeof (dkioc_free_list_t) + (num_exts - 1) * 16)
+
+#define DKIOC (0x04 << 8)
+#define DKIOCFLUSHWRITECACHE (DKIOC|34) /* flush cache to phys medium */
+
+/*
+ * ioctl to free space (e.g. SCSI UNMAP) off a disk.
+ * Pass a dkioc_free_list_t containing a list of extents to be freed.
+ */
+#define DKIOCFREE (DKIOC|50)
+
+#endif /* _SPL_DKIO_H */
diff --git a/include/os/linux/spl/sys/errno.h b/include/os/linux/spl/sys/errno.h
new file mode 100644
index 000000000000..f6d9212a613f
--- /dev/null
+++ b/include/os/linux/spl/sys/errno.h
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 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 2000 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _SYS_ERRNO_H
+#define _SYS_ERRNO_H
+
+#include <linux/errno.h>
+
+#define ENOTSUP EOPNOTSUPP
+
+/*
+ * 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
+
+/* Similar for ENOACTIVE */
+#define ENOTACTIVE ENOANO
+
+#endif /* _SYS_ERRNO_H */
diff --git a/include/os/linux/spl/sys/fcntl.h b/include/os/linux/spl/sys/fcntl.h
new file mode 100644
index 000000000000..3faa5dad78cb
--- /dev/null
+++ b/include/os/linux/spl/sys/fcntl.h
@@ -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/include/os/linux/spl/sys/file.h b/include/os/linux/spl/sys/file.h
new file mode 100644
index 000000000000..05dbc0814296
--- /dev/null
+++ b/include/os/linux/spl/sys/file.h
@@ -0,0 +1,52 @@
+/*
+ * 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
+#define ED_CASE_CONFLICT 0x10
+
+#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_H */
diff --git a/include/os/linux/spl/sys/inttypes.h b/include/os/linux/spl/sys/inttypes.h
new file mode 100644
index 000000000000..92e76206ba52
--- /dev/null
+++ b/include/os/linux/spl/sys/inttypes.h
@@ -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/include/os/linux/spl/sys/isa_defs.h b/include/os/linux/spl/sys/isa_defs.h
new file mode 100644
index 000000000000..af064e567e13
--- /dev/null
+++ b/include/os/linux/spl/sys/isa_defs.h
@@ -0,0 +1,254 @@
+/*
+ * 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(_ILP32)
+/* x32-specific defines; careful to *not* define _LP64 here */
+#else
+#if !defined(_LP64)
+#define _LP64
+#endif
+#endif
+
+#define _ALIGNMENT_REQUIRED 1
+
+
+/* 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
+
+#define _ALIGNMENT_REQUIRED 0
+
+/* 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
+
+/*
+ * Illumos doesn't define _ALIGNMENT_REQUIRED for PPC, so default to 1
+ * out of paranoia.
+ */
+#define _ALIGNMENT_REQUIRED 1
+
+/* 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 _ZFS_LITTLE_ENDIAN
+#else
+#define _ZFS_BIG_ENDIAN
+#endif
+
+/*
+ * Illumos doesn't define _ALIGNMENT_REQUIRED for ARM, so default to 1
+ * out of paranoia.
+ */
+#define _ALIGNMENT_REQUIRED 1
+
+/* 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 _ZFS_BIG_ENDIAN
+#define _SUNOS_VTOC_16
+#define _ALIGNMENT_REQUIRED 1
+
+/* 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 _ZFS_BIG_ENDIAN
+
+/*
+ * Illumos doesn't define _ALIGNMENT_REQUIRED for s390, so default to 1
+ * out of paranoia.
+ */
+#define _ALIGNMENT_REQUIRED 1
+
+/* MIPS arch specific defines */
+#elif defined(__mips__)
+
+#if defined(__MIPSEB__)
+#define _ZFS_BIG_ENDIAN
+#elif defined(__MIPSEL__)
+#define _ZFS_LITTLE_ENDIAN
+#else
+#error MIPS no endian specified
+#endif
+
+#ifndef _LP64
+#define _ILP32
+#endif
+
+#define _SUNOS_VTOC_16
+
+/*
+ * Illumos doesn't define _ALIGNMENT_REQUIRED for MIPS, so default to 1
+ * out of paranoia.
+ */
+#define _ALIGNMENT_REQUIRED 1
+
+/*
+ * RISC-V arch specific defines
+ * only RV64G (including atomic) LP64 is supported yet
+ */
+#elif defined(__riscv) && defined(_LP64) && _LP64 && \
+ defined(__riscv_atomic) && __riscv_atomic
+
+#ifndef __riscv__
+#define __riscv__
+#endif
+
+#ifndef __rv64g__
+#define __rv64g__
+#endif
+
+#define _ZFS_LITTLE_ENDIAN
+
+#define _SUNOS_VTOC_16
+
+#define _ALIGNMENT_REQUIRED 1
+
+#else
+/*
+ * Currently supported:
+ * x86_64, x32, i386, arm, powerpc, s390, sparc, mips, and RV64G
+ */
+#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>
+
+/*
+ * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS will be defined by the Linux
+ * kernel for architectures which support efficient unaligned access.
+ */
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+#define HAVE_EFFICIENT_UNALIGNED_ACCESS
+#endif
+
+#if defined(_ZFS_LITTLE_ENDIAN) && defined(_ZFS_BIG_ENDIAN)
+#error "Both _ZFS_LITTLE_ENDIAN and _ZFS_BIG_ENDIAN are defined"
+#endif
+
+#if !defined(_ZFS_LITTLE_ENDIAN) && !defined(_ZFS_BIG_ENDIAN)
+#error "Neither _ZFS_LITTLE_ENDIAN or _ZFS_BIG_ENDIAN are defined"
+#endif
+
+#endif /* _SPL_ISA_DEFS_H */
diff --git a/include/os/linux/spl/sys/kmem.h b/include/os/linux/spl/sys/kmem.h
new file mode 100644
index 000000000000..c09c40fa34b9
--- /dev/null
+++ b/include/os/linux/spl/sys/kmem.h
@@ -0,0 +1,211 @@
+/*
+ * 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>
+#include <linux/mm.h>
+#include <linux/vmalloc.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 *kmem_strdup(const char *str);
+extern void kmem_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)
+
+static int spl_fstrans_check(void);
+void *spl_kvmalloc(size_t size, gfp_t flags);
+
+/*
+ * 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 (spl_fstrans_check())
+ 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;
+
+/*
+ * Introduced in Linux 3.9, however this cannot be solely relied on before
+ * Linux 3.18 as it doesn't turn off __GFP_FS as it should.
+ */
+#ifdef PF_MEMALLOC_NOIO
+#define __SPL_PF_MEMALLOC_NOIO (PF_MEMALLOC_NOIO)
+#else
+#define __SPL_PF_MEMALLOC_NOIO (0)
+#endif
+
+/*
+ * PF_FSTRANS is removed from Linux 4.12
+ */
+#ifdef PF_FSTRANS
+#define __SPL_PF_FSTRANS (PF_FSTRANS)
+#else
+#define __SPL_PF_FSTRANS (0)
+#endif
+
+#define SPL_FSTRANS (__SPL_PF_FSTRANS|__SPL_PF_MEMALLOC_NOIO)
+
+static inline fstrans_cookie_t
+spl_fstrans_mark(void)
+{
+ fstrans_cookie_t cookie;
+
+ BUILD_BUG_ON(SPL_FSTRANS == 0);
+
+ 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 & SPL_FSTRANS);
+}
+
+/*
+ * specifically used to check PF_FSTRANS flag, cannot be relied on for
+ * checking spl_fstrans_mark().
+ */
+static inline int
+__spl_pf_fstrans_check(void)
+{
+ return (current->flags & __SPL_PF_FSTRANS);
+}
+
+/*
+ * Kernel compatibility for GFP flags
+ */
+/* < 4.13 */
+#ifndef __GFP_RETRY_MAYFAIL
+#define __GFP_RETRY_MAYFAIL __GFP_REPEAT
+#endif
+/* < 4.4 */
+#ifndef __GFP_RECLAIM
+#define __GFP_RECLAIM __GFP_WAIT
+#endif
+
+#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))
+#define kmem_cache_reap_active spl_kmem_cache_reap_active
+
+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);
+
+/*
+ * 5.8 API change, pgprot_t argument removed.
+ */
+#ifdef HAVE_VMALLOC_PAGE_KERNEL
+#define spl_vmalloc(size, flags) __vmalloc(size, flags, PAGE_KERNEL)
+#else
+#define spl_vmalloc(size, flags) __vmalloc(size, flags)
+#endif
+
+/*
+ * 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);
+extern int spl_kmem_cache_reap_active(void);
+
+#endif /* _SPL_KMEM_H */
diff --git a/include/os/linux/spl/sys/kmem_cache.h b/include/os/linux/spl/sys/kmem_cache.h
new file mode 100644
index 000000000000..ffb8c97c9c91
--- /dev/null
+++ b/include/os/linux/spl/sys/kmem_cache.h
@@ -0,0 +1,216 @@
+/*
+ * 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 virtual 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.
+ */
+typedef enum kmc_bit {
+ KMC_BIT_NODEBUG = 1, /* Default behavior */
+ KMC_BIT_KVMEM = 7, /* Use kvmalloc linux allocator */
+ KMC_BIT_SLAB = 8, /* Use Linux slab cache */
+ 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 */
+} kmc_bit_t;
+
+/* 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_NODEBUG (1 << KMC_BIT_NODEBUG)
+#define KMC_KVMEM (1 << KMC_BIT_KVMEM)
+#define KMC_SLAB (1 << KMC_BIT_SLAB)
+#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_RECLAIM_ONCE 0x1 /* Force a single shrinker pass */
+
+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_OBJ_PER_SLAB 8 /* Target 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 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 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 */
+ 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 */
+ 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 */
+ spl_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 */
+ struct percpu_counter skc_linux_alloc; /* Linux-backed Obj alloc */
+ 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,
+ void *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);
+extern void spl_kmem_reap(void);
+extern uint64_t spl_kmem_cache_inuse(kmem_cache_t *cache);
+extern uint64_t spl_kmem_cache_entry_size(kmem_cache_t *cache);
+
+#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)
+#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/include/os/linux/spl/sys/kstat.h b/include/os/linux/spl/sys/kstat.h
new file mode 100644
index 000000000000..c93c53171d88
--- /dev/null
+++ b/include/os/linux/spl/sys/kstat.h
@@ -0,0 +1,223 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#define KSTAT_STRLEN 255
+#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_INVALID 0x20
+#define KSTAT_FLAG_LONGSTRINGS 0x40
+#define KSTAT_FLAG_NO_HEADERS 0x80
+
+#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;
+
+typedef struct kstat_proc_entry {
+ char kpe_name[KSTAT_STRLEN+1]; /* kstat name */
+ char kpe_module[KSTAT_STRLEN+1]; /* provider module name */
+ kstat_module_t *kpe_owner; /* kstat module linkage */
+ struct list_head kpe_list; /* kstat linkage */
+ struct proc_dir_entry *kpe_proc; /* procfs entry */
+} kstat_proc_entry_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 */
+ int ks_instance; /* provider module instance */
+ 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 data records */
+ size_t ks_data_size; /* size of kstat data section */
+ 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 */
+ 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 */
+ kstat_proc_entry_t ks_proc; /* data for procfs entry */
+};
+
+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)
+
+#ifdef HAVE_PROC_OPS_STRUCT
+typedef struct proc_ops kstat_proc_op_t;
+#else
+typedef struct file_operations kstat_proc_op_t;
+#endif
+
+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 len*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_proc_entry_init(kstat_proc_entry_t *kpep,
+ const char *module, const char *name);
+extern void kstat_proc_entry_delete(kstat_proc_entry_t *kpep);
+extern void kstat_proc_entry_install(kstat_proc_entry_t *kpep, mode_t mode,
+ const kstat_proc_op_t *file_ops, void *data);
+
+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/include/os/linux/spl/sys/list.h b/include/os/linux/spl/sys/list.h
new file mode 100644
index 000000000000..be38f328fc65
--- /dev/null
+++ b/include/os/linux/spl/sys/list.h
@@ -0,0 +1,210 @@
+/*
+ * 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 <sys/debug.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)
+{
+ list->list_size = size;
+ list->list_offset = offset;
+ INIT_LIST_HEAD(&list->list_head);
+}
+
+static inline void
+list_destroy(list_t *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)
+{
+ 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)
+{
+ EQUIV(node->next == LIST_POISON1, node->prev == LIST_POISON2);
+ return (node->next != LIST_POISON1);
+}
+
+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)
+{
+ 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/include/os/linux/spl/sys/mod_os.h b/include/os/linux/spl/sys/mod_os.h
new file mode 100644
index 000000000000..8adf6212907f
--- /dev/null
+++ b/include/os/linux/spl/sys/mod_os.h
@@ -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_MOD_H
+#define _SPL_MOD_H
+#include <linux/mod_compat.h>
+
+#endif /* SPL_MOD_H */
diff --git a/include/os/linux/spl/sys/mutex.h b/include/os/linux/spl/sys/mutex.h
new file mode 100644
index 000000000000..93f3af8fe016
--- /dev/null
+++ b/include/os/linux/spl/sys/mutex.h
@@ -0,0 +1,185 @@
+/*
+ * 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/sched.h>
+#include <linux/mutex.h>
+#include <linux/lockdep.h>
+#include <linux/compiler_compat.h>
+
+typedef enum {
+ MUTEX_DEFAULT = 0,
+ MUTEX_SPIN = 1,
+ MUTEX_ADAPTIVE = 2,
+ MUTEX_NOLOCKDEP = 3
+} kmutex_type_t;
+
+typedef struct {
+ struct mutex m_mutex;
+ spinlock_t m_lock; /* used for serializing mutex_exit */
+ kthread_t *m_owner;
+#ifdef CONFIG_LOCKDEP
+ kmutex_type_t m_type;
+#endif /* CONFIG_LOCKDEP */
+} kmutex_t;
+
+#define MUTEX(mp) (&((mp)->m_mutex))
+
+static inline void
+spl_mutex_set_owner(kmutex_t *mp)
+{
+ mp->m_owner = current;
+}
+
+static inline void
+spl_mutex_clear_owner(kmutex_t *mp)
+{
+ mp->m_owner = NULL;
+}
+
+#define mutex_owner(mp) (READ_ONCE((mp)->m_owner))
+#define mutex_owned(mp) (mutex_owner(mp) == current)
+#define MUTEX_HELD(mp) mutex_owned(mp)
+#define MUTEX_NOT_HELD(mp) (!MUTEX_HELD(mp))
+
+#ifdef CONFIG_LOCKDEP
+static inline void
+spl_mutex_set_type(kmutex_t *mp, kmutex_type_t type)
+{
+ mp->m_type = type;
+}
+static inline void
+spl_mutex_lockdep_off_maybe(kmutex_t *mp) \
+{ \
+ if (mp && mp->m_type == MUTEX_NOLOCKDEP) \
+ lockdep_off(); \
+}
+static inline void
+spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
+{ \
+ if (mp && mp->m_type == MUTEX_NOLOCKDEP) \
+ lockdep_on(); \
+}
+#else /* CONFIG_LOCKDEP */
+#define spl_mutex_set_type(mp, type)
+#define spl_mutex_lockdep_off_maybe(mp)
+#define spl_mutex_lockdep_on_maybe(mp)
+#endif /* CONFIG_LOCKDEP */
+
+/*
+ * 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 || type == MUTEX_NOLOCKDEP); \
+ \
+ __mutex_init(MUTEX(mp), (name) ? (#name) : (#mp), &__key); \
+ spin_lock_init(&(mp)->m_lock); \
+ spl_mutex_clear_owner(mp); \
+ spl_mutex_set_type(mp, type); \
+}
+
+#undef mutex_destroy
+#define mutex_destroy(mp) \
+{ \
+ VERIFY3P(mutex_owner(mp), ==, NULL); \
+}
+
+/* BEGIN CSTYLED */
+#define mutex_tryenter(mp) \
+({ \
+ int _rc_; \
+ \
+ spl_mutex_lockdep_off_maybe(mp); \
+ if ((_rc_ = mutex_trylock(MUTEX(mp))) == 1) \
+ spl_mutex_set_owner(mp); \
+ spl_mutex_lockdep_on_maybe(mp); \
+ \
+ _rc_; \
+})
+/* END CSTYLED */
+
+#define NESTED_SINGLE 1
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define mutex_enter_nested(mp, subclass) \
+{ \
+ ASSERT3P(mutex_owner(mp), !=, current); \
+ spl_mutex_lockdep_off_maybe(mp); \
+ mutex_lock_nested(MUTEX(mp), (subclass)); \
+ spl_mutex_lockdep_on_maybe(mp); \
+ spl_mutex_set_owner(mp); \
+}
+#else /* CONFIG_DEBUG_LOCK_ALLOC */
+#define mutex_enter_nested(mp, subclass) \
+{ \
+ ASSERT3P(mutex_owner(mp), !=, current); \
+ spl_mutex_lockdep_off_maybe(mp); \
+ mutex_lock(MUTEX(mp)); \
+ spl_mutex_lockdep_on_maybe(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) \
+{ \
+ spl_mutex_clear_owner(mp); \
+ spin_lock(&(mp)->m_lock); \
+ spl_mutex_lockdep_off_maybe(mp); \
+ mutex_unlock(MUTEX(mp)); \
+ spl_mutex_lockdep_on_maybe(mp); \
+ spin_unlock(&(mp)->m_lock); \
+ /* NOTE: do not dereference mp after this point */ \
+}
+
+#endif /* _SPL_MUTEX_H */
diff --git a/include/os/linux/spl/sys/param.h b/include/os/linux/spl/sys/param.h
new file mode 100644
index 000000000000..4ef929151ae4
--- /dev/null
+++ b/include/os/linux/spl/sys/param.h
@@ -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/include/os/linux/spl/sys/proc.h b/include/os/linux/spl/sys/proc.h
new file mode 100644
index 000000000000..fefce515eb24
--- /dev/null
+++ b/include/os/linux/spl/sys/proc.h
@@ -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_PROC_H
+#define _SPL_PROC_H
+
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+
+extern struct proc_dir_entry *proc_spl_kstat;
+
+int spl_proc_init(void);
+void spl_proc_fini(void);
+
+static inline boolean_t
+zfs_proc_is_caller(struct task_struct *t)
+{
+ return (t->group_leader == current->group_leader);
+}
+
+#endif /* SPL_PROC_H */
diff --git a/include/os/linux/spl/sys/processor.h b/include/os/linux/spl/sys/processor.h
new file mode 100644
index 000000000000..a70101fa2f90
--- /dev/null
+++ b/include/os/linux/spl/sys/processor.h
@@ -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/include/os/linux/spl/sys/procfs_list.h b/include/os/linux/spl/sys/procfs_list.h
new file mode 100644
index 000000000000..eb1519c0ad63
--- /dev/null
+++ b/include/os/linux/spl/sys/procfs_list.h
@@ -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) 2018 by Delphix. All rights reserved.
+ */
+
+#ifndef _SPL_PROCFS_LIST_H
+#define _SPL_PROCFS_LIST_H
+
+#include <sys/kstat.h>
+#include <sys/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+typedef struct procfs_list procfs_list_t;
+struct procfs_list {
+ /* Accessed only by user of a procfs_list */
+ void *pl_private;
+
+ /*
+ * Accessed both by user of a procfs_list and by procfs_list
+ * implementation
+ */
+ kmutex_t pl_lock;
+ list_t pl_list;
+
+ /* Accessed only by procfs_list implementation */
+ uint64_t pl_next_id;
+ int (*pl_show)(struct seq_file *f, void *p);
+ int (*pl_show_header)(struct seq_file *f);
+ int (*pl_clear)(procfs_list_t *procfs_list);
+ size_t pl_node_offset;
+ kstat_proc_entry_t pl_kstat_entry;
+};
+
+typedef struct procfs_list_node {
+ list_node_t pln_link;
+ uint64_t pln_id;
+} procfs_list_node_t;
+
+void procfs_list_install(const char *module,
+ const char *name,
+ mode_t mode,
+ procfs_list_t *procfs_list,
+ int (*show)(struct seq_file *f, void *p),
+ int (*show_header)(struct seq_file *f),
+ int (*clear)(procfs_list_t *procfs_list),
+ size_t procfs_list_node_off);
+void procfs_list_uninstall(procfs_list_t *procfs_list);
+void procfs_list_destroy(procfs_list_t *procfs_list);
+
+void procfs_list_add(procfs_list_t *procfs_list, void *p);
+
+#endif /* _SPL_PROCFS_LIST_H */
diff --git a/include/os/linux/spl/sys/random.h b/include/os/linux/spl/sys/random.h
new file mode 100644
index 000000000000..93e244f566be
--- /dev/null
+++ b/include/os/linux/spl/sys/random.h
@@ -0,0 +1,40 @@
+/*
+ * 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);
+}
+
+extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
+
+#endif /* _SPL_RANDOM_H */
diff --git a/include/os/linux/spl/sys/rwlock.h b/include/os/linux/spl/sys/rwlock.h
new file mode 100644
index 000000000000..60f5bfd986b4
--- /dev/null
+++ b/include/os/linux/spl/sys/rwlock.h
@@ -0,0 +1,201 @@
+/*
+ * 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/sched.h>
+
+typedef enum {
+ RW_DRIVER = 2,
+ RW_DEFAULT = 4,
+ RW_NOLOCKDEP = 5
+} 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;
+#ifdef CONFIG_LOCKDEP
+ krw_type_t rw_type;
+#endif /* CONFIG_LOCKDEP */
+} krwlock_t;
+
+#define SEM(rwp) (&(rwp)->rw_rwlock)
+
+static inline void
+spl_rw_set_owner(krwlock_t *rwp)
+{
+ rwp->rw_owner = current;
+}
+
+static inline void
+spl_rw_clear_owner(krwlock_t *rwp)
+{
+ rwp->rw_owner = NULL;
+}
+
+static inline kthread_t *
+rw_owner(krwlock_t *rwp)
+{
+ return (rwp->rw_owner);
+}
+
+#ifdef CONFIG_LOCKDEP
+static inline void
+spl_rw_set_type(krwlock_t *rwp, krw_type_t type)
+{
+ rwp->rw_type = type;
+}
+static inline void
+spl_rw_lockdep_off_maybe(krwlock_t *rwp) \
+{ \
+ if (rwp && rwp->rw_type == RW_NOLOCKDEP) \
+ lockdep_off(); \
+}
+static inline void
+spl_rw_lockdep_on_maybe(krwlock_t *rwp) \
+{ \
+ if (rwp && rwp->rw_type == RW_NOLOCKDEP) \
+ lockdep_on(); \
+}
+#else /* CONFIG_LOCKDEP */
+#define spl_rw_set_type(rwp, type)
+#define spl_rw_lockdep_off_maybe(rwp)
+#define spl_rw_lockdep_on_maybe(rwp)
+#endif /* CONFIG_LOCKDEP */
+
+static inline int
+RW_LOCK_HELD(krwlock_t *rwp)
+{
+ return (rwsem_is_locked(SEM(rwp)));
+}
+
+static inline int
+RW_WRITE_HELD(krwlock_t *rwp)
+{
+ return (rw_owner(rwp) == current);
+}
+
+static inline int
+RW_READ_HELD(krwlock_t *rwp)
+{
+ return (RW_LOCK_HELD(rwp) && rw_owner(rwp) == NULL);
+}
+
+/*
+ * 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
+ */
+/* BEGIN CSTYLED */
+#define rw_init(rwp, name, type, arg) \
+({ \
+ static struct lock_class_key __key; \
+ ASSERT(type == RW_DEFAULT || type == RW_NOLOCKDEP); \
+ \
+ __init_rwsem(SEM(rwp), #rwp, &__key); \
+ spl_rw_clear_owner(rwp); \
+ spl_rw_set_type(rwp, type); \
+})
+
+/*
+ * The Linux rwsem implementation does not require a matching destroy.
+ */
+#define rw_destroy(rwp) ((void) 0)
+
+/*
+ * Upgrading a rwsem from a reader to a writer is not supported by the
+ * Linux kernel. The lock must be dropped and reacquired as a writer.
+ */
+#define rw_tryupgrade(rwp) RW_WRITE_HELD(rwp)
+
+#define rw_tryenter(rwp, rw) \
+({ \
+ int _rc_ = 0; \
+ \
+ spl_rw_lockdep_off_maybe(rwp); \
+ 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); \
+ } \
+ spl_rw_lockdep_on_maybe(rwp); \
+ _rc_; \
+})
+
+#define rw_enter(rwp, rw) \
+({ \
+ spl_rw_lockdep_off_maybe(rwp); \
+ 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); \
+ } \
+ spl_rw_lockdep_on_maybe(rwp); \
+})
+
+#define rw_exit(rwp) \
+({ \
+ spl_rw_lockdep_off_maybe(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)); \
+ } \
+ spl_rw_lockdep_on_maybe(rwp); \
+})
+
+#define rw_downgrade(rwp) \
+({ \
+ spl_rw_lockdep_off_maybe(rwp); \
+ spl_rw_clear_owner(rwp); \
+ downgrade_write(SEM(rwp)); \
+ spl_rw_lockdep_on_maybe(rwp); \
+})
+/* END CSTYLED */
+
+#endif /* _SPL_RWLOCK_H */
diff --git a/include/os/linux/spl/sys/shrinker.h b/include/os/linux/spl/sys/shrinker.h
new file mode 100644
index 000000000000..cc34d8ab1931
--- /dev/null
+++ b/include/os/linux/spl/sys/shrinker.h
@@ -0,0 +1,110 @@
+/*
+ * 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_SHRINKER_H
+#define _SPL_SHRINKER_H
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+
+/*
+ * Due to frequent changes in the shrinker API the following
+ * compatibility wrappers should be used. They are as follows:
+ *
+ * SPL_SHRINKER_DECLARE(varname, countfunc, scanfunc, seek_cost);
+ *
+ * SPL_SHRINKER_DECLARE is used to declare a shrinker with the name varname,
+ * which is passed to spl_register_shrinker()/spl_unregister_shrinker().
+ * The countfunc returns the number of free-able objects.
+ * The scanfunc returns the number of objects that were freed.
+ * The callbacks can return SHRINK_STOP if further calls can't make any more
+ * progress. Note that a return value of SHRINK_EMPTY is currently not
+ * supported.
+ *
+ * Example:
+ *
+ * static unsigned long
+ * my_count(struct shrinker *shrink, struct shrink_control *sc)
+ * {
+ * ...calculate number of objects in the cache...
+ *
+ * return (number of objects in the cache);
+ * }
+ *
+ * static unsigned long
+ * my_scan(struct shrinker *shrink, struct shrink_control *sc)
+ * {
+ * ...scan objects in the cache and reclaim them...
+ * }
+ *
+ * SPL_SHRINKER_DECLARE(my_shrinker, my_count, my_scan, DEFAULT_SEEKS);
+ *
+ * void my_init_func(void) {
+ * spl_register_shrinker(&my_shrinker);
+ * }
+ */
+
+#define spl_register_shrinker(x) register_shrinker(x)
+#define spl_unregister_shrinker(x) unregister_shrinker(x)
+
+/*
+ * Linux 3.0 to 3.11 Shrinker API Compatibility.
+ */
+#if defined(HAVE_SINGLE_SHRINKER_CALLBACK)
+#define SPL_SHRINKER_DECLARE(varname, countfunc, scanfunc, seek_cost) \
+static int \
+__ ## varname ## _wrapper(struct shrinker *shrink, struct shrink_control *sc)\
+{ \
+ if (sc->nr_to_scan != 0) { \
+ (void) scanfunc(shrink, sc); \
+ } \
+ return (countfunc(shrink, sc)); \
+} \
+ \
+static struct shrinker varname = { \
+ .shrink = __ ## varname ## _wrapper, \
+ .seeks = seek_cost, \
+}
+
+#define SHRINK_STOP (-1)
+
+/*
+ * Linux 3.12 and later Shrinker API Compatibility.
+ */
+#elif defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+#define SPL_SHRINKER_DECLARE(varname, countfunc, scanfunc, seek_cost) \
+static struct shrinker varname = { \
+ .count_objects = countfunc, \
+ .scan_objects = scanfunc, \
+ .seeks = seek_cost, \
+}
+
+#else
+/*
+ * Linux 2.x to 2.6.22, or a newer shrinker API has been introduced.
+ */
+#error "Unknown shrinker callback"
+#endif
+
+#endif /* SPL_SHRINKER_H */
diff --git a/include/os/linux/spl/sys/sid.h b/include/os/linux/spl/sys/sid.h
new file mode 100644
index 000000000000..731b62c47e70
--- /dev/null
+++ b/include/os/linux/spl/sys/sid.h
@@ -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/include/os/linux/spl/sys/signal.h b/include/os/linux/spl/sys/signal.h
new file mode 100644
index 000000000000..36b8b5d985a9
--- /dev/null
+++ b/include/os/linux/spl/sys/signal.h
@@ -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_SIGNAL_H
+#define _SPL_SIGNAL_H
+
+#include <linux/sched.h>
+
+#ifdef HAVE_SCHED_SIGNAL_HEADER
+#include <linux/sched/signal.h>
+#endif
+
+#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/include/os/linux/spl/sys/simd.h b/include/os/linux/spl/sys/simd.h
new file mode 100644
index 000000000000..f2048d9e121c
--- /dev/null
+++ b/include/os/linux/spl/sys/simd.h
@@ -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_SYS_SIMD_H
+#define _SPL_SYS_SIMD_H
+
+#include <sys/isa_defs.h>
+#include <linux/simd.h>
+
+#endif /* _SPL_SYS_SIMD_H */
diff --git a/include/os/linux/spl/sys/stat.h b/include/os/linux/spl/sys/stat.h
new file mode 100644
index 000000000000..83018e89442f
--- /dev/null
+++ b/include/os/linux/spl/sys/stat.h
@@ -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/include/os/linux/spl/sys/strings.h b/include/os/linux/spl/sys/strings.h
new file mode 100644
index 000000000000..4fb80320635c
--- /dev/null
+++ b/include/os/linux/spl/sys/strings.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ * 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_SYS_STRINGS_H
+#define _SPL_SYS_STRINGS_H
+
+#include <linux/string.h>
+
+#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))
+
+#endif /* _SPL_SYS_STRINGS_H */
diff --git a/include/os/linux/spl/sys/sunddi.h b/include/os/linux/spl/sys/sunddi.h
new file mode 100644
index 000000000000..29a6fe00d1f4
--- /dev/null
+++ b/include/os/linux/spl/sys/sunddi.h
@@ -0,0 +1,58 @@
+/*
+ * 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/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/include/os/linux/spl/sys/sysmacros.h b/include/os/linux/spl/sys/sysmacros.h
new file mode 100644
index 000000000000..7314588bcf82
--- /dev/null
+++ b/include/os/linux/spl/sys/sysmacros.h
@@ -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/>.
+ */
+
+#ifndef _SPL_SYSMACROS_H
+#define _SPL_SYSMACROS_H
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/sched/rt.h>
+#include <linux/cpumask.h>
+#include <sys/debug.h>
+#include <sys/zone.h>
+#include <sys/signal.h>
+#include <asm/page.h>
+
+
+#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 MAXMSGLEN 256
+#define MAXNAMELEN 256
+#define MAXPATHLEN 4096
+#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 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
+
+#ifndef PAGESHIFT
+#define PAGESHIFT PAGE_SHIFT
+#endif
+
+/* Missing globals */
+extern char spl_gitrev[64];
+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 highbit(x) __fls(x)
+#define lowbit(x) __ffs(x)
+
+#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)))
+
+#define SET_ERROR(err) \
+ (__set_error(__FILE__, __func__, __LINE__, err), err)
+
+#include <linux/sort.h>
+#define qsort(base, num, size, cmp) \
+ sort(base, num, size, cmp, NULL)
+
+#if !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/include/os/linux/spl/sys/systeminfo.h b/include/os/linux/spl/sys/systeminfo.h
new file mode 100644
index 000000000000..2255691580f9
--- /dev/null
+++ b/include/os/linux/spl/sys/systeminfo.h
@@ -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/include/os/linux/spl/sys/taskq.h b/include/os/linux/spl/sys/taskq.h
new file mode 100644
index 000000000000..7a1ee9ec4f1b
--- /dev/null
+++ b/include/os/linux/spl/sys/taskq.h
@@ -0,0 +1,164 @@
+/*
+ * 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>
+#include <sys/rwlock.h>
+#include <sys/wait.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
+
+/*
+ * Reserved taskqid values.
+ */
+#define TASKQID_INVALID ((taskqid_t)0)
+#define TASKQID_INITIAL ((taskqid_t)1)
+
+/*
+ * spin_lock(lock) and spin_lock_nested(lock,0) are equivalent,
+ * so TQ_LOCK_DYNAMIC must not evaluate to 0
+ */
+typedef enum tq_lock_role {
+ TQ_LOCK_GENERAL = 0,
+ TQ_LOCK_DYNAMIC = 1,
+} tq_lock_role_t;
+
+typedef unsigned long taskqid_t;
+typedef void (task_func_t)(void *);
+
+typedef struct taskq {
+ spinlock_t tq_lock; /* protects taskq_t */
+ char *tq_name; /* taskq name */
+ int tq_instance; /* instance of tq_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 taskq_ent_t pool size */
+ int tq_maxalloc; /* max taskq_ent_t pool size */
+ int tq_nalloc; /* cur taskq_ent_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 taskq_ent_t's */
+ struct list_head tq_pend_list; /* pending taskq_ent_t's */
+ struct list_head tq_prio_list; /* priority taskq_ent_t's */
+ struct list_head tq_delay_list; /* delayed taskq_ent_t's */
+ struct list_head tq_taskqs; /* all taskq_t's */
+ spl_wait_queue_head_t tq_work_waitq; /* new work waitq */
+ spl_wait_queue_head_t tq_wait_waitq; /* wait waitq */
+ tq_lock_role_t tq_lock_class; /* class when taking tq_lock */
+} taskq_t;
+
+typedef struct taskq_ent {
+ spinlock_t tqent_lock;
+ spl_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;
+ unsigned long tqent_birth;
+} 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;
+/* Global dynamic task queue for long delay */
+extern taskq_t *system_delay_taskq;
+
+/* List of all taskqs */
+extern struct list_head tq_list;
+extern struct rw_semaphore tq_list_sem;
+
+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 *, kthread_t *);
+extern taskq_t *taskq_of_curthread(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/include/os/linux/spl/sys/thread.h b/include/os/linux/spl/sys/thread.h
new file mode 100644
index 000000000000..72dcf9f05d0d
--- /dev/null
+++ b/include/os/linux/spl/sys/thread.h
@@ -0,0 +1,74 @@
+/*
+ * 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_named(name, stk, stksize, func, arg, len, \
+ pp, state, pri) \
+ __thread_create(stk, stksize, (thread_func_t)func, \
+ name, arg, len, pp, state, pri)
+
+/* BEGIN CSTYLED */
+#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)
+/* END CSTYLED */
+
+#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[], ...);
+
+extern proc_t p0;
+
+#endif /* _SPL_THREAD_H */
diff --git a/include/os/linux/spl/sys/time.h b/include/os/linux/spl/sys/time.h
new file mode 100644
index 000000000000..4309c300b268
--- /dev/null
+++ b/include/os/linux/spl/sys/time.h
@@ -0,0 +1,118 @@
+/*
+ * 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))
+
+#define USEC2NSEC(m) ((hrtime_t)(m) * (NANOSEC / MICROSEC))
+#define NSEC2USEC(n) ((n) / (NANOSEC / MICROSEC))
+
+#define NSEC2SEC(n) ((n) / (NANOSEC / SEC))
+#define SEC2NSEC(m) ((hrtime_t)(m) * (NANOSEC / SEC))
+
+static const int hz = HZ;
+
+typedef longlong_t hrtime_t;
+typedef struct timespec timespec_t;
+
+#define TIMESPEC_OVERFLOW(ts) \
+ ((ts)->tv_sec < TIME_MIN || (ts)->tv_sec > TIME_MAX)
+
+#if defined(HAVE_INODE_TIMESPEC64_TIMES)
+typedef struct timespec64 inode_timespec_t;
+#else
+typedef struct timespec inode_timespec_t;
+#endif
+
+/* Include for Lustre compatibility */
+#define timestruc_t inode_timespec_t
+
+static inline void
+gethrestime(inode_timespec_t *ts)
+{
+#if defined(HAVE_INODE_TIMESPEC64_TIMES)
+
+#if defined(HAVE_KTIME_GET_COARSE_REAL_TS64)
+ ktime_get_coarse_real_ts64(ts);
+#else
+ *ts = current_kernel_time64();
+#endif /* HAVE_KTIME_GET_COARSE_REAL_TS64 */
+
+#else
+ *ts = current_kernel_time();
+#endif
+}
+
+static inline uint64_t
+gethrestime_sec(void)
+{
+#if defined(HAVE_INODE_TIMESPEC64_TIMES)
+#if defined(HAVE_KTIME_GET_COARSE_REAL_TS64)
+ inode_timespec_t ts;
+ ktime_get_coarse_real_ts64(&ts);
+#else
+ inode_timespec_t ts = current_kernel_time64();
+#endif /* HAVE_KTIME_GET_COARSE_REAL_TS64 */
+
+#else
+ inode_timespec_t ts = current_kernel_time();
+#endif
+ return (ts.tv_sec);
+}
+
+static inline hrtime_t
+gethrtime(void)
+{
+#if defined(HAVE_KTIME_GET_RAW_TS64)
+ struct timespec64 ts;
+ ktime_get_raw_ts64(&ts);
+#else
+ struct timespec ts;
+ getrawmonotonic(&ts);
+#endif
+ return (((hrtime_t)ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec);
+}
+
+#endif /* _SPL_TIME_H */
diff --git a/include/os/linux/spl/sys/timer.h b/include/os/linux/spl/sys/timer.h
new file mode 100644
index 000000000000..40be12047ae4
--- /dev/null
+++ b/include/os/linux/spl/sys/timer.h
@@ -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_TIMER_H
+#define _SPL_TIMER_H
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/time.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)
+
+#ifndef from_timer
+#define from_timer(var, timer, timer_field) \
+ container_of(timer, typeof(*var), timer_field)
+#endif
+
+#ifdef HAVE_KERNEL_TIMER_FUNCTION_TIMER_LIST
+typedef struct timer_list *spl_timer_list_t;
+#else
+typedef unsigned long spl_timer_list_t;
+#endif
+
+#ifndef HAVE_KERNEL_TIMER_SETUP
+
+static inline void
+timer_setup(struct timer_list *timer, void (*func)(spl_timer_list_t), u32 fl)
+{
+#ifdef HAVE_KERNEL_TIMER_LIST_FLAGS
+ (timer)->flags = fl;
+#endif
+ init_timer(timer);
+ setup_timer(timer, func, (spl_timer_list_t)(timer));
+}
+
+#endif /* HAVE_KERNEL_TIMER_SETUP */
+
+#endif /* _SPL_TIMER_H */
diff --git a/include/os/linux/spl/sys/trace.h b/include/os/linux/spl/sys/trace.h
new file mode 100644
index 000000000000..b148ace6abd3
--- /dev/null
+++ b/include/os/linux/spl/sys/trace.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+
+/*
+ * Calls to DTRACE_PROBE* are mapped to standard Linux kernel trace points
+ * when they are available(when HAVE_DECLARE_EVENT_CLASS is defined). The
+ * tracepoint event class definitions are found in the general tracing
+ * header file: include/sys/trace_*.h. See include/sys/trace_vdev.h for
+ * a good example.
+ *
+ * If tracepoints are not available, stub functions are generated which can
+ * be traced using kprobes. In this case, the DEFINE_DTRACE_PROBE* macros
+ * are used to provide the stub functions and also the prototypes for
+ * those functions. The mechanism to do this relies on DEFINE_DTRACE_PROBE
+ * macros defined in the general tracing headers(see trace_vdev.h) and
+ * CREATE_TRACE_POINTS being defined only in module/zfs/trace.c. When ZFS
+ * source files include the general tracing headers, e.g.
+ * module/zfs/vdev_removal.c including trace_vdev.h, DTRACE_PROBE calls
+ * are mapped to stub functions calls and prototypes for those calls are
+ * declared via DEFINE_DTRACE_PROBE*. Only module/zfs/trace.c defines
+ * CREATE_TRACE_POINTS. That is followed by includes of all the general
+ * tracing headers thereby defining all stub functions in one place via
+ * the DEFINE_DTRACE_PROBE macros.
+ *
+ * When adding new DTRACE_PROBEs to zfs source, both a tracepoint event
+ * class definition and a DEFINE_DTRACE_PROBE definition are needed to
+ * avoid undefined function errors.
+ */
+
+#if 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>
+
+/*
+ * DTRACE_PROBE with 0 arguments is not currently available with
+ * tracepoint events
+ */
+#define DTRACE_PROBE(name) \
+ ((void)0)
+
+#define DTRACE_PROBE1(name, t1, arg1) \
+ trace_zfs_##name((arg1))
+
+#define DTRACE_PROBE2(name, t1, arg1, t2, arg2) \
+ trace_zfs_##name((arg1), (arg2))
+
+#define DTRACE_PROBE3(name, t1, arg1, t2, arg2, t3, arg3) \
+ trace_zfs_##name((arg1), (arg2), (arg3))
+
+#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>
+
+#else /* HAVE_DECLARE_EVENT_CLASS */
+
+#define DTRACE_PROBE(name) \
+ trace_zfs_##name()
+
+#define DTRACE_PROBE1(name, t1, arg1) \
+ trace_zfs_##name((uintptr_t)(arg1))
+
+#define DTRACE_PROBE2(name, t1, arg1, t2, arg2) \
+ trace_zfs_##name((uintptr_t)(arg1), (uintptr_t)(arg2))
+
+#define DTRACE_PROBE3(name, t1, arg1, t2, arg2, t3, arg3) \
+ trace_zfs_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \
+ (uintptr_t)(arg3))
+
+#define DTRACE_PROBE4(name, t1, arg1, t2, arg2, t3, arg3, t4, arg4) \
+ trace_zfs_##name((uintptr_t)(arg1), (uintptr_t)(arg2), \
+ (uintptr_t)(arg3), (uintptr_t)(arg4))
+
+#define PROTO_DTRACE_PROBE(name) \
+ noinline void trace_zfs_##name(void)
+#define PROTO_DTRACE_PROBE1(name) \
+ noinline void trace_zfs_##name(uintptr_t)
+#define PROTO_DTRACE_PROBE2(name) \
+ noinline void trace_zfs_##name(uintptr_t, uintptr_t)
+#define PROTO_DTRACE_PROBE3(name) \
+ noinline void trace_zfs_##name(uintptr_t, uintptr_t, \
+ uintptr_t)
+#define PROTO_DTRACE_PROBE4(name) \
+ noinline void trace_zfs_##name(uintptr_t, uintptr_t, \
+ uintptr_t, uintptr_t)
+
+#if defined(CREATE_TRACE_POINTS)
+
+#define FUNC_DTRACE_PROBE(name) \
+PROTO_DTRACE_PROBE(name); \
+noinline void trace_zfs_##name(void) { } \
+EXPORT_SYMBOL(trace_zfs_##name)
+
+#define FUNC_DTRACE_PROBE1(name) \
+PROTO_DTRACE_PROBE1(name); \
+noinline void trace_zfs_##name(uintptr_t arg1) { } \
+EXPORT_SYMBOL(trace_zfs_##name)
+
+#define FUNC_DTRACE_PROBE2(name) \
+PROTO_DTRACE_PROBE2(name); \
+noinline void trace_zfs_##name(uintptr_t arg1, \
+ uintptr_t arg2) { } \
+EXPORT_SYMBOL(trace_zfs_##name)
+
+#define FUNC_DTRACE_PROBE3(name) \
+PROTO_DTRACE_PROBE3(name); \
+noinline void trace_zfs_##name(uintptr_t arg1, \
+ uintptr_t arg2, uintptr_t arg3) { } \
+EXPORT_SYMBOL(trace_zfs_##name)
+
+#define FUNC_DTRACE_PROBE4(name) \
+PROTO_DTRACE_PROBE4(name); \
+noinline void trace_zfs_##name(uintptr_t arg1, \
+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) { } \
+EXPORT_SYMBOL(trace_zfs_##name)
+
+#undef DEFINE_DTRACE_PROBE
+#define DEFINE_DTRACE_PROBE(name) FUNC_DTRACE_PROBE(name)
+
+#undef DEFINE_DTRACE_PROBE1
+#define DEFINE_DTRACE_PROBE1(name) FUNC_DTRACE_PROBE1(name)
+
+#undef DEFINE_DTRACE_PROBE2
+#define DEFINE_DTRACE_PROBE2(name) FUNC_DTRACE_PROBE2(name)
+
+#undef DEFINE_DTRACE_PROBE3
+#define DEFINE_DTRACE_PROBE3(name) FUNC_DTRACE_PROBE3(name)
+
+#undef DEFINE_DTRACE_PROBE4
+#define DEFINE_DTRACE_PROBE4(name) FUNC_DTRACE_PROBE4(name)
+
+#else /* CREATE_TRACE_POINTS */
+
+#define DEFINE_DTRACE_PROBE(name) PROTO_DTRACE_PROBE(name)
+#define DEFINE_DTRACE_PROBE1(name) PROTO_DTRACE_PROBE1(name)
+#define DEFINE_DTRACE_PROBE2(name) PROTO_DTRACE_PROBE2(name)
+#define DEFINE_DTRACE_PROBE3(name) PROTO_DTRACE_PROBE3(name)
+#define DEFINE_DTRACE_PROBE4(name) PROTO_DTRACE_PROBE4(name)
+
+#endif /* CREATE_TRACE_POINTS */
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/spl/sys/trace_spl.h b/include/os/linux/spl/sys/trace_spl.h
new file mode 100644
index 000000000000..bffd91d9129b
--- /dev/null
+++ b/include/os/linux/spl/sys/trace_spl.h
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#ifndef _OS_LINUX_SPL_TRACE_H
+#define _OS_LINUX_SPL_TRACE_H
+
+#include <sys/taskq.h>
+
+#include <sys/trace.h>
+#include <sys/trace_taskq.h>
+
+#endif
diff --git a/include/os/linux/spl/sys/trace_taskq.h b/include/os/linux/spl/sys/trace_taskq.h
new file mode 100644
index 000000000000..dbbb3c4c7960
--- /dev/null
+++ b/include/os/linux/spl/sys/trace_taskq.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+#if defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define TRACE_SYSTEM_VAR zfs_taskq
+
+#if !defined(_TRACE_TASKQ_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TASKQ_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for single argument tracepoints of the form:
+ *
+ * DTRACE_PROBE1(...,
+ * taskq_ent_t *, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_taskq_ent_class,
+ TP_PROTO(taskq_ent_t *taskq_ent),
+ TP_ARGS(taskq_ent),
+ TP_STRUCT__entry(
+ __field(taskq_ent_t *, taskq_ent)
+ ),
+ TP_fast_assign(
+ __entry->taskq_ent = taskq_ent;
+ ),
+ TP_printk("taskq_ent %p", __entry->taskq_ent)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_TASKQ_EVENT(name) \
+DEFINE_EVENT(zfs_taskq_ent_class, name, \
+ TP_PROTO(taskq_ent_t *taskq_ent), \
+ TP_ARGS(taskq_ent))
+/* END CSTYLED */
+DEFINE_TASKQ_EVENT(zfs_taskq_ent__birth);
+DEFINE_TASKQ_EVENT(zfs_taskq_ent__start);
+DEFINE_TASKQ_EVENT(zfs_taskq_ent__finish);
+
+#endif /* _TRACE_TASKQ_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH sys
+#define TRACE_INCLUDE_FILE trace_taskq
+#include <trace/define_trace.h>
+
+#else
+
+/*
+ * When tracepoints are not available, a DEFINE_DTRACE_PROBE* macro is
+ * needed for each DTRACE_PROBE. These will be used to generate stub
+ * tracing functions and prototypes for those functions. See
+ * include/os/linux/spl/sys/trace.h.
+ */
+
+DEFINE_DTRACE_PROBE1(taskq_ent__birth);
+DEFINE_DTRACE_PROBE1(taskq_ent__start);
+DEFINE_DTRACE_PROBE1(taskq_ent__finish);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/spl/sys/tsd.h b/include/os/linux/spl/sys/tsd.h
new file mode 100644
index 000000000000..39a291bf3dee
--- /dev/null
+++ b/include/os/linux/spl/sys/tsd.h
@@ -0,0 +1,46 @@
+/*
+ * 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_get_by_thread(uint_t, kthread_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/include/os/linux/spl/sys/types.h b/include/os/linux/spl/sys/types.h
new file mode 100644
index 000000000000..719a44646e6b
--- /dev/null
+++ b/include/os/linux/spl/sys/types.h
@@ -0,0 +1,58 @@
+/*
+ * 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>
+
+typedef enum {
+ B_FALSE = 0,
+ B_TRUE = 1
+} boolean_t;
+
+typedef unsigned char uchar_t;
+typedef unsigned short ushort_t;
+typedef unsigned int uint_t;
+typedef unsigned long ulong_t;
+typedef unsigned long long u_longlong_t;
+typedef long long longlong_t;
+
+typedef unsigned long intptr_t;
+typedef unsigned long long rlim64_t;
+
+typedef struct task_struct kthread_t;
+typedef struct task_struct proc_t;
+
+typedef int id_t;
+typedef short pri_t;
+typedef short index_t;
+typedef longlong_t offset_t;
+typedef u_longlong_t u_offset_t;
+typedef ulong_t pgcnt_t;
+
+typedef int major_t;
+typedef int minor_t;
+
+#endif /* _SPL_TYPES_H */
diff --git a/include/os/linux/spl/sys/types32.h b/include/os/linux/spl/sys/types32.h
new file mode 100644
index 000000000000..c60ba8c97019
--- /dev/null
+++ b/include/os/linux/spl/sys/types32.h
@@ -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_TYPES32_H
+#define _SPL_TYPES32_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/include/os/linux/spl/sys/uio.h b/include/os/linux/spl/sys/uio.h
new file mode 100644
index 000000000000..0e631d6779a2
--- /dev/null
+++ b/include/os/linux/spl/sys/uio.h
@@ -0,0 +1,144 @@
+/*
+ * 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 <sys/debug.h>
+#include <linux/uio.h>
+#include <linux/blkdev.h>
+#include <linux/blkdev_compat.h>
+#include <linux/mm.h>
+#include <linux/bio.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;
+ boolean_t uio_fault_disable;
+ 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
+
+#define uio_segflg(uio) (uio)->uio_segflg
+#define uio_offset(uio) (uio)->uio_loffset
+#define uio_resid(uio) (uio)->uio_resid
+#define uio_iovcnt(uio) (uio)->uio_iovcnt
+#define uio_iovlen(uio, idx) (uio)->uio_iov[(idx)].iov_len
+#define uio_iovbase(uio, idx) (uio)->uio_iov[(idx)].iov_base
+
+static inline void
+uio_iov_at_index(uio_t *uio, uint_t idx, void **base, uint64_t *len)
+{
+ *base = uio_iovbase(uio, idx);
+ *len = uio_iovlen(uio, idx);
+}
+
+static inline void
+uio_advance(uio_t *uio, size_t size)
+{
+ uio->uio_resid -= size;
+ uio->uio_loffset += size;
+}
+
+static inline offset_t
+uio_index_at_offset(uio_t *uio, offset_t off, uint_t *vec_idx)
+{
+ *vec_idx = 0;
+ while (*vec_idx < uio_iovcnt(uio) && off >= uio_iovlen(uio, *vec_idx)) {
+ off -= uio_iovlen(uio, *vec_idx);
+ (*vec_idx)++;
+ }
+
+ return (off);
+}
+
+#endif /* SPL_UIO_H */
diff --git a/include/os/linux/spl/sys/user.h b/include/os/linux/spl/sys/user.h
new file mode 100644
index 000000000000..b12cb240e39b
--- /dev/null
+++ b/include/os/linux/spl/sys/user.h
@@ -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 and we do not do a getf() between
+ * the change and using it, 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/include/os/linux/spl/sys/vfs.h b/include/os/linux/spl/sys/vfs.h
new file mode 100644
index 000000000000..0d5e1d51d7aa
--- /dev/null
+++ b/include/os/linux/spl/sys/vfs.h
@@ -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/include/os/linux/spl/sys/vmem.h b/include/os/linux/spl/sys/vmem.h
new file mode 100644
index 000000000000..a31b4728c367
--- /dev/null
+++ b/include/os/linux/spl/sys/vmem.h
@@ -0,0 +1,102 @@
+/*
+ * 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;
+
+/*
+ * 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))
+
+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/include/os/linux/spl/sys/vmsystm.h b/include/os/linux/spl/sys/vmsystm.h
new file mode 100644
index 000000000000..705339486bc8
--- /dev/null
+++ b/include/os/linux/spl/sys/vmsystm.h
@@ -0,0 +1,103 @@
+/*
+ * 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>
+
+#ifdef HAVE_TOTALRAM_PAGES_FUNC
+#define zfs_totalram_pages totalram_pages()
+#else
+#define zfs_totalram_pages totalram_pages
+#endif
+
+#ifdef HAVE_TOTALHIGH_PAGES
+#define zfs_totalhigh_pages totalhigh_pages()
+#else
+#define zfs_totalhigh_pages totalhigh_pages
+#endif
+
+#define membar_producer() smp_wmb()
+#define physmem zfs_totalram_pages
+#ifdef ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE_B
+#define freemem (nr_free_pages() + \
+ global_page_state(NR_INACTIVE_FILE) + \
+ global_page_state(NR_INACTIVE_ANON) + \
+ global_page_state(NR_SLAB_RECLAIMABLE_B))
+#else
+#define freemem (nr_free_pages() + \
+ global_page_state(NR_INACTIVE_FILE) + \
+ global_page_state(NR_INACTIVE_ANON) + \
+ global_page_state(NR_SLAB_RECLAIMABLE))
+#endif /* ZFS_ENUM_NODE_STAT_ITEM_NR_SLAB_RECLAIMABLE_B */
+
+#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/include/os/linux/spl/sys/vnode.h b/include/os/linux/spl/sys/vnode.h
new file mode 100644
index 000000000000..07eac8e44173
--- /dev/null
+++ b/include/os/linux/spl/sys/vnode.h
@@ -0,0 +1,107 @@
+/*
+ * 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>
+
+/*
+ * 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 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 (1U << 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 struct vattr {
+ uint32_t va_mask; /* attribute bit-mask */
+ ushort_t 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 */
+ inode_timespec_t va_atime; /* last acc */
+ inode_timespec_t va_mtime; /* last mod */
+ inode_timespec_t va_ctime; /* last chg */
+ dev_t va_rdev; /* dev */
+ uint64_t va_nblocks; /* space used */
+ uint32_t va_blksize; /* block size */
+ struct dentry *va_dentry; /* dentry to wire */
+} vattr_t;
+#endif /* SPL_VNODE_H */
diff --git a/include/os/linux/spl/sys/wait.h b/include/os/linux/spl/sys/wait.h
new file mode 100644
index 000000000000..5311ff8b971b
--- /dev/null
+++ b/include/os/linux/spl/sys/wait.h
@@ -0,0 +1,55 @@
+/*
+ * 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_H
+#define _SPL_WAIT_H
+
+#include <linux/sched.h>
+#include <linux/wait.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 */
+
+#ifdef HAVE_WAIT_QUEUE_ENTRY_T
+typedef wait_queue_head_t spl_wait_queue_head_t;
+typedef wait_queue_entry_t spl_wait_queue_entry_t;
+#else
+typedef wait_queue_head_t spl_wait_queue_head_t;
+typedef wait_queue_t spl_wait_queue_entry_t;
+#endif
+
+#endif /* SPL_WAIT_H */
diff --git a/include/os/linux/spl/sys/zmod.h b/include/os/linux/spl/sys/zmod.h
new file mode 100644
index 000000000000..5380bd6fd022
--- /dev/null
+++ b/include/os/linux/spl/sys/zmod.h
@@ -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/>.
+ *
+ *
+ * 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/include/os/linux/spl/sys/zone.h b/include/os/linux/spl/sys/zone.h
new file mode 100644
index 000000000000..b2efd13b8e0d
--- /dev/null
+++ b/include/os/linux/spl/sys/zone.h
@@ -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/include/os/linux/zfs/Makefile.am b/include/os/linux/zfs/Makefile.am
new file mode 100644
index 000000000000..081839c48c8f
--- /dev/null
+++ b/include/os/linux/zfs/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = sys
diff --git a/include/os/linux/zfs/sys/Makefile.am b/include/os/linux/zfs/sys/Makefile.am
new file mode 100644
index 000000000000..732d94ee804e
--- /dev/null
+++ b/include/os/linux/zfs/sys/Makefile.am
@@ -0,0 +1,30 @@
+KERNEL_H = \
+ policy.h \
+ sha2.h \
+ trace_acl.h \
+ trace_arc.h \
+ trace_common.h \
+ trace_zfs.h \
+ trace_dbgmsg.h \
+ trace_dbuf.h \
+ trace_dmu.h \
+ trace_dnode.h \
+ trace_multilist.h \
+ trace_rrwlock.h \
+ trace_txg.h \
+ trace_vdev.h \
+ trace_zil.h \
+ trace_zio.h \
+ trace_zrlock.h \
+ zfs_context_os.h \
+ zfs_ctldir.h \
+ zfs_dir.h \
+ zfs_vfsops.h \
+ zfs_vnops.h \
+ zfs_znode_impl.h \
+ zpl.h
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys
+kernel_HEADERS = $(KERNEL_H)
+endif
diff --git a/include/os/linux/zfs/sys/policy.h b/include/os/linux/zfs/sys/policy.h
new file mode 100644
index 000000000000..77a73ad149c5
--- /dev/null
+++ b/include/os/linux/zfs/sys/policy.h
@@ -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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2016, Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _SYS_POLICY_H
+#define _SYS_POLICY_H
+
+#ifdef _KERNEL
+
+#include <sys/cred.h>
+#include <sys/types.h>
+#include <sys/xvattr.h>
+#include <sys/zpl.h>
+
+int secpolicy_nfs(const cred_t *);
+int secpolicy_sys_config(const cred_t *, boolean_t);
+int secpolicy_vnode_access2(const cred_t *, struct inode *,
+ uid_t, mode_t, mode_t);
+int secpolicy_vnode_any_access(const cred_t *, struct inode *, uid_t);
+int secpolicy_vnode_chown(const cred_t *, uid_t);
+int secpolicy_vnode_create_gid(const cred_t *);
+int secpolicy_vnode_remove(const cred_t *);
+int secpolicy_vnode_setdac(const cred_t *, uid_t);
+int secpolicy_vnode_setid_retain(const cred_t *, boolean_t);
+int secpolicy_vnode_setids_setgids(const cred_t *, gid_t);
+int secpolicy_zinject(const cred_t *);
+int secpolicy_zfs(const cred_t *);
+int secpolicy_zfs_proc(const cred_t *, proc_t *);
+void secpolicy_setid_clear(vattr_t *, cred_t *);
+int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
+ const vattr_t *, cred_t *);
+int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, mode_t);
+int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *,
+ const struct vattr *, int, int (void *, int, cred_t *), void *);
+int secpolicy_basic_link(const cred_t *);
+
+#endif /* _KERNEL */
+#endif /* _SYS_POLICY_H */
diff --git a/include/os/linux/zfs/sys/sha2.h b/include/os/linux/zfs/sys/sha2.h
new file mode 100644
index 000000000000..4dd966b6cab3
--- /dev/null
+++ b/include/os/linux/zfs/sys/sha2.h
@@ -0,0 +1,151 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright 2013 Saso Kiselkov. All rights reserved. */
+
+#ifndef _SYS_SHA2_H
+#define _SYS_SHA2_H
+
+#include <sys/types.h> /* for uint_* */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHA2_HMAC_MIN_KEY_LEN 1 /* SHA2-HMAC min key length in bytes */
+#define SHA2_HMAC_MAX_KEY_LEN INT_MAX /* SHA2-HMAC max key length in bytes */
+
+#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
+#define SHA384_DIGEST_LENGTH 48 /* SHA384 digest length in bytes */
+#define SHA512_DIGEST_LENGTH 64 /* SHA512 digest length in bytes */
+
+/* Truncated versions of SHA-512 according to FIPS-180-4, section 5.3.6 */
+#define SHA512_224_DIGEST_LENGTH 28 /* SHA512/224 digest length */
+#define SHA512_256_DIGEST_LENGTH 32 /* SHA512/256 digest length */
+
+#define SHA256_HMAC_BLOCK_SIZE 64 /* SHA256-HMAC block size */
+#define SHA512_HMAC_BLOCK_SIZE 128 /* SHA512-HMAC block size */
+
+#define SHA256 0
+#define SHA256_HMAC 1
+#define SHA256_HMAC_GEN 2
+#define SHA384 3
+#define SHA384_HMAC 4
+#define SHA384_HMAC_GEN 5
+#define SHA512 6
+#define SHA512_HMAC 7
+#define SHA512_HMAC_GEN 8
+#define SHA512_224 9
+#define SHA512_256 10
+
+/*
+ * SHA2 context.
+ * The contents of this structure are a private interface between the
+ * Init/Update/Final calls of the functions defined below.
+ * Callers must never attempt to read or write any of the fields
+ * in this structure directly.
+ */
+typedef struct {
+ uint32_t algotype; /* Algorithm Type */
+
+ /* state (ABCDEFGH) */
+ union {
+ uint32_t s32[8]; /* for SHA256 */
+ uint64_t s64[8]; /* for SHA384/512 */
+ } state;
+ /* number of bits */
+ union {
+ uint32_t c32[2]; /* for SHA256 , modulo 2^64 */
+ uint64_t c64[2]; /* for SHA384/512, modulo 2^128 */
+ } count;
+ union {
+ uint8_t buf8[128]; /* undigested input */
+ uint32_t buf32[32]; /* realigned input */
+ uint64_t buf64[16]; /* realigned input */
+ } buf_un;
+} SHA2_CTX;
+
+typedef SHA2_CTX SHA256_CTX;
+typedef SHA2_CTX SHA384_CTX;
+typedef SHA2_CTX SHA512_CTX;
+
+extern void SHA2Init(uint64_t mech, SHA2_CTX *);
+
+extern void SHA2Update(SHA2_CTX *, const void *, size_t);
+
+extern void SHA2Final(void *, SHA2_CTX *);
+
+extern void SHA256Init(SHA256_CTX *);
+
+extern void SHA256Update(SHA256_CTX *, const void *, size_t);
+
+extern void SHA256Final(void *, SHA256_CTX *);
+
+extern void SHA384Init(SHA384_CTX *);
+
+extern void SHA384Update(SHA384_CTX *, const void *, size_t);
+
+extern void SHA384Final(void *, SHA384_CTX *);
+
+extern void SHA512Init(SHA512_CTX *);
+
+extern void SHA512Update(SHA512_CTX *, const void *, size_t);
+
+extern void SHA512Final(void *, SHA512_CTX *);
+
+#ifdef _SHA2_IMPL
+/*
+ * The following types/functions are all private to the implementation
+ * of the SHA2 functions and must not be used by consumers of the interface
+ */
+
+/*
+ * List of support mechanisms in this module.
+ *
+ * It is important to note that in the module, division or modulus calculations
+ * are used on the enumerated type to determine which mechanism is being used;
+ * therefore, changing the order or additional mechanisms should be done
+ * carefully
+ */
+typedef enum sha2_mech_type {
+ SHA256_MECH_INFO_TYPE, /* SUN_CKM_SHA256 */
+ SHA256_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC */
+ SHA256_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC_GENERAL */
+ SHA384_MECH_INFO_TYPE, /* SUN_CKM_SHA384 */
+ SHA384_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA384_HMAC */
+ SHA384_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA384_HMAC_GENERAL */
+ SHA512_MECH_INFO_TYPE, /* SUN_CKM_SHA512 */
+ SHA512_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC */
+ SHA512_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC_GENERAL */
+ SHA512_224_MECH_INFO_TYPE, /* SUN_CKM_SHA512_224 */
+ SHA512_256_MECH_INFO_TYPE /* SUN_CKM_SHA512_256 */
+} sha2_mech_type_t;
+
+#endif /* _SHA2_IMPL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SHA2_H */
diff --git a/include/os/linux/zfs/sys/trace_acl.h b/include/os/linux/zfs/sys/trace_acl.h
new file mode 100644
index 000000000000..083560952f0b
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_acl.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+#if 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 <linux/vfs_compat.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ * znode_t *, ...,
+ * zfs_ace_hdr_t *, ...,
+ * uint32_t, ...);
+ */
+/* BEGIN CSTYLED */
+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_size)
+ __field(uint64_t, z_pflags)
+ __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(uint32_t, i_uid)
+ __field(uint32_t, i_gid)
+ __field(unsigned long, i_ino)
+ __field(unsigned int, i_nlink)
+ __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_size = zn->z_size;
+ __entry->z_pflags = zn->z_pflags;
+ __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_uid = KUID_TO_SUID(ZTOI(zn)->i_uid);
+ __entry->i_gid = KGID_TO_SGID(ZTOI(zn)->i_gid);
+ __entry->i_ino = zn->z_inode.i_ino;
+ __entry->i_nlink = zn->z_inode.i_nlink;
+ __entry->i_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 size %llu pflags %llu "
+ "sync_cnt %u mode 0x%x is_sa %d "
+ "is_mapped %d is_ctldir %d is_stale %d inode { "
+ "uid %u gid %u ino %lu nlink %u 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_size,
+ __entry->z_pflags, __entry->z_sync_cnt, __entry->z_mode,
+ __entry->z_is_sa, __entry->z_is_mapped,
+ __entry->z_is_ctldir, __entry->z_is_stale, __entry->i_uid,
+ __entry->i_gid, __entry->i_ino, __entry->i_nlink,
+ __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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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>
+
+#else
+
+DEFINE_DTRACE_PROBE3(zfs__ace__denies);
+DEFINE_DTRACE_PROBE3(zfs__ace__allows);
+DEFINE_DTRACE_PROBE(zfs__fastpath__execute__access__miss);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_arc.h b/include/os/linux/zfs/sys/trace_arc.h
new file mode 100644
index 000000000000..3df491f8b392
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_arc.h
@@ -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
+ */
+
+#include <sys/list.h>
+
+#if defined(_KERNEL)
+#if 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>
+#include <sys/trace_common.h> /* For ZIO macros */
+
+/*
+ * Generic support for one argument tracepoints of the form:
+ *
+ * DTRACE_PROBE1(...,
+ * arc_buf_hdr_t *, ...);
+ */
+/* BEGIN CSTYLED */
+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_bufcnt)
+ __field(arc_buf_contents_t, hdr_type)
+ __field(uint16_t, hdr_psize)
+ __field(uint16_t, hdr_lsize)
+ __field(uint64_t, hdr_spa)
+ __field(arc_state_type_t, hdr_state_type)
+ __field(clock_t, hdr_access)
+ __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_bufcnt = ab->b_l1hdr.b_bufcnt;
+ __entry->hdr_psize = ab->b_psize;
+ __entry->hdr_lsize = ab->b_lsize;
+ __entry->hdr_spa = ab->b_spa;
+ __entry->hdr_state_type = ab->b_l1hdr.b_state->arcs_state;
+ __entry->hdr_access = ab->b_l1hdr.b_arc_access;
+ __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 bufcnt %u type %u psize %u lsize %u spa %llu "
+ "state_type %u access %lu mru_hits %u mru_ghost_hits %u "
+ "mfu_hits %u mfu_ghost_hits %u l2_hits %u refcount %lli }",
+ __entry->hdr_dva_word[0], __entry->hdr_dva_word[1],
+ __entry->hdr_birth, __entry->hdr_flags,
+ __entry->hdr_bufcnt, __entry->hdr_type, __entry->hdr_psize,
+ __entry->hdr_lsize, __entry->hdr_spa, __entry->hdr_state_type,
+ __entry->hdr_access, __entry->hdr_mru_hits,
+ __entry->hdr_mru_ghost_hits, __entry->hdr_mfu_hits,
+ __entry->hdr_mfu_ghost_hits, __entry->hdr_l2_hits,
+ __entry->hdr_refcount)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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_arc__async__upgrade__sync);
+DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__demand__hit__predictive__prefetch);
+DEFINE_ARC_BUF_HDR_EVENT(zfs_l2arc__hit);
+DEFINE_ARC_BUF_HDR_EVENT(zfs_l2arc__miss);
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ * vdev_t *, ...,
+ * zio_t *, ...);
+ */
+/* BEGIN CSTYLED */
+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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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 *, ...);
+ */
+/* BEGIN CSTYLED */
+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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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 *);
+ */
+/* BEGIN CSTYLED */
+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_bufcnt)
+ __field(arc_buf_contents_t, hdr_type)
+ __field(uint16_t, hdr_psize)
+ __field(uint16_t, hdr_lsize)
+ __field(uint64_t, hdr_spa)
+ __field(arc_state_type_t, hdr_state_type)
+ __field(clock_t, hdr_access)
+ __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_bufcnt = hdr->b_l1hdr.b_bufcnt;
+ __entry->hdr_psize = hdr->b_psize;
+ __entry->hdr_lsize = hdr->b_lsize;
+ __entry->hdr_spa = hdr->b_spa;
+ __entry->hdr_state_type = hdr->b_l1hdr.b_state->arcs_state;
+ __entry->hdr_access = hdr->b_l1hdr.b_arc_access;
+ __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 bufcnt %u psize %u lsize %u spa %llu state_type %u "
+ "access %lu mru_hits %u mru_ghost_hits %u mfu_hits %u "
+ "mfu_ghost_hits %u l2_hits %u refcount %lli } "
+ "bp { dva0 0x%llx:0x%llx dva1 0x%llx:0x%llx dva2 "
+ "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_bufcnt, __entry->hdr_psize, __entry->hdr_lsize,
+ __entry->hdr_spa, __entry->hdr_state_type, __entry->hdr_access,
+ __entry->hdr_mru_hits, __entry->hdr_mru_ghost_hits,
+ __entry->hdr_mfu_hits, __entry->hdr_mfu_ghost_hits,
+ __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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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, ...);
+ */
+/* BEGIN CSTYLED */
+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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+DEFINE_L2ARC_EVICT_EVENT(zfs_l2arc__evict);
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ * uint64_t, ...,
+ * uint64_t, ...,
+ * uint64_t, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_arc_wait_for_eviction_class,
+ TP_PROTO(uint64_t amount, uint64_t arc_evict_count, uint64_t aew_count),
+ TP_ARGS(amount, arc_evict_count, aew_count),
+ TP_STRUCT__entry(
+ __field(uint64_t, amount)
+ __field(uint64_t, arc_evict_count)
+ __field(uint64_t, aew_count)
+ ),
+ TP_fast_assign(
+ __entry->amount = amount;
+ __entry->arc_evict_count = arc_evict_count;
+ __entry->aew_count = aew_count;
+ ),
+ TP_printk("amount %llu arc_evict_count %llu aew_count %llu",
+ __entry->amount, __entry->arc_evict_count, __entry->aew_count)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_ARC_WAIT_FOR_EVICTION_EVENT(name) \
+DEFINE_EVENT(zfs_arc_wait_for_eviction_class, name, \
+ TP_PROTO(uint64_t amount, uint64_t arc_evict_count, uint64_t aew_count), \
+ TP_ARGS(amount, arc_evict_count, aew_count))
+/* END CSTYLED */
+DEFINE_ARC_WAIT_FOR_EVICTION_EVENT(zfs_arc__wait__for__eviction);
+
+#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>
+
+#else
+
+DEFINE_DTRACE_PROBE1(arc__hit);
+DEFINE_DTRACE_PROBE1(arc__evict);
+DEFINE_DTRACE_PROBE1(arc__delete);
+DEFINE_DTRACE_PROBE1(new_state__mru);
+DEFINE_DTRACE_PROBE1(new_state__mfu);
+DEFINE_DTRACE_PROBE1(arc__async__upgrade__sync);
+DEFINE_DTRACE_PROBE1(arc__demand__hit__predictive__prefetch);
+DEFINE_DTRACE_PROBE1(l2arc__hit);
+DEFINE_DTRACE_PROBE1(l2arc__miss);
+DEFINE_DTRACE_PROBE2(l2arc__read);
+DEFINE_DTRACE_PROBE2(l2arc__write);
+DEFINE_DTRACE_PROBE2(l2arc__iodone);
+DEFINE_DTRACE_PROBE3(arc__wait__for__eviction);
+DEFINE_DTRACE_PROBE4(arc__miss);
+DEFINE_DTRACE_PROBE4(l2arc__evict);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_common.h b/include/os/linux/zfs/sys/trace_common.h
new file mode 100644
index 000000000000..6922d1a1810a
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_common.h
@@ -0,0 +1,112 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * This file contains commonly used trace macros. Feel free to add and use
+ * them in your tracepoint headers.
+ */
+
+#ifndef _SYS_TRACE_COMMON_H
+#define _SYS_TRACE_COMMON_H
+#include <linux/tracepoint.h>
+
+/* ZIO macros */
+#define ZIO_TP_STRUCT_ENTRY \
+ __field(zio_type_t, zio_type) \
+ __field(int, zio_cmd) \
+ __field(zio_priority_t, zio_priority) \
+ __field(uint64_t, zio_size) \
+ __field(uint64_t, zio_orig_size) \
+ __field(uint64_t, zio_offset) \
+ __field(hrtime_t, zio_timestamp) \
+ __field(hrtime_t, zio_delta) \
+ __field(uint64_t, zio_delay) \
+ __field(enum zio_flag, zio_flags) \
+ __field(enum zio_stage, zio_stage) \
+ __field(enum zio_stage, zio_pipeline) \
+ __field(enum zio_flag, zio_orig_flags) \
+ __field(enum zio_stage, zio_orig_stage) \
+ __field(enum zio_stage, zio_orig_pipeline) \
+ __field(uint8_t, zio_reexecute) \
+ __field(uint64_t, zio_txg) \
+ __field(int, zio_error) \
+ __field(uint64_t, zio_ena) \
+ \
+ __field(enum zio_checksum, zp_checksum) \
+ __field(enum zio_compress, zp_compress) \
+ __field(dmu_object_type_t, zp_type) \
+ __field(uint8_t, zp_level) \
+ __field(uint8_t, zp_copies) \
+ __field(boolean_t, zp_dedup) \
+ __field(boolean_t, zp_dedup_verify) \
+ __field(boolean_t, zp_nopwrite)
+
+#define ZIO_TP_FAST_ASSIGN \
+ __entry->zio_type = zio->io_type; \
+ __entry->zio_cmd = zio->io_cmd; \
+ __entry->zio_priority = zio->io_priority; \
+ __entry->zio_size = zio->io_size; \
+ __entry->zio_orig_size = zio->io_orig_size; \
+ __entry->zio_offset = zio->io_offset; \
+ __entry->zio_timestamp = zio->io_timestamp; \
+ __entry->zio_delta = zio->io_delta; \
+ __entry->zio_delay = zio->io_delay; \
+ __entry->zio_flags = zio->io_flags; \
+ __entry->zio_stage = zio->io_stage; \
+ __entry->zio_pipeline = zio->io_pipeline; \
+ __entry->zio_orig_flags = zio->io_orig_flags; \
+ __entry->zio_orig_stage = zio->io_orig_stage; \
+ __entry->zio_orig_pipeline = zio->io_orig_pipeline; \
+ __entry->zio_reexecute = zio->io_reexecute; \
+ __entry->zio_txg = zio->io_txg; \
+ __entry->zio_error = zio->io_error; \
+ __entry->zio_ena = zio->io_ena; \
+ \
+ __entry->zp_checksum = zio->io_prop.zp_checksum; \
+ __entry->zp_compress = zio->io_prop.zp_compress; \
+ __entry->zp_type = zio->io_prop.zp_type; \
+ __entry->zp_level = zio->io_prop.zp_level; \
+ __entry->zp_copies = zio->io_prop.zp_copies; \
+ __entry->zp_dedup = zio->io_prop.zp_dedup; \
+ __entry->zp_nopwrite = zio->io_prop.zp_nopwrite; \
+ __entry->zp_dedup_verify = zio->io_prop.zp_dedup_verify;
+
+#define ZIO_TP_PRINTK_FMT \
+ "zio { type %u cmd %i prio %u size %llu orig_size %llu " \
+ "offset %llu timestamp %llu delta %llu delay %llu " \
+ "flags 0x%x stage 0x%x pipeline 0x%x orig_flags 0x%x " \
+ "orig_stage 0x%x orig_pipeline 0x%x reexecute %u " \
+ "txg %llu error %d ena %llu prop { checksum %u compress %u " \
+ "type %u level %u copies %u dedup %u dedup_verify %u nopwrite %u } }"
+
+#define ZIO_TP_PRINTK_ARGS \
+ __entry->zio_type, __entry->zio_cmd, __entry->zio_priority, \
+ __entry->zio_size, __entry->zio_orig_size, __entry->zio_offset, \
+ __entry->zio_timestamp, __entry->zio_delta, __entry->zio_delay, \
+ __entry->zio_flags, __entry->zio_stage, __entry->zio_pipeline, \
+ __entry->zio_orig_flags, __entry->zio_orig_stage, \
+ __entry->zio_orig_pipeline, __entry->zio_reexecute, \
+ __entry->zio_txg, __entry->zio_error, __entry->zio_ena, \
+ __entry->zp_checksum, __entry->zp_compress, __entry->zp_type, \
+ __entry->zp_level, __entry->zp_copies, __entry->zp_dedup, \
+ __entry->zp_dedup_verify, __entry->zp_nopwrite
+
+#endif /* _SYS_TRACE_COMMON_H */
diff --git a/include/os/linux/zfs/sys/trace_dbgmsg.h b/include/os/linux/zfs/sys/trace_dbgmsg.h
new file mode 100644
index 000000000000..513918d004a4
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_dbgmsg.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+#if defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define TRACE_SYSTEM_VAR zfs_dbgmsg
+
+#if !defined(_TRACE_DBGMSG_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_DBGMSG_H
+
+#include <linux/tracepoint.h>
+
+/*
+ * 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 one argument tracepoints of the form:
+ *
+ * DTRACE_PROBE1(...,
+ * const char *, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_dprintf_class,
+ TP_PROTO(const char *msg),
+ TP_ARGS(msg),
+ TP_STRUCT__entry(
+ __string(msg, msg)
+ ),
+ TP_fast_assign(
+ __assign_str(msg, msg);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_DPRINTF_EVENT(name) \
+DEFINE_EVENT(zfs_dprintf_class, name, \
+ TP_PROTO(const char *msg), \
+ TP_ARGS(msg))
+/* END CSTYLED */
+DEFINE_DPRINTF_EVENT(zfs_zfs__dprintf);
+
+#endif /* _TRACE_DBGMSG_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH sys
+#define TRACE_INCLUDE_FILE trace_dbgmsg
+#include <trace/define_trace.h>
+
+#else
+
+DEFINE_DTRACE_PROBE1(zfs__dprintf);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_dbuf.h b/include/os/linux/zfs/sys/trace_dbuf.h
new file mode 100644
index 000000000000..bd7d791a46e7
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_dbuf.h
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this 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)
+#if 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>
+
+#ifndef TRACE_DBUF_MSG_MAX
+#define TRACE_DBUF_MSG_MAX 512
+#endif
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ * dmu_buf_impl_t *, ...,
+ * zio_t *, ...);
+ */
+
+#define DBUF_TP_STRUCT_ENTRY \
+ __dynamic_array(char, os_spa, TRACE_DBUF_MSG_MAX) \
+ __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) \
+ __dynamic_array(char, msg, TRACE_DBUF_MSG_MAX)
+
+#define DBUF_TP_FAST_ASSIGN \
+ if (db != NULL) { \
+ __assign_str(os_spa, \
+ spa_name(DB_DNODE(db)->dn_objset->os_spa)); \
+ \
+ __entry->ds_object = db->db_objset->os_dsl_dataset ? \
+ db->db_objset->os_dsl_dataset->ds_object : 0; \
+ \
+ __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 = zfs_refcount_count(&db->db_holds); \
+ snprintf(__get_str(msg), TRACE_DBUF_MSG_MAX, \
+ DBUF_TP_PRINTK_FMT, DBUF_TP_PRINTK_ARGS); \
+ } else { \
+ __assign_str(os_spa, "NULL") \
+ __entry->ds_object = 0; \
+ __entry->db_object = 0; \
+ __entry->db_level = 0; \
+ __entry->db_blkid = 0; \
+ __entry->db_offset = 0; \
+ __entry->db_size = 0; \
+ __entry->db_state = 0; \
+ __entry->db_holds = 0; \
+ snprintf(__get_str(msg), TRACE_DBUF_MSG_MAX, \
+ "dbuf { NULL }"); \
+ }
+
+#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 \
+ __get_str(os_spa), __entry->ds_object, \
+ __entry->db_object, __entry->db_level, \
+ __entry->db_blkid, __entry->db_offset, \
+ __entry->db_size, __entry->db_state, __entry->db_holds
+
+/* BEGIN CSTYLED */
+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("%s", __get_str(msg))
+);
+
+DECLARE_EVENT_CLASS(zfs_dbuf_state_class,
+ TP_PROTO(dmu_buf_impl_t *db, const char *why),
+ TP_ARGS(db, why),
+ TP_STRUCT__entry(DBUF_TP_STRUCT_ENTRY),
+ TP_fast_assign(DBUF_TP_FAST_ASSIGN),
+ TP_printk("%s", __get_str(msg))
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+DEFINE_DBUF_EVENT(zfs_blocked__read);
+
+/* BEGIN CSTYLED */
+#define DEFINE_DBUF_STATE_EVENT(name) \
+DEFINE_EVENT(zfs_dbuf_state_class, name, \
+ TP_PROTO(dmu_buf_impl_t *db, const char *why), \
+ TP_ARGS(db, why))
+/* END CSTYLED */
+DEFINE_DBUF_STATE_EVENT(zfs_dbuf__state_change);
+
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_dbuf_evict_one_class,
+ TP_PROTO(dmu_buf_impl_t *db, multilist_sublist_t *mls),
+ TP_ARGS(db, mls),
+ TP_STRUCT__entry(DBUF_TP_STRUCT_ENTRY),
+ TP_fast_assign(DBUF_TP_FAST_ASSIGN),
+ TP_printk("%s", __get_str(msg))
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_DBUF_EVICT_ONE_EVENT(name) \
+DEFINE_EVENT(zfs_dbuf_evict_one_class, name, \
+ TP_PROTO(dmu_buf_impl_t *db, multilist_sublist_t *mls), \
+ TP_ARGS(db, mls))
+/* END CSTYLED */
+DEFINE_DBUF_EVICT_ONE_EVENT(zfs_dbuf__evict__one);
+
+#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>
+
+#else
+
+DEFINE_DTRACE_PROBE2(blocked__read);
+DEFINE_DTRACE_PROBE2(dbuf__evict__one);
+DEFINE_DTRACE_PROBE2(dbuf__state_change);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_dmu.h b/include/os/linux/zfs/sys/trace_dmu.h
new file mode 100644
index 000000000000..3c64a370f842
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_dmu.h
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL)
+#if 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, ...);
+ */
+/* BEGIN CSTYLED */
+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_dirty_delayed)
+ __field(hrtime_t, tx_start)
+ __field(boolean_t, tx_wait_dirty)
+ __field(int, tx_err)
+ __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_dirty_delayed = tx->tx_dirty_delayed;
+ __entry->tx_start = tx->tx_start;
+ __entry->tx_wait_dirty = tx->tx_wait_dirty;
+ __entry->tx_err = tx->tx_err;
+ __entry->dirty = dirty;
+ __entry->min_tx_time = min_tx_time;
+ ),
+ TP_printk("tx { txg %llu lastsnap_txg %llu tx_lasttried_txg %llu "
+ "anyobj %d dirty_delayed %d start %llu wait_dirty %d err %i "
+ "} dirty %llu min_tx_time %llu",
+ __entry->tx_txg, __entry->tx_lastsnap_txg,
+ __entry->tx_lasttried_txg, __entry->tx_anyobj,
+ __entry->tx_dirty_delayed, __entry->tx_start,
+ __entry->tx_wait_dirty, __entry->tx_err,
+ __entry->dirty, __entry->min_tx_time)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+DEFINE_DELAY_MINTIME_EVENT(zfs_delay__mintime);
+
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_free_long_range_class,
+ TP_PROTO(uint64_t long_free_dirty_all_txgs, uint64_t chunk_len, \
+ uint64_t txg),
+ TP_ARGS(long_free_dirty_all_txgs, chunk_len, txg),
+ TP_STRUCT__entry(
+ __field(uint64_t, long_free_dirty_all_txgs)
+ __field(uint64_t, chunk_len)
+ __field(uint64_t, txg)
+ ),
+ TP_fast_assign(
+ __entry->long_free_dirty_all_txgs = long_free_dirty_all_txgs;
+ __entry->chunk_len = chunk_len;
+ __entry->txg = txg;
+ ),
+ TP_printk("long_free_dirty_all_txgs %llu chunk_len %llu txg %llu",
+ __entry->long_free_dirty_all_txgs,
+ __entry->chunk_len, __entry->txg)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_FREE_LONG_RANGE_EVENT(name) \
+DEFINE_EVENT(zfs_free_long_range_class, name, \
+ TP_PROTO(uint64_t long_free_dirty_all_txgs, \
+ uint64_t chunk_len, uint64_t txg), \
+ TP_ARGS(long_free_dirty_all_txgs, chunk_len, txg))
+/* END CSTYLED */
+DEFINE_FREE_LONG_RANGE_EVENT(zfs_free__long__range);
+
+#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>
+
+#else
+
+DEFINE_DTRACE_PROBE3(delay__mintime);
+DEFINE_DTRACE_PROBE3(free__long__range);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_dnode.h b/include/os/linux/zfs/sys/trace_dnode.h
new file mode 100644
index 000000000000..27ad6cba16d6
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_dnode.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+#if 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, ...);
+ */
+/* BEGIN CSTYLED */
+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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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>
+
+#else
+
+DEFINE_DTRACE_PROBE3(dnode__move);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_multilist.h b/include/os/linux/zfs/sys/trace_multilist.h
new file mode 100644
index 000000000000..fe68d5296f73
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_multilist.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+#if 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 *, ...);
+ */
+/* BEGIN CSTYLED */
+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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#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))
+/* END CSTYLED */
+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>
+
+#else
+
+DEFINE_DTRACE_PROBE3(multilist__insert);
+DEFINE_DTRACE_PROBE3(multilist__remove);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_rrwlock.h b/include/os/linux/zfs/sys/trace_rrwlock.h
new file mode 100644
index 000000000000..4c74d6257309
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_rrwlock.h
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL)
+#if defined(HAVE_DECLARE_EVENT_CLASS)
+
+#else
+
+DEFINE_DTRACE_PROBE(zfs__rrwfastpath__rdmiss);
+DEFINE_DTRACE_PROBE(zfs__rrwfastpath__exitmiss);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_txg.h b/include/os/linux/zfs/sys/trace_txg.h
new file mode 100644
index 000000000000..23d5d358bc42
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_txg.h
@@ -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
+ */
+
+#if defined(_KERNEL)
+#if 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, ...);
+ */
+/* BEGIN CSTYLED */
+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)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_TXG_EVENT(name) \
+DEFINE_EVENT(zfs_txg_class, name, \
+ TP_PROTO(dsl_pool_t *dp, uint64_t txg), \
+ TP_ARGS(dp, txg))
+/* END CSTYLED */
+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>
+
+#else
+
+DEFINE_DTRACE_PROBE2(dsl_pool_sync__done);
+DEFINE_DTRACE_PROBE2(txg__quiescing);
+DEFINE_DTRACE_PROBE2(txg__opened);
+DEFINE_DTRACE_PROBE2(txg__syncing);
+DEFINE_DTRACE_PROBE2(txg__synced);
+DEFINE_DTRACE_PROBE2(txg__quiesced);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_vdev.h b/include/os/linux/zfs/sys/trace_vdev.h
new file mode 100644
index 000000000000..50711446ffa4
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_vdev.h
@@ -0,0 +1,140 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL)
+#if defined(HAVE_DECLARE_EVENT_CLASS)
+
+/*
+ * If tracepoints are available define dtrace_probe events for vdev
+ * related probes. Definitions in include/os/linux/spl/sys/trace.h
+ * will map DTRACE_PROBE* calls to tracepoints.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define TRACE_SYSTEM_VAR zfs_vdev
+
+#if !defined(_TRACE_VDEV_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_VDEV_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+
+/*
+ * Generic support for three argument tracepoints of the form:
+ *
+ * DTRACE_PROBE3(...,
+ * spa_t *, ...,
+ * uint64_t, ...,
+ * uint64_t, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_removing_class_3,
+ TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size),
+ TP_ARGS(spa, offset, size),
+ TP_STRUCT__entry(
+ __field(spa_t *, vdev_spa)
+ __field(uint64_t, vdev_offset)
+ __field(uint64_t, vdev_size)
+ ),
+ TP_fast_assign(
+ __entry->vdev_spa = spa;
+ __entry->vdev_offset = offset;
+ __entry->vdev_size = size;
+ ),
+ TP_printk("spa %p offset %llu size %llu",
+ __entry->vdev_spa, __entry->vdev_offset,
+ __entry->vdev_size)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_REMOVE_FREE_EVENT(name) \
+DEFINE_EVENT(zfs_removing_class_3, name, \
+ TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size), \
+ TP_ARGS(spa, offset, size))
+/* END CSTYLED */
+DEFINE_REMOVE_FREE_EVENT(zfs_remove__free__synced);
+DEFINE_REMOVE_FREE_EVENT(zfs_remove__free__unvisited);
+
+/*
+ * Generic support for four argument tracepoints of the form:
+ *
+ * DTRACE_PROBE4(...,
+ * spa_t *, ...,
+ * uint64_t, ...,
+ * uint64_t, ...,
+ * uint64_t, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_removing_class_4,
+ TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size, uint64_t txg),
+ TP_ARGS(spa, offset, size, txg),
+ TP_STRUCT__entry(
+ __field(spa_t *, vdev_spa)
+ __field(uint64_t, vdev_offset)
+ __field(uint64_t, vdev_size)
+ __field(uint64_t, vdev_txg)
+ ),
+ TP_fast_assign(
+ __entry->vdev_spa = spa;
+ __entry->vdev_offset = offset;
+ __entry->vdev_size = size;
+ __entry->vdev_txg = txg;
+ ),
+ TP_printk("spa %p offset %llu size %llu txg %llu",
+ __entry->vdev_spa, __entry->vdev_offset,
+ __entry->vdev_size, __entry->vdev_txg)
+);
+
+/* BEGIN CSTYLED */
+#define DEFINE_REMOVE_FREE_EVENT_TXG(name) \
+DEFINE_EVENT(zfs_removing_class_4, name, \
+ TP_PROTO(spa_t *spa, uint64_t offset, uint64_t size,uint64_t txg), \
+ TP_ARGS(spa, offset, size, txg))
+/* END CSTYLED */
+DEFINE_REMOVE_FREE_EVENT_TXG(zfs_remove__free__inflight);
+
+#endif /* _TRACE_VDEV_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH sys
+#define TRACE_INCLUDE_FILE trace_vdev
+#include <trace/define_trace.h>
+
+#else
+
+/*
+ * When tracepoints are not available, a DEFINE_DTRACE_PROBE* macro is
+ * needed for each DTRACE_PROBE. These will be used to generate stub
+ * tracing functions and prototypes for those functions. See
+ * include/os/linux/spl/sys/trace.h.
+ */
+
+DEFINE_DTRACE_PROBE3(remove__free__synced);
+DEFINE_DTRACE_PROBE3(remove__free__unvisited);
+DEFINE_DTRACE_PROBE4(remove__free__inflight);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_zfs.h b/include/os/linux/zfs/sys/trace_zfs.h
new file mode 100644
index 000000000000..0e19f8d186d0
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_zfs.h
@@ -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
+ */
+
+#ifndef _OS_LINUX_ZFS_TRACE_H
+#define _OS_LINUX_ZFS_TRACE_H
+
+#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/zfs_znode.h>
+#include <sys/zil_impl.h>
+#include <sys/zrlock.h>
+
+#include <sys/trace.h>
+#include <sys/trace_acl.h>
+#include <sys/trace_arc.h>
+#include <sys/trace_dbgmsg.h>
+#include <sys/trace_dbuf.h>
+#include <sys/trace_dmu.h>
+#include <sys/trace_dnode.h>
+#include <sys/trace_multilist.h>
+#include <sys/trace_rrwlock.h>
+#include <sys/trace_txg.h>
+#include <sys/trace_vdev.h>
+#include <sys/trace_zil.h>
+#include <sys/trace_zio.h>
+#include <sys/trace_zrlock.h>
+
+#endif
diff --git a/include/os/linux/zfs/sys/trace_zil.h b/include/os/linux/zfs/sys/trace_zil.h
new file mode 100644
index 000000000000..526846e664b2
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_zil.h
@@ -0,0 +1,229 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL)
+#if 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>
+
+#define 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_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_cur_used) \
+ __field(clock_t, zl_replay_time) \
+ __field(uint64_t, zl_replay_blks)
+
+#define ZILOG_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_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_cur_used = zilog->zl_cur_used; \
+ __entry->zl_replay_time = zilog->zl_replay_time; \
+ __entry->zl_replay_blks = zilog->zl_replay_blks;
+
+#define ZILOG_TP_PRINTK_FMT \
+ "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 logbias %u sync %u " \
+ "parse_error %u parse_blk_seq %llu parse_lr_seq %llu " \
+ "parse_blk_count %llu parse_lr_count %llu " \
+ "cur_used %llu replay_time %lu replay_blks %llu }"
+
+#define ZILOG_TP_PRINTK_ARGS \
+ __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_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_cur_used, \
+ __entry->zl_replay_time, __entry->zl_replay_blks
+
+#define ITX_TP_STRUCT_ENTRY \
+ __field(itx_wr_state_t, itx_wr_state) \
+ __field(uint8_t, itx_sync) \
+ __field(zil_callback_t, itx_callback) \
+ __field(void *, itx_callback_data) \
+ __field(uint64_t, itx_oid) \
+ \
+ __field(uint64_t, lrc_txtype) \
+ __field(uint64_t, lrc_reclen) \
+ __field(uint64_t, lrc_txg) \
+ __field(uint64_t, lrc_seq)
+
+#define ITX_TP_FAST_ASSIGN \
+ __entry->itx_wr_state = itx->itx_wr_state; \
+ __entry->itx_sync = itx->itx_sync; \
+ __entry->itx_callback = itx->itx_callback; \
+ __entry->itx_callback_data = itx->itx_callback_data; \
+ __entry->itx_oid = itx->itx_oid; \
+ \
+ __entry->lrc_txtype = itx->itx_lr.lrc_txtype; \
+ __entry->lrc_reclen = itx->itx_lr.lrc_reclen; \
+ __entry->lrc_txg = itx->itx_lr.lrc_txg; \
+ __entry->lrc_seq = itx->itx_lr.lrc_seq;
+
+#define ITX_TP_PRINTK_FMT \
+ "itx { wr_state %u sync %u callback %p callback_data %p oid %llu" \
+ " { txtype %llu reclen %llu txg %llu seq %llu } }"
+
+#define ITX_TP_PRINTK_ARGS \
+ __entry->itx_wr_state, __entry->itx_sync, __entry->itx_callback,\
+ __entry->itx_callback_data, __entry->itx_oid, \
+ __entry->lrc_txtype, __entry->lrc_reclen, __entry->lrc_txg, \
+ __entry->lrc_seq
+
+#define ZCW_TP_STRUCT_ENTRY \
+ __field(lwb_t *, zcw_lwb) \
+ __field(boolean_t, zcw_done) \
+ __field(int, zcw_zio_error) \
+
+#define ZCW_TP_FAST_ASSIGN \
+ __entry->zcw_lwb = zcw->zcw_lwb; \
+ __entry->zcw_done = zcw->zcw_done; \
+ __entry->zcw_zio_error = zcw->zcw_zio_error;
+
+#define ZCW_TP_PRINTK_FMT \
+ "zcw { lwb %p done %u error %u }"
+
+#define ZCW_TP_PRINTK_ARGS \
+ __entry->zcw_lwb, __entry->zcw_done, __entry->zcw_zio_error
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ * zilog_t *, ...,
+ * itx_t *, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_zil_process_itx_class,
+ TP_PROTO(zilog_t *zilog, itx_t *itx),
+ TP_ARGS(zilog, itx),
+ TP_STRUCT__entry(
+ ZILOG_TP_STRUCT_ENTRY
+ ITX_TP_STRUCT_ENTRY
+ ),
+ TP_fast_assign(
+ ZILOG_TP_FAST_ASSIGN
+ ITX_TP_FAST_ASSIGN
+ ),
+ TP_printk(
+ ZILOG_TP_PRINTK_FMT " " ITX_TP_PRINTK_FMT,
+ ZILOG_TP_PRINTK_ARGS, ITX_TP_PRINTK_ARGS)
+);
+/* END CSTYLED */
+
+/* BEGIN CSTYLED */
+#define DEFINE_ZIL_PROCESS_ITX_EVENT(name) \
+DEFINE_EVENT(zfs_zil_process_itx_class, name, \
+ TP_PROTO(zilog_t *zilog, itx_t *itx), \
+ TP_ARGS(zilog, itx))
+DEFINE_ZIL_PROCESS_ITX_EVENT(zfs_zil__process__commit__itx);
+DEFINE_ZIL_PROCESS_ITX_EVENT(zfs_zil__process__normal__itx);
+/* END CSTYLED */
+
+/*
+ * Generic support for two argument tracepoints of the form:
+ *
+ * DTRACE_PROBE2(...,
+ * zilog_t *, ...,
+ * zil_commit_waiter_t *, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_zil_commit_io_error_class,
+ TP_PROTO(zilog_t *zilog, zil_commit_waiter_t *zcw),
+ TP_ARGS(zilog, zcw),
+ TP_STRUCT__entry(
+ ZILOG_TP_STRUCT_ENTRY
+ ZCW_TP_STRUCT_ENTRY
+ ),
+ TP_fast_assign(
+ ZILOG_TP_FAST_ASSIGN
+ ZCW_TP_FAST_ASSIGN
+ ),
+ TP_printk(
+ ZILOG_TP_PRINTK_FMT " " ZCW_TP_PRINTK_FMT,
+ ZILOG_TP_PRINTK_ARGS, ZCW_TP_PRINTK_ARGS)
+);
+
+/* BEGIN CSTYLED */
+#define DEFINE_ZIL_COMMIT_IO_ERROR_EVENT(name) \
+DEFINE_EVENT(zfs_zil_commit_io_error_class, name, \
+ TP_PROTO(zilog_t *zilog, zil_commit_waiter_t *zcw), \
+ TP_ARGS(zilog, zcw))
+DEFINE_ZIL_COMMIT_IO_ERROR_EVENT(zfs_zil__commit__io__error);
+/* END CSTYLED */
+
+#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>
+
+#else
+
+DEFINE_DTRACE_PROBE2(zil__process__commit__itx);
+DEFINE_DTRACE_PROBE2(zil__process__normal__itx);
+DEFINE_DTRACE_PROBE2(zil__commit__io__error);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_zio.h b/include/os/linux/zfs/sys/trace_zio.h
new file mode 100644
index 000000000000..8655e245c043
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_zio.h
@@ -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
+ */
+
+#include <sys/list.h>
+
+#if defined(_KERNEL)
+#if defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define TRACE_SYSTEM_VAR zfs_zio
+
+#if !defined(_TRACE_ZIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ZIO_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+#include <sys/trace_common.h> /* For ZIO macros */
+
+/* BEGIN CSTYLED */
+TRACE_EVENT(zfs_zio__delay__miss,
+ TP_PROTO(zio_t *zio, hrtime_t now),
+ TP_ARGS(zio, now),
+ TP_STRUCT__entry(
+ ZIO_TP_STRUCT_ENTRY
+ __field(hrtime_t, now)
+ ),
+ TP_fast_assign(
+ ZIO_TP_FAST_ASSIGN
+ __entry->now = now;
+ ),
+ TP_printk("now %llu " ZIO_TP_PRINTK_FMT, __entry->now,
+ ZIO_TP_PRINTK_ARGS)
+);
+
+TRACE_EVENT(zfs_zio__delay__hit,
+ TP_PROTO(zio_t *zio, hrtime_t now, hrtime_t diff),
+ TP_ARGS(zio, now, diff),
+ TP_STRUCT__entry(
+ ZIO_TP_STRUCT_ENTRY
+ __field(hrtime_t, now)
+ __field(hrtime_t, diff)
+ ),
+ TP_fast_assign(
+ ZIO_TP_FAST_ASSIGN
+ __entry->now = now;
+ __entry->diff = diff;
+ ),
+ TP_printk("now %llu diff %llu " ZIO_TP_PRINTK_FMT, __entry->now,
+ __entry->diff, ZIO_TP_PRINTK_ARGS)
+);
+
+TRACE_EVENT(zfs_zio__delay__skip,
+ TP_PROTO(zio_t *zio),
+ TP_ARGS(zio),
+ TP_STRUCT__entry(ZIO_TP_STRUCT_ENTRY),
+ TP_fast_assign(ZIO_TP_FAST_ASSIGN),
+ TP_printk(ZIO_TP_PRINTK_FMT, ZIO_TP_PRINTK_ARGS)
+);
+/* END CSTYLED */
+
+#endif /* _TRACE_ZIO_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH sys
+#define TRACE_INCLUDE_FILE trace_zio
+#include <trace/define_trace.h>
+
+#else
+
+DEFINE_DTRACE_PROBE2(zio__delay__miss);
+DEFINE_DTRACE_PROBE3(zio__delay__hit);
+DEFINE_DTRACE_PROBE1(zio__delay__skip);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/trace_zrlock.h b/include/os/linux/zfs/sys/trace_zrlock.h
new file mode 100644
index 000000000000..23f9577ba15f
--- /dev/null
+++ b/include/os/linux/zfs/sys/trace_zrlock.h
@@ -0,0 +1,94 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#if defined(_KERNEL)
+#if 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, ...);
+ */
+/* BEGIN CSTYLED */
+DECLARE_EVENT_CLASS(zfs_zrlock_class,
+ TP_PROTO(zrlock_t *zrl, kthread_t *owner, uint32_t n),
+ TP_ARGS(zrl, owner, 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 = owner ? owner->pid : 0;
+ __entry->caller = zrl->zr_caller ? zrl->zr_caller : "(null)";
+#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
+);
+/* END_CSTYLED */
+
+#define DEFINE_ZRLOCK_EVENT(name) \
+DEFINE_EVENT(zfs_zrlock_class, name, \
+ TP_PROTO(zrlock_t *zrl, kthread_t *owner, uint32_t n), \
+ TP_ARGS(zrl, owner, 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>
+
+#else
+
+DEFINE_DTRACE_PROBE3(zrlock__reentry);
+
+#endif /* HAVE_DECLARE_EVENT_CLASS */
+#endif /* _KERNEL */
diff --git a/include/os/linux/zfs/sys/zfs_context_os.h b/include/os/linux/zfs/sys/zfs_context_os.h
new file mode 100644
index 000000000000..9e5fdd79f019
--- /dev/null
+++ b/include/os/linux/zfs/sys/zfs_context_os.h
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#ifndef ZFS_CONTEXT_OS_H
+#define ZFS_CONTEXT_OS_H
+
+#include <sys/uio_impl.h>
+#include <linux/dcache_compat.h>
+#include <linux/utsname_compat.h>
+
+#endif
diff --git a/include/os/linux/zfs/sys/zfs_ctldir.h b/include/os/linux/zfs/sys/zfs_ctldir.h
new file mode 100644
index 000000000000..51933bc4fe47
--- /dev/null
+++ b/include/os/linux/zfs/sys/zfs_ctldir.h
@@ -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 (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(zfsvfs_t *);
+extern void zfsctl_destroy(zfsvfs_t *);
+extern struct inode *zfsctl_root(znode_t *);
+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 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_snapdir_vget(struct super_block *sb, uint64_t objsetid,
+ int gen, struct inode **ipp);
+
+/* 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/include/os/linux/zfs/sys/zfs_dir.h b/include/os/linux/zfs/sys/zfs_dir.h
new file mode 100644
index 000000000000..0f15e43452b2
--- /dev/null
+++ b/include/os/linux/zfs/sys/zfs_dir.h
@@ -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 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 */
+#define IS_TMPFILE 0x04 /* create a tmpfile */
+
+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 *, znode_t **, 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(zfsvfs_t *zfsvfs);
+extern void zfs_unlinked_drain_stop_wait(zfsvfs_t *zfsvfs);
+extern int zfs_sticky_remove_access(znode_t *, znode_t *, cred_t *cr);
+extern int zfs_get_xattrdir(znode_t *, znode_t **, cred_t *, int);
+extern int zfs_make_xattrdir(znode_t *, vattr_t *, znode_t **, cred_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_DIR_H */
diff --git a/include/os/linux/zfs/sys/zfs_vfsops.h b/include/os/linux/zfs/sys/zfs_vfsops.h
new file mode 100644
index 000000000000..24a0a2e6a05f
--- /dev/null
+++ b/include/os/linux/zfs/sys/zfs_vfsops.h
@@ -0,0 +1,227 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_FS_ZFS_VFSOPS_H
+#define _SYS_FS_ZFS_VFSOPS_H
+
+#include <sys/dataset_kstats.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/dsl_dataset.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/objlist.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zfsvfs zfsvfs_t;
+struct znode;
+
+/*
+ * This structure emulates the vfs_t from other platforms. It's purpose
+ * is to facilitate the handling of mount options and minimize structural
+ * differences between the platforms.
+ */
+typedef struct vfs {
+ struct zfsvfs *vfs_data;
+ char *vfs_mntpoint; /* Primary mount point */
+ uint64_t vfs_xattr;
+ boolean_t vfs_readonly;
+ boolean_t vfs_do_readonly;
+ boolean_t vfs_setuid;
+ boolean_t vfs_do_setuid;
+ boolean_t vfs_exec;
+ boolean_t vfs_do_exec;
+ boolean_t vfs_devices;
+ boolean_t vfs_do_devices;
+ boolean_t vfs_do_xattr;
+ boolean_t vfs_atime;
+ boolean_t vfs_do_atime;
+ boolean_t vfs_relatime;
+ boolean_t vfs_do_relatime;
+ boolean_t vfs_nbmand;
+ boolean_t vfs_do_nbmand;
+} vfs_t;
+
+typedef struct zfs_mnt {
+ const char *mnt_osname; /* Objset name */
+ char *mnt_data; /* Raw mount options */
+} zfs_mnt_t;
+
+struct zfsvfs {
+ vfs_t *z_vfs; /* generic fs struct */
+ struct super_block *z_sb; /* generic super_block */
+ struct zfsvfs *z_parent; /* parent fs */
+ objset_t *z_os; /* objset reference */
+ 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_mode; /* acl chmod/mode behavior */
+ 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_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 deferral */
+ 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 */
+ boolean_t z_draining; /* is true when drain is active */
+ boolean_t z_drain_cancel; /* signal the unlinked drain to stop */
+ uint64_t z_version; /* ZPL version */
+ uint64_t z_shares_dir; /* hidden shares dir */
+ dataset_kstats_t z_kstat; /* fs kstats */
+ kmutex_t z_lock;
+ uint64_t z_userquota_obj;
+ uint64_t z_groupquota_obj;
+ uint64_t z_userobjquota_obj;
+ uint64_t z_groupobjquota_obj;
+ uint64_t z_projectquota_obj;
+ uint64_t z_projectobjquota_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 */
+ taskqid_t z_drain_task; /* task id for the unlink drain task */
+};
+
+#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 void zfs_init(void);
+extern void zfs_fini(void);
+
+extern int zfs_suspend_fs(zfsvfs_t *zfsvfs);
+extern int zfs_resume_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
+extern int zfs_end_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
+extern void zfs_exit_fs(zfsvfs_t *zfsvfs);
+extern int zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers);
+extern int zfsvfs_create(const char *name, boolean_t readony, zfsvfs_t **zfvp);
+extern int zfsvfs_create_impl(zfsvfs_t **zfvp, zfsvfs_t *zfsvfs, objset_t *os);
+extern void zfsvfs_free(zfsvfs_t *zfsvfs);
+extern int zfs_check_global_label(const char *dsname, const char *hexsl);
+
+extern boolean_t zfs_is_readonly(zfsvfs_t *zfsvfs);
+extern int zfs_domount(struct super_block *sb, zfs_mnt_t *zm, 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_mnt_t *zm);
+extern int zfs_statvfs(struct inode *ip, struct kstatfs *statp);
+extern int zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp);
+extern int zfs_prune(struct super_block *sb, unsigned long nr_to_scan,
+ int *objects);
+extern int zfs_get_temporary_prop(dsl_dataset_t *ds, zfs_prop_t zfs_prop,
+ uint64_t *val, char *setpoint);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_VFSOPS_H */
diff --git a/include/os/linux/zfs/sys/zfs_vnops.h b/include/os/linux/zfs/sys/zfs_vnops.h
new file mode 100644
index 000000000000..24a2082d35d6
--- /dev/null
+++ b/include/os/linux/zfs/sys/zfs_vnops.h
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (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>
+#include <sys/zfs_file.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_write_simple(znode_t *zp, const void *data, size_t len,
+ loff_t pos, size_t *resid);
+extern int zfs_access(struct inode *ip, int mode, int flag, cred_t *cr);
+extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp,
+ int flags, cred_t *cr, int *direntflags, pathname_t *realpnp);
+extern int zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl,
+ int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp);
+extern int zfs_tmpfile(struct inode *dip, vattr_t *vapzfs, int excl,
+ int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp);
+extern int zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags);
+extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap,
+ znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp);
+extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd,
+ cred_t *cr, int flags);
+extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr);
+extern int zfs_fsync(znode_t *zp, int syncflag, cred_t *cr);
+extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp);
+extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr);
+extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp,
+ char *tnm, cred_t *cr, int flags);
+extern int zfs_symlink(znode_t *dzp, char *name, vattr_t *vap,
+ char *link, znode_t **zpp, cred_t *cr, int flags);
+extern int zfs_readlink(struct inode *ip, uio_t *uio, cred_t *cr);
+extern int zfs_link(znode_t *tdzp, znode_t *szp,
+ char *name, cred_t *cr, int flags);
+extern void zfs_inactive(struct inode *ip);
+extern int zfs_space(znode_t *zp, 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(znode_t *zp, 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_zrele_async(znode_t *zp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_VNOPS_H */
diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h
new file mode 100644
index 000000000000..39bbd135ac06
--- /dev/null
+++ b/include/os/linux/zfs/sys/zfs_znode_impl.h
@@ -0,0 +1,168 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL 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, 2018 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_ZFS_ZNODE_IMPL_H
+#define _SYS_ZFS_ZNODE_IMPL_H
+
+#ifndef _KERNEL
+#error "no user serviceable parts within"
+#endif
+
+#include <sys/isa_defs.h>
+#include <sys/types32.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>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZNODE_OS_FIELDS \
+ struct inode z_inode;
+
+
+/*
+ * 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) ((zfsvfs_t *)(ZTOI(znode)->i_sb->s_fs_info))
+#define ITOZSB(inode) ((zfsvfs_t *)((inode)->i_sb->s_fs_info))
+
+#define ZTOTYPE(zp) (ZTOI(zp)->i_mode)
+#define ZTOGID(zp) (ZTOI(zp)->i_gid)
+#define ZTOUID(zp) (ZTOI(zp)->i_uid)
+#define ZTONLNK(zp) (ZTOI(zp)->i_nlink)
+
+#define Z_ISBLK(type) S_ISBLK(type)
+#define Z_ISCHR(type) S_ISCHR(type)
+#define Z_ISLNK(type) S_ISLNK(type)
+#define Z_ISDEV(type) (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type))
+
+#define zhold(zp) igrab(ZTOI((zp)))
+#define zrele(zp) iput(ZTOI((zp)))
+
+/* Called on entry to each ZFS inode and vfs operation. */
+#define ZFS_ENTER_ERROR(zfsvfs, error) \
+do { \
+ rrm_enter_read(&(zfsvfs)->z_teardown_lock, FTAG); \
+ if ((zfsvfs)->z_unmounted) { \
+ ZFS_EXIT(zfsvfs); \
+ return (error); \
+ } \
+} while (0)
+#define ZFS_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, EIO)
+#define ZPL_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, -EIO)
+
+/* Must be called before exiting the operation. */
+#define ZFS_EXIT(zfsvfs) \
+do { \
+ zfs_exit_fs(zfsvfs); \
+ rrm_exit(&(zfsvfs)->z_teardown_lock, FTAG); \
+} while (0)
+#define ZPL_EXIT(zfsvfs) ZFS_EXIT(zfsvfs)
+
+/* Verifies the znode is valid. */
+#define ZFS_VERIFY_ZP_ERROR(zp, error) \
+do { \
+ if ((zp)->z_sa_hdl == NULL) { \
+ ZFS_EXIT(ZTOZSB(zp)); \
+ return (error); \
+ } \
+} while (0)
+#define ZFS_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, EIO)
+#define ZPL_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, -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(zfsvfs, obj) ((obj) & ((zfsvfs->z_hold_size) - 1))
+
+extern unsigned int zfs_object_mutex_size;
+
+/*
+ * Encode ZFS stored time values from a struct timespec / struct timespec64.
+ */
+#define ZFS_TIME_ENCODE(tp, stmp) \
+do { \
+ (stmp)[0] = (uint64_t)(tp)->tv_sec; \
+ (stmp)[1] = (uint64_t)(tp)->tv_nsec; \
+} while (0)
+
+#if defined(HAVE_INODE_TIMESPEC64_TIMES)
+/*
+ * Decode ZFS stored time values to a struct timespec64
+ * 4.18 and newer kernels.
+ */
+#define ZFS_TIME_DECODE(tp, stmp) \
+do { \
+ (tp)->tv_sec = (time64_t)(stmp)[0]; \
+ (tp)->tv_nsec = (long)(stmp)[1]; \
+} while (0)
+#else
+/*
+ * Decode ZFS stored time values to a struct timespec
+ * 4.17 and older kernels.
+ */
+#define ZFS_TIME_DECODE(tp, stmp) \
+do { \
+ (tp)->tv_sec = (time_t)(stmp)[0]; \
+ (tp)->tv_nsec = (long)(stmp)[1]; \
+} while (0)
+#endif /* HAVE_INODE_TIMESPEC64_TIMES */
+
+struct znode;
+
+extern int zfs_sync(struct super_block *, int, cred_t *);
+extern int zfs_inode_alloc(struct super_block *, struct inode **ip);
+extern void zfs_inode_destroy(struct inode *);
+extern void zfs_inode_update(struct znode *);
+extern void zfs_mark_inode_dirty(struct inode *);
+extern boolean_t zfs_relatime_need_update(const struct inode *);
+
+#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;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_ZNODE_IMPL_H */
diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h
new file mode 100644
index 000000000000..ef5a0b842d09
--- /dev/null
+++ b/include/os/linux/zfs/sys/zpl.h
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (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/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,
+ 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);
+
+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)
+#if defined(HAVE_SET_ACL)
+extern int zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type);
+#endif /* HAVE_SET_ACL */
+extern struct posix_acl *zpl_get_acl(struct inode *ip, int type);
+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;
+extern const struct dentry_operations zpl_dops_snapdirs;
+
+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 ZPL_DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
+ .actor = _actor, \
+ .pos = _pos, \
+}
+
+typedef struct dir_context zpl_dir_context_t;
+
+#define zpl_dir_emit dir_emit
+#define zpl_dir_emit_dot dir_emit_dot
+#define zpl_dir_emit_dotdot dir_emit_dotdot
+#define zpl_dir_emit_dots dir_emit_dots
+
+#else
+
+typedef struct zpl_dir_context {
+ void *dirent;
+ const filldir_t actor;
+ loff_t pos;
+} zpl_dir_context_t;
+
+#define ZPL_DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
+ .dirent = _dirent, \
+ .actor = _actor, \
+ .pos = _pos, \
+}
+
+static inline bool
+zpl_dir_emit(zpl_dir_context_t *ctx, const char *name, int namelen,
+ uint64_t ino, unsigned type)
+{
+ return (!ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type));
+}
+
+static inline bool
+zpl_dir_emit_dot(struct file *file, zpl_dir_context_t *ctx)
+{
+ return (ctx->actor(ctx->dirent, ".", 1, ctx->pos,
+ file_inode(file)->i_ino, DT_DIR) == 0);
+}
+
+static inline bool
+zpl_dir_emit_dotdot(struct file *file, zpl_dir_context_t *ctx)
+{
+ return (ctx->actor(ctx->dirent, "..", 2, ctx->pos,
+ parent_ino(file_dentry(file)), DT_DIR) == 0);
+}
+
+static inline bool
+zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx)
+{
+ if (ctx->pos == 0) {
+ if (!zpl_dir_emit_dot(file, ctx))
+ return (false);
+ ctx->pos = 1;
+ }
+ if (ctx->pos == 1) {
+ if (!zpl_dir_emit_dotdot(file, ctx))
+ return (false);
+ ctx->pos = 2;
+ }
+ return (true);
+}
+#endif /* HAVE_VFS_ITERATE */
+
+#if defined(HAVE_INODE_TIMESTAMP_TRUNCATE)
+#define zpl_inode_timestamp_truncate(ts, ip) timestamp_truncate(ts, ip)
+#elif defined(HAVE_INODE_TIMESPEC64_TIMES)
+#define zpl_inode_timestamp_truncate(ts, ip) \
+ timespec64_trunc(ts, (ip)->i_sb->s_time_gran)
+#else
+#define zpl_inode_timestamp_truncate(ts, ip) \
+ timespec_trunc(ts, (ip)->i_sb->s_time_gran)
+#endif
+
+#endif /* _SYS_ZPL_H */