Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137934473
D11124.id45344.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
58 KB
Referenced Files
None
Subscribers
None
D11124.id45344.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D11124: ZSTD compression for ZFS
Attached
Detach File
Event Timeline
Log In to Comment