From dbee1a907f51064f9c02fd4f434352d17ae0864d Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 19 Jun 2023 13:04:04 +1000 Subject: [PATCH] compress: add "slack" compression option The "slack" option simply searches from the end of the block backwards to the last non-zero byte, and sets that position as the "compressed" size. This patch is highly experimental; please see the associated PR for discussion. Signed-off-by: Rob Norris Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. --- include/sys/zio_compress.h | 5 +++ include/zfeature_common.h | 1 + lib/libzpool/Makefile.am | 1 + module/Kbuild.in | 1 + module/Makefile.bsd | 1 + module/zcommon/zfeature_common.c | 14 +++++++ module/zcommon/zfs_prop.c | 1 + module/zfs/slack.c | 72 ++++++++++++++++++++++++++++++++ module/zfs/zfs_ioctl.c | 14 +++++++ module/zfs/zio_compress.c | 4 ++ 10 files changed, 114 insertions(+) create mode 100644 module/zfs/slack.c diff --git a/include/sys/zio_compress.h b/include/sys/zio_compress.h index 31602039a150..7b38f890bf63 100644 --- a/include/sys/zio_compress.h +++ b/include/sys/zio_compress.h @@ -54,6 +54,7 @@ enum zio_compress { ZIO_COMPRESS_ZLE, ZIO_COMPRESS_LZ4, ZIO_COMPRESS_ZSTD, + ZIO_COMPRESS_SLACK, ZIO_COMPRESS_FUNCTIONS }; @@ -169,6 +170,10 @@ extern size_t zfs_lz4_compress(abd_t *src, abd_t *dst, size_t s_len, size_t d_len, int level); extern int zfs_lz4_decompress(abd_t *src, abd_t *dst, size_t s_len, size_t d_len, int level); +extern size_t zfs_slack_compress(abd_t *src, abd_t *dst, size_t s_len, + size_t d_len, int level); +extern int zfs_slack_decompress(abd_t *src, abd_t *dst, size_t s_len, + size_t d_len, int level); /* * Compress and decompress data if necessary. diff --git a/include/zfeature_common.h b/include/zfeature_common.h index 5733a8187a95..84d27da89061 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -83,6 +83,7 @@ typedef enum spa_feature { SPA_FEATURE_REDACTION_LIST_SPILL, SPA_FEATURE_RAIDZ_EXPANSION, SPA_FEATURE_FAST_DEDUP, + SPA_FEATURE_SLACK_COMPRESS, SPA_FEATURES } spa_feature_t; diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index ff30af7d2b9f..9c5287d3502b 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -126,6 +126,7 @@ nodist_libzpool_la_SOURCES = \ module/zfs/rrwlock.c \ module/zfs/sa.c \ module/zfs/sha2_zfs.c \ + module/zfs/slack.c \ module/zfs/skein_zfs.c \ module/zfs/spa.c \ module/zfs/spa_checkpoint.c \ diff --git a/module/Kbuild.in b/module/Kbuild.in index 0472a9348c13..c9cfbd7ea095 100644 --- a/module/Kbuild.in +++ b/module/Kbuild.in @@ -368,6 +368,7 @@ ZFS_OBJS := \ sa.o \ sha2_zfs.o \ skein_zfs.o \ + slack.o \ spa.o \ spa_checkpoint.o \ spa_config.o \ diff --git a/module/Makefile.bsd b/module/Makefile.bsd index 9161204c99d3..8986002e21f8 100644 --- a/module/Makefile.bsd +++ b/module/Makefile.bsd @@ -297,6 +297,7 @@ SRCS+= abd.c \ sa.c \ sha2_zfs.c \ skein_zfs.c \ + slack.c \ spa.c \ space_map.c \ space_reftree.c \ diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c index 8dec5f27b0af..ddbe5eef9817 100644 --- a/module/zcommon/zfeature_common.c +++ b/module/zcommon/zfeature_common.c @@ -760,6 +760,20 @@ zpool_feature_init(void) ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures); + { + { + static const spa_feature_t slack_deps[] = { + SPA_FEATURE_EXTENSIBLE_DATASET, + SPA_FEATURE_NONE + }; + zfeature_register(SPA_FEATURE_SLACK_COMPRESS, + "com.klarasystems:slack_compress", "slack_compress", + "slack compression support", + ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN, + slack_deps, sfeatures); + } + } + zfs_mod_list_supported_free(sfeatures); } diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 764993b45e7c..e5c7b8c386a9 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -130,6 +130,7 @@ zfs_prop_init(void) { "gzip-9", ZIO_COMPRESS_GZIP_9 }, { "zle", ZIO_COMPRESS_ZLE }, { "lz4", ZIO_COMPRESS_LZ4 }, + { "slack", ZIO_COMPRESS_SLACK }, { "zstd", ZIO_COMPRESS_ZSTD }, { "zstd-fast", ZIO_COMPLEVEL_ZSTD(ZIO_ZSTD_LEVEL_FAST_DEFAULT) }, diff --git a/module/zfs/slack.c b/module/zfs/slack.c new file mode 100644 index 000000000000..29a078844a3a --- /dev/null +++ b/module/zfs/slack.c @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2023, Klara Inc. + */ + +#include +#include + +/* + * Slack compression simply searches for the last non-zero byte in the buffer, + * and sets the position as the size of the "compressed" data. + */ + +static size_t +zfs_slack_compress_buf(void *src, void *dst, size_t s_len, size_t d_len, + int level) +{ + (void) level; + + ASSERT3U(s_len, >, 0); + ASSERT0(P2PHASE(s_len, sizeof (uint64_t))); + + uint64_t *buf = (uint64_t *)src; + + int p = (s_len / sizeof (uint64_t)) - 1; + for (; p >= 0; p--) + if (buf[p] != 0) + break; + + if (p < 0) + return (s_len); + + size_t c_len = (p + 1) * sizeof (uint64_t); + if (c_len > d_len) + return (s_len); + + memcpy(dst, src, c_len); + return (c_len); +} + +static int +zfs_slack_decompress_buf(void *src, void *dst, size_t s_len, size_t d_len, + int level) +{ + (void) level; + ASSERT3U(d_len, >=, s_len); + memcpy(dst, src, s_len); + return (0); +} + +ZFS_COMPRESS_WRAP_DECL(zfs_slack_compress) +ZFS_DECOMPRESS_WRAP_DECL(zfs_slack_decompress) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 53366ad49781..5d396ae21cf9 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -4806,6 +4806,20 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) } spa_close(spa, FTAG); } + + if (compval == ZIO_COMPRESS_SLACK) { + spa_t *spa; + + if ((err = spa_open(dsname, &spa, FTAG)) != 0) + return (err); + + if (!spa_feature_is_enabled(spa, + SPA_FEATURE_SLACK_COMPRESS)) { + spa_close(spa, FTAG); + return (SET_ERROR(ENOTSUP)); + } + spa_close(spa, FTAG); + } } break; diff --git a/module/zfs/zio_compress.c b/module/zfs/zio_compress.c index 9182917f75eb..1ab21fe2dd84 100644 --- a/module/zfs/zio_compress.c +++ b/module/zfs/zio_compress.c @@ -84,6 +84,8 @@ zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { zfs_lz4_compress, zfs_lz4_decompress, NULL}, {"zstd", ZIO_ZSTD_LEVEL_DEFAULT, zfs_zstd_compress, zfs_zstd_decompress, zfs_zstd_decompress_level}, + {"slack", 0, + zfs_slack_compress, zfs_slack_decompress, NULL }, }; uint8_t @@ -200,6 +202,8 @@ zio_compress_to_feature(enum zio_compress comp) switch (comp) { case ZIO_COMPRESS_ZSTD: return (SPA_FEATURE_ZSTD_COMPRESS); + case ZIO_COMPRESS_SLACK: + return (SPA_FEATURE_SLACK_COMPRESS); default: break; }