2 * BSD 3-Clause New License (https://spdx.org/licenses/BSD-3-Clause.html)
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
32 * Copyright (c) 2016-2018, Klara Inc.
33 * Copyright (c) 2016-2018, Allan Jude
34 * Copyright (c) 2018-2020, Sebastian Gottschall
35 * Copyright (c) 2019-2020, Michael Niewöhner
36 * Copyright (c) 2020, The FreeBSD Foundation [1]
38 * [1] Portions of this software were developed by Allan Jude
39 * under sponsorship from the FreeBSD Foundation.
51 * NOTE: all fields in this header are in big endian order.
53 typedef struct zfs_zstd_header
{
54 /* Compressed size of data */
58 * Version and compression level
59 * We used to use a union to reference compression level
60 * and version easily, but as it turns out, relying on the
61 * ordering of bitfields is not remotely portable.
62 * So now we have get/set functions in zfs_zstd.c for
63 * manipulating this in just the right way forever.
65 uint32_t raw_version_level
;
70 * Simple struct to pass the data from raw_version_level around.
72 typedef struct zfs_zstd_meta
{
80 #define ZSTDSTAT(stat) (zstd_stats.stat.value.ui64)
81 #define ZSTDSTAT_ZERO(stat) \
82 atomic_store_64(&zstd_stats.stat.value.ui64, 0)
83 #define ZSTDSTAT_ADD(stat, val) \
84 atomic_add_64(&zstd_stats.stat.value.ui64, (val))
85 #define ZSTDSTAT_SUB(stat, val) \
86 atomic_sub_64(&zstd_stats.stat.value.ui64, (val))
87 #define ZSTDSTAT_BUMP(stat) ZSTDSTAT_ADD(stat, 1)
89 /* (de)init for user space / kernel emulation */
93 size_t zfs_zstd_compress(abd_t
*src
, abd_t
*dst
, size_t s_len
,
94 size_t d_len
, int level
);
95 int zfs_zstd_get_level(void *s_start
, size_t s_len
, uint8_t *level
);
96 int zfs_zstd_decompress_level(abd_t
*src
, abd_t
*dst
, size_t s_len
,
97 size_t d_len
, uint8_t *level
);
98 int zfs_zstd_decompress(abd_t
*src
, abd_t
*dst
, size_t s_len
,
100 void zfs_zstd_cache_reap_now(void);
103 * So, the reason we have all these complicated set/get functions is that
104 * originally, in the zstd "header" we wrote out to disk, we used a 32-bit
105 * bitfield to store the "level" (8 bits) and "version" (24 bits).
107 * Unfortunately, bitfields make few promises about how they're arranged in
110 * By way of example, if we were using version 1.4.5 and level 3, it'd be
111 * level = 0x03, version = 10405/0x0028A5, which gets broken into Vhigh = 0x00,
112 * Vmid = 0x28, Vlow = 0xA5. We include these positions below to help follow
113 * which data winds up where.
115 * As a consequence, we wound up with little endian platforms with a layout
116 * like this in memory:
119 * +-------+-------+-------+-------+
120 * | Vlow | Vmid | Vhigh | level |
121 * +-------+-------+-------+-------+
124 * ...and then, after being run through BE_32(), serializing this out to
128 * +-------+-------+-------+-------+
129 * | level | Vhigh | Vmid | Vlow |
130 * +-------+-------+-------+-------+
133 * while on big-endian systems, since BE_32() is a noop there, both in
134 * memory and on disk, we wind up with:
137 * +-------+-------+-------+-------+
138 * | Vhigh | Vmid | Vlow | level |
139 * +-------+-------+-------+-------+
142 * (Vhigh is always 0 until version exceeds 6.55.35. Vmid and Vlow are the
143 * other two bytes of the "version" data.)
145 * So now we use the BF32_SET macros to get consistent behavior (the
146 * ondisk LE encoding, since x86 currently rules the world) across
147 * platforms, but the "get" behavior requires that we check each of the
148 * bytes in the aforementioned former-bitfield for 0x00, and from there,
149 * we can know which possible layout we're dealing with. (Only the two
150 * that have been observed in the wild are illustrated above, but handlers
151 * for all 4 positions of 0x00 are implemented.
155 zfs_get_hdrmeta(const zfs_zstdhdr_t
*blob
, zfs_zstdmeta_t
*res
)
157 uint32_t raw
= blob
->raw_version_level
;
158 uint8_t findme
= 0xff;
160 for (shift
= 0; shift
< 4; shift
++) {
161 findme
= BF32_GET(raw
, 8*shift
, 8);
167 res
->level
= BF32_GET(raw
, 24, 8);
168 res
->version
= BSWAP_32(raw
);
169 res
->version
= BF32_GET(res
->version
, 8, 24);
172 res
->level
= BF32_GET(raw
, 0, 8);
173 res
->version
= BSWAP_32(raw
);
174 res
->version
= BF32_GET(res
->version
, 0, 24);
177 res
->level
= BF32_GET(raw
, 24, 8);
178 res
->version
= BF32_GET(raw
, 0, 24);
181 res
->level
= BF32_GET(raw
, 0, 8);
182 res
->version
= BF32_GET(raw
, 8, 24);
191 static inline uint8_t
192 zfs_get_hdrlevel(const zfs_zstdhdr_t
*blob
)
196 zfs_get_hdrmeta(blob
, &res
);
201 static inline uint32_t
202 zfs_get_hdrversion(const zfs_zstdhdr_t
*blob
)
204 uint32_t version
= 0;
206 zfs_get_hdrmeta(blob
, &res
);
207 version
= res
.version
;
213 zfs_set_hdrversion(zfs_zstdhdr_t
*blob
, uint32_t version
)
215 /* cppcheck-suppress syntaxError */
216 BF32_SET(blob
->raw_version_level
, 0, 24, version
);
220 zfs_set_hdrlevel(zfs_zstdhdr_t
*blob
, uint8_t level
)
222 /* cppcheck-suppress syntaxError */
223 BF32_SET(blob
->raw_version_level
, 24, 8, level
);
231 #endif /* _ZFS_ZSTD_H */