You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1135 lines
36 KiB
1135 lines
36 KiB
# Calculate format=diff
|
|
From 9d55c70c87606f9632da8bf9fdcf0f633f165f2f Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:06 -0700
|
|
Subject: [PATCH 1/9] lib: prepare zstd for preboot environment
|
|
|
|
* Don't export symbols if ZSTD_PREBOOT is defined.
|
|
* Remove a double definition of the CHECK_F macro when the zstd
|
|
library is amalgamated.
|
|
* Switch ZSTD_copy8() to __builtin_memcpy(), because in the preboot
|
|
environment on x86 gcc can't inline `memcpy()` otherwise.
|
|
* Limit the gcc hack in ZSTD_wildcopy() to the broken gcc version. See
|
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
|
|
|
|
These changes are necessary to get the build to work in the preboot
|
|
environment, and to get reasonable performance. ZSTD_copy8() and
|
|
ZSTD_wildcopy() are in the core of the zstd hot loop. So outlining
|
|
these calls to memcpy(), and having an extra branch are very
|
|
detrimental to performance.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
lib/zstd/decompress.c | 2 ++
|
|
lib/zstd/fse_decompress.c | 9 +--------
|
|
lib/zstd/zstd_internal.h | 14 ++++++++++++--
|
|
3 files changed, 15 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/lib/zstd/decompress.c b/lib/zstd/decompress.c
|
|
index 269ee9a79..73ded6327 100644
|
|
--- a/lib/zstd/decompress.c
|
|
+++ b/lib/zstd/decompress.c
|
|
@@ -2490,6 +2490,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inB
|
|
}
|
|
}
|
|
|
|
+#ifndef ZSTD_PREBOOT
|
|
EXPORT_SYMBOL(ZSTD_DCtxWorkspaceBound);
|
|
EXPORT_SYMBOL(ZSTD_initDCtx);
|
|
EXPORT_SYMBOL(ZSTD_decompressDCtx);
|
|
@@ -2529,3 +2530,4 @@ EXPORT_SYMBOL(ZSTD_insertBlock);
|
|
|
|
MODULE_LICENSE("Dual BSD/GPL");
|
|
MODULE_DESCRIPTION("Zstd Decompressor");
|
|
+#endif
|
|
diff --git a/lib/zstd/fse_decompress.c b/lib/zstd/fse_decompress.c
|
|
index a84300e5a..0b353530f 100644
|
|
--- a/lib/zstd/fse_decompress.c
|
|
+++ b/lib/zstd/fse_decompress.c
|
|
@@ -47,6 +47,7 @@
|
|
****************************************************************/
|
|
#include "bitstream.h"
|
|
#include "fse.h"
|
|
+#include "zstd_internal.h"
|
|
#include <linux/compiler.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h> /* memcpy, memset */
|
|
@@ -60,14 +61,6 @@
|
|
enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
|
|
} /* use only *after* variable declarations */
|
|
|
|
-/* check and forward error code */
|
|
-#define CHECK_F(f) \
|
|
- { \
|
|
- size_t const e = f; \
|
|
- if (FSE_isError(e)) \
|
|
- return e; \
|
|
- }
|
|
-
|
|
/* **************************************************************
|
|
* Templates
|
|
****************************************************************/
|
|
diff --git a/lib/zstd/zstd_internal.h b/lib/zstd/zstd_internal.h
|
|
index 1a79fab9e..dac753397 100644
|
|
--- a/lib/zstd/zstd_internal.h
|
|
+++ b/lib/zstd/zstd_internal.h
|
|
@@ -127,7 +127,14 @@ static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
|
|
* Shared functions to include for inlining
|
|
*********************************************/
|
|
ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) {
|
|
- memcpy(dst, src, 8);
|
|
+ /*
|
|
+ * zstd relies heavily on gcc being able to analyze and inline this
|
|
+ * memcpy() call, since it is called in a tight loop. Preboot mode
|
|
+ * is compiled in freestanding mode, which stops gcc from analyzing
|
|
+ * memcpy(). Use __builtin_memcpy() to tell gcc to analyze this as a
|
|
+ * regular memcpy().
|
|
+ */
|
|
+ __builtin_memcpy(dst, src, 8);
|
|
}
|
|
/*! ZSTD_wildcopy() :
|
|
* custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
|
|
@@ -137,13 +144,16 @@ ZSTD_STATIC void ZSTD_wildcopy(void *dst, const void *src, ptrdiff_t length)
|
|
const BYTE* ip = (const BYTE*)src;
|
|
BYTE* op = (BYTE*)dst;
|
|
BYTE* const oend = op + length;
|
|
- /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
|
|
+#if defined(GCC_VERSION) && GCC_VERSION >= 70000 && GCC_VERSION < 70200
|
|
+ /*
|
|
+ * Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
|
|
* Avoid the bad case where the loop only runs once by handling the
|
|
* special case separately. This doesn't trigger the bug because it
|
|
* doesn't involve pointer/integer overflow.
|
|
*/
|
|
if (length <= 8)
|
|
return ZSTD_copy8(dst, src);
|
|
+#endif
|
|
do {
|
|
ZSTD_copy8(op, ip);
|
|
op += 8;
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From f2f7175166743fee3fe359a487f341dfb2f1ee50 Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:07 -0700
|
|
Subject: [PATCH 2/9] lib: prepare xxhash for preboot environment
|
|
|
|
Don't export symbols if XXH_PREBOOT is defined.
|
|
|
|
This change is necessary to get xxhash to work in a preboot environment,
|
|
which is needed to support zstd-compressed kernels.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
lib/xxhash.c | 21 ++++++++++++---------
|
|
1 file changed, 12 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/lib/xxhash.c b/lib/xxhash.c
|
|
index aa61e2a38..b4364e011 100644
|
|
--- a/lib/xxhash.c
|
|
+++ b/lib/xxhash.c
|
|
@@ -80,13 +80,11 @@ void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
|
|
{
|
|
memcpy(dst, src, sizeof(*dst));
|
|
}
|
|
-EXPORT_SYMBOL(xxh32_copy_state);
|
|
|
|
void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
|
|
{
|
|
memcpy(dst, src, sizeof(*dst));
|
|
}
|
|
-EXPORT_SYMBOL(xxh64_copy_state);
|
|
|
|
/*-***************************
|
|
* Simple Hash Functions
|
|
@@ -151,7 +149,6 @@ uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
|
|
|
|
return h32;
|
|
}
|
|
-EXPORT_SYMBOL(xxh32);
|
|
|
|
static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
|
|
{
|
|
@@ -234,7 +231,6 @@ uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
|
|
|
|
return h64;
|
|
}
|
|
-EXPORT_SYMBOL(xxh64);
|
|
|
|
/*-**************************************************
|
|
* Advanced Hash Functions
|
|
@@ -251,7 +247,6 @@ void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
|
|
state.v4 = seed - PRIME32_1;
|
|
memcpy(statePtr, &state, sizeof(state));
|
|
}
|
|
-EXPORT_SYMBOL(xxh32_reset);
|
|
|
|
void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
|
|
{
|
|
@@ -265,7 +260,6 @@ void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
|
|
state.v4 = seed - PRIME64_1;
|
|
memcpy(statePtr, &state, sizeof(state));
|
|
}
|
|
-EXPORT_SYMBOL(xxh64_reset);
|
|
|
|
int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
|
|
{
|
|
@@ -334,7 +328,6 @@ int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
|
|
|
|
return 0;
|
|
}
|
|
-EXPORT_SYMBOL(xxh32_update);
|
|
|
|
uint32_t xxh32_digest(const struct xxh32_state *state)
|
|
{
|
|
@@ -372,7 +365,6 @@ uint32_t xxh32_digest(const struct xxh32_state *state)
|
|
|
|
return h32;
|
|
}
|
|
-EXPORT_SYMBOL(xxh32_digest);
|
|
|
|
int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
|
|
{
|
|
@@ -439,7 +431,6 @@ int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
|
|
|
|
return 0;
|
|
}
|
|
-EXPORT_SYMBOL(xxh64_update);
|
|
|
|
uint64_t xxh64_digest(const struct xxh64_state *state)
|
|
{
|
|
@@ -494,7 +485,19 @@ uint64_t xxh64_digest(const struct xxh64_state *state)
|
|
|
|
return h64;
|
|
}
|
|
+
|
|
+#ifndef XXH_PREBOOT
|
|
+EXPORT_SYMBOL(xxh32_copy_state);
|
|
+EXPORT_SYMBOL(xxh64_copy_state);
|
|
+EXPORT_SYMBOL(xxh32);
|
|
+EXPORT_SYMBOL(xxh64);
|
|
+EXPORT_SYMBOL(xxh32_reset);
|
|
+EXPORT_SYMBOL(xxh64_reset);
|
|
+EXPORT_SYMBOL(xxh32_update);
|
|
+EXPORT_SYMBOL(xxh32_digest);
|
|
+EXPORT_SYMBOL(xxh64_update);
|
|
EXPORT_SYMBOL(xxh64_digest);
|
|
|
|
MODULE_LICENSE("Dual BSD/GPL");
|
|
MODULE_DESCRIPTION("xxHash");
|
|
+#endif
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From 2800faddf67a8fabbb4532cb520b84acaadd054e Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:08 -0700
|
|
Subject: [PATCH 3/9] lib: add zstd support to decompress
|
|
|
|
* Add unzstd() and the zstd decompress interface.
|
|
* Add zstd support to decompress_method().
|
|
|
|
The decompress_method() and unzstd() functions are used to decompress
|
|
the initramfs and the initrd. The __decompress() function is used in
|
|
the preboot environment to decompress a zstd compressed kernel.
|
|
|
|
The zstd decompression function allows the input and output buffers to
|
|
overlap because that is used by x86 kernel decompression.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
include/linux/decompress/unzstd.h | 11 +
|
|
lib/Kconfig | 4 +
|
|
lib/Makefile | 1 +
|
|
lib/decompress.c | 5 +
|
|
lib/decompress_unzstd.c | 342 ++++++++++++++++++++++++++++++
|
|
5 files changed, 363 insertions(+)
|
|
create mode 100644 include/linux/decompress/unzstd.h
|
|
create mode 100644 lib/decompress_unzstd.c
|
|
|
|
diff --git a/include/linux/decompress/unzstd.h b/include/linux/decompress/unzstd.h
|
|
new file mode 100644
|
|
index 000000000..56d539ae8
|
|
--- /dev/null
|
|
+++ b/include/linux/decompress/unzstd.h
|
|
@@ -0,0 +1,11 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+#ifndef LINUX_DECOMPRESS_UNZSTD_H
|
|
+#define LINUX_DECOMPRESS_UNZSTD_H
|
|
+
|
|
+int unzstd(unsigned char *inbuf, long len,
|
|
+ long (*fill)(void*, unsigned long),
|
|
+ long (*flush)(void*, unsigned long),
|
|
+ unsigned char *output,
|
|
+ long *pos,
|
|
+ void (*error_fn)(char *x));
|
|
+#endif
|
|
diff --git a/lib/Kconfig b/lib/Kconfig
|
|
index bc7e56370..11de5fa09 100644
|
|
--- a/lib/Kconfig
|
|
+++ b/lib/Kconfig
|
|
@@ -336,6 +336,10 @@ config DECOMPRESS_LZ4
|
|
select LZ4_DECOMPRESS
|
|
tristate
|
|
|
|
+config DECOMPRESS_ZSTD
|
|
+ select ZSTD_DECOMPRESS
|
|
+ tristate
|
|
+
|
|
#
|
|
# Generic allocator support is selected if needed
|
|
#
|
|
diff --git a/lib/Makefile b/lib/Makefile
|
|
index 611872c06..09ad45ba6 100644
|
|
--- a/lib/Makefile
|
|
+++ b/lib/Makefile
|
|
@@ -160,6 +160,7 @@ lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o
|
|
lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o
|
|
lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o
|
|
lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o
|
|
+lib-$(CONFIG_DECOMPRESS_ZSTD) += decompress_unzstd.o
|
|
|
|
obj-$(CONFIG_TEXTSEARCH) += textsearch.o
|
|
obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
|
|
diff --git a/lib/decompress.c b/lib/decompress.c
|
|
index 857ab1af1..ab3fc90ff 100644
|
|
--- a/lib/decompress.c
|
|
+++ b/lib/decompress.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/decompress/inflate.h>
|
|
#include <linux/decompress/unlzo.h>
|
|
#include <linux/decompress/unlz4.h>
|
|
+#include <linux/decompress/unzstd.h>
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/string.h>
|
|
@@ -37,6 +38,9 @@
|
|
#ifndef CONFIG_DECOMPRESS_LZ4
|
|
# define unlz4 NULL
|
|
#endif
|
|
+#ifndef CONFIG_DECOMPRESS_ZSTD
|
|
+# define unzstd NULL
|
|
+#endif
|
|
|
|
struct compress_format {
|
|
unsigned char magic[2];
|
|
@@ -52,6 +56,7 @@ static const struct compress_format compressed_formats[] __initconst = {
|
|
{ {0xfd, 0x37}, "xz", unxz },
|
|
{ {0x89, 0x4c}, "lzo", unlzo },
|
|
{ {0x02, 0x21}, "lz4", unlz4 },
|
|
+ { {0x28, 0xb5}, "zstd", unzstd },
|
|
{ {0, 0}, NULL, NULL }
|
|
};
|
|
|
|
diff --git a/lib/decompress_unzstd.c b/lib/decompress_unzstd.c
|
|
new file mode 100644
|
|
index 000000000..f317afab5
|
|
--- /dev/null
|
|
+++ b/lib/decompress_unzstd.c
|
|
@@ -0,0 +1,342 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+/*
|
|
+ * Important notes about in-place decompression
|
|
+ *
|
|
+ * At least on x86, the kernel is decompressed in place: the compressed data
|
|
+ * is placed to the end of the output buffer, and the decompressor overwrites
|
|
+ * most of the compressed data. There must be enough safety margin to
|
|
+ * guarantee that the write position is always behind the read position.
|
|
+ *
|
|
+ * The safety margin for ZSTD with a 128 KB block size is calculated below.
|
|
+ * Note that the margin with ZSTD is bigger than with GZIP or XZ!
|
|
+ *
|
|
+ * The worst case for in-place decompression is that the beginning of
|
|
+ * the file is compressed extremely well, and the rest of the file is
|
|
+ * uncompressible. Thus, we must look for worst-case expansion when the
|
|
+ * compressor is encoding uncompressible data.
|
|
+ *
|
|
+ * The structure of the .zst file in case of a compresed kernel is as follows.
|
|
+ * Maximum sizes (as bytes) of the fields are in parenthesis.
|
|
+ *
|
|
+ * Frame Header: (18)
|
|
+ * Blocks: (N)
|
|
+ * Checksum: (4)
|
|
+ *
|
|
+ * The frame header and checksum overhead is at most 22 bytes.
|
|
+ *
|
|
+ * ZSTD stores the data in blocks. Each block has a header whose size is
|
|
+ * a 3 bytes. After the block header, there is up to 128 KB of payload.
|
|
+ * The maximum uncompressed size of the payload is 128 KB. The minimum
|
|
+ * uncompressed size of the payload is never less than the payload size
|
|
+ * (excluding the block header).
|
|
+ *
|
|
+ * The assumption, that the uncompressed size of the payload is never
|
|
+ * smaller than the payload itself, is valid only when talking about
|
|
+ * the payload as a whole. It is possible that the payload has parts where
|
|
+ * the decompressor consumes more input than it produces output. Calculating
|
|
+ * the worst case for this would be tricky. Instead of trying to do that,
|
|
+ * let's simply make sure that the decompressor never overwrites any bytes
|
|
+ * of the payload which it is currently reading.
|
|
+ *
|
|
+ * Now we have enough information to calculate the safety margin. We need
|
|
+ * - 22 bytes for the .zst file format headers;
|
|
+ * - 3 bytes per every 128 KiB of uncompressed size (one block header per
|
|
+ * block); and
|
|
+ * - 128 KiB (biggest possible zstd block size) to make sure that the
|
|
+ * decompressor never overwrites anything from the block it is currently
|
|
+ * reading.
|
|
+ *
|
|
+ * We get the following formula:
|
|
+ *
|
|
+ * safety_margin = 22 + uncompressed_size * 3 / 131072 + 131072
|
|
+ * <= 22 + (uncompressed_size >> 15) + 131072
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Preboot environments #include "path/to/decompress_unzstd.c".
|
|
+ * All of the source files we depend on must be #included.
|
|
+ * zstd's only source dependeny is xxhash, which has no source
|
|
+ * dependencies.
|
|
+ *
|
|
+ * zstd and xxhash avoid declaring themselves as modules
|
|
+ * when ZSTD_PREBOOT and XXH_PREBOOT are defined.
|
|
+ */
|
|
+#ifdef STATIC
|
|
+# define ZSTD_PREBOOT
|
|
+# define XXH_PREBOOT
|
|
+# include "xxhash.c"
|
|
+# include "zstd/entropy_common.c"
|
|
+# include "zstd/fse_decompress.c"
|
|
+# include "zstd/huf_decompress.c"
|
|
+# include "zstd/zstd_common.c"
|
|
+# include "zstd/decompress.c"
|
|
+#endif
|
|
+
|
|
+#include <linux/decompress/mm.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/zstd.h>
|
|
+
|
|
+/* 128MB is the maximum window size supported by zstd. */
|
|
+#define ZSTD_WINDOWSIZE_MAX (1 << ZSTD_WINDOWLOG_MAX)
|
|
+/* Size of the input and output buffers in multi-call mode.
|
|
+ * Pick a larger size because it isn't used during kernel decompression,
|
|
+ * since that is single pass, and we have to allocate a large buffer for
|
|
+ * zstd's window anyways. The larger size speeds up initramfs decompression.
|
|
+ */
|
|
+#define ZSTD_IOBUF_SIZE (1 << 17)
|
|
+
|
|
+static int INIT handle_zstd_error(size_t ret, void (*error)(char *x))
|
|
+{
|
|
+ const int err = ZSTD_getErrorCode(ret);
|
|
+
|
|
+ if (!ZSTD_isError(ret))
|
|
+ return 0;
|
|
+
|
|
+ switch (err) {
|
|
+ case ZSTD_error_memory_allocation:
|
|
+ error("ZSTD decompressor ran out of memory");
|
|
+ break;
|
|
+ case ZSTD_error_prefix_unknown:
|
|
+ error("Input is not in the ZSTD format (wrong magic bytes)");
|
|
+ break;
|
|
+ case ZSTD_error_dstSize_tooSmall:
|
|
+ case ZSTD_error_corruption_detected:
|
|
+ case ZSTD_error_checksum_wrong:
|
|
+ error("ZSTD-compressed data is corrupt");
|
|
+ break;
|
|
+ default:
|
|
+ error("ZSTD-compressed data is probably corrupt");
|
|
+ break;
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Handle the case where we have the entire input and output in one segment.
|
|
+ * We can allocate less memory (no circular buffer for the sliding window),
|
|
+ * and avoid some memcpy() calls.
|
|
+ */
|
|
+static int INIT decompress_single(const u8 *in_buf, long in_len, u8 *out_buf,
|
|
+ long out_len, long *in_pos,
|
|
+ void (*error)(char *x))
|
|
+{
|
|
+ const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
|
|
+ void *wksp = large_malloc(wksp_size);
|
|
+ ZSTD_DCtx *dctx = ZSTD_initDCtx(wksp, wksp_size);
|
|
+ int err;
|
|
+ size_t ret;
|
|
+
|
|
+ if (dctx == NULL) {
|
|
+ error("Out of memory while allocating ZSTD_DCtx");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ /*
|
|
+ * Find out how large the frame actually is, there may be junk at
|
|
+ * the end of the frame that ZSTD_decompressDCtx() can't handle.
|
|
+ */
|
|
+ ret = ZSTD_findFrameCompressedSize(in_buf, in_len);
|
|
+ err = handle_zstd_error(ret, error);
|
|
+ if (err)
|
|
+ goto out;
|
|
+ in_len = (long)ret;
|
|
+
|
|
+ ret = ZSTD_decompressDCtx(dctx, out_buf, out_len, in_buf, in_len);
|
|
+ err = handle_zstd_error(ret, error);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ if (in_pos != NULL)
|
|
+ *in_pos = in_len;
|
|
+
|
|
+ err = 0;
|
|
+out:
|
|
+ if (wksp != NULL)
|
|
+ large_free(wksp);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int INIT __unzstd(unsigned char *in_buf, long in_len,
|
|
+ long (*fill)(void*, unsigned long),
|
|
+ long (*flush)(void*, unsigned long),
|
|
+ unsigned char *out_buf, long out_len,
|
|
+ long *in_pos,
|
|
+ void (*error)(char *x))
|
|
+{
|
|
+ ZSTD_inBuffer in;
|
|
+ ZSTD_outBuffer out;
|
|
+ ZSTD_frameParams params;
|
|
+ void *in_allocated = NULL;
|
|
+ void *out_allocated = NULL;
|
|
+ void *wksp = NULL;
|
|
+ size_t wksp_size;
|
|
+ ZSTD_DStream *dstream;
|
|
+ int err;
|
|
+ size_t ret;
|
|
+
|
|
+ if (out_len == 0)
|
|
+ out_len = LONG_MAX; /* no limit */
|
|
+
|
|
+ if (fill == NULL && flush == NULL)
|
|
+ /*
|
|
+ * We can decompress faster and with less memory when we have a
|
|
+ * single chunk.
|
|
+ */
|
|
+ return decompress_single(in_buf, in_len, out_buf, out_len,
|
|
+ in_pos, error);
|
|
+
|
|
+ /*
|
|
+ * If in_buf is not provided, we must be using fill(), so allocate
|
|
+ * a large enough buffer. If it is provided, it must be at least
|
|
+ * ZSTD_IOBUF_SIZE large.
|
|
+ */
|
|
+ if (in_buf == NULL) {
|
|
+ in_allocated = large_malloc(ZSTD_IOBUF_SIZE);
|
|
+ if (in_allocated == NULL) {
|
|
+ error("Out of memory while allocating input buffer");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ in_buf = in_allocated;
|
|
+ in_len = 0;
|
|
+ }
|
|
+ /* Read the first chunk, since we need to decode the frame header. */
|
|
+ if (fill != NULL)
|
|
+ in_len = fill(in_buf, ZSTD_IOBUF_SIZE);
|
|
+ if (in_len < 0) {
|
|
+ error("ZSTD-compressed data is truncated");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ /* Set the first non-empty input buffer. */
|
|
+ in.src = in_buf;
|
|
+ in.pos = 0;
|
|
+ in.size = in_len;
|
|
+ /* Allocate the output buffer if we are using flush(). */
|
|
+ if (flush != NULL) {
|
|
+ out_allocated = large_malloc(ZSTD_IOBUF_SIZE);
|
|
+ if (out_allocated == NULL) {
|
|
+ error("Out of memory while allocating output buffer");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ out_buf = out_allocated;
|
|
+ out_len = ZSTD_IOBUF_SIZE;
|
|
+ }
|
|
+ /* Set the output buffer. */
|
|
+ out.dst = out_buf;
|
|
+ out.pos = 0;
|
|
+ out.size = out_len;
|
|
+
|
|
+ /*
|
|
+ * We need to know the window size to allocate the ZSTD_DStream.
|
|
+ * Since we are streaming, we need to allocate a buffer for the sliding
|
|
+ * window. The window size varies from 1 KB to ZSTD_WINDOWSIZE_MAX
|
|
+ * (8 MB), so it is important to use the actual value so as not to
|
|
+ * waste memory when it is smaller.
|
|
+ */
|
|
+ ret = ZSTD_getFrameParams(¶ms, in.src, in.size);
|
|
+ err = handle_zstd_error(ret, error);
|
|
+ if (err)
|
|
+ goto out;
|
|
+ if (ret != 0) {
|
|
+ error("ZSTD-compressed data has an incomplete frame header");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ if (params.windowSize > ZSTD_WINDOWSIZE_MAX) {
|
|
+ error("ZSTD-compressed data has too large a window size");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Allocate the ZSTD_DStream now that we know how much memory is
|
|
+ * required.
|
|
+ */
|
|
+ wksp_size = ZSTD_DStreamWorkspaceBound(params.windowSize);
|
|
+ wksp = large_malloc(wksp_size);
|
|
+ dstream = ZSTD_initDStream(params.windowSize, wksp, wksp_size);
|
|
+ if (dstream == NULL) {
|
|
+ error("Out of memory while allocating ZSTD_DStream");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Decompression loop:
|
|
+ * Read more data if necessary (error if no more data can be read).
|
|
+ * Call the decompression function, which returns 0 when finished.
|
|
+ * Flush any data produced if using flush().
|
|
+ */
|
|
+ if (in_pos != NULL)
|
|
+ *in_pos = 0;
|
|
+ do {
|
|
+ /*
|
|
+ * If we need to reload data, either we have fill() and can
|
|
+ * try to get more data, or we don't and the input is truncated.
|
|
+ */
|
|
+ if (in.pos == in.size) {
|
|
+ if (in_pos != NULL)
|
|
+ *in_pos += in.pos;
|
|
+ in_len = fill ? fill(in_buf, ZSTD_IOBUF_SIZE) : -1;
|
|
+ if (in_len < 0) {
|
|
+ error("ZSTD-compressed data is truncated");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ in.pos = 0;
|
|
+ in.size = in_len;
|
|
+ }
|
|
+ /* Returns zero when the frame is complete. */
|
|
+ ret = ZSTD_decompressStream(dstream, &out, &in);
|
|
+ err = handle_zstd_error(ret, error);
|
|
+ if (err)
|
|
+ goto out;
|
|
+ /* Flush all of the data produced if using flush(). */
|
|
+ if (flush != NULL && out.pos > 0) {
|
|
+ if (out.pos != flush(out.dst, out.pos)) {
|
|
+ error("Failed to flush()");
|
|
+ err = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ out.pos = 0;
|
|
+ }
|
|
+ } while (ret != 0);
|
|
+
|
|
+ if (in_pos != NULL)
|
|
+ *in_pos += in.pos;
|
|
+
|
|
+ err = 0;
|
|
+out:
|
|
+ if (in_allocated != NULL)
|
|
+ large_free(in_allocated);
|
|
+ if (out_allocated != NULL)
|
|
+ large_free(out_allocated);
|
|
+ if (wksp != NULL)
|
|
+ large_free(wksp);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+#ifndef ZSTD_PREBOOT
|
|
+STATIC int INIT unzstd(unsigned char *buf, long len,
|
|
+ long (*fill)(void*, unsigned long),
|
|
+ long (*flush)(void*, unsigned long),
|
|
+ unsigned char *out_buf,
|
|
+ long *pos,
|
|
+ void (*error)(char *x))
|
|
+{
|
|
+ return __unzstd(buf, len, fill, flush, out_buf, 0, pos, error);
|
|
+}
|
|
+#else
|
|
+STATIC int INIT __decompress(unsigned char *buf, long len,
|
|
+ long (*fill)(void*, unsigned long),
|
|
+ long (*flush)(void*, unsigned long),
|
|
+ unsigned char *out_buf, long out_len,
|
|
+ long *pos,
|
|
+ void (*error)(char *x))
|
|
+{
|
|
+ return __unzstd(buf, len, fill, flush, out_buf, out_len, pos, error);
|
|
+}
|
|
+#endif
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From 9bf3c117ce579a699388ad7877b06be37f9f74b0 Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:09 -0700
|
|
Subject: [PATCH 4/9] init: add support for zstd compressed kernel
|
|
|
|
* Adds the zstd cmd to scripts/Makefile.lib
|
|
* Adds the HAVE_KERNEL_ZSTD and KERNEL_ZSTD options
|
|
|
|
Architecture specific support is still needed for decompression.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
init/Kconfig | 15 ++++++++++++++-
|
|
scripts/Makefile.lib | 15 +++++++++++++++
|
|
2 files changed, 29 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/init/Kconfig b/init/Kconfig
|
|
index 4f717bfdb..b7c280818 100644
|
|
--- a/init/Kconfig
|
|
+++ b/init/Kconfig
|
|
@@ -173,13 +173,16 @@ config HAVE_KERNEL_LZO
|
|
config HAVE_KERNEL_LZ4
|
|
bool
|
|
|
|
+config HAVE_KERNEL_ZSTD
|
|
+ bool
|
|
+
|
|
config HAVE_KERNEL_UNCOMPRESSED
|
|
bool
|
|
|
|
choice
|
|
prompt "Kernel compression mode"
|
|
default KERNEL_GZIP
|
|
- depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_UNCOMPRESSED
|
|
+ depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_ZSTD || HAVE_KERNEL_UNCOMPRESSED
|
|
help
|
|
The linux kernel is a kind of self-extracting executable.
|
|
Several compression algorithms are available, which differ
|
|
@@ -258,6 +261,16 @@ config KERNEL_LZ4
|
|
is about 8% bigger than LZO. But the decompression speed is
|
|
faster than LZO.
|
|
|
|
+config KERNEL_ZSTD
|
|
+ bool "ZSTD"
|
|
+ depends on HAVE_KERNEL_ZSTD
|
|
+ help
|
|
+ ZSTD is a compression algorithm targeting intermediate compression
|
|
+ with fast decompression speed. It will compress better than GZIP and
|
|
+ decompress around the same speed as LZO, but slower than LZ4. You
|
|
+ will need at least 192 KB RAM or more for booting. The zstd command
|
|
+ line tools is required for compression.
|
|
+
|
|
config KERNEL_UNCOMPRESSED
|
|
bool "None"
|
|
depends on HAVE_KERNEL_UNCOMPRESSED
|
|
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
|
|
index f24ff5a90..373b1f9ab 100644
|
|
--- a/scripts/Makefile.lib
|
|
+++ b/scripts/Makefile.lib
|
|
@@ -394,6 +394,21 @@ quiet_cmd_xzkern = XZKERN $@
|
|
quiet_cmd_xzmisc = XZMISC $@
|
|
cmd_xzmisc = cat $(real-prereqs) | xz --check=crc32 --lzma2=dict=1MiB > $@
|
|
|
|
+# ZSTD
|
|
+# ---------------------------------------------------------------------------
|
|
+# Appends the uncompressed size of the data using size_append. The .zst
|
|
+# format has the size information available at the beginning of the file too,
|
|
+# but it's in a more complex format and it's good to avoid changing the part
|
|
+# of the boot code that reads the uncompressed size.
|
|
+# Note that the bytes added by size_append will make the zstd tool think that
|
|
+# the file is corrupt. This is expected.
|
|
+
|
|
+quiet_cmd_zstd = ZSTD $@
|
|
+cmd_zstd = (cat $(filter-out FORCE,$^) | \
|
|
+ zstd -19 && \
|
|
+ $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
|
+ (rm -f $@ ; false)
|
|
+
|
|
# ASM offsets
|
|
# ---------------------------------------------------------------------------
|
|
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From 1f95b525c42775a393bf9525767748f55fe38b53 Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:10 -0700
|
|
Subject: [PATCH 5/9] usr: add support for zstd compressed initramfs
|
|
|
|
* Add support for a zstd compressed initramfs.
|
|
* Add compression for compressing built-in initramfs with zstd.
|
|
|
|
I have tested this patch by boot testing with buildroot and QEMU.
|
|
Specifically, I booted the kernel with both a zstd and gzip compressed
|
|
initramfs, both built into the kernel and separate. I ensured that the
|
|
correct compression algorithm was used. I tested on arm, aarch64, i386,
|
|
and x86_64.
|
|
|
|
This patch has been tested in production on aarch64 and x86_64 devices.
|
|
|
|
Additionally, I have performance measurements from internal use in
|
|
production. On an aarch64 device we saw 19 second boot time improvement
|
|
from switching from lzma to zstd (27 seconds to 8 seconds). On an x86_64
|
|
device we saw a 9 second boot time reduction from switching from xz to
|
|
zstd.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
usr/Kconfig | 20 ++++++++++++++++++++
|
|
usr/Makefile | 1 +
|
|
2 files changed, 21 insertions(+)
|
|
|
|
diff --git a/usr/Kconfig b/usr/Kconfig
|
|
index 96afb03b6..2599bc21c 100644
|
|
--- a/usr/Kconfig
|
|
+++ b/usr/Kconfig
|
|
@@ -100,6 +100,15 @@ config RD_LZ4
|
|
Support loading of a LZ4 encoded initial ramdisk or cpio buffer
|
|
If unsure, say N.
|
|
|
|
+config RD_ZSTD
|
|
+ bool "Support initial ramdisk/ramfs compressed using ZSTD"
|
|
+ default y
|
|
+ depends on BLK_DEV_INITRD
|
|
+ select DECOMPRESS_ZSTD
|
|
+ help
|
|
+ Support loading of a ZSTD encoded initial ramdisk or cpio buffer.
|
|
+ If unsure, say N.
|
|
+
|
|
choice
|
|
prompt "Built-in initramfs compression mode"
|
|
depends on INITRAMFS_SOURCE != ""
|
|
@@ -196,6 +205,17 @@ config INITRAMFS_COMPRESSION_LZ4
|
|
If you choose this, keep in mind that most distros don't provide lz4
|
|
by default which could cause a build failure.
|
|
|
|
+config INITRAMFS_COMPRESSION_ZSTD
|
|
+ bool "ZSTD"
|
|
+ depends on RD_ZSTD
|
|
+ help
|
|
+ ZSTD is a compression algorithm targeting intermediate compression
|
|
+ with fast decompression speed. It will compress better than GZIP and
|
|
+ decompress around the same speed as LZO, but slower than LZ4.
|
|
+
|
|
+ If you choose this, keep in mind that you may need to install the zstd
|
|
+ tool to be able to compress the initram.
|
|
+
|
|
config INITRAMFS_COMPRESSION_NONE
|
|
bool "None"
|
|
help
|
|
@@ -221,10 +195,12 @@
|
|
default ".xz" if INITRAMFS_COMPRESSION_XZ
|
|
default ".lzo" if INITRAMFS_COMPRESSION_LZO
|
|
default ".lz4" if INITRAMFS_COMPRESSION_LZ4
|
|
+ default ".zst" if INITRAMFS_COMPRESSION_ZSTD
|
|
default ".gz" if RD_GZIP
|
|
default ".lz4" if RD_LZ4
|
|
default ".lzo" if RD_LZO
|
|
default ".xz" if RD_XZ
|
|
default ".lzma" if RD_LZMA
|
|
default ".bz2" if RD_BZIP2
|
|
+ default ".zst" if RD_ZSTD
|
|
default ""
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From b87b45972a43502a4a916e014e13b74997f824aa Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:11 -0700
|
|
Subject: [PATCH 6/9] x86: bump ZO_z_extra_bytes margin for zstd
|
|
|
|
Bump the ZO_z_extra_bytes margin for zstd.
|
|
|
|
Zstd needs 3 bytes per 128 KB, and has a 22 byte fixed overhead.
|
|
Zstd needs to maintain 128 KB of space at all times, since that is
|
|
the maximum block size. See the comments regarding in-place
|
|
decompression added in lib/decompress_unzstd.c for details.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
arch/x86/boot/header.S | 8 +++++++-
|
|
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
|
|
index 97d9b6d6c..b820875c5 100644
|
|
--- a/arch/x86/boot/header.S
|
|
+++ b/arch/x86/boot/header.S
|
|
@@ -536,8 +536,14 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
|
|
# the size-dependent part now grows so fast.
|
|
#
|
|
# extra_bytes = (uncompressed_size >> 8) + 65536
|
|
+#
|
|
+# ZSTD compressed data grows by at most 3 bytes per 128K, and only has a 22
|
|
+# byte fixed overhead but has a maximum block size of 128K, so it needs a
|
|
+# larger margin.
|
|
+#
|
|
+# extra_bytes = (uncompressed_size >> 8) + 131072
|
|
|
|
-#define ZO_z_extra_bytes ((ZO_z_output_len >> 8) + 65536)
|
|
+#define ZO_z_extra_bytes ((ZO_z_output_len >> 8) + 131072)
|
|
#if ZO_z_output_len > ZO_z_input_len
|
|
# define ZO_z_extract_offset (ZO_z_output_len + ZO_z_extra_bytes - \
|
|
ZO_z_input_len)
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From 8b89e11b22775c5a3bad1d36b785baf781289304 Mon Sep 17 00:00:00 2001
|
|
From: Nick Terrell <terrelln@fb.com>
|
|
Date: Tue, 31 Mar 2020 22:39:12 -0700
|
|
Subject: [PATCH 7/9] x86: Add support for ZSTD compressed kernel
|
|
|
|
* Add support for zstd compressed kernel
|
|
* Bump the heap size for zstd.
|
|
* Update the documentation.
|
|
|
|
Integrates the ZSTD decompression code to the x86 pre-boot code.
|
|
|
|
Zstandard requires slightly more memory during the kernel decompression
|
|
on x86 (192 KB vs 64 KB), and the memory usage is independent of the
|
|
window size.
|
|
|
|
This patch has been boot tested with both a zstd and gzip compressed
|
|
kernel on i386 and x86_64 using buildroot and QEMU.
|
|
|
|
Additionally, this has been tested in production on x86_64 devices.
|
|
We saw a 2 second boot time reduction by switching kernel compression
|
|
from xz to zstd.
|
|
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
---
|
|
Documentation/x86/boot.rst | 6 +++---
|
|
arch/x86/Kconfig | 1 +
|
|
arch/x86/boot/compressed/Makefile | 5 ++++-
|
|
arch/x86/boot/compressed/misc.c | 4 ++++
|
|
arch/x86/include/asm/boot.h | 6 ++++--
|
|
5 files changed, 16 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/Documentation/x86/boot.rst b/Documentation/x86/boot.rst
|
|
index c9c201596..cedcf4d49 100644
|
|
--- a/Documentation/x86/boot.rst
|
|
+++ b/Documentation/x86/boot.rst
|
|
@@ -786,9 +786,9 @@ Protocol: 2.08+
|
|
uncompressed data should be determined using the standard magic
|
|
numbers. The currently supported compression formats are gzip
|
|
(magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA
|
|
- (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number
|
|
- 02 21). The uncompressed payload is currently always ELF (magic
|
|
- number 7F 45 4C 46).
|
|
+ (magic number 5D 00), XZ (magic number FD 37), LZ4 (magic number
|
|
+ 02 21) and ZSTD (magic number 28 B5). The uncompressed payload is
|
|
+ currently always ELF (magic number 7F 45 4C 46).
|
|
|
|
============ ==============
|
|
Field name: payload_length
|
|
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
|
index beea77046..12d88997a 100644
|
|
--- a/arch/x86/Kconfig
|
|
+++ b/arch/x86/Kconfig
|
|
@@ -183,6 +183,7 @@ config X86
|
|
select HAVE_KERNEL_LZMA
|
|
select HAVE_KERNEL_LZO
|
|
select HAVE_KERNEL_XZ
|
|
+ select HAVE_KERNEL_ZSTD
|
|
select HAVE_KPROBES
|
|
select HAVE_KPROBES_ON_FTRACE
|
|
select HAVE_FUNCTION_ERROR_INJECTION
|
|
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
|
|
index 26050ae0b..8233f598f 100644
|
|
--- a/arch/x86/boot/compressed/Makefile
|
|
+++ b/arch/x86/boot/compressed/Makefile
|
|
@@ -24,7 +24,7 @@ OBJECT_FILES_NON_STANDARD := y
|
|
KCOV_INSTRUMENT := n
|
|
|
|
targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
|
|
- vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
|
|
+ vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 vmlinux.bin.zst
|
|
|
|
KBUILD_CFLAGS := -m$(BITS) -O2
|
|
KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
|
|
@@ -145,6 +145,8 @@ $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
|
|
$(call if_changed,lzo)
|
|
$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE
|
|
$(call if_changed,lz4)
|
|
+$(obj)/vmlinux.bin.zst: $(vmlinux.bin.all-y) FORCE
|
|
+ $(call if_changed,zstd)
|
|
|
|
suffix-$(CONFIG_KERNEL_GZIP) := gz
|
|
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
|
|
@@ -152,6 +154,7 @@ suffix-$(CONFIG_KERNEL_LZMA) := lzma
|
|
suffix-$(CONFIG_KERNEL_XZ) := xz
|
|
suffix-$(CONFIG_KERNEL_LZO) := lzo
|
|
suffix-$(CONFIG_KERNEL_LZ4) := lz4
|
|
+suffix-$(CONFIG_KERNEL_ZSTD) := zst
|
|
|
|
quiet_cmd_mkpiggy = MKPIGGY $@
|
|
cmd_mkpiggy = $(obj)/mkpiggy $< > $@
|
|
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
|
|
index 9652d5c2a..39e592d0e 100644
|
|
--- a/arch/x86/boot/compressed/misc.c
|
|
+++ b/arch/x86/boot/compressed/misc.c
|
|
@@ -77,6 +77,10 @@ static int lines, cols;
|
|
#ifdef CONFIG_KERNEL_LZ4
|
|
#include "../../../../lib/decompress_unlz4.c"
|
|
#endif
|
|
+
|
|
+#ifdef CONFIG_KERNEL_ZSTD
|
|
+#include "../../../../lib/decompress_unzstd.c"
|
|
+#endif
|
|
/*
|
|
* NOTE: When adding a new decompressor, please update the analysis in
|
|
* ../header.S.
|
|
diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h
|
|
index 680c32036..d6dd43d25 100644
|
|
--- a/arch/x86/include/asm/boot.h
|
|
+++ b/arch/x86/include/asm/boot.h
|
|
@@ -24,9 +24,11 @@
|
|
# error "Invalid value for CONFIG_PHYSICAL_ALIGN"
|
|
#endif
|
|
|
|
-#ifdef CONFIG_KERNEL_BZIP2
|
|
+#if defined(CONFIG_KERNEL_BZIP2)
|
|
# define BOOT_HEAP_SIZE 0x400000
|
|
-#else /* !CONFIG_KERNEL_BZIP2 */
|
|
+#elif defined(CONFIG_KERNEL_ZSTD)
|
|
+# define BOOT_HEAP_SIZE 0x30000
|
|
+#else
|
|
# define BOOT_HEAP_SIZE 0x10000
|
|
#endif
|
|
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From 0d7151172b1ffad727607d69acc2b51a6086def1 Mon Sep 17 00:00:00 2001
|
|
From: Adam Borowski <kilobyte@angband.pl>
|
|
Date: Tue, 31 Mar 2020 22:39:13 -0700
|
|
Subject: [PATCH 8/9] .gitignore: add ZSTD-compressed files
|
|
|
|
For now, that's arch/x86/boot/compressed/vmlinux.bin.zst but probably more
|
|
will come, thus let's be consistent with all other compressors.
|
|
|
|
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Signed-off-by: Nick Terrell <terrelln@fb.com>
|
|
Signed-off-by: Adam Borowski <kilobyte@angband.pl>
|
|
---
|
|
.gitignore | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index 72ef86a55..edb0191c2 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -43,6 +43,7 @@
|
|
*.tab.[ch]
|
|
*.tar
|
|
*.xz
|
|
+*.zst
|
|
Module.symvers
|
|
modules.builtin
|
|
modules.order
|
|
--
|
|
2.27.0.rc0
|
|
|
|
|
|
From 9687fd64db136fbdb2e7805e0b6354620516597c Mon Sep 17 00:00:00 2001
|
|
From: NihilisticPandemoniun
|
|
<152417+nihilisticpandemonium@users.noreply.github.com>
|
|
Date: Thu, 19 Dec 2019 00:08:37 -0800
|
|
Subject: [PATCH 9/9] init: add support for zstd compressed modules
|
|
|
|
Signed-off-by: Alexandre Frade <admfrade@gmail.com>
|
|
---
|
|
Makefile | 7 +++++--
|
|
init/Kconfig | 9 ++++++---
|
|
2 files changed, 11 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index d25221966..f812df12f 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -972,8 +972,8 @@ endif # INSTALL_MOD_STRIP
|
|
export mod_strip_cmd
|
|
|
|
# CONFIG_MODULE_COMPRESS, if defined, will cause module to be compressed
|
|
-# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP
|
|
-# or CONFIG_MODULE_COMPRESS_XZ.
|
|
+# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP,
|
|
+# CONFIG_MODULE_COMPRESS_XZ, or CONFIG_MODULE_COMPRESS_ZSTD.
|
|
|
|
mod_compress_cmd = true
|
|
ifdef CONFIG_MODULE_COMPRESS
|
|
@@ -983,6 +983,9 @@ ifdef CONFIG_MODULE_COMPRESS
|
|
ifdef CONFIG_MODULE_COMPRESS_XZ
|
|
mod_compress_cmd = xz -f
|
|
endif # CONFIG_MODULE_COMPRESS_XZ
|
|
+ ifdef CONFIG_MODULE_COMPRESS_ZSTD
|
|
+ mod_compress_cmd = zstd -T0 -20 --ultra --rm -f
|
|
+ endif
|
|
endif # CONFIG_MODULE_COMPRESS
|
|
export mod_compress_cmd
|
|
|
|
diff --git a/init/Kconfig b/init/Kconfig
|
|
index b7c280818..3d3b72926 100644
|
|
--- a/init/Kconfig
|
|
+++ b/init/Kconfig
|
|
@@ -2142,8 +2142,8 @@ config MODULE_COMPRESS
|
|
bool "Compress modules on installation"
|
|
help
|
|
|
|
- Compresses kernel modules when 'make modules_install' is run; gzip or
|
|
- xz depending on "Compression algorithm" below.
|
|
+ Compresses kernel modules when 'make modules_install' is run; gzip,
|
|
+ xz, or zstd depending on "Compression algorithm" below.
|
|
|
|
module-init-tools MAY support gzip, and kmod MAY support gzip and xz.
|
|
|
|
@@ -2165,7 +2165,7 @@ choice
|
|
This determines which sort of compression will be used during
|
|
'make modules_install'.
|
|
|
|
- GZIP (default) and XZ are supported.
|
|
+ GZIP (default), XZ, and ZSTD are supported.
|
|
|
|
config MODULE_COMPRESS_GZIP
|
|
bool "GZIP"
|
|
@@ -2173,6 +2173,9 @@ config MODULE_COMPRESS_GZIP
|
|
config MODULE_COMPRESS_XZ
|
|
bool "XZ"
|
|
|
|
+config MODULE_COMPRESS_ZSTD
|
|
+ bool "ZSTD"
|
|
+
|
|
endchoice
|
|
|
|
config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
|
--
|
|
2.27.0.rc0
|
|
|