aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorRich Ercolani <[email protected]>2021-08-30 17:13:46 -0400
committerTony Hutter <[email protected]>2021-09-14 15:05:55 -0700
commit72a989cf60b4c7b9a46dc5854c0bd2561ce6b576 (patch)
tree8133d7ee2002161fe3f3c20c7020d3d7c5b15e5c /module
parent6bb6410570e6aeb19ae82d9287922927432f8c74 (diff)
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 <[email protected]> Reviewed-by: Matthew Ahrens <[email protected]> Signed-off-by: Rich Ercolani <[email protected]> Closes #12008 Closes #12022
Diffstat (limited to 'module')
-rw-r--r--module/zstd/Makefile.in1
-rw-r--r--module/zstd/include/sparc_compat.h4
-rw-r--r--module/zstd/zfs_zstd.c14
-rw-r--r--module/zstd/zstd_sparc.c11
4 files changed, 24 insertions, 6 deletions
diff --git a/module/zstd/Makefile.in b/module/zstd/Makefile.in
index f67db710f..091f7cea3 100644
--- a/module/zstd/Makefile.in
+++ b/module/zstd/Makefile.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
diff --git a/module/zstd/include/sparc_compat.h b/module/zstd/include/sparc_compat.h
new file mode 100644
index 000000000..14c1bdde9
--- /dev/null
+++ b/module/zstd/include/sparc_compat.h
@@ -0,0 +1,4 @@
+#if defined(__sparc)
+uint64_t __bswapdi2(uint64_t in);
+uint32_t __bswapsi2(uint32_t in);
+#endif
diff --git a/module/zstd/zfs_zstd.c b/module/zstd/zfs_zstd.c
index a91ed1be9..2c698716c 100644
--- a/module/zstd/zfs_zstd.c
+++ b/module/zstd/zfs_zstd.c
@@ -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);
diff --git a/module/zstd/zstd_sparc.c b/module/zstd/zstd_sparc.c
new file mode 100644
index 000000000..463df99bd
--- /dev/null
+++ b/module/zstd/zstd_sparc.c
@@ -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