summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMichael Niewöhner <[email protected]>2020-08-18 19:10:17 +0200
committerBrian Behlendorf <[email protected]>2020-08-20 10:30:06 -0700
commit10b3c7f5e424f54b3ba82dbf1600d866e64ec0a0 (patch)
tree6d4debce2b3e4232411399e7dde1221a95af061a /include
parentdc544aba15758f7fbf55ef6a95ae8b93e241c533 (diff)
Add zstd support to zfs
This PR adds two new compression types, based on ZStandard: - zstd: A basic ZStandard compression algorithm Available compression. Levels for zstd are zstd-1 through zstd-19, where the compression increases with every level, but speed decreases. - zstd-fast: A faster version of the ZStandard compression algorithm zstd-fast is basically a "negative" level of zstd. The compression decreases with every level, but speed increases. Available compression levels for zstd-fast: - zstd-fast-1 through zstd-fast-10 - zstd-fast-20 through zstd-fast-100 (in increments of 10) - zstd-fast-500 and zstd-fast-1000 For more information check the man page. Implementation details: Rather than treat each level of zstd as a different algorithm (as was done historically with gzip), the block pointer `enum zio_compress` value is simply zstd for all levels, including zstd-fast, since they all use the same decompression function. The compress= property (a 64bit unsigned integer) uses the lower 7 bits to store the compression algorithm (matching the number of bits used in a block pointer, as the 8th bit was borrowed for embedded block pointers). The upper bits are used to store the compression level. It is necessary to be able to determine what compression level was used when later reading a block back, so the concept used in LZ4, where the first 32bits of the on-disk value are the size of the compressed data (since the allocation is rounded up to the nearest ashift), was extended, and we store the version of ZSTD and the level as well as the compressed size. This value is returned when decompressing a block, so that if the block needs to be recompressed (L2ARC, nop-write, etc), that the same parameters will be used to result in the matching checksum. All of the internal ZFS code ( `arc_buf_hdr_t`, `objset_t`, `zio_prop_t`, etc.) uses the separated _compress and _complevel variables. Only the properties ZAP contains the combined/bit-shifted value. The combined value is split when the compression_changed_cb() callback is called, and sets both objset members (os_compress and os_complevel). The userspace tools all use the combined/bit-shifted value. Additional notes: zdb can now also decode the ZSTD compression header (flag -Z) and inspect the size, version and compression level saved in that header. For each record, if it is ZSTD compressed, the parameters of the decoded compression header get printed. ZSTD is included with all current tests and new tests are added as-needed. Per-dataset feature flags now get activated when the property is set. If a compression algorithm requires a feature flag, zfs activates the feature when the property is set, rather than waiting for the first block to be born. This is currently only used by zstd but can be extended as needed. Portions-Sponsored-By: The FreeBSD Foundation Co-authored-by: Allan Jude <[email protected]> Co-authored-by: Brian Behlendorf <[email protected]> Co-authored-by: Sebastian Gottschall <[email protected]> Co-authored-by: Kjeld Schouten-Lebbing <[email protected]> Co-authored-by: Michael Niewöhner <[email protected]> Signed-off-by: Allan Jude <[email protected]> Signed-off-by: Allan Jude <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Signed-off-by: Sebastian Gottschall <[email protected]> Signed-off-by: Kjeld Schouten-Lebbing <[email protected]> Signed-off-by: Michael Niewöhner <[email protected]> Closes #6247 Closes #9024 Closes #10277 Closes #10278
Diffstat (limited to 'include')
-rw-r--r--include/sys/Makefile.am2
-rw-r--r--include/sys/arc.h12
-rw-r--r--include/sys/arc_impl.h6
-rw-r--r--include/sys/dmu_objset.h1
-rw-r--r--include/sys/dsl_dataset.h2
-rw-r--r--include/sys/spa.h3
-rw-r--r--include/sys/zfs_context.h6
-rw-r--r--include/sys/zfs_ioctl.h5
-rw-r--r--include/sys/zio.h15
-rw-r--r--include/sys/zio_compress.h81
-rw-r--r--include/sys/zio_impl.h6
-rw-r--r--include/sys/zstd/Makefile.am18
-rw-r--r--include/sys/zstd/zstd.h98
-rw-r--r--include/zfeature_common.h1
14 files changed, 242 insertions, 14 deletions
diff --git a/include/sys/Makefile.am b/include/sys/Makefile.am
index cbe21b791..c2bc3be03 100644
--- a/include/sys/Makefile.am
+++ b/include/sys/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = fm fs crypto lua sysevent
+SUBDIRS = fm fs crypto lua sysevent zstd
COMMON_H = \
abd.h \
diff --git a/include/sys/arc.h b/include/sys/arc.h
index 3fdf36e2a..a0852b4d5 100644
--- a/include/sys/arc.h
+++ b/include/sys/arc.h
@@ -22,6 +22,8 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2019, Klara Inc.
*/
#ifndef _SYS_ARC_H
@@ -252,18 +254,20 @@ void arc_convert_to_raw(arc_buf_t *buf, uint64_t dsobj, boolean_t byteorder,
arc_buf_t *arc_alloc_buf(spa_t *spa, void *tag, arc_buf_contents_t type,
int32_t size);
arc_buf_t *arc_alloc_compressed_buf(spa_t *spa, void *tag,
- uint64_t psize, uint64_t lsize, enum zio_compress compression_type);
+ uint64_t psize, uint64_t lsize, enum zio_compress compression_type,
+ uint8_t complevel);
arc_buf_t *arc_alloc_raw_buf(spa_t *spa, void *tag, uint64_t dsobj,
boolean_t byteorder, const uint8_t *salt, const uint8_t *iv,
const uint8_t *mac, dmu_object_type_t ot, uint64_t psize, uint64_t lsize,
- enum zio_compress compression_type);
+ enum zio_compress compression_type, uint8_t complevel);
+uint8_t arc_get_complevel(arc_buf_t *buf);
arc_buf_t *arc_loan_buf(spa_t *spa, boolean_t is_metadata, int size);
arc_buf_t *arc_loan_compressed_buf(spa_t *spa, uint64_t psize, uint64_t lsize,
- enum zio_compress compression_type);
+ enum zio_compress compression_type, uint8_t complevel);
arc_buf_t *arc_loan_raw_buf(spa_t *spa, uint64_t dsobj, boolean_t byteorder,
const uint8_t *salt, const uint8_t *iv, const uint8_t *mac,
dmu_object_type_t ot, uint64_t psize, uint64_t lsize,
- enum zio_compress compression_type);
+ enum zio_compress compression_type, uint8_t complevel);
void arc_return_buf(arc_buf_t *buf, void *tag);
void arc_loan_inuse_buf(arc_buf_t *buf, void *tag);
void arc_buf_destroy(arc_buf_t *buf, void *tag);
diff --git a/include/sys/arc_impl.h b/include/sys/arc_impl.h
index d07791d07..9051fd2bf 100644
--- a/include/sys/arc_impl.h
+++ b/include/sys/arc_impl.h
@@ -269,12 +269,13 @@ typedef struct l2arc_log_ent_phys {
*/
uint64_t le_prop;
uint64_t le_daddr; /* buf location on l2dev */
+ uint64_t le_complevel;
/*
* We pad the size of each entry to a power of 2 so that the size of
* l2arc_log_blk_phys_t is power-of-2 aligned with SPA_MINBLOCKSHIFT,
* because of the L2ARC_SET_*SIZE macros.
*/
- const uint64_t le_pad[3]; /* pad to 64 bytes */
+ const uint64_t le_pad[2]; /* pad to 64 bytes */
} l2arc_log_ent_phys_t;
#define L2ARC_LOG_BLK_MAX_ENTRIES (1022)
@@ -460,6 +461,9 @@ struct arc_buf_hdr {
uint64_t b_birth;
arc_buf_contents_t b_type;
+ uint8_t b_complevel;
+ uint8_t b_reserved1; /* used for 4 byte alignment */
+ uint16_t b_reserved2; /* used for 4 byte alignment */
arc_buf_hdr_t *b_hash_next;
arc_flags_t b_flags;
diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h
index a77131ef1..1af69832c 100644
--- a/include/sys/dmu_objset.h
+++ b/include/sys/dmu_objset.h
@@ -118,6 +118,7 @@ struct objset {
uint64_t os_dnodesize; /* default dnode size for new objects */
enum zio_checksum os_checksum;
enum zio_compress os_compress;
+ uint8_t os_complevel;
uint8_t os_copies;
enum zio_checksum os_dedup_checksum;
boolean_t os_dedup_verify;
diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h
index 90cb68927..f5816a934 100644
--- a/include/sys/dsl_dataset.h
+++ b/include/sys/dsl_dataset.h
@@ -435,6 +435,8 @@ int dsl_dataset_set_refquota(const char *dsname, zprop_source_t source,
uint64_t quota);
int dsl_dataset_set_refreservation(const char *dsname, zprop_source_t source,
uint64_t reservation);
+int dsl_dataset_set_compression(const char *dsname, zprop_source_t source,
+ uint64_t compression);
boolean_t dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
uint64_t earlier_txg);
diff --git a/include/sys/spa.h b/include/sys/spa.h
index 67de57980..e53d0d64c 100644
--- a/include/sys/spa.h
+++ b/include/sys/spa.h
@@ -28,6 +28,8 @@
* Copyright 2017 Joyent, Inc.
* Copyright (c) 2017, 2019, Datto Inc. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
+ * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2019, Klara Inc.
*/
#ifndef _SYS_SPA_H
@@ -120,6 +122,7 @@ struct dsl_crypto_params;
#define SPA_COMPRESSBITS 7
#define SPA_VDEVBITS 24
+#define SPA_COMPRESSMASK ((1U << SPA_COMPRESSBITS) - 1)
/*
* All SPA data is represented by 128-bit data virtual addresses (DVAs).
diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h
index 0d41941dd..16df302c8 100644
--- a/include/sys/zfs_context.h
+++ b/include/sys/zfs_context.h
@@ -748,6 +748,12 @@ extern int kmem_cache_reap_active(void);
#define ____cacheline_aligned
+/*
+ * Kernel modules
+ */
+#define __init
+#define __exit
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/include/sys/zfs_ioctl.h b/include/sys/zfs_ioctl.h
index bfaf81038..136075a1f 100644
--- a/include/sys/zfs_ioctl.h
+++ b/include/sys/zfs_ioctl.h
@@ -105,7 +105,7 @@ typedef enum drr_headertype {
#define DMU_BACKUP_FEATURE_COMPRESSED (1 << 22)
#define DMU_BACKUP_FEATURE_LARGE_DNODE (1 << 23)
#define DMU_BACKUP_FEATURE_RAW (1 << 24)
-/* flag #25 is reserved for the ZSTD compression feature */
+#define DMU_BACKUP_FEATURE_ZSTD (1 << 25)
#define DMU_BACKUP_FEATURE_HOLDS (1 << 26)
/*
* The SWITCH_TO_LARGE_BLOCKS feature indicates that we can receive
@@ -132,7 +132,8 @@ typedef enum drr_headertype {
DMU_BACKUP_FEATURE_RESUMING | DMU_BACKUP_FEATURE_LARGE_BLOCKS | \
DMU_BACKUP_FEATURE_COMPRESSED | DMU_BACKUP_FEATURE_LARGE_DNODE | \
DMU_BACKUP_FEATURE_RAW | DMU_BACKUP_FEATURE_HOLDS | \
- DMU_BACKUP_FEATURE_REDACTED | DMU_BACKUP_FEATURE_SWITCH_TO_LARGE_BLOCKS)
+ DMU_BACKUP_FEATURE_REDACTED | DMU_BACKUP_FEATURE_SWITCH_TO_LARGE_BLOCKS | \
+ DMU_BACKUP_FEATURE_ZSTD)
/* Are all features in the given flag word currently supported? */
#define DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK))
diff --git a/include/sys/zio.h b/include/sys/zio.h
index dc4942a5d..f3b5a1207 100644
--- a/include/sys/zio.h
+++ b/include/sys/zio.h
@@ -26,6 +26,9 @@
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright 2016 Toomas Soome <[email protected]>
+ * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2019, Klara Inc.
+ * Copyright (c) 2019-2020, Michael Niewöhner
*/
#ifndef _ZIO_H
@@ -156,9 +159,18 @@ enum zio_encrypt {
(compress) == ZIO_COMPRESS_GZIP_8 || \
(compress) == ZIO_COMPRESS_GZIP_9 || \
(compress) == ZIO_COMPRESS_ZLE || \
+ (compress) == ZIO_COMPRESS_ZSTD || \
(compress) == ZIO_COMPRESS_ON || \
(compress) == ZIO_COMPRESS_OFF)
+
+#define ZIO_COMPRESS_ALGO(x) (x & SPA_COMPRESSMASK)
+#define ZIO_COMPRESS_LEVEL(x) ((x & ~SPA_COMPRESSMASK) >> SPA_COMPRESSBITS)
+#define ZIO_COMPRESS_RAW(type, level) (type | ((level) << SPA_COMPRESSBITS))
+
+#define ZIO_COMPLEVEL_ZSTD(level) \
+ ZIO_COMPRESS_RAW(ZIO_COMPRESS_ZSTD, level)
+
#define ZIO_FAILURE_MODE_WAIT 0
#define ZIO_FAILURE_MODE_CONTINUE 1
#define ZIO_FAILURE_MODE_PANIC 2
@@ -329,6 +341,7 @@ struct zbookmark_phys {
typedef struct zio_prop {
enum zio_checksum zp_checksum;
enum zio_compress zp_compress;
+ uint8_t zp_complevel;
dmu_object_type_t zp_type;
uint8_t zp_level;
uint8_t zp_copies;
@@ -627,6 +640,8 @@ extern enum zio_checksum zio_checksum_dedup_select(spa_t *spa,
enum zio_checksum child, enum zio_checksum parent);
extern enum zio_compress zio_compress_select(spa_t *spa,
enum zio_compress child, enum zio_compress parent);
+extern uint8_t zio_complevel_select(spa_t *spa, enum zio_compress compress,
+ uint8_t child, uint8_t parent);
extern void zio_suspend(spa_t *spa, zio_t *zio, zio_suspend_reason_t);
extern int zio_resume(spa_t *spa);
diff --git a/include/sys/zio_compress.h b/include/sys/zio_compress.h
index 208117eee..4a22ad2a2 100644
--- a/include/sys/zio_compress.h
+++ b/include/sys/zio_compress.h
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2019, Klara Inc.
* Use is subject to license terms.
* Copyright (c) 2015, 2016 by Delphix. All rights reserved.
*/
@@ -51,15 +53,86 @@ enum zio_compress {
ZIO_COMPRESS_GZIP_9,
ZIO_COMPRESS_ZLE,
ZIO_COMPRESS_LZ4,
+ ZIO_COMPRESS_ZSTD,
ZIO_COMPRESS_FUNCTIONS
};
+/* Compression algorithms that have levels */
+#define ZIO_COMPRESS_HASLEVEL(compress) ((compress == ZIO_COMPRESS_ZSTD || \
+ (compress >= ZIO_COMPRESS_GZIP_1 && \
+ compress <= ZIO_COMPRESS_GZIP_9)))
+
+#define ZIO_COMPLEVEL_INHERIT 0
+#define ZIO_COMPLEVEL_DEFAULT 255
+
+enum zio_zstd_levels {
+ ZIO_ZSTD_LEVEL_INHERIT = 0,
+ ZIO_ZSTD_LEVEL_1,
+#define ZIO_ZSTD_LEVEL_MIN ZIO_ZSTD_LEVEL_1
+ ZIO_ZSTD_LEVEL_2,
+ ZIO_ZSTD_LEVEL_3,
+#define ZIO_ZSTD_LEVEL_DEFAULT ZIO_ZSTD_LEVEL_3
+ ZIO_ZSTD_LEVEL_4,
+ ZIO_ZSTD_LEVEL_5,
+ ZIO_ZSTD_LEVEL_6,
+ ZIO_ZSTD_LEVEL_7,
+ ZIO_ZSTD_LEVEL_8,
+ ZIO_ZSTD_LEVEL_9,
+ ZIO_ZSTD_LEVEL_10,
+ ZIO_ZSTD_LEVEL_11,
+ ZIO_ZSTD_LEVEL_12,
+ ZIO_ZSTD_LEVEL_13,
+ ZIO_ZSTD_LEVEL_14,
+ ZIO_ZSTD_LEVEL_15,
+ ZIO_ZSTD_LEVEL_16,
+ ZIO_ZSTD_LEVEL_17,
+ ZIO_ZSTD_LEVEL_18,
+ ZIO_ZSTD_LEVEL_19,
+#define ZIO_ZSTD_LEVEL_MAX ZIO_ZSTD_LEVEL_19
+ ZIO_ZSTD_LEVEL_RESERVE = 101, /* Leave room for new positive levels */
+ ZIO_ZSTD_LEVEL_FAST, /* Fast levels are negative */
+ ZIO_ZSTD_LEVEL_FAST_1,
+#define ZIO_ZSTD_LEVEL_FAST_DEFAULT ZIO_ZSTD_LEVEL_FAST_1
+ ZIO_ZSTD_LEVEL_FAST_2,
+ ZIO_ZSTD_LEVEL_FAST_3,
+ ZIO_ZSTD_LEVEL_FAST_4,
+ ZIO_ZSTD_LEVEL_FAST_5,
+ ZIO_ZSTD_LEVEL_FAST_6,
+ ZIO_ZSTD_LEVEL_FAST_7,
+ ZIO_ZSTD_LEVEL_FAST_8,
+ ZIO_ZSTD_LEVEL_FAST_9,
+ ZIO_ZSTD_LEVEL_FAST_10,
+ ZIO_ZSTD_LEVEL_FAST_20,
+ ZIO_ZSTD_LEVEL_FAST_30,
+ ZIO_ZSTD_LEVEL_FAST_40,
+ ZIO_ZSTD_LEVEL_FAST_50,
+ ZIO_ZSTD_LEVEL_FAST_60,
+ ZIO_ZSTD_LEVEL_FAST_70,
+ ZIO_ZSTD_LEVEL_FAST_80,
+ ZIO_ZSTD_LEVEL_FAST_90,
+ ZIO_ZSTD_LEVEL_FAST_100,
+ ZIO_ZSTD_LEVEL_FAST_500,
+ ZIO_ZSTD_LEVEL_FAST_1000,
+#define ZIO_ZSTD_LEVEL_FAST_MAX ZIO_ZSTD_LEVEL_FAST_1000
+ ZIO_ZSTD_LEVEL_AUTO = 251, /* Reserved for future use */
+ ZIO_ZSTD_LEVEL_LEVELS
+};
+
+/* Forward Declaration to avoid visibility problems */
+struct zio_prop;
+
/* Common signature for all zio compress functions. */
typedef size_t zio_compress_func_t(void *src, void *dst,
size_t s_len, size_t d_len, int);
/* Common signature for all zio decompress functions. */
typedef int zio_decompress_func_t(void *src, void *dst,
size_t s_len, size_t d_len, int);
+/* Common signature for all zio decompress and get level functions. */
+typedef int zio_decompresslevel_func_t(void *src, void *dst,
+ size_t s_len, size_t d_len, uint8_t *level);
+/* Common signature for all zio get-compression-level functions. */
+typedef int zio_getlevel_func_t(void *src, size_t s_len, uint8_t *level);
+
/*
* Common signature for all zio decompress functions using an ABD as input.
@@ -76,6 +149,7 @@ typedef const struct zio_compress_info {
int ci_level;
zio_compress_func_t *ci_compress;
zio_decompress_func_t *ci_decompress;
+ zio_decompresslevel_func_t *ci_decompress_level;
} zio_compress_info_t;
extern zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS];
@@ -110,11 +184,12 @@ extern int lz4_decompress_zfs(void *src, void *dst, size_t s_len, size_t d_len,
* Compress and decompress data if necessary.
*/
extern size_t zio_compress_data(enum zio_compress c, abd_t *src, void *dst,
- size_t s_len);
+ size_t s_len, uint8_t level);
extern int zio_decompress_data(enum zio_compress c, abd_t *src, void *dst,
- size_t s_len, size_t d_len);
+ size_t s_len, size_t d_len, uint8_t *level);
extern int zio_decompress_data_buf(enum zio_compress c, void *src, void *dst,
- size_t s_len, size_t d_len);
+ size_t s_len, size_t d_len, uint8_t *level);
+extern int zio_compress_to_feature(enum zio_compress comp);
#ifdef __cplusplus
}
diff --git a/include/sys/zio_impl.h b/include/sys/zio_impl.h
index 8ca124631..4c9985716 100644
--- a/include/sys/zio_impl.h
+++ b/include/sys/zio_impl.h
@@ -73,9 +73,9 @@ extern "C" {
* the supported transformations:
*
* Compression:
- * ZFS supports three different flavors of compression -- gzip, lzjb, and
- * zle. Compression occurs as part of the write pipeline and is performed
- * in the ZIO_STAGE_WRITE_BP_INIT stage.
+ * ZFS supports five different flavors of compression -- gzip, lzjb, lz4, zle,
+ * and zstd. Compression occurs as part of the write pipeline and is
+ * performed in the ZIO_STAGE_WRITE_BP_INIT stage.
*
* Dedup:
* Dedup reads are handled by the ZIO_STAGE_DDT_READ_START and
diff --git a/include/sys/zstd/Makefile.am b/include/sys/zstd/Makefile.am
new file mode 100644
index 000000000..16666fe63
--- /dev/null
+++ b/include/sys/zstd/Makefile.am
@@ -0,0 +1,18 @@
+COMMON_H = \
+ $(top_srcdir)/include/sys/zstd/zstd.h
+
+KERNEL_H =
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys/zstd
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/zstd
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/include/sys/zstd/zstd.h b/include/sys/zstd/zstd.h
new file mode 100644
index 000000000..db1f27716
--- /dev/null
+++ b/include/sys/zstd/zstd.h
@@ -0,0 +1,98 @@
+/*
+ * BSD 3-Clause New License (https://spdx.org/licenses/BSD-3-Clause.html)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2016-2018, Klara Inc.
+ * Copyright (c) 2016-2018, Allan Jude
+ * Copyright (c) 2018-2020, Sebastian Gottschall
+ * Copyright (c) 2019-2020, Michael Niewöhner
+ * Copyright (c) 2020, The FreeBSD Foundation [1]
+ *
+ * [1] Portions of this software were developed by Allan Jude
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#ifndef _ZFS_ZSTD_H
+#define _ZFS_ZSTD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ZSTD block header
+ * NOTE: all fields in this header are in big endian order.
+ */
+typedef struct zfs_zstd_header {
+ /* Compressed size of data */
+ uint32_t c_len;
+
+ /*
+ * Version and compression level
+ * We use a union to be able to big endian encode a single 32 bit
+ * unsigned integer, but still access the individual bitmasked
+ * components easily.
+ */
+ union {
+ uint32_t raw_version_level;
+ struct {
+ uint32_t version : 24;
+ uint8_t level;
+ };
+ };
+
+ char data[];
+} zfs_zstdhdr_t;
+
+/*
+ * kstat helper macros
+ */
+#define ZSTDSTAT(stat) (zstd_stats.stat.value.ui64)
+#define ZSTDSTAT_INCR(stat, val) \
+ atomic_add_64(&zstd_stats.stat.value.ui64, (val))
+#define ZSTDSTAT_BUMP(stat) ZSTDSTAT_INCR(stat, 1)
+
+/* (de)init for user space / kernel emulation */
+int zstd_init(void);
+void zstd_fini(void);
+
+size_t zstd_compress(void *s_start, void *d_start, size_t s_len, size_t d_len,
+ int level);
+int zstd_get_level(void *s_start, size_t s_len, uint8_t *level);
+int zstd_decompress_level(void *s_start, void *d_start, size_t s_len,
+ size_t d_len, uint8_t *level);
+int zstd_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len,
+ int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_ZSTD_H */
diff --git a/include/zfeature_common.h b/include/zfeature_common.h
index 7e19a62e2..db0138ae8 100644
--- a/include/zfeature_common.h
+++ b/include/zfeature_common.h
@@ -75,6 +75,7 @@ typedef enum spa_feature {
SPA_FEATURE_LOG_SPACEMAP,
SPA_FEATURE_LIVELIST,
SPA_FEATURE_DEVICE_REBUILD,
+ SPA_FEATURE_ZSTD_COMPRESS,
SPA_FEATURES
} spa_feature_t;