mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Fix cross-endian interoperability of zstd
It turns out that layouts of union bitfields are a pain, and the current code results in an inconsistent layout between BE and LE systems, leading to zstd-active datasets on one erroring out on the other. Switch everyone over to the LE layout, and add compatibility code to read both. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Matthew Ahrens <mahrens@delphix.com> Signed-off-by: Rich Ercolani <rincebrain@gmail.com> Closes #12008 Closes #12022
This commit is contained in:
@@ -33,6 +33,7 @@ $(obj)/zfs_zstd.o: c_flags += -include $(zstd_include)/zstd_compat_wrapper.h
|
||||
|
||||
$(MODULE)-objs += zfs_zstd.o
|
||||
$(MODULE)-objs += lib/zstd.o
|
||||
$(MODULE)-objs += zstd_sparc.o
|
||||
|
||||
all:
|
||||
mkdir -p lib
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#if defined(__sparc)
|
||||
uint64_t __bswapdi2(uint64_t in);
|
||||
uint32_t __bswapsi2(uint32_t in);
|
||||
#endif
|
||||
@@ -380,6 +380,7 @@ zstd_enum_to_level(enum zio_zstd_levels level, int16_t *zstd_level)
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* Compress block using zstd */
|
||||
size_t
|
||||
zfs_zstd_compress(void *s_start, void *d_start, size_t s_len, size_t d_len,
|
||||
@@ -477,8 +478,8 @@ zfs_zstd_compress(void *s_start, void *d_start, size_t s_len, size_t d_len,
|
||||
* As soon as such incompatibility occurs, handling code needs to be
|
||||
* added, differentiating between the versions.
|
||||
*/
|
||||
hdr->version = ZSTD_VERSION_NUMBER;
|
||||
hdr->level = level;
|
||||
zfs_set_hdrversion(hdr, ZSTD_VERSION_NUMBER);
|
||||
zfs_set_hdrlevel(hdr, level);
|
||||
hdr->raw_version_level = BE_32(hdr->raw_version_level);
|
||||
|
||||
return (c_len + sizeof (*hdr));
|
||||
@@ -504,6 +505,7 @@ zfs_zstd_decompress_level(void *s_start, void *d_start, size_t s_len,
|
||||
* not modify the original data that may be used again later.
|
||||
*/
|
||||
hdr_copy.raw_version_level = BE_32(hdr->raw_version_level);
|
||||
uint8_t curlevel = zfs_get_hdrlevel(&hdr_copy);
|
||||
|
||||
/*
|
||||
* NOTE: We ignore the ZSTD version for now. As soon as any
|
||||
@@ -516,13 +518,13 @@ zfs_zstd_decompress_level(void *s_start, void *d_start, size_t s_len,
|
||||
* An invalid level is a strong indicator for data corruption! In such
|
||||
* case return an error so the upper layers can try to fix it.
|
||||
*/
|
||||
if (zstd_enum_to_level(hdr_copy.level, &zstd_level)) {
|
||||
if (zstd_enum_to_level(curlevel, &zstd_level)) {
|
||||
ZSTDSTAT_BUMP(zstd_stat_dec_inval);
|
||||
return (1);
|
||||
}
|
||||
|
||||
ASSERT3U(d_len, >=, s_len);
|
||||
ASSERT3U(hdr_copy.level, !=, ZIO_COMPLEVEL_INHERIT);
|
||||
ASSERT3U(curlevel, !=, ZIO_COMPLEVEL_INHERIT);
|
||||
|
||||
/* Invalid compressed buffer size encoded at start */
|
||||
if (c_len + sizeof (*hdr) > s_len) {
|
||||
@@ -553,7 +555,7 @@ zfs_zstd_decompress_level(void *s_start, void *d_start, size_t s_len,
|
||||
}
|
||||
|
||||
if (level) {
|
||||
*level = hdr_copy.level;
|
||||
*level = curlevel;
|
||||
}
|
||||
|
||||
return (0);
|
||||
@@ -783,7 +785,7 @@ module_exit(zstd_fini);
|
||||
|
||||
ZFS_MODULE_DESCRIPTION("ZSTD Compression for ZFS");
|
||||
ZFS_MODULE_LICENSE("Dual BSD/GPL");
|
||||
ZFS_MODULE_VERSION(ZSTD_VERSION_STRING);
|
||||
ZFS_MODULE_VERSION(ZSTD_VERSION_STRING "a");
|
||||
|
||||
EXPORT_SYMBOL(zfs_zstd_compress);
|
||||
EXPORT_SYMBOL(zfs_zstd_decompress_level);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifdef __sparc__
|
||||
#include <stdint.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include "include/sparc_compat.h"
|
||||
uint64_t __bswapdi2(uint64_t in) {
|
||||
return (BSWAP_64(in));
|
||||
}
|
||||
uint32_t __bswapsi2(uint32_t in) {
|
||||
return (BSWAP_32(in));
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user