Page MenuHomeFreeBSD

D11124.id45344.diff
No OneTemporary

D11124.id45344.diff

Index: Makefile.inc1
===================================================================
--- Makefile.inc1
+++ Makefile.inc1
@@ -2529,7 +2529,7 @@
lib/libufs \
lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \
${_secure_lib_libcrypto} ${_lib_libldns} \
- ${_secure_lib_libssh} ${_secure_lib_libssl}
+ ${_secure_lib_libssh} ${_secure_lib_libssl} lib/libzstd
.if ${MK_GNUCXX} != "no"
_prebuild_libs+= gnu/lib/libstdc++ gnu/lib/libsupc++
Index: cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
===================================================================
--- cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
+++ cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
@@ -590,6 +590,52 @@
once all filesystems that have ever had their checksum set to
.Sy skein
are destroyed.
+.It Sy zstd_compress
+.Bl -column "READ\-ONLY COMPATIBLE" "org.freebsd:zstd_compress"
+.It GUID Ta org.freebsd:zstd_compress
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta none
+.El
+.Pp
+.Sy zstd
+is a high-performance compression algorithm that features a combination
+of high compression ratios and high speed.
+Compared to
+.Sy gzip ,
+.Sy zstd
+offers slighty better compression at much higher speeds.
+Compared to
+.Sy lz4 ,
+.Sy zstd
+offers much better compression while being only modestly slower.
+Typically,
+.Sy zstd
+compression speed is approximately 250 megabytes/second/thread, and
+decompression speed is 1 gigabyte/second/thread.
+Booting off of
+.Sy zstd Ns
+-compressed root pools is supported.
+.Pp
+When the
+.Sy zstd
+feature is set to
+.Sy enabled ,
+the administrator can turn on
+.Sy zstd
+compression of any dataset using the
+.Dl # zfs set compress=zstd Ar dataset
+command.
+This feature becomes
+.Sy active
+once a
+.Sy compress
+property has been set to
+.Sy zstd ,
+and will return to being
+.Sy enabled
+once all filesystems that have ever had their compress property set to
+.Sy zstd
+are destroyed.
.El
.Sh SEE ALSO
.Xr zpool 8
Index: cddl/lib/libzfs/Makefile
===================================================================
--- cddl/lib/libzfs/Makefile
+++ cddl/lib/libzfs/Makefile
@@ -7,7 +7,7 @@
.PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libcmdutils/common
LIB= zfs
-LIBADD= md pthread umem util uutil m avl bsdxml geom nvpair z zfs_core
+LIBADD= md pthread umem util uutil m avl bsdxml geom nvpair z zfs_core zstd
SRCS= deviceid.c \
fsshare.c \
mkdirp.c \
Index: cddl/lib/libzpool/Makefile
===================================================================
--- cddl/lib/libzpool/Makefile
+++ cddl/lib/libzpool/Makefile
@@ -62,8 +62,10 @@
CFLAGS+= -I${SRCTOP}/lib/libpthread/thread
CFLAGS+= -I${SRCTOP}/lib/libpthread/sys
CFLAGS+= -I${SRCTOP}/lib/libthr/arch/${MACHINE_CPUARCH}/include
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib/common
-LIBADD= md pthread z nvpair avl umem
+LIBADD= md pthread z nvpair avl umem zstd
# atomic.S doesn't like profiling.
MK_PROFILE= no
Index: rescue/rescue/Makefile
===================================================================
--- rescue/rescue/Makefile
+++ rescue/rescue/Makefile
@@ -126,7 +126,7 @@
CRUNCH_LIBS+= -l80211 -lalias -lcam -lncursesw -ldevstat -lipsec -llzma
.if ${MK_ZFS} != "no"
-CRUNCH_LIBS+= -lavl -lzpool -lzfs_core -lzfs -lnvpair -lpthread -luutil -lumem
+CRUNCH_LIBS+= -lavl -lzpool -lzfs_core -lzfs -lnvpair -lpthread -luutil -lumem -lprivatezstd
.else
# liblzma needs pthread
CRUNCH_LIBS+= -lpthread
Index: share/mk/src.libnames.mk
===================================================================
--- share/mk/src.libnames.mk
+++ share/mk/src.libnames.mk
@@ -332,9 +332,9 @@
_DP_fifolog= z
_DP_ipf= kvm
_DP_zfs= md pthread umem util uutil m nvpair avl bsdxml geom nvpair z \
- zfs_core
+ zfs_core zstd
_DP_zfs_core= nvpair
-_DP_zpool= md pthread z nvpair avl umem
+_DP_zpool= md pthread z nvpair avl umem zstd
# OFED support
.if ${MK_OFED} != "no"
Index: stand/efi/boot1/Makefile
===================================================================
--- stand/efi/boot1/Makefile
+++ stand/efi/boot1/Makefile
@@ -29,6 +29,7 @@
CFLAGS.zfs_module.c+= -I${ZFSSRC}
CFLAGS.zfs_module.c+= -I${SYSDIR}/cddl/boot/zfs
CFLAGS.zfs_module.c+= -I${SYSDIR}/crypto/skein
+CFLAGS+= -I${SYSDIR}/contrib/zstd/lib
CFLAGS+= -DEFI_ZFS_BOOT
.endif
Index: stand/efi/boot1/boot1.c
===================================================================
--- stand/efi/boot1/boot1.c
+++ stand/efi/boot1/boot1.c
@@ -71,6 +71,18 @@
return (NULL);
}
+void *
+Calloc(size_t number, size_t len, const char *file __unused, int line __unused)
+{
+ uintptr_t bytes = (uintptr_t)number * (uintptr_t)len;
+ void *out;
+
+ if ((out = Malloc(bytes, file, line)) != NULL)
+ bzero(out, bytes);
+
+ return(out);
+}
+
void
Free(void *buf, const char *file __unused, int line __unused)
{
Index: stand/i386/gptzfsboot/Makefile
===================================================================
--- stand/i386/gptzfsboot/Makefile
+++ stand/i386/gptzfsboot/Makefile
@@ -30,6 +30,7 @@
-I${ZFSSRC} \
-I${SYSDIR}/crypto/skein \
-I${SYSDIR}/cddl/boot/zfs \
+ -I${SYSDIR}/contrib/zstd/lib \
-I${BOOTSRC}/i386/btx/lib \
-I${BOOTSRC}/i386/boot2 \
-Wall -Waggregate-return -Wbad-function-cast \
Index: stand/i386/zfsboot/Makefile
===================================================================
--- stand/i386/zfsboot/Makefile
+++ stand/i386/zfsboot/Makefile
@@ -29,6 +29,7 @@
-I${ZFSSRC} \
-I${SYSDIR}/crypto/skein \
-I${SYSDIR}/cddl/boot/zfs \
+ -I${SYSDIR}/contrib/zstd/lib \
-I${BOOTSRC}/i386/boot2 \
-Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
Index: stand/libsa/Makefile
===================================================================
--- stand/libsa/Makefile
+++ stand/libsa/Makefile
@@ -85,6 +85,31 @@
.PATH: ${SASRC}/${LIBSA_CPUARCH}
SRCS+= _setjmp.S
+# decompression functionality from libzstd
+.PATH: ${SRCTOP}/sys/contrib/zstd/lib
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib
+.PATH: ${SRCTOP}/sys/contrib/zstd/lib/common
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib/common
+.PATH: ${SRCTOP}/sys/contrib/zstd/lib/compress
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib/compress
+.PATH: ${SRCTOP}/sys/contrib/zstd/lib/decompress
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib/decompress
+.for file in zstd_common.c fse_decompress.c entropy_common.c error_private.c \
+ xxhash.c zstd_compress.c fse_compress.c huf_compress.c \
+ zstd_double_fast.c zstd_fast.c zstd_lazy.c zstd_ldm.c zstd_opt.c \
+ zstd_decompress.c huf_decompress.c
+SRCS+= _${file}
+CLEANFILES+= _${file}
+
+_${file}: ${file}
+ sed -e 's|<stddef.h>|"stand.h"|' \
+ -e 's|<string.h>|"stand.h"|' \
+ -e 's|<stdio.h>|"stand.h"|' \
+ -e 's|<stdlib.h>|"stand.h"|' \
+ -e 's|<stdint.h>|"stand.h"|' \
+ ${.ALLSRC} > ${.TARGET}
+.endfor
+
# decompression functionality from libbz2
# NOTE: to actually test this functionality after libbz2 upgrade compile
# loader(8) with LOADER_BZIP2_SUPPORT defined
Index: stand/libsa/zfs/zfsimpl.c
===================================================================
--- stand/libsa/zfs/zfsimpl.c
+++ stand/libsa/zfs/zfsimpl.c
@@ -62,6 +62,7 @@
"org.illumos:sha512",
"org.illumos:skein",
"org.zfsonlinux:large_dnode",
+ "org.freebsd:zstd_compress",
NULL
};
Index: sys/cddl/boot/zfs/zfsimpl.h
===================================================================
--- sys/cddl/boot/zfs/zfsimpl.h
+++ sys/cddl/boot/zfs/zfsimpl.h
@@ -561,6 +561,7 @@
ZIO_COMPRESS_GZIP_9,
ZIO_COMPRESS_ZLE,
ZIO_COMPRESS_LZ4,
+ ZIO_COMPRESS_ZSTD,
ZIO_COMPRESS_FUNCTIONS
};
Index: sys/cddl/boot/zfs/zfssubr.c
===================================================================
--- sys/cddl/boot/zfs/zfssubr.c
+++ sys/cddl/boot/zfs/zfssubr.c
@@ -162,6 +162,7 @@
#include "lzjb.c"
#include "zle.c"
#include "lz4.c"
+#include "zstd.c"
/*
* Compression vectors.
@@ -183,6 +184,7 @@
{NULL, NULL, 9, "gzip-9"},
{NULL, zle_decompress, 64, "zle"},
{NULL, lz4_decompress, 0, "lz4"},
+ {NULL, zstd_decompress, 0, "zstd"},
};
static void
Index: sys/cddl/boot/zfs/zstd.c
===================================================================
--- /dev/null
+++ sys/cddl/boot/zfs/zstd.c
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2016-2018 by Klara Systems Inc.
+ * Copyright (c) 2016-2018 Allan Jude <allanjude@freebsd.org>.
+ */
+
+#include <netinet/in.h>
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h>
+
+/* Allocate just one decompression context and reuse it */
+static char *dctxbuf = NULL;
+static size_t dctxsize;
+
+static int
+zstd_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+ const char *src = s_start;
+ uint32_t bufsiz = htonl(*(uint32_t *)src);
+ uint32_t cookie = htonl(*(uint32_t *)(&src[sizeof (bufsiz)]));
+ size_t result;
+
+ ASSERT(d_len >= s_len);
+
+ /* invalid compressed buffer size encoded at start */
+ if (bufsiz + sizeof (bufsiz) + sizeof (cookie) > s_len) {
+ printf("ZFS: Failed to decode ZSTD decompression header\n");
+ return (1);
+ }
+
+ /*
+ * Returns 0 on success (decompression function returned non-negative)
+ * and non-zero on failure (decompression function returned negative.
+ */
+ ZSTD_DCtx *dctx;
+
+ if (dctxbuf == NULL) {
+ dctxsize = ZSTD_estimateDCtxSize();
+ dctxbuf = malloc(dctxsize + 8);
+ if (dctxbuf == NULL) {
+ printf("ZFS: memory allocation failure\n");
+ return (1);
+ }
+ /* Pointer must be 8 byte aligned */
+ dctxbuf = (char *)roundup2((uintptr_t)dctxbuf, 8);
+ }
+ dctx = ZSTD_initStaticDCtx(dctxbuf, dctxsize);
+ if (dctx == NULL) {
+ printf("ZFS: failed to initialize ZSTD decompress context\n");
+ return (1);
+ }
+
+ result = ZSTD_decompressDCtx(dctx, d_start, d_len,
+ &src[sizeof (bufsiz) + sizeof (cookie)], bufsiz);
+ if (ZSTD_isError(result)) {
+ printf("ZFS: Failed to decompress block: %s\n",
+ ZSTD_getErrorName(result));
+ return (1);
+ }
+
+ return (0);
+}
Index: sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h
===================================================================
--- sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h
+++ sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h
@@ -60,6 +60,7 @@
SPA_FEATURE_DEVICE_REMOVAL,
SPA_FEATURE_OBSOLETE_COUNTS,
SPA_FEATURE_POOL_CHECKPOINT,
+ SPA_FEATURE_ZSTD_COMPRESS,
SPA_FEATURES
} spa_feature_t;
Index: sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c
===================================================================
--- sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c
+++ sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c
@@ -268,4 +268,9 @@
"Reduce memory used by removed devices when their blocks are "
"freed or remapped.",
ZFEATURE_FLAG_READONLY_COMPAT, obsolete_counts_deps);
+
+ zfeature_register(SPA_FEATURE_ZSTD_COMPRESS,
+ "org.freebsd:zstd_compress", "zstd_compress",
+ "zstd compression algorithm support.",
+ ZFEATURE_FLAG_PER_DATASET, NULL);
}
Index: sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
===================================================================
--- sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
+++ sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
@@ -116,6 +116,97 @@
{ "gzip-9", ZIO_COMPRESS_GZIP_9 },
{ "zle", ZIO_COMPRESS_ZLE },
{ "lz4", ZIO_COMPRESS_LZ4 },
+ { "zstd", ZIO_COMPRESS_ZSTD },
+ /*
+ * ZSTD 1-19 are synthetic. We store the compression level in a
+ * separate hidden property to avoid wasting a large amount of
+ * space in the ZIO_COMPRESS enum. We do not need to know the
+ * compression level at decompress time, so it does not need
+ * to be stored on disk in the block pointer.
+ */
+ { "zstd-1", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_1 << SPA_COMPRESSBITS) },
+ { "zstd-2", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_2 << SPA_COMPRESSBITS) },
+ { "zstd-3", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_3 << SPA_COMPRESSBITS) },
+ { "zstd-4", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_4 << SPA_COMPRESSBITS) },
+ { "zstd-5", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_5 << SPA_COMPRESSBITS) },
+ { "zstd-6", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_6 << SPA_COMPRESSBITS) },
+ { "zstd-7", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_7 << SPA_COMPRESSBITS) },
+ { "zstd-8", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_8 << SPA_COMPRESSBITS) },
+ { "zstd-9", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_9 << SPA_COMPRESSBITS) },
+ { "zstd-10", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_10 << SPA_COMPRESSBITS) },
+ { "zstd-11", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_11 << SPA_COMPRESSBITS) },
+ { "zstd-12", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_12 << SPA_COMPRESSBITS) },
+ { "zstd-13", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_13 << SPA_COMPRESSBITS) },
+ { "zstd-14", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_14 << SPA_COMPRESSBITS) },
+ { "zstd-15", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_15 << SPA_COMPRESSBITS) },
+ { "zstd-16", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_16 << SPA_COMPRESSBITS) },
+ { "zstd-17", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_17 << SPA_COMPRESSBITS) },
+ { "zstd-18", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_18 << SPA_COMPRESSBITS) },
+ { "zstd-19", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_19 << SPA_COMPRESSBITS) },
+ /*
+ * The ZSTD-Fast levels are also synthetic.
+ */
+ { "zstd-fast-1", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_1 << SPA_COMPRESSBITS) },
+ { "zstd-fast-2", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_2 << SPA_COMPRESSBITS) },
+ { "zstd-fast-3", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_3 << SPA_COMPRESSBITS) },
+ { "zstd-fast-4", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_4 << SPA_COMPRESSBITS) },
+ { "zstd-fast-5", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_5 << SPA_COMPRESSBITS) },
+ { "zstd-fast-6", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_6 << SPA_COMPRESSBITS) },
+ { "zstd-fast-7", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_7 << SPA_COMPRESSBITS) },
+ { "zstd-fast-8", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_8 << SPA_COMPRESSBITS) },
+ { "zstd-fast-9", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_9 << SPA_COMPRESSBITS) },
+ { "zstd-fast-10", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_10 << SPA_COMPRESSBITS) },
+ { "zstd-fast-20", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_20 << SPA_COMPRESSBITS) },
+ { "zstd-fast-30", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_30 << SPA_COMPRESSBITS) },
+ { "zstd-fast-40", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_40 << SPA_COMPRESSBITS) },
+ { "zstd-fast-50", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_50 << SPA_COMPRESSBITS) },
+ { "zstd-fast-60", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_60 << SPA_COMPRESSBITS) },
+ { "zstd-fast-70", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_70 << SPA_COMPRESSBITS) },
+ { "zstd-fast-80", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_80 << SPA_COMPRESSBITS) },
+ { "zstd-fast-90", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_90 << SPA_COMPRESSBITS) },
+ { "zstd-fast-100", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_100 << SPA_COMPRESSBITS) },
+ { "zstd-fast-500", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_500 << SPA_COMPRESSBITS) },
+ { "zstd-fast-1000", ZIO_COMPRESS_ZSTD |
+ (ZIO_ZSTDLVL_FAST_1000 << SPA_COMPRESSBITS) },
{ NULL }
};
@@ -250,7 +341,9 @@
zprop_register_index(ZFS_PROP_COMPRESSION, "compression",
ZIO_COMPRESS_DEFAULT, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off | lzjb | gzip | gzip-[1-9] | zle | lz4",
+ "on | off | lzjb | gzip | gzip-[1-9] | zle | lz4 | "
+ "zstd | zstd-[1-19] | "
+ "zstd-fast-[1-10,20,30,40,50,60,70,80,90,100,500,1000]",
"COMPRESS", compress_table);
zprop_register_index(ZFS_PROP_SNAPDIR, "snapdir", ZFS_SNAPDIR_HIDDEN,
PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
@@ -462,6 +555,10 @@
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PREVSNAP");
/* oddball properties */
+ zprop_register_impl(ZFS_PROP_ZSTD_LEVEL, "zstd_compress_level",
+ PROP_TYPE_NUMBER, ZIO_ZSTDLVL_DEFAULT, NULL, PROP_INHERIT,
+ ZFS_TYPE_DATASET, "<zio_zstd_levels>", "ZSTDLEVEL", B_TRUE,
+ B_FALSE, NULL);
zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0,
NULL, PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
"<date>", "CREATION", B_FALSE, B_TRUE, NULL);
Index: sys/cddl/contrib/opensolaris/uts/common/Makefile.files
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/Makefile.files
+++ sys/cddl/contrib/opensolaris/uts/common/Makefile.files
@@ -152,6 +152,7 @@
zio_inject.o \
zle.o \
zrlock.o \
+ zstd.o \
zthr.o
ZFS_SHARED_OBJS += \
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
@@ -1077,6 +1077,7 @@
arc_buf_contents_t b_type;
arc_buf_hdr_t *b_hash_next;
arc_flags_t b_flags;
+ uint8_t b_complevel;
/*
* This field stores the size of the data buffer after
@@ -1913,11 +1914,23 @@
uint64_t lsize = HDR_GET_LSIZE(hdr);
uint64_t csize;
- abd_t *cdata = abd_alloc_linear(HDR_GET_PSIZE(hdr), B_TRUE);
+ abd_t *cdata = abd_alloc_linear(lsize, B_TRUE);
csize = zio_compress_data(compress, zio->io_abd,
- abd_to_buf(cdata), lsize);
+ abd_to_buf(cdata), lsize, &zio->io_prop);
- ASSERT3U(csize, <=, HDR_GET_PSIZE(hdr));
+ if (csize == 0 || csize == lsize) {
+ /* Compression has failed */
+ /* XXX: Should we retry here? */
+ return (B_FALSE);
+ }
+
+ if (csize > HDR_GET_PSIZE(hdr)) {
+ /*
+ * Compression produced a larger output, the checksum
+ * cannot possibly match.
+ */
+ return (B_FALSE);
+ }
if (csize < HDR_GET_PSIZE(hdr)) {
/*
* Compressed blocks are always a multiple of the
@@ -5218,6 +5231,9 @@
} else {
hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS;
}
+ if (BP_GET_COMPRESS(zio->io_bp) == ZIO_COMPRESS_ZSTD) {
+ hdr->b_complevel = zio->io_prop.zp_zstd_level;
+ }
}
arc_hdr_clear_flags(hdr, ARC_FLAG_L2_EVICTED);
@@ -6235,6 +6251,9 @@
* the pre-compressed buffer's compression algorithm.
*/
localprop.zp_compress = HDR_GET_COMPRESS(hdr);
+ if (localprop.zp_compress == ZIO_COMPRESS_ZSTD) {
+ localprop.zp_zstd_level = hdr->b_complevel;
+ }
ASSERT3U(HDR_GET_LSIZE(hdr), !=, arc_buf_size(buf));
zio_flags |= ZIO_FLAG_RAW;
@@ -7349,6 +7368,9 @@
zio->io_bp_copy = cb->l2rcb_bp; /* XXX fix in L2ARC 2.0 */
zio->io_bp = &zio->io_bp_copy; /* XXX fix in L2ARC 2.0 */
+ if (BP_GET_COMPRESS(zio->io_bp) == ZIO_COMPRESS_ZSTD) {
+ zio->io_prop.zp_zstd_level = hdr->b_complevel;
+ }
valid_cksum = arc_cksum_is_equal(hdr, zio);
if (valid_cksum && zio->io_error == 0 && !HDR_L2_EVICTED(hdr)) {
mutex_exit(hash_lock);
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
@@ -2345,6 +2345,7 @@
(wp & WP_SPILL));
enum zio_checksum checksum = os->os_checksum;
enum zio_compress compress = os->os_compress;
+ enum zio_zstd_levels zstd_level = os->os_zstd_level;
enum zio_checksum dedup_checksum = os->os_dedup_checksum;
boolean_t dedup = B_FALSE;
boolean_t nopwrite = B_FALSE;
@@ -2439,6 +2440,8 @@
zp->zp_checksum = checksum;
zp->zp_compress = compress;
ASSERT3U(zp->zp_compress, !=, ZIO_COMPRESS_INHERIT);
+ zp->zp_zstd_level = zstd_level;
+ ASSERT(zp->zp_zstd_level != ZIO_ZSTDLVL_INHERIT);
zp->zp_type = (wp & WP_SPILL) ? dn->dn_bonustype : type;
zp->zp_level = level;
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
@@ -179,6 +179,15 @@
}
static void
+zstd_level_changed_cb(void *arg, uint64_t newval)
+{
+ objset_t *os = arg;
+
+ os->os_zstd_level = zio_zstd_level_select(os->os_spa, newval,
+ ZIO_ZSTDLVL_DEFAULT);
+}
+
+static void
copies_changed_cb(void *arg, uint64_t newval)
{
objset_t *os = arg;
@@ -449,6 +458,11 @@
}
if (err == 0) {
err = dsl_prop_register(ds,
+ zfs_prop_to_name(ZFS_PROP_ZSTD_LEVEL),
+ zstd_level_changed_cb, os);
+ }
+ if (err == 0) {
+ err = dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_COPIES),
copies_changed_cb, os);
}
@@ -490,6 +504,7 @@
/* It's the meta-objset. */
os->os_checksum = ZIO_CHECKSUM_FLETCHER_4;
os->os_compress = ZIO_COMPRESS_ON;
+ os->os_zstd_level = ZIO_ZSTDLVL_DEFAULT;
os->os_copies = spa_max_replication(spa);
os->os_dedup_checksum = ZIO_CHECKSUM_OFF;
os->os_dedup_verify = B_FALSE;
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
@@ -835,6 +835,9 @@
if (compressok) {
featureflags |= DMU_BACKUP_FEATURE_COMPRESSED;
}
+ if ((compressok || embedok) &&
+ to_ds->ds_feature_inuse[SPA_FEATURE_ZSTD_COMPRESS])
+ featureflags |= DMU_BACKUP_FEATURE_ZSTD;
if ((featureflags &
(DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_COMPRESSED)) !=
0 && spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) {
@@ -1431,6 +1434,13 @@
*/
if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
+ return (SET_ERROR(ENOTSUP));
+
+ if ((featureflags & DMU_BACKUP_FEATURE_ZSTD) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ZSTD_COMPRESS))
+ return (SET_ERROR(ENOTSUP));
+
+ if (!(DMU_STREAM_SUPPORTED(featureflags)))
return (SET_ERROR(ENOTSUP));
error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
@@ -128,6 +128,7 @@
int compressed = BP_GET_PSIZE(bp);
int uncompressed = BP_GET_UCSIZE(bp);
int64_t delta;
+ spa_feature_t f;
dprintf_bp(bp, "ds=%p", ds);
@@ -157,7 +158,11 @@
B_TRUE;
}
- spa_feature_t f = zio_checksum_to_feature(BP_GET_CHECKSUM(bp));
+ f = zio_checksum_to_feature(BP_GET_CHECKSUM(bp));
+ if (f != SPA_FEATURE_NONE)
+ ds->ds_feature_activation_needed[f] = B_TRUE;
+
+ f = zio_compress_to_feature(BP_GET_COMPRESS(bp));
if (f != SPA_FEATURE_NONE)
ds->ds_feature_activation_needed[f] = B_TRUE;
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
@@ -2086,6 +2086,7 @@
metaslab_alloc_trace_init();
zio_init();
lz4_init();
+ zstd_init();
dmu_init();
zil_init();
vdev_cache_stat_init();
@@ -2116,6 +2117,7 @@
zil_fini();
dmu_fini();
lz4_fini();
+ zstd_fini();
zio_fini();
metaslab_alloc_trace_fini();
range_tree_fini();
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_objset.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_objset.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_objset.h
@@ -91,6 +91,7 @@
/* can change, under dsl_dir's locks: */
enum zio_checksum os_checksum;
enum zio_compress os_compress;
+ enum zio_zstd_levels os_zstd_level;
uint8_t os_copies;
enum zio_checksum os_dedup_checksum;
boolean_t os_dedup_verify;
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h
@@ -154,6 +154,7 @@
#define SPA_ASIZEBITS 24 /* ASIZE up to 64 times larger */
#define SPA_COMPRESSBITS 7
+#define SPA_COMPRESSMASK ((1U<<SPA_COMPRESSBITS)-1)
/*
* All SPA data is represented by 128-bit data virtual addresses (DVAs).
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -94,6 +94,8 @@
/* flag #21 is reserved for a Delphix feature */
#define DMU_BACKUP_FEATURE_COMPRESSED (1 << 22)
/* flag #23 is reserved for the large dnode feature */
+/* flag #24 is reserved for the raw send feature */
+#define DMU_BACKUP_FEATURE_ZSTD (1 << 25)
/*
* Mask of all supported backup features
@@ -103,7 +105,7 @@
DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_LZ4 | \
DMU_BACKUP_FEATURE_RESUMING | \
DMU_BACKUP_FEATURE_LARGE_BLOCKS | \
- DMU_BACKUP_FEATURE_COMPRESSED)
+ DMU_BACKUP_FEATURE_COMPRESSED | DMU_BACKUP_FEATURE_ZSTD)
/* Are all features in the given flag word currently supported? */
#define DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK))
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
@@ -124,6 +124,7 @@
#define BOOTFS_COMPRESS_VALID(compress) \
((compress) == ZIO_COMPRESS_LZJB || \
(compress) == ZIO_COMPRESS_LZ4 || \
+ (compress) == ZIO_COMPRESS_ZSTD || \
(compress) == ZIO_COMPRESS_ON || \
(compress) == ZIO_COMPRESS_OFF)
@@ -295,6 +296,7 @@
typedef struct zio_prop {
enum zio_checksum zp_checksum;
enum zio_compress zp_compress;
+ enum zio_zstd_levels zp_zstd_level;
dmu_object_type_t zp_type;
uint8_t zp_level;
uint8_t zp_copies;
@@ -604,6 +606,8 @@
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 enum zio_zstd_levels zio_zstd_level_select(spa_t *spa,
+ enum zio_zstd_levels child, enum zio_zstd_levels parent);
extern void zio_suspend(spa_t *spa, zio_t *zio);
extern int zio_resume(spa_t *spa);
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_compress.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_compress.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_compress.h
@@ -54,15 +54,75 @@
ZIO_COMPRESS_GZIP_9,
ZIO_COMPRESS_ZLE,
ZIO_COMPRESS_LZ4,
+ ZIO_COMPRESS_ZSTD,
ZIO_COMPRESS_FUNCTIONS
};
+#define ZIO_ZSTD_LEVEL_MIN 1
+#define ZIO_ZSTD_LEVEL_DEFAULT 3
+#define ZIO_ZSTD_LEVEL_MAX 19
+
+enum zio_zstd_levels {
+ ZIO_ZSTDLVL_INHERIT = 0,
+ ZIO_ZSTDLVL_1,
+ ZIO_ZSTDLVL_2,
+ ZIO_ZSTDLVL_3,
+ ZIO_ZSTDLVL_4,
+ ZIO_ZSTDLVL_5,
+ ZIO_ZSTDLVL_6,
+ ZIO_ZSTDLVL_7,
+ ZIO_ZSTDLVL_8,
+ ZIO_ZSTDLVL_9,
+ ZIO_ZSTDLVL_10,
+ ZIO_ZSTDLVL_11,
+ ZIO_ZSTDLVL_12,
+ ZIO_ZSTDLVL_13,
+ ZIO_ZSTDLVL_14,
+ ZIO_ZSTDLVL_15,
+ ZIO_ZSTDLVL_16,
+ ZIO_ZSTDLVL_17,
+ ZIO_ZSTDLVL_18,
+ ZIO_ZSTDLVL_19,
+#define ZIO_ZSTDLVL_MAX ZIO_ZSTDLVL_19
+ ZIO_ZSTDLVL_RESERVE = 31, /* Leave room for new positive levels */
+ ZIO_ZSTDLVL_FAST, /* Fast levels are negative */
+ ZIO_ZSTDLVL_FAST_1,
+ ZIO_ZSTDLVL_FAST_2,
+ ZIO_ZSTDLVL_FAST_3,
+ ZIO_ZSTDLVL_FAST_4,
+ ZIO_ZSTDLVL_FAST_5,
+ ZIO_ZSTDLVL_FAST_6,
+ ZIO_ZSTDLVL_FAST_7,
+ ZIO_ZSTDLVL_FAST_8,
+ ZIO_ZSTDLVL_FAST_9,
+ ZIO_ZSTDLVL_FAST_10,
+ ZIO_ZSTDLVL_FAST_20,
+ ZIO_ZSTDLVL_FAST_30,
+ ZIO_ZSTDLVL_FAST_40,
+ ZIO_ZSTDLVL_FAST_50,
+ ZIO_ZSTDLVL_FAST_60,
+ ZIO_ZSTDLVL_FAST_70,
+ ZIO_ZSTDLVL_FAST_80,
+ ZIO_ZSTDLVL_FAST_90,
+ ZIO_ZSTDLVL_FAST_100,
+ ZIO_ZSTDLVL_FAST_500,
+ ZIO_ZSTDLVL_FAST_1000,
+ ZIO_ZSTDLVL_DEFAULT = 62, /* Allow the default level to change */
+ ZIO_ZSTDLVL_AUTO = 63, /* Reserved for future use */
+ ZIO_ZSTDLVL_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 get-compression-level functions. */
+typedef int zio_getcomplevel_func_t(void *src, size_t s_len);
/*
* Common signature for all zio decompress functions using an ABD as input.
* This is helpful if you have both compressed ARC and scatter ABDs enabled,
@@ -79,6 +139,7 @@
int ci_level;
zio_compress_func_t *ci_compress;
zio_decompress_func_t *ci_decompress;
+ zio_getcomplevel_func_t *ci_getlevel;
} zio_compress_info_t;
extern zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS];
@@ -104,16 +165,27 @@
int level);
extern int lz4_decompress(void *src, void *dst, size_t s_len, size_t d_len,
int level);
+extern void zstd_init(void);
+extern void zstd_fini(void);
+extern size_t zstd_compress(void *src, void *dst, size_t s_len, size_t d_len,
+ int level);
+extern int zstd_decompress(void *src, void *dst, size_t s_len, size_t d_len,
+ int level);
+extern int zstd_getlevel(void *src, size_t s_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, struct zio_prop *zp);
extern int zio_decompress_data(enum zio_compress c, abd_t *src, void *dst,
size_t s_len, size_t d_len);
extern int zio_decompress_data_buf(enum zio_compress c, void *src, void *dst,
size_t s_len, size_t d_len);
+extern int zio_getcomplevel(enum zio_compress c, abd_t *src, size_t s_len);
+extern int zio_decompress_getlevel(enum zio_compress c, abd_t *src, void *dst,
+ size_t s_len, size_t d_len, enum zio_zstd_levels *level);
+extern int zio_compress_to_feature(enum zio_compress comp);
/*
* Module lifetime management.
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h
@@ -76,9 +76,9 @@
* 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
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zcp_get.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zcp_get.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zcp_get.c
@@ -325,6 +325,7 @@
char setpoint[ZFS_MAX_DATASET_NAME_LEN] =
"Internal error - setpoint not determined";
zfs_type_t ds_type;
+ const char *prop_name = zfs_prop_to_name(zfs_prop);
zprop_type_t prop_type = zfs_prop_get_type(zfs_prop);
(void) get_objset_type(ds, &ds_type);
@@ -463,6 +464,24 @@
}
break;
}
+ case ZFS_PROP_COMPRESSION:
+ error = dsl_prop_get_ds(ds, prop_name, sizeof (numval), 1,
+ &numval, setpoint);
+ /* Special handling is only required for ZSTD */
+ if (error || numval != ZIO_COMPRESS_ZSTD)
+ break;
+
+ uint64_t levelval;
+ const char *zstd_name = zfs_prop_to_name(ZFS_PROP_ZSTD_LEVEL);
+
+ error = dsl_prop_get_ds(ds, zstd_name, sizeof (levelval),
+ 1, &levelval, setpoint);
+ if (error == 0) {
+ if (levelval == ZIO_ZSTDLVL_DEFAULT)
+ break;
+ numval |= levelval << SPA_COMPRESSBITS;
+ }
+ break;
default:
/* Did not match these props, check in the dsl_dir */
error = get_dsl_dir_prop(ds, zfs_prop, &numval);
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -2153,6 +2153,34 @@
}
static int
+get_prop_uint64(nvlist_t *nv, const char *prop, nvlist_t **nvp,
+ uint64_t *val)
+{
+ int err = 0;
+ nvlist_t *subnv;
+ nvpair_t *pair;
+ nvpair_t *propval;
+
+ if (nvlist_lookup_nvpair(nv, prop, &pair) != 0)
+ return (EINVAL);
+
+ /* decode the property value */
+ propval = pair;
+ if (nvpair_type(pair) == DATA_TYPE_NVLIST) {
+ subnv = fnvpair_value_nvlist(pair);
+ if (nvp != NULL)
+ *nvp = subnv;
+ if (nvlist_lookup_nvpair(subnv, ZPROP_VALUE, &propval) != 0)
+ err = EINVAL;
+ }
+ if (nvpair_type(propval) == DATA_TYPE_UINT64) {
+ *val = fnvpair_value_uint64(propval);
+ }
+
+ return (err);
+}
+
+static int
zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os)
{
int error = 0;
@@ -2177,6 +2205,28 @@
return (error);
VERIFY0(error);
}
+ /*
+ * ZSTD stores the compression level in a separate hidden
+ * property to avoid using up a large chunk of space in the
+ * on-disk compression algorithm enum. We need to swap things
+ * back around when the property is read.
+ */
+ nvlist_t *cnv;
+ uint64_t compval, levelval;
+
+ if (get_prop_uint64(nv, "compression", &cnv, &compval) != 0)
+ error = EINVAL;
+
+ if (error == 0 && compval == ZIO_COMPRESS_ZSTD &&
+ get_prop_uint64(nv, "zstd_compress_level", NULL,
+ &levelval) == 0) {
+ if (levelval == ZIO_ZSTDLVL_DEFAULT)
+ levelval = 0;
+ fnvlist_remove(cnv, ZPROP_VALUE);
+ fnvlist_add_uint64(cnv, ZPROP_VALUE,
+ compval | (levelval << SPA_COMPRESSBITS));
+ }
+
error = put_nvlist(zc, nv);
nvlist_free(nv);
}
@@ -2576,6 +2626,32 @@
}
break;
}
+ case ZFS_PROP_COMPRESSION:
+ /* Special handling is only required for ZSTD */
+ if (intval & SPA_COMPRESSMASK != ZIO_COMPRESS_ZSTD) {
+ err = -1;
+ break;
+ }
+ /*
+ * Store the ZSTD compression level separate from the compress
+ * property in its own hidden property.
+ */
+ uint64_t levelval;
+
+ if (intval == ZIO_COMPRESS_ZSTD) {
+ levelval = ZIO_ZSTDLVL_DEFAULT;
+ } else {
+ levelval = (intval & ~SPA_COMPRESSMASK)
+ >> SPA_COMPRESSBITS;
+ }
+ err = dsl_prop_set_int(dsname, "zstd_compress_level", source,
+ levelval);
+ if (err == 0) {
+ /* Store the compression algorithm normally */
+ err = dsl_prop_set_int(dsname, propname, source,
+ intval & SPA_COMPRESSMASK);
+ }
+ break;
default:
err = -1;
}
@@ -4075,6 +4151,20 @@
if (!spa_feature_is_enabled(spa,
SPA_FEATURE_LZ4_COMPRESS)) {
+ spa_close(spa, FTAG);
+ return (SET_ERROR(ENOTSUP));
+ }
+ spa_close(spa, FTAG);
+ }
+
+ if (intval == ZIO_COMPRESS_ZSTD) {
+ spa_t *spa;
+
+ if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+ return (err);
+
+ if (!spa_feature_is_enabled(spa,
+ SPA_FEATURE_ZSTD_COMPRESS)) {
spa_close(spa, FTAG);
return (SET_ERROR(ENOTSUP));
}
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
@@ -407,8 +407,17 @@
{
if (zio->io_error == 0) {
void *tmp = abd_borrow_buf(data, size);
- int ret = zio_decompress_data(BP_GET_COMPRESS(zio->io_bp),
- zio->io_abd, tmp, zio->io_size, size);
+ int ret;
+
+ if (BP_GET_COMPRESS(zio->io_bp) == ZIO_COMPRESS_ZSTD) {
+ ret = zio_decompress_getlevel(
+ BP_GET_COMPRESS(zio->io_bp), zio->io_abd, tmp,
+ zio->io_size, size, &zio->io_prop.zp_zstd_level);
+ } else {
+ ret = zio_decompress_data(BP_GET_COMPRESS(zio->io_bp),
+ zio->io_abd, tmp, zio->io_size, size);
+ }
+
abd_return_buf_copy(data, tmp, size);
if (ret != 0)
@@ -1449,7 +1458,8 @@
/* If it's a compressed write that is not raw, compress the buffer. */
if (compress != ZIO_COMPRESS_OFF && psize == lsize) {
void *cbuf = zio_buf_alloc(lsize);
- psize = zio_compress_data(compress, zio->io_abd, cbuf, lsize);
+ psize = zio_compress_data(compress, zio->io_abd, cbuf, lsize,
+ zp);
if (psize == 0 || psize == lsize) {
compress = ZIO_COMPRESS_OFF;
zio_buf_free(cbuf, lsize);
@@ -2400,6 +2410,7 @@
zp.zp_checksum = gio->io_prop.zp_checksum;
zp.zp_compress = ZIO_COMPRESS_OFF;
+ zp.zp_zstd_level = ZIO_ZSTDLVL_DEFAULT;
zp.zp_type = DMU_OT_NONE;
zp.zp_level = 0;
zp.zp_copies = gio->io_prop.zp_copies;
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_compress.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_compress.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_compress.c
@@ -59,24 +59,42 @@
* Compression vectors.
*/
zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = {
- {"inherit", 0, NULL, NULL},
- {"on", 0, NULL, NULL},
- {"uncompressed", 0, NULL, NULL},
- {"lzjb", 0, lzjb_compress, lzjb_decompress},
- {"empty", 0, NULL, NULL},
- {"gzip-1", 1, gzip_compress, gzip_decompress},
- {"gzip-2", 2, gzip_compress, gzip_decompress},
- {"gzip-3", 3, gzip_compress, gzip_decompress},
- {"gzip-4", 4, gzip_compress, gzip_decompress},
- {"gzip-5", 5, gzip_compress, gzip_decompress},
- {"gzip-6", 6, gzip_compress, gzip_decompress},
- {"gzip-7", 7, gzip_compress, gzip_decompress},
- {"gzip-8", 8, gzip_compress, gzip_decompress},
- {"gzip-9", 9, gzip_compress, gzip_decompress},
- {"zle", 64, zle_compress, zle_decompress},
- {"lz4", 0, lz4_compress, lz4_decompress}
+ {"inherit", 0, NULL, NULL, NULL},
+ {"on", 0, NULL, NULL, NULL},
+ {"uncompressed", 0, NULL, NULL, NULL},
+ {"lzjb", 0, lzjb_compress, lzjb_decompress, NULL},
+ {"empty", 0, NULL, NULL, NULL},
+ {"gzip-1", 1, gzip_compress, gzip_decompress, NULL},
+ {"gzip-2", 2, gzip_compress, gzip_decompress, NULL},
+ {"gzip-3", 3, gzip_compress, gzip_decompress, NULL},
+ {"gzip-4", 4, gzip_compress, gzip_decompress, NULL},
+ {"gzip-5", 5, gzip_compress, gzip_decompress, NULL},
+ {"gzip-6", 6, gzip_compress, gzip_decompress, NULL},
+ {"gzip-7", 7, gzip_compress, gzip_decompress, NULL},
+ {"gzip-8", 8, gzip_compress, gzip_decompress, NULL},
+ {"gzip-9", 9, gzip_compress, gzip_decompress, NULL},
+ {"zle", 64, zle_compress, zle_decompress, NULL},
+ {"lz4", 0, lz4_compress, lz4_decompress, NULL},
+ {"zstd", 0, zstd_compress, zstd_decompress, zstd_getlevel},
};
+enum zio_zstd_levels
+zio_zstd_level_select(spa_t *spa, enum zio_zstd_levels child,
+ enum zio_zstd_levels parent)
+{
+ enum zio_zstd_levels result;
+
+ ASSERT(child < ZIO_ZSTDLVL_LEVELS);
+ ASSERT(parent < ZIO_ZSTDLVL_LEVELS);
+ ASSERT(parent != ZIO_ZSTDLVL_INHERIT);
+
+ result = child;
+ if (result == ZIO_ZSTDLVL_INHERIT)
+ result = parent;
+
+ return (result);
+}
+
enum zio_compress
zio_compress_select(spa_t *spa, enum zio_compress child,
enum zio_compress parent)
@@ -114,9 +132,11 @@
}
size_t
-zio_compress_data(enum zio_compress c, abd_t *src, void *dst, size_t s_len)
+zio_compress_data(enum zio_compress c, abd_t *src, void *dst, size_t s_len,
+ zio_prop_t *zp)
{
size_t c_len, d_len;
+ int level;
zio_compress_info_t *ci = &zio_compress_table[c];
ASSERT((uint_t)c < ZIO_COMPRESS_FUNCTIONS);
@@ -139,9 +159,19 @@
/* Compress at least 12.5% */
d_len = s_len - (s_len >> 3);
+ level = ci->ci_level;
+
+ if (c == ZIO_COMPRESS_ZSTD) {
+ ASSERT(zp != NULL);
+ if (zp->zp_zstd_level == ZIO_ZSTDLVL_DEFAULT)
+ level = ZIO_ZSTD_LEVEL_DEFAULT;
+ else
+ level = zp->zp_zstd_level;
+ }
+
/* No compression algorithms can read from ABDs directly */
void *tmp = abd_borrow_buf_copy(src, s_len);
- c_len = ci->ci_compress(tmp, dst, s_len, d_len, ci->ci_level);
+ c_len = ci->ci_compress(tmp, dst, s_len, d_len, level);
abd_return_buf(src, tmp, s_len);
if (c_len > d_len) {
@@ -173,6 +203,52 @@
abd_return_buf(src, tmp, s_len);
return (ret);
+}
+
+int
+zio_getcomplevel(enum zio_compress c, abd_t *src, size_t s_len)
+{
+ void *tmp = abd_borrow_buf_copy(src, s_len);
+ zio_compress_info_t *ci = &zio_compress_table[c];
+ int ret;
+
+ if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_getlevel == NULL)
+ return (-1);
+
+ ret = ci->ci_getlevel(tmp, s_len);
+
+ abd_return_buf(src, tmp, s_len);
+
+ return (ret);
+}
+
+int
+zio_decompress_getlevel(enum zio_compress c, abd_t *src, void *dst,
+ size_t s_len, size_t d_len, enum zio_zstd_levels *level)
+{
+ void *tmp = abd_borrow_buf_copy(src, s_len);
+ int ret = zio_decompress_data_buf(c, tmp, dst, s_len, d_len);
+
+ zio_compress_info_t *ci = &zio_compress_table[c];
+ if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_getlevel == NULL)
+ return (-1);
+
+ *level = ci->ci_getlevel(tmp, s_len);
+
+ abd_return_buf(src, tmp, s_len);
+
+ return (ret);
+}
+
+int
+zio_compress_to_feature(enum zio_compress comp)
+{
+
+ switch (comp) {
+ case ZIO_COMPRESS_ZSTD:
+ return (SPA_FEATURE_ZSTD_COMPRESS);
+ }
+ return (SPA_FEATURE_NONE);
}
void
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zstd.c
===================================================================
--- /dev/null
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zstd.c
@@ -0,0 +1,478 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, 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-2018 by Klara Systems Inc.
+ * Copyright (c) 2016-2018 Allan Jude <allanjude@freebsd.org>.
+ */
+
+#include <sys/param.h>
+#include <sys/zfs_context.h>
+#include <sys/zio_compress.h>
+#include <sys/spa.h>
+#include <sys/malloc.h>
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h>
+#include <zstd_errors.h>
+
+#define ZSTD_KMEM_MAGIC 0x20160831
+
+static size_t real_zstd_compress(const char *source, char *dest, int isize,
+ int osize, int level);
+static size_t real_zstd_decompress(const char *source, char *dest, int isize,
+ int maxosize);
+
+void *zstd_alloc(void *opaque, size_t size);
+void zstd_free(void *opaque, void *ptr);
+
+static const ZSTD_customMem zstd_malloc = {
+ zstd_alloc,
+ zstd_free,
+ NULL,
+};
+
+enum zstd_kmem_type {
+ ZSTD_KMEM_UNKNOWN = 0,
+ ZSTD_KMEM_CCTX,
+ ZSTD_KMEM_WRKSPC_4K_MIN,
+ ZSTD_KMEM_WRKSPC_4K_DEF,
+ ZSTD_KMEM_WRKSPC_4K_MAX,
+ ZSTD_KMEM_WRKSPC_16K_MIN,
+ ZSTD_KMEM_WRKSPC_16K_DEF,
+ ZSTD_KMEM_WRKSPC_16K_MAX,
+ ZSTD_KMEM_WRKSPC_128K_MIN,
+ ZSTD_KMEM_WRKSPC_128K_DEF,
+ ZSTD_KMEM_WRKSPC_128K_MAX,
+ /* SPA_MAXBLOCKSIZE */
+ ZSTD_KMEM_WRKSPC_MBS_MIN,
+ ZSTD_KMEM_WRKSPC_MBS_DEF,
+ ZSTD_KMEM_WRKSPC_MBS_MAX,
+ ZSTD_KMEM_DCTX,
+ ZSTD_KMEM_COUNT,
+};
+
+struct zstd_kmem {
+ uint_t kmem_magic;
+ enum zstd_kmem_type kmem_type;
+ size_t kmem_size;
+};
+
+struct zstd_kmem_config {
+ size_t block_size;
+ int compress_level;
+ char* cache_name;
+};
+
+static kmem_cache_t *zstd_kmem_cache[ZSTD_KMEM_COUNT] = { NULL };
+static struct zstd_kmem zstd_cache_size[ZSTD_KMEM_COUNT] = {
+ { ZSTD_KMEM_MAGIC, 0, 0 } };
+static struct zstd_kmem_config zstd_cache_config[ZSTD_KMEM_COUNT] = {
+ { 0, 0, "zstd_unknown" },
+ { 0, 0, "zstd_cctx" },
+ { 4096, ZIO_ZSTD_LEVEL_MIN, "zstd_wrkspc_4k_min" },
+ { 4096, ZIO_ZSTD_LEVEL_DEFAULT, "zstd_wrkspc_4k_def" },
+ { 4096, ZIO_ZSTD_LEVEL_MAX, "zstd_wrkspc_4k_max" },
+ { 16384, ZIO_ZSTD_LEVEL_MIN, "zstd_wrkspc_16k_min" },
+ { 16384, ZIO_ZSTD_LEVEL_DEFAULT, "zstd_wrkspc_16k_def" },
+ { 16384, ZIO_ZSTD_LEVEL_MAX, "zstd_wrkspc_16k_max" },
+ { SPA_OLD_MAXBLOCKSIZE, ZIO_ZSTD_LEVEL_MIN, "zstd_wrkspc_128k_min" },
+ { SPA_OLD_MAXBLOCKSIZE, ZIO_ZSTD_LEVEL_DEFAULT,
+ "zstd_wrkspc_128k_def" },
+ { SPA_OLD_MAXBLOCKSIZE, ZIO_ZSTD_LEVEL_MAX, "zstd_wrkspc_128k_max" },
+ { SPA_MAXBLOCKSIZE, ZIO_ZSTD_LEVEL_MIN, "zstd_wrkspc_mbs_min" },
+ { SPA_MAXBLOCKSIZE, ZIO_ZSTD_LEVEL_DEFAULT, "zstd_wrkspc_mbs_def" },
+ { SPA_MAXBLOCKSIZE, ZIO_ZSTD_LEVEL_MAX, "zstd_wrkspc_mbs_max" },
+ { 0, 0, "zstd_dctx" },
+ };
+
+static int
+zstd_compare(const void *a, const void *b)
+{
+ struct zstd_kmem *x, *y;
+
+ x = (struct zstd_kmem*)a;
+ y = (struct zstd_kmem*)b;
+
+ ASSERT(x->kmem_magic == ZSTD_KMEM_MAGIC);
+ ASSERT(y->kmem_magic == ZSTD_KMEM_MAGIC);
+
+ if (x->kmem_size > y->kmem_size) {
+ return (1);
+ } else if (x->kmem_size == y->kmem_size) {
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+static enum zio_zstd_levels
+zstd_level_to_enum(int level)
+{
+ enum zio_zstd_levels elevel = ZIO_ZSTDLVL_INHERIT;
+
+ if (level > 0 && level <= ZIO_ZSTDLVL_MAX) {
+ elevel = level;
+ return (elevel);
+ } else if (level < 0) {
+ switch (level) {
+ case -1:
+ return (ZIO_ZSTDLVL_FAST_1);
+ case -2:
+ return (ZIO_ZSTDLVL_FAST_2);
+ case -3:
+ return (ZIO_ZSTDLVL_FAST_3);
+ case -4:
+ return (ZIO_ZSTDLVL_FAST_4);
+ case -5:
+ return (ZIO_ZSTDLVL_FAST_5);
+ case -6:
+ return (ZIO_ZSTDLVL_FAST_6);
+ case -7:
+ return (ZIO_ZSTDLVL_FAST_7);
+ case -8:
+ return (ZIO_ZSTDLVL_FAST_8);
+ case -9:
+ return (ZIO_ZSTDLVL_FAST_9);
+ case -10:
+ return (ZIO_ZSTDLVL_FAST_10);
+ case -20:
+ return (ZIO_ZSTDLVL_FAST_20);
+ case -30:
+ return (ZIO_ZSTDLVL_FAST_30);
+ case -40:
+ return (ZIO_ZSTDLVL_FAST_40);
+ case -50:
+ return (ZIO_ZSTDLVL_FAST_50);
+ case -60:
+ return (ZIO_ZSTDLVL_FAST_60);
+ case -70:
+ return (ZIO_ZSTDLVL_FAST_70);
+ case -80:
+ return (ZIO_ZSTDLVL_FAST_80);
+ case -90:
+ return (ZIO_ZSTDLVL_FAST_90);
+ case -100:
+ return (ZIO_ZSTDLVL_FAST_100);
+ case -500:
+ return (ZIO_ZSTDLVL_FAST_500);
+ case -1000:
+ return (ZIO_ZSTDLVL_FAST_1000);
+ }
+ }
+
+ /* This shouldn't happen. Cause a panic. */
+ panic("Invalid ZSTD level encountered: %d", level);
+
+ return (ZIO_ZSTDLVL_INHERIT);
+}
+
+static int
+zstd_enum_to_level(enum zio_zstd_levels elevel)
+{
+ int level = 0;
+
+ if (elevel > ZIO_ZSTDLVL_INHERIT && elevel <= ZIO_ZSTDLVL_MAX) {
+ level = elevel;
+ return (level);
+ } else if (elevel > ZIO_ZSTDLVL_FAST) {
+ switch (elevel) {
+ case ZIO_ZSTDLVL_FAST_1:
+ return (-1);
+ case ZIO_ZSTDLVL_FAST_2:
+ return (-2);
+ case ZIO_ZSTDLVL_FAST_3:
+ return (-3);
+ case ZIO_ZSTDLVL_FAST_4:
+ return (-4);
+ case ZIO_ZSTDLVL_FAST_5:
+ return (-5);
+ case ZIO_ZSTDLVL_FAST_6:
+ return (-6);
+ case ZIO_ZSTDLVL_FAST_7:
+ return (-7);
+ case ZIO_ZSTDLVL_FAST_8:
+ return (-8);
+ case ZIO_ZSTDLVL_FAST_9:
+ return (-9);
+ case ZIO_ZSTDLVL_FAST_10:
+ return (-10);
+ case ZIO_ZSTDLVL_FAST_20:
+ return (-20);
+ case ZIO_ZSTDLVL_FAST_30:
+ return (-30);
+ case ZIO_ZSTDLVL_FAST_40:
+ return (-40);
+ case ZIO_ZSTDLVL_FAST_50:
+ return (-50);
+ case ZIO_ZSTDLVL_FAST_60:
+ return (-60);
+ case ZIO_ZSTDLVL_FAST_70:
+ return (-70);
+ case ZIO_ZSTDLVL_FAST_80:
+ return (-80);
+ case ZIO_ZSTDLVL_FAST_90:
+ return (-90);
+ case ZIO_ZSTDLVL_FAST_100:
+ return (-100);
+ case ZIO_ZSTDLVL_FAST_500:
+ return (-500);
+ case ZIO_ZSTDLVL_FAST_1000:
+ return (-1000);
+ }
+ }
+
+ /* This shouldn't happen. Cause a panic. */
+ panic("Invalid ZSTD enum level encountered: %d", elevel);
+
+ return (0);
+}
+
+size_t
+zstd_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+ size_t c_len;
+ uint32_t bufsiz;
+ int32_t zstdlevel;
+ char *dest = d_start;
+
+ ASSERT(d_len >= sizeof (bufsiz));
+ ASSERT(d_len <= s_len);
+
+ zstdlevel = zstd_enum_to_level(n);
+
+ /* XXX: this could overflow, but we never have blocks that big */
+ c_len = real_zstd_compress(s_start,
+ &dest[sizeof (bufsiz) + sizeof (zstdlevel)], s_len,
+ d_len - sizeof (bufsiz) - sizeof (zstdlevel), zstdlevel);
+
+ /* Signal an error if the compression routine returned an error. */
+ if (ZSTD_isError(c_len))
+ return (s_len);
+
+ /*
+ * Encode the compresed buffer size at the start. We'll need this in
+ * decompression to counter the effects of padding which might be
+ * added to the compressed buffer and which, if unhandled, would
+ * confuse the hell out of our decompression function.
+ */
+ bufsiz = c_len;
+ *(uint32_t *)dest = BE_32(bufsiz);
+ /*
+ * Encode the compression level as well. We may need to know the
+ * original compression level if compressed_arc is disabled, to match
+ * the compression settings to write this block to the L2ARC.
+ * Encode the actual level, so if the enum changes in the future,
+ * we will be compatible.
+ */
+ *(uint32_t *)(&dest[sizeof (bufsiz)]) = BE_32(zstdlevel);
+
+ return (c_len + sizeof (bufsiz) + sizeof (zstdlevel));
+}
+
+int
+zstd_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
+{
+ const char *src = s_start;
+ uint32_t bufsiz = BE_IN32(src);
+ uint32_t cookie = BE_IN32(&src[sizeof (bufsiz)]);
+ int32_t zstdlevel = zstd_level_to_enum(cookie);
+
+ ASSERT(d_len >= s_len);
+ ASSERT(zstdlevel > ZIO_ZSTDLVL_INHERIT);
+ ASSERT(zstdlevel < ZIO_ZSTDLVL_LEVELS);
+
+ /* invalid compressed buffer size encoded at start */
+ if (bufsiz + sizeof (bufsiz) > s_len)
+ return (1);
+
+ /*
+ * Returns 0 on success (decompression function returned non-negative)
+ * and non-zero on failure (decompression function returned negative.
+ */
+ if (ZSTD_isError(real_zstd_decompress(
+ &src[sizeof (bufsiz) + sizeof (zstdlevel)], d_start, bufsiz, d_len)))
+ return (1);
+
+ return (0);
+}
+
+int
+zstd_getlevel(void *s_start, size_t s_len __unused)
+{
+ const char *src = s_start;
+ uint32_t cookie = BE_IN32(&src[sizeof (uint32_t)]);
+ int32_t zstdlevel = zstd_level_to_enum(cookie);
+
+ ASSERT(zstdlevel > ZIO_ZSTDLVL_INHERIT);
+ ASSERT(zstdlevel < ZIO_ZSTDLVL_LEVELS);
+
+ return (zstdlevel);
+}
+
+static size_t
+real_zstd_compress(const char *source, char *dest, int isize, int osize,
+ int level)
+{
+ size_t result;
+ ZSTD_CCtx *cctx;
+
+ ASSERT(level != 0);
+ if (level == ZIO_ZSTDLVL_DEFAULT)
+ level = ZIO_ZSTD_LEVEL_DEFAULT;
+
+ cctx = ZSTD_createCCtx_advanced(zstd_malloc);
+ /*
+ * out of kernel memory, gently fall through - this will disable
+ * compression in zio_compress_data
+ */
+ if (cctx == NULL)
+ return (0);
+
+ result = ZSTD_compressCCtx(cctx, dest, osize, source, isize, level);
+
+ ZSTD_freeCCtx(cctx);
+ return (result);
+}
+
+
+static size_t
+real_zstd_decompress(const char *source, char *dest, int isize, int maxosize)
+{
+ size_t result;
+ ZSTD_DCtx *dctx;
+
+ dctx = ZSTD_createDCtx_advanced(zstd_malloc);
+ if (dctx == NULL)
+ return (ZSTD_error_memory_allocation);
+
+ result = ZSTD_decompressDCtx(dctx, dest, maxosize, source, isize);
+
+ ZSTD_freeDCtx(dctx);
+ return (result);
+}
+
+extern void *
+zstd_alloc(void *opaque __unused, size_t size)
+{
+ size_t nbytes = sizeof(struct zstd_kmem) + size;
+ struct zstd_kmem *z;
+ enum zstd_kmem_type type;
+ int i;
+
+ type = ZSTD_KMEM_UNKNOWN;
+ for (i = 0; i < ZSTD_KMEM_COUNT; i++) {
+ if (nbytes <= zstd_cache_size[i].kmem_size) {
+ type = zstd_cache_size[i].kmem_type;
+ z = kmem_cache_alloc(zstd_kmem_cache[type],
+ KM_NOSLEEP | M_ZERO);
+ break;
+ }
+ }
+ /* No matching cache */
+ if (type == ZSTD_KMEM_UNKNOWN) {
+ z = kmem_alloc(nbytes, KM_NOSLEEP | M_ZERO);
+ }
+ if (z == NULL) {
+ return (NULL);
+ }
+
+ z->kmem_magic = ZSTD_KMEM_MAGIC;
+ z->kmem_type = type;
+ z->kmem_size = nbytes;
+
+ return ((void*)z + (sizeof(struct zstd_kmem)));
+}
+
+extern void
+zstd_free(void *opaque __unused, void *ptr)
+{
+ struct zstd_kmem *z = ptr - sizeof(struct zstd_kmem);
+
+ ASSERT(z->kmem_magic == ZSTD_KMEM_MAGIC);
+ ASSERT(z->kmem_type < ZSTD_KMEM_COUNT);
+ ASSERT(z->kmem_type >= ZSTD_KMEM_UNKNOWN);
+
+ if (z->kmem_type == ZSTD_KMEM_UNKNOWN) {
+ kmem_free(z, z->kmem_size);
+ } else {
+ kmem_cache_free(zstd_kmem_cache[z->kmem_type], z);
+ }
+}
+
+extern void
+zstd_init(void)
+{
+ int i;
+
+ /* There is no estimate function for the CCtx itself */
+ zstd_cache_size[1].kmem_magic = ZSTD_KMEM_MAGIC;
+ zstd_cache_size[1].kmem_type = 1;
+ zstd_cache_size[1].kmem_size = roundup2(zstd_cache_config[1].block_size
+ + sizeof(struct zstd_kmem), PAGE_SIZE);
+ zstd_kmem_cache[1] = kmem_cache_create(
+ zstd_cache_config[1].cache_name, zstd_cache_size[1].kmem_size,
+ 0, NULL, NULL, NULL, NULL, NULL, 0);
+
+ /*
+ * Estimate the size of the ZSTD CCtx workspace required for each record
+ * size at each compression level.
+ */
+ for (i = 2; i < ZSTD_KMEM_DCTX; i++) {
+ ASSERT(zstd_cache_config[i].cache_name != NULL);
+ zstd_cache_size[i].kmem_magic = ZSTD_KMEM_MAGIC;
+ zstd_cache_size[i].kmem_type = i;
+ zstd_cache_size[i].kmem_size = roundup2(
+ ZSTD_estimateCCtxSize_usingCParams(
+ ZSTD_getCParams(zstd_cache_config[i].compress_level,
+ zstd_cache_config[i].block_size, 0)) +
+ sizeof(struct zstd_kmem), PAGE_SIZE);
+ zstd_kmem_cache[i] = kmem_cache_create(
+ zstd_cache_config[i].cache_name,
+ zstd_cache_size[i].kmem_size,
+ 0, NULL, NULL, NULL, NULL, NULL, 0);
+ }
+ /* Estimate the size of the decompression context */
+ zstd_cache_size[i].kmem_magic = ZSTD_KMEM_MAGIC;
+ zstd_cache_size[i].kmem_type = i;
+ zstd_cache_size[i].kmem_size = roundup2(ZSTD_estimateDCtxSize() +
+ sizeof(struct zstd_kmem), PAGE_SIZE);
+ zstd_kmem_cache[i] = kmem_cache_create(zstd_cache_config[i].cache_name,
+ zstd_cache_size[i].kmem_size, 0, NULL, NULL, NULL, NULL, NULL, 0);
+
+ /* Sort the kmem caches for later searching */
+ qsort(zstd_cache_size, ZSTD_KMEM_COUNT, sizeof(struct zstd_kmem),
+ zstd_compare);
+
+}
+
+extern void
+zstd_fini(void)
+{
+ int i, type;
+
+ for (i = 0; i < ZSTD_KMEM_COUNT; i++) {
+ type = zstd_cache_size[i].kmem_type;
+ if (zstd_kmem_cache[type] != NULL) {
+ kmem_cache_destroy(zstd_kmem_cache[type]);
+ }
+ }
+}
Index: sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
+++ sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
@@ -166,6 +166,7 @@
ZFS_PROP_PREV_SNAP,
ZFS_PROP_RECEIVE_RESUME_TOKEN,
ZFS_PROP_REMAPTXG, /* not exposed to the user */
+ ZFS_PROP_ZSTD_LEVEL, /* not exposed to the user */
ZFS_NUM_PROPS
} zfs_prop_t;
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -635,22 +635,22 @@
contrib/ngatm/netnatm/sig/sig_verify.c optional ngatm_uni \
compile-with "${NORMAL_C} -I$S/contrib/ngatm"
# Zstd
-contrib/zstd/lib/freebsd/zstd_kmalloc.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/common/zstd_common.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/common/fse_decompress.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/common/entropy_common.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/common/error_private.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/common/xxhash.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/zstd_compress.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/fse_compress.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/huf_compress.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/zstd_double_fast.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/zstd_fast.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/zstd_lazy.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/zstd_ldm.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/compress/zstd_opt.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/decompress/zstd_decompress.c optional zstdio compile-with ${ZSTD_C}
-contrib/zstd/lib/decompress/huf_decompress.c optional zstdio compile-with ${ZSTD_C}
+contrib/zstd/lib/freebsd/zstd_kmalloc.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/common/zstd_common.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/common/fse_decompress.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/common/entropy_common.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/common/error_private.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/common/xxhash.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/zstd_compress.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/fse_compress.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/huf_compress.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/zstd_double_fast.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/zstd_fast.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/zstd_lazy.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/zstd_ldm.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/compress/zstd_opt.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/decompress/zstd_decompress.c optional zstdio | zfs compile-with ${ZSTD_C}
+contrib/zstd/lib/decompress/huf_decompress.c optional zstdio | zfs compile-with ${ZSTD_C}
# Blake 2
contrib/libb2/blake2b-ref.c optional crypto | ipsec | ipsec_support \
compile-with "${NORMAL_C} -I$S/crypto/blake2 -Wno-cast-qual -DSUFFIX=_ref -Wno-unused-function"
Index: sys/modules/zfs/Makefile
===================================================================
--- sys/modules/zfs/Makefile
+++ sys/modules/zfs/Makefile
@@ -72,6 +72,11 @@
.PATH: ${SYSDIR}/crypto/skein
SRCS+= skein.c skein_block.c
+.PATH: ${SYSDIR}/contrib/zstd/lib
+CFLAGS+=-I${SYSDIR}/contrib/zstd/lib
+CFLAGS+=-I${SYSDIR}/contrib/zstd/lib/freebsd
+CFLAGS+=-I${SYSDIR}/contrib/zstd/lib/common
+
.PATH: ${SUNW}/common/zfs
.include "${SUNW}/uts/common/Makefile.files"
.PATH: ${SUNW}/uts/common/fs/zfs

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 28, 10:18 AM (11 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26281140
Default Alt Text
D11124.id45344.diff (58 KB)

Event Timeline