* [PATCH RFC 2/9] lib/lz4: backport upstream's -Wmissing-prototypes fix
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 3/9] lib/lz4: add the build environment for the vendored sources Michal Wilczynski
` (9 subsequent siblings)
10 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
v1.10.0 defines LZ4_loadDict_internal() in lz4.c and LZ4HC_searchExtDict()
in lz4hc.c with external linkage and no prototype, which the kernel's
-Wmissing-prototypes rejects. The first also prevents linking, since
lz4_compress.c and lz4_decompress.c both include lz4.c and would each
define it.
Neither can be forward declared static in lz4_deps.h like the other bare
helpers, because their signatures use types declared inside the .c files.
Take the two hunks of upstream commit 5ef1f16929b5
("fix -Wmissing-prototypes warnings") that apply to the files we vendor.
This is the only deviation from the tag, and goes away at the next
re-sync.
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
lib/lz4/upstream/lz4.c | 2 +-
lib/lz4/upstream/lz4hc.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/lz4/upstream/lz4.c b/lib/lz4/upstream/lz4.c
index a2f7abee19fb9a5c768f2a6c266acf5b571f0855..0d474be0236a698d297ab9a430f5082485eb3709 100644
--- a/lib/lz4/upstream/lz4.c
+++ b/lib/lz4/upstream/lz4.c
@@ -1584,7 +1584,7 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
typedef enum { _ld_fast, _ld_slow } LoadDict_mode_e;
#define HASH_UNIT sizeof(reg_t)
-int LZ4_loadDict_internal(LZ4_stream_t* LZ4_dict,
+static int LZ4_loadDict_internal(LZ4_stream_t* LZ4_dict,
const char* dictionary, int dictSize,
LoadDict_mode_e _ld)
{
diff --git a/lib/lz4/upstream/lz4hc.c b/lib/lz4/upstream/lz4hc.c
index 4d8c36a6978fcae09e4c4a936572b4b271513466..32b29f382268d961d65383b24c7225494d9044ad 100644
--- a/lib/lz4/upstream/lz4hc.c
+++ b/lib/lz4/upstream/lz4hc.c
@@ -360,7 +360,7 @@ typedef struct {
int back; /* negative value */
} LZ4HC_match_t;
-LZ4HC_match_t LZ4HC_searchExtDict(const BYTE* ip, U32 ipIndex,
+static LZ4HC_match_t LZ4HC_searchExtDict(const BYTE* ip, U32 ipIndex,
const BYTE* const iLowLimit, const BYTE* const iHighLimit,
const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex,
int currentBestML, int nbAttempts)
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH RFC 3/9] lib/lz4: add the build environment for the vendored sources
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 2/9] lib/lz4: backport upstream's -Wmissing-prototypes fix Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-28 5:48 ` Sergey Senozhatsky
2026-09-25 11:27 ` [PATCH RFC 4/9] arch: boot: put the LZ4 freestanding headers on the decompressor path Michal Wilczynski
` (8 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
lz4_deps.h makes the unmodified upstream sources compile in the kernel:
it supplies the ISO C spellings they expect, gives every upstream entry
point internal linkage so an object carries only the codec it forwards,
keeps every workspace off the stack, and renames the entry points the
kernel re-exports with a trailing wrkmem argument.
freestanding/ forwards the four ISO C headers upstream includes
(stddef.h, stdint.h, limits.h, string.h) to their <linux/> equivalents.
The vendored functions an object does not forward are unreferenced, so
LZ4LIB_VISIBILITY carries __maybe_unused rather than disabling
-Wunused-function for a directory. This also covers the pre-boot
decompressors, which compile lz4_decompress.c textually and never see
lib/lz4's ccflags.
For the same reason this header includes <linux/build_bug.h>: the entry
points static_assert upstream's structure sizes, and only some
architectures' pre-boot environments have static_assert in scope.
lz4_kernel_api.h undoes the renaming for the entry point files and
declares what lib/lz4 exports. It starts out carrying its own copy of
those prototypes, because it cannot include <linux/lz4.h> while that
header still defines the three stream types upstream's headers also
define. A later patch folds it away once they are incomplete.
Nothing includes either header yet.
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
lib/lz4/freestanding/limits.h | 14 +++++++
lib/lz4/freestanding/stddef.h | 15 +++++++
lib/lz4/freestanding/stdint.h | 14 +++++++
lib/lz4/freestanding/string.h | 14 +++++++
lib/lz4/lz4_deps.h | 96 ++++++++++++++++++++++++++++++++++++++++++
lib/lz4/lz4_kernel_api.h | 98 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 251 insertions(+)
diff --git a/lib/lz4/freestanding/limits.h b/lib/lz4/freestanding/limits.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d1cafbc77eb5d2f564b51feaa911748446abf60
--- /dev/null
+++ b/lib/lz4/freestanding/limits.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ *
+ * Freestanding <limits.h> for the vendored upstream LZ4 sources; lz4.c needs
+ * UINT_MAX and lz4hc.c needs INT_MAX.
+ */
+#ifndef __LZ4_FREESTANDING_LIMITS_H__
+#define __LZ4_FREESTANDING_LIMITS_H__
+
+#include <linux/limits.h>
+
+#endif
diff --git a/lib/lz4/freestanding/stddef.h b/lib/lz4/freestanding/stddef.h
new file mode 100644
index 0000000000000000000000000000000000000000..aaafd2413849210fa4ec4fa03ba0e9453a9fe026
--- /dev/null
+++ b/lib/lz4/freestanding/stddef.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ *
+ * Freestanding <stddef.h> for the vendored upstream LZ4 sources; -nostdinc
+ * drops the compiler's copy, and lz4.h needs size_t and NULL.
+ */
+#ifndef __LZ4_FREESTANDING_STDDEF_H__
+#define __LZ4_FREESTANDING_STDDEF_H__
+
+#include <linux/stddef.h> /* NULL, offsetof */
+#include <linux/types.h> /* size_t, ptrdiff_t */
+
+#endif
diff --git a/lib/lz4/freestanding/stdint.h b/lib/lz4/freestanding/stdint.h
new file mode 100644
index 0000000000000000000000000000000000000000..923db05b19f23fb4051d16e5df2bf134cd5ac11e
--- /dev/null
+++ b/lib/lz4/freestanding/stdint.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ *
+ * Freestanding <stdint.h> for the vendored upstream LZ4 sources; forwards to
+ * <linux/types.h>.
+ */
+#ifndef __LZ4_FREESTANDING_STDINT_H__
+#define __LZ4_FREESTANDING_STDINT_H__
+
+#include <linux/types.h>
+
+#endif
diff --git a/lib/lz4/freestanding/string.h b/lib/lz4/freestanding/string.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f3ea3b63013608a780a52fe9c33bf5df557584e
--- /dev/null
+++ b/lib/lz4/freestanding/string.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ *
+ * Freestanding <string.h> for the vendored upstream LZ4 sources; lz4.c
+ * includes it for memcpy()/memset(), which must resolve under -nostdinc.
+ */
+#ifndef __LZ4_FREESTANDING_STRING_H__
+#define __LZ4_FREESTANDING_STRING_H__
+
+#include <linux/string.h>
+
+#endif
diff --git a/lib/lz4/lz4_deps.h b/lib/lz4/lz4_deps.h
new file mode 100644
index 0000000000000000000000000000000000000000..3855aac051585f216df71c5039cff19bcee37ca4
--- /dev/null
+++ b/lib/lz4/lz4_deps.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ *
+ * Build environment for the vendored upstream LZ4 sources.
+ *
+ * The four files under upstream/ are copied verbatim; do not edit them. The
+ * three entry point files include this header before them.
+ */
+
+#ifndef __LZ4_DEPS_H__
+#define __LZ4_DEPS_H__
+
+#include <linux/build_bug.h> /* static_assert */
+#include <linux/compiler.h> /* __maybe_unused */
+#include <linux/string.h>
+#include <linux/types.h>
+
+/* lz4.c uses "current" as a local; <asm/current.h> breaks the build. */
+#undef current
+
+/* Static so an object carries only the codec it forwards; __maybe_unused
+ * for the ones it does not, which the pre-boot decompressors compile
+ * without lib/lz4's ccflags.
+ */
+#define LZ4LIB_VISIBILITY static __maybe_unused
+
+/* Route upstream's "static linking only" entry points through
+ * LZ4LIB_VISIBILITY too.
+ */
+#define LZ4_PUBLISH_STATIC_FUNCTIONS
+
+/* Heap mode only: the stack mode puts LZ4HC's ~64K opt[] in a frame.
+ * Allocation goes through the failing stubs below; upstream handles
+ * NULL by returning 0.
+ */
+#define LZ4_USER_MEMORY_FUNCTIONS
+#define LZ4_HEAPMODE 1
+#define LZ4HC_HEAPMODE 1
+
+/* Failing stubs; nothing in the kernel reaches these. */
+static void *LZ4_malloc(size_t s) { return NULL; }
+static void *LZ4_calloc(size_t n, size_t s) { return NULL; }
+static void LZ4_free(void *p) { }
+
+/* LZ4_decompress_fast() and LZ4_resetStream() are still kernel API. */
+#define LZ4_DISABLE_DEPRECATE_WARNINGS 1
+
+/* Rename upstream's entry points out of the way; four of them take a
+ * trailing wrkmem argument in the kernel.
+ */
+#define LZ4_compress_fast __lz4_compress_fast
+#define LZ4_compress_default __lz4_compress_default
+#define LZ4_compress_destSize __lz4_compress_destSize
+#define LZ4_resetStream __lz4_resetStream
+#define LZ4_loadDict __lz4_loadDict
+#define LZ4_saveDict __lz4_saveDict
+#define LZ4_compress_fast_continue __lz4_compress_fast_continue
+
+#define LZ4_decompress_safe __lz4_decompress_safe
+#define LZ4_decompress_safe_partial __lz4_decompress_safe_partial
+#define LZ4_decompress_fast __lz4_decompress_fast
+#define LZ4_setStreamDecode __lz4_setStreamDecode
+#define LZ4_decompress_safe_continue __lz4_decompress_safe_continue
+#define LZ4_decompress_fast_continue __lz4_decompress_fast_continue
+#define LZ4_decompress_safe_usingDict __lz4_decompress_safe_usingDict
+#define LZ4_decompress_fast_usingDict __lz4_decompress_fast_usingDict
+
+#define LZ4_compress_HC __lz4_compress_HC
+#define LZ4_resetStreamHC __lz4_resetStreamHC
+#define LZ4_loadDictHC __lz4_loadDictHC
+#define LZ4_compress_HC_continue __lz4_compress_HC_continue
+#define LZ4_saveDictHC __lz4_saveDictHC
+
+/* Upstream declares these bare, so both entry point objects would define
+ * them. Declaring them static first gives them internal linkage (C11
+ * 6.2.2p4): this one in lz4.h, the three below in lz4.c.
+ */
+static __maybe_unused int LZ4_compress_destSize_extState(void *state, const char *src,
+ char *dst, int *srcSizePtr, int targetDstSize,
+ int acceleration);
+
+#include "upstream/lz4.h"
+
+static __maybe_unused int LZ4_compress_forceExtDict(LZ4_stream_t *LZ4_dict,
+ const char *source, char *dest, int srcSize);
+static __maybe_unused int LZ4_decompress_safe_forceExtDict(const char *source,
+ char *dest,
+ int compressedSize, int maxOutputSize,
+ const void *dictStart, size_t dictSize);
+static __maybe_unused int LZ4_decompress_safe_partial_forceExtDict(const char *source,
+ char *dest, int compressedSize, int targetOutputSize,
+ int dstCapacity, const void *dictStart, size_t dictSize);
+
+#endif /* __LZ4_DEPS_H__ */
diff --git a/lib/lz4/lz4_kernel_api.h b/lib/lz4/lz4_kernel_api.h
new file mode 100644
index 0000000000000000000000000000000000000000..795434a64d2cb744c8ac8027d9ed59485ef6e7f3
--- /dev/null
+++ b/lib/lz4/lz4_kernel_api.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ *
+ * lz4_kernel_api.h -- the LZ4 API this directory exports
+ *
+ * lz4_deps.h renames upstream's entry points to __lz4_* so that the kernel's
+ * own definitions can use the real names; this header undoes that renaming
+ * and declares what lib/lz4 exports.
+ *
+ * The same functions are declared to callers in <linux/lz4.h>, in terms of
+ * opaque stream types. We cannot include that header here -- it and
+ * upstream's lz4.h describe the same library and collide -- so the
+ * declarations are repeated, expressed in upstream's own types. Keep the two
+ * in step; <linux/lz4.h> is the one callers compile against.
+ *
+ * Include after upstream/lz4.c or upstream/lz4hc.c.
+ */
+
+#undef LZ4_compress_fast
+#undef LZ4_compress_default
+#undef LZ4_compress_destSize
+#undef LZ4_resetStream
+#undef LZ4_loadDict
+#undef LZ4_saveDict
+#undef LZ4_compress_fast_continue
+
+#undef LZ4_decompress_safe
+#undef LZ4_decompress_safe_partial
+#undef LZ4_decompress_fast
+#undef LZ4_setStreamDecode
+#undef LZ4_decompress_safe_continue
+#undef LZ4_decompress_fast_continue
+#undef LZ4_decompress_safe_usingDict
+#undef LZ4_decompress_fast_usingDict
+
+#undef LZ4_compress_HC
+#undef LZ4_resetStreamHC
+#undef LZ4_loadDictHC
+#undef LZ4_compress_HC_continue
+#undef LZ4_saveDictHC
+
+/*
+ * The objects that do not build lz4hc.c never see this type, and it is only
+ * ever used through a pointer here. Upstream declares it the same way.
+ */
+typedef union LZ4_streamHC_u LZ4_streamHC_t;
+
+/* Compression. wrkmem is LZ4_MEM_COMPRESS bytes, supplied by the caller. */
+int LZ4_compress_default(const char *source, char *dest, int inputSize,
+ int maxOutputSize, void *wrkmem);
+int LZ4_compress_fast(const char *source, char *dest, int inputSize,
+ int maxOutputSize, int acceleration, void *wrkmem);
+int LZ4_compress_destSize(const char *source, char *dest, int *sourceSizePtr,
+ int targetDestSize, void *wrkmem);
+
+/* Streaming compression. */
+void LZ4_resetStream(LZ4_stream_t *LZ4_stream);
+int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary,
+ int dictSize);
+int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int dictSize);
+int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src,
+ char *dst, int srcSize, int maxDstSize,
+ int acceleration);
+
+/* Decompression. */
+int LZ4_decompress_safe(const char *source, char *dest, int compressedSize,
+ int maxDecompressedSize);
+int LZ4_decompress_safe_partial(const char *source, char *dest,
+ int compressedSize, int targetOutputSize,
+ int maxDecompressedSize);
+int LZ4_decompress_fast(const char *source, char *dest, int originalSize);
+int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode,
+ const char *dictionary, int dictSize);
+int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode,
+ const char *source, char *dest,
+ int compressedSize, int maxDecompressedSize);
+int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode,
+ const char *source, char *dest,
+ int originalSize);
+int LZ4_decompress_safe_usingDict(const char *source, char *dest,
+ int compressedSize, int maxDecompressedSize,
+ const char *dictStart, int dictSize);
+int LZ4_decompress_fast_usingDict(const char *source, char *dest,
+ int originalSize, const char *dictStart,
+ int dictSize);
+
+/* HC compression. wrkmem is LZ4HC_MEM_COMPRESS bytes. */
+int LZ4_compress_HC(const char *src, char *dst, int srcSize, int dstCapacity,
+ int compressionLevel, void *wrkmem);
+void LZ4_resetStreamHC(LZ4_streamHC_t *streamHCPtr, int compressionLevel);
+int LZ4_loadDictHC(LZ4_streamHC_t *streamHCPtr, const char *dictionary,
+ int dictSize);
+int LZ4_compress_HC_continue(LZ4_streamHC_t *streamHCPtr, const char *src,
+ char *dst, int srcSize, int maxDstSize);
+int LZ4_saveDictHC(LZ4_streamHC_t *streamHCPtr, char *safeBuffer,
+ int maxDictSize);
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH RFC 3/9] lib/lz4: add the build environment for the vendored sources
2026-09-25 11:27 ` [PATCH RFC 3/9] lib/lz4: add the build environment for the vendored sources Michal Wilczynski
@ 2026-09-28 5:48 ` Sergey Senozhatsky
2026-10-04 0:05 ` Michal Wilczynski
0 siblings, 1 reply; 25+ messages in thread
From: Sergey Senozhatsky @ 2026-09-28 5:48 UTC (permalink / raw)
To: Michal Wilczynski
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Sergey Senozhatsky, Jens Axboe, Andrew Morton,
linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
On (26/09/25 13:27), Michal Wilczynski wrote:
[..]
> +
> +/* LZ4_decompress_fast() and LZ4_resetStream() are still kernel API. */
> +#define LZ4_DISABLE_DEPRECATE_WARNINGS 1
Is this upstream code? As far as I understand it, LZ4_decompress_fast*()
deprecated upstream and are strongly discouraged. Do we want to suppress
deprecation warnings?
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH RFC 3/9] lib/lz4: add the build environment for the vendored sources
2026-09-28 5:48 ` Sergey Senozhatsky
@ 2026-10-04 0:05 ` Michal Wilczynski
0 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-10-04 0:05 UTC (permalink / raw)
To: Sergey Senozhatsky
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Jens Axboe, Andrew Morton, linux-kernel, llvm,
linux-arm-kernel, linux-mips, linux-parisc, linux-s390,
linux-block, Yann Collet, Nick Terrell, Gao Xiang, Chao Yu,
Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk, Jaehoon Chung,
Marek Szyprowski, linux-erofs, linux-f2fs-devel, linux-crypto
On 9/28/26 07:48, Sergey Senozhatsky wrote:
> On (26/09/25 13:27), Michal Wilczynski wrote:
> [..]
>> +
>> +/* LZ4_decompress_fast() and LZ4_resetStream() are still kernel API. */
>> +#define LZ4_DISABLE_DEPRECATE_WARNINGS 1
>
> Is this upstream code? As far as I understand it, LZ4_decompress_fast*()
> deprecated upstream and are strongly discouraged. Do we want to suppress
> deprecation warnings?
>
It's ours lz4_deps.h but upstream's lz4.c sets the same switch for
itself lz4.c, since its own code calls deprecated functions. We
include lz4.h before lz4.c, so we have to set it first.
I agree on the direction. The only in-tree _fast() user is the pre boot
path of lib/decompress_unlz4.c, so as a follow-up I'd move it to
LZ4_decompress_safe_partial() and drop the three _fast exports.
Best regards,
--
Michal Wilczynski <m.wilczynski@samsung.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH RFC 4/9] arch: boot: put the LZ4 freestanding headers on the decompressor path
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 2/9] lib/lz4: backport upstream's -Wmissing-prototypes fix Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 3/9] lib/lz4: add the build environment for the vendored sources Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 5/9] lib/lz4: switch the compressor to the vendored sources Michal Wilczynski
` (7 subsequent siblings)
10 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
lib/decompress_unlz4.c pulls lib/lz4/lz4_decompress.c into the pre-boot
decompressor on these five arches. A later patch makes that file include
the vendored LZ4 sources, which include ISO C headers that -nostdinc does
not provide, so put lib/lz4/freestanding on the include path first.
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
arch/arm/boot/compressed/Makefile | 3 +++
arch/mips/boot/compressed/Makefile | 4 ++++
arch/parisc/boot/compressed/Makefile | 3 +++
arch/s390/boot/Makefile | 3 +++
arch/x86/boot/compressed/Makefile | 3 +++
5 files changed, 16 insertions(+)
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index e3f550d6285786c8405b16768255af87b4dc8222..c0418ef2618bbcbf18f905e619031c37661563ed 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -92,6 +92,9 @@ targets := vmlinux vmlinux.lds piggy_data piggy.o \
head.o $(OBJS)
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+# decompress_unlz4.c builds the vendored LZ4 sources, which include a few
+# ISO C headers -nostdinc drops.
+KBUILD_CFLAGS += -I$(srctree)/lib/lz4/freestanding
ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin \
-I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index e0b8ec9a9516281933b6cc5b175e82f4013c2f54..b832b8a26f20073d817fb50bc4c8015de006b5e4 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -30,6 +30,10 @@ endif
KBUILD_CFLAGS := $(KBUILD_CFLAGS) -D__KERNEL__ -D__DISABLE_EXPORTS \
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull"
+# decompress_unlz4.c builds the vendored LZ4 sources, which include a few
+# ISO C headers -nostdinc drops.
+KBUILD_CFLAGS += -I$(srctree)/lib/lz4/freestanding
+
KBUILD_AFLAGS := $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
-DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS)
diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile
index 14eefb5ed5d1d781a4ee0cb2ef61ab86c905cc56..1d4a3e66e3503714c1f723dedb15598183ec8b0a 100644
--- a/arch/parisc/boot/compressed/Makefile
+++ b/arch/parisc/boot/compressed/Makefile
@@ -12,6 +12,9 @@ targets += $(OBJECTS) sizes.h
KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+# decompress_unlz4.c builds the vendored LZ4 sources, which include a few
+# ISO C headers -nostdinc drops.
+KBUILD_CFLAGS += -I$(srctree)/lib/lz4/freestanding
KBUILD_CFLAGS += -fno-strict-aliasing
KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf
KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 10b75e053a6f6bb9083548e8f82796f0aa9a9958..fd88523eb1102af1eb1f821e156b8faadb502879 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -21,6 +21,9 @@ KBUILD_AFLAGS := $(filter-out $(CC_FLAGS_MARCH),$(KBUILD_AFLAGS_DECOMPRESSOR))
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_MARCH),$(KBUILD_CFLAGS_DECOMPRESSOR))
KBUILD_AFLAGS += $(CC_FLAGS_MARCH_MINIMUM) -D__DISABLE_EXPORTS
KBUILD_CFLAGS += $(CC_FLAGS_MARCH_MINIMUM) -D__DISABLE_EXPORTS
+# decompress_unlz4.c builds the vendored LZ4 sources, which include a few
+# ISO C headers -nostdinc drops.
+KBUILD_CFLAGS += -I$(srctree)/lib/lz4/freestanding
KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe)
CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 06934f9691d6a9d6952532ae5f7d96f5858719dd..d200a0a4c28b9e7be1be45f603e625eb573d0220 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -30,6 +30,9 @@ KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
KBUILD_CFLAGS += -fno-jump-tables
KBUILD_CFLAGS += -Wundef
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+# decompress_unlz4.c builds the vendored LZ4 sources, which include a few
+# ISO C headers -nostdinc drops.
+KBUILD_CFLAGS += -I$(srctree)/lib/lz4/freestanding
cflags-$(CONFIG_X86_32) := -march=i386
cflags-$(CONFIG_X86_64) := -mcmodel=small -mno-red-zone
KBUILD_CFLAGS += $(cflags-y)
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH RFC 5/9] lib/lz4: switch the compressor to the vendored sources
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (2 preceding siblings ...)
2026-09-25 11:27 ` [PATCH RFC 4/9] arch: boot: put the LZ4 freestanding headers on the decompressor path Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 6/9] lib/lz4: switch the HC " Michal Wilczynski
` (6 subsequent siblings)
10 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
Replace the forked compressor with thin entry points over the vendored
lz4.c.
LZ4_compress_default(), LZ4_compress_fast() and LZ4_compress_destSize()
keep the trailing wrkmem argument and forward to upstream's *_extState()
entry points. The rest are plain forwarders.
Compressed output is not quite bit-for-bit identical: it differs on a
small fraction of inputs by a byte or two, with no measurable change in
ratio. Both implementations decode each other's output, so nothing
already on disk changes meaning.
<linux/lz4.h> spelled out LZ4_stream_t's layout for the fork's benefit:
lz4defs.h included the public header and the fork read internal_donotuse
back out. The vendored compressor brings upstream's own definition, so
make the public type incomplete, repeating upstream's forward
declaration. Both headers then name the same type, which
lib/decompress_unlz4.c needs since it ends up including both.
LZ4_MEMORY_USAGE, LZ4_HASHLOG, LZ4_HASHTABLESIZE, LZ4_HASH_SIZE_U32,
LZ4_STREAMSIZE_U64 and LZ4_STREAMSIZE only existed to lay that structure
out, and go with it. LZ4_MEM_COMPRESS keeps its value, 16416, as a
plain number.
Callers now allocate LZ4_MEM_COMPRESS bytes instead of
sizeof(LZ4_stream_t). Every caller but zram already did; zram is
adjusted here.
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
drivers/block/zram/backend_lz4.c | 6 +-
include/linux/lz4.h | 47 +-
lib/lz4/Makefile | 11 +-
lib/lz4/lz4_compress.c | 941 ++-------------------------------------
4 files changed, 68 insertions(+), 937 deletions(-)
diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c
index 1e4ad31d39a63f45b3bddd3d8a467d8d7d095beb..50265e3ce256490994cb6dae32a45da376e408e0 100644
--- a/drivers/block/zram/backend_lz4.c
+++ b/drivers/block/zram/backend_lz4.c
@@ -42,7 +42,7 @@ static int lz4_setup_params(struct zcomp_params *params)
if (!params->dict || !params->dict_sz)
return 0;
- dict_stream = kzalloc_obj(*dict_stream);
+ dict_stream = kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
if (!dict_stream)
return -ENOMEM;
@@ -88,7 +88,7 @@ static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
if (!zctx->dstrm)
goto error;
- zctx->cstrm = kzalloc_obj(*zctx->cstrm);
+ zctx->cstrm = kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
if (!zctx->cstrm)
goto error;
}
@@ -112,7 +112,7 @@ static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
zctx->mem);
} else {
/* Cstrm needs to be reset */
- memcpy(zctx->cstrm, params->drv_data, sizeof(*zctx->cstrm));
+ memcpy(zctx->cstrm, params->drv_data, LZ4_MEM_COMPRESS);
ret = LZ4_compress_fast_continue(zctx->cstrm, req->src,
req->dst, req->src_len,
req->dst_len, params->level);
diff --git a/include/linux/lz4.h b/include/linux/lz4.h
index ad6042a718b5428792b795db7a8d4ad44c24a985..e96353a67d617a4d734cecaf3764814df692428b 100644
--- a/include/linux/lz4.h
+++ b/include/linux/lz4.h
@@ -47,16 +47,6 @@
/*-************************************************************************
* CONSTANTS
**************************************************************************/
-/*
- * LZ4_MEMORY_USAGE :
- * Memory usage formula : N->2^N Bytes
- * (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
- * Increasing memory usage improves compression ratio
- * Reduced memory usage can improve speed, due to cache effect
- * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
- */
-#define LZ4_MEMORY_USAGE 14
-
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define LZ4_COMPRESSBOUND(isize) (\
(unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE \
@@ -64,9 +54,6 @@
: (isize) + ((isize)/255) + 16)
#define LZ4_ACCELERATION_DEFAULT 1
-#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
-#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
-#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG)
#define LZ4HC_MIN_CLEVEL 3
#define LZ4HC_DEFAULT_CLEVEL 9
@@ -82,9 +69,6 @@
/*-************************************************************************
* STREAMING CONSTANTS AND STRUCTURES
**************************************************************************/
-#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE - 3)) + 4)
-#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long))
-
#define LZ4_STREAMHCSIZE 262192
#define LZ4_STREAMHCSIZE_SIZET (262192 / sizeof(size_t))
@@ -93,20 +77,10 @@
sizeof(unsigned long long))
/*
- * LZ4_stream_t - information structure to track an LZ4 stream.
+ * LZ4_stream_t - an LZ4 stream. Incomplete: lib/lz4 owns the layout.
+ * Allocate LZ4_MEM_COMPRESS bytes and cast, do not sizeof().
*/
-typedef struct {
- uint32_t hashTable[LZ4_HASH_SIZE_U32];
- uint32_t currentOffset;
- uint32_t initCheck;
- const uint8_t *dictionary;
- uint8_t *bufferStart;
- uint32_t dictSize;
-} LZ4_stream_t_internal;
-typedef union {
- unsigned long long table[LZ4_STREAMSIZE_U64];
- LZ4_stream_t_internal internal_donotuse;
-} LZ4_stream_t;
+typedef union LZ4_stream_u LZ4_stream_t;
/*
* LZ4_streamHC_t - information structure to track an LZ4HC stream.
@@ -153,7 +127,12 @@ typedef union {
/*-************************************************************************
* SIZE OF STATE
**************************************************************************/
-#define LZ4_MEM_COMPRESS LZ4_STREAMSIZE
+/*
+ * Working memory for the compressors. It must be aligned to at least 8
+ * bytes; anything from kmalloc() or vmalloc() already is. A misaligned
+ * buffer is rejected, and the stateless entry points cannot report that.
+ */
+#define LZ4_MEM_COMPRESS 16416
#define LZ4HC_MEM_COMPRESS LZ4_STREAMHCSIZE
/*-************************************************************************
@@ -180,7 +159,7 @@ static inline int LZ4_compressBound(size_t isize)
* @maxOutputSize: full or partial size of buffer 'dest'
* which must be already allocated
* @wrkmem: address of the working memory.
- * This requires 'workmem' of LZ4_MEM_COMPRESS.
+ * This requires 'workmem' of LZ4_MEM_COMPRESS, aligned to 8 bytes.
*
* Compresses 'sourceSize' bytes from buffer 'source'
* into already allocated 'dest' buffer of size 'maxOutputSize'.
@@ -206,7 +185,7 @@ int LZ4_compress_default(const char *source, char *dest, int inputSize,
* which must be already allocated
* @acceleration: acceleration factor
* @wrkmem: address of the working memory.
- * This requires 'workmem' of LZ4_MEM_COMPRESS.
+ * This requires 'workmem' of LZ4_MEM_COMPRESS, aligned to 8 bytes.
*
* Same as LZ4_compress_default(), but allows to select an "acceleration"
* factor. The larger the acceleration value, the faster the algorithm,
@@ -230,7 +209,7 @@ int LZ4_compress_fast(const char *source, char *dest, int inputSize,
* from 'source' to fill 'dest'. New value is necessarily <= old value.
* @targetDestSize: Size of buffer 'dest' which must be already allocated
* @wrkmem: address of the working memory.
- * This requires 'workmem' of LZ4_MEM_COMPRESS.
+ * This requires 'workmem' of LZ4_MEM_COMPRESS, aligned to 8 bytes.
*
* Reverse the logic, by compressing as much data as possible
* from 'source' buffer into already allocated buffer 'dest'
@@ -335,7 +314,7 @@ int LZ4_decompress_safe_partial(const char *source, char *dest,
* value between 1 and LZ4HC_MAX_CLEVEL will work.
* Values >LZ4HC_MAX_CLEVEL behave the same as 16.
* @wrkmem: address of the working memory.
- * This requires 'wrkmem' of size LZ4HC_MEM_COMPRESS.
+ * This requires 'wrkmem' of size LZ4HC_MEM_COMPRESS, aligned to 8 bytes.
*
* Compress data from 'src' into 'dst', using the more powerful
* but slower "HC" algorithm. Compression is guaranteed to succeed if
diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile
index 5b42242afaa20deb165d8a2f0b1c0c842dfcdc39..e9d83cff4ea4efe1097f54caba72e268cecb04af 100644
--- a/lib/lz4/Makefile
+++ b/lib/lz4/Makefile
@@ -1,6 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y += -O3
-obj-$(CONFIG_LZ4_COMPRESS) += lz4_compress.o
-obj-$(CONFIG_LZ4HC_COMPRESS) += lz4hc_compress.o
-obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o
+# upstream/ holds verbatim copies of the upstream LZ4 sources; do not edit
+# them. The three entry point files include them. freestanding/ supplies
+# the ISO C headers upstream includes that -nostdinc does not provide.
+ccflags-y += -I $(src)/freestanding
+
+obj-$(CONFIG_LZ4_COMPRESS) += lz4_compress.o
+obj-$(CONFIG_LZ4HC_COMPRESS) += lz4hc_compress.o
+obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o
diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c
index 2a397bb2c661d9c2e4a7a67d5f50f06bfd42f1f2..19b877fc96d1dde6fd5ff832f79beca42d5b783b 100644
--- a/lib/lz4/lz4_compress.c
+++ b/lib/lz4/lz4_compress.c
@@ -1,937 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
/*
- * LZ4 - Fast LZ compression algorithm
* Copyright (C) 2011 - 2016, Yann Collet.
- * BSD 2 - Clause License (http://www.opensource.org/licenses/bsd - license.php)
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * You can contact the author at :
- * - LZ4 homepage : http://www.lz4.org
- * - LZ4 source repository : https://github.com/lz4/lz4
+ * Copyright (C) 2016, Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
*
- * Changed for kernel usage by:
- * Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
- */
-
-/*-************************************
- * Dependencies
- **************************************/
-#include "lz4defs.h"
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/unaligned.h>
-
-static const int LZ4_minLength = (MFLIMIT + 1);
-static const int LZ4_64Klimit = ((64 * KB) + (MFLIMIT - 1));
-
-/*-******************************
- * Compression functions
- ********************************/
-static FORCE_INLINE U32 LZ4_hash4(
- U32 sequence,
- tableType_t const tableType)
-{
- if (tableType == byU16)
- return ((sequence * 2654435761U)
- >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1)));
- else
- return ((sequence * 2654435761U)
- >> ((MINMATCH * 8) - LZ4_HASHLOG));
-}
-
-static FORCE_INLINE U32 LZ4_hash5(
- U64 sequence,
- tableType_t const tableType)
-{
- const U32 hashLog = (tableType == byU16)
- ? LZ4_HASHLOG + 1
- : LZ4_HASHLOG;
-
-#if LZ4_LITTLE_ENDIAN
- static const U64 prime5bytes = 889523592379ULL;
-
- return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));
-#else
- static const U64 prime8bytes = 11400714785074694791ULL;
-
- return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));
-#endif
-}
-
-static FORCE_INLINE U32 LZ4_hashPosition(
- const void *p,
- tableType_t const tableType)
-{
-#if LZ4_ARCH64
- if (tableType == byU32)
- return LZ4_hash5(LZ4_read_ARCH(p), tableType);
-#endif
-
- return LZ4_hash4(LZ4_read32(p), tableType);
-}
-
-static void LZ4_putPositionOnHash(
- const BYTE *p,
- U32 h,
- void *tableBase,
- tableType_t const tableType,
- const BYTE *srcBase)
-{
- switch (tableType) {
- case byPtr:
- {
- const BYTE **hashTable = (const BYTE **)tableBase;
-
- hashTable[h] = p;
- return;
- }
- case byU32:
- {
- U32 *hashTable = (U32 *) tableBase;
-
- hashTable[h] = (U32)(p - srcBase);
- return;
- }
- case byU16:
- {
- U16 *hashTable = (U16 *) tableBase;
-
- hashTable[h] = (U16)(p - srcBase);
- return;
- }
- }
-}
-
-static FORCE_INLINE void LZ4_putPosition(
- const BYTE *p,
- void *tableBase,
- tableType_t tableType,
- const BYTE *srcBase)
-{
- U32 const h = LZ4_hashPosition(p, tableType);
-
- LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
-}
-
-static const BYTE *LZ4_getPositionOnHash(
- U32 h,
- void *tableBase,
- tableType_t tableType,
- const BYTE *srcBase)
-{
- if (tableType == byPtr) {
- const BYTE **hashTable = (const BYTE **) tableBase;
-
- return hashTable[h];
- }
-
- if (tableType == byU32) {
- const U32 * const hashTable = (U32 *) tableBase;
-
- return hashTable[h] + srcBase;
- }
-
- {
- /* default, to ensure a return */
- const U16 * const hashTable = (U16 *) tableBase;
-
- return hashTable[h] + srcBase;
- }
-}
-
-static FORCE_INLINE const BYTE *LZ4_getPosition(
- const BYTE *p,
- void *tableBase,
- tableType_t tableType,
- const BYTE *srcBase)
-{
- U32 const h = LZ4_hashPosition(p, tableType);
-
- return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
-}
-
-
-/*
- * LZ4_compress_generic() :
- * inlined, to ensure branches are decided at compilation time
+ * LZ4 compressor -- kernel entry points
+ *
+ * The compressor is upstream's, in the verbatim lz4.c included below. The
+ * kernel has no heap at these call sites, so LZ4_compress_default(),
+ * LZ4_compress_fast() and LZ4_compress_destSize() take a trailing wrkmem
+ * argument and forward to upstream's *_extState() entry points.
*/
-static FORCE_INLINE int LZ4_compress_generic(
- LZ4_stream_t_internal * const dictPtr,
- const char * const source,
- char * const dest,
- const int inputSize,
- const int maxOutputSize,
- const limitedOutput_directive outputLimited,
- const tableType_t tableType,
- const dict_directive dict,
- const dictIssue_directive dictIssue,
- const U32 acceleration)
-{
- const BYTE *ip = (const BYTE *) source;
- const BYTE *base;
- const BYTE *lowLimit;
- const BYTE * const lowRefLimit = ip - dictPtr->dictSize;
- const BYTE * const dictionary = dictPtr->dictionary;
- const BYTE * const dictEnd = dictionary + dictPtr->dictSize;
- const size_t dictDelta = dictEnd - (const BYTE *)source;
- const BYTE *anchor = (const BYTE *) source;
- const BYTE * const iend = ip + inputSize;
- const BYTE * const mflimit = iend - MFLIMIT;
- const BYTE * const matchlimit = iend - LASTLITERALS;
-
- BYTE *op = (BYTE *) dest;
- BYTE * const olimit = op + maxOutputSize;
-
- U32 forwardH;
- size_t refDelta = 0;
-
- /* Init conditions */
- if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) {
- /* Unsupported inputSize, too large (or negative) */
- return 0;
- }
-
- switch (dict) {
- case noDict:
- default:
- base = (const BYTE *)source;
- lowLimit = (const BYTE *)source;
- break;
- case withPrefix64k:
- base = (const BYTE *)source - dictPtr->currentOffset;
- lowLimit = (const BYTE *)source - dictPtr->dictSize;
- break;
- case usingExtDict:
- base = (const BYTE *)source - dictPtr->currentOffset;
- lowLimit = (const BYTE *)source;
- break;
- }
-
- if ((tableType == byU16)
- && (inputSize >= LZ4_64Klimit)) {
- /* Size too large (not within 64K limit) */
- return 0;
- }
-
- if (inputSize < LZ4_minLength) {
- /* Input too small, no compression (all literals) */
- goto _last_literals;
- }
-
- /* First Byte */
- LZ4_putPosition(ip, dictPtr->hashTable, tableType, base);
- ip++;
- forwardH = LZ4_hashPosition(ip, tableType);
-
- /* Main Loop */
- for ( ; ; ) {
- const BYTE *match;
- BYTE *token;
-
- /* Find a match */
- {
- const BYTE *forwardIp = ip;
- unsigned int step = 1;
- unsigned int searchMatchNb = acceleration << LZ4_SKIPTRIGGER;
-
- do {
- U32 const h = forwardH;
-
- ip = forwardIp;
- forwardIp += step;
- step = (searchMatchNb++ >> LZ4_SKIPTRIGGER);
-
- if (unlikely(forwardIp > mflimit))
- goto _last_literals;
-
- match = LZ4_getPositionOnHash(h,
- dictPtr->hashTable,
- tableType, base);
-
- if (dict == usingExtDict) {
- if (match < (const BYTE *)source) {
- refDelta = dictDelta;
- lowLimit = dictionary;
- } else {
- refDelta = 0;
- lowLimit = (const BYTE *)source;
- } }
-
- forwardH = LZ4_hashPosition(forwardIp,
- tableType);
-
- LZ4_putPositionOnHash(ip, h, dictPtr->hashTable,
- tableType, base);
- } while (((dictIssue == dictSmall)
- ? (match < lowRefLimit)
- : 0)
- || ((tableType == byU16)
- ? 0
- : (match + MAX_DISTANCE < ip))
- || (LZ4_read32(match + refDelta)
- != LZ4_read32(ip)));
- }
-
- /* Catch up */
- while (((ip > anchor) & (match + refDelta > lowLimit))
- && (unlikely(ip[-1] == match[refDelta - 1]))) {
- ip--;
- match--;
- }
-
- /* Encode Literals */
- {
- unsigned const int litLength = (unsigned int)(ip - anchor);
-
- token = op++;
-
- if ((outputLimited) &&
- /* Check output buffer overflow */
- (unlikely(op + litLength +
- (2 + 1 + LASTLITERALS) +
- (litLength / 255) > olimit)))
- return 0;
-
- if (litLength >= RUN_MASK) {
- int len = (int)litLength - RUN_MASK;
-
- *token = (RUN_MASK << ML_BITS);
-
- for (; len >= 255; len -= 255)
- *op++ = 255;
- *op++ = (BYTE)len;
- } else
- *token = (BYTE)(litLength << ML_BITS);
-
- /* Copy Literals */
- LZ4_wildCopy(op, anchor, op + litLength);
- op += litLength;
- }
-
-_next_match:
- /* Encode Offset */
- LZ4_writeLE16(op, (U16)(ip - match));
- op += 2;
-
- /* Encode MatchLength */
- {
- unsigned int matchCode;
-
- if ((dict == usingExtDict)
- && (lowLimit == dictionary)) {
- const BYTE *limit;
-
- match += refDelta;
- limit = ip + (dictEnd - match);
-
- if (limit > matchlimit)
- limit = matchlimit;
-
- matchCode = LZ4_count(ip + MINMATCH,
- match + MINMATCH, limit);
-
- ip += MINMATCH + matchCode;
-
- if (ip == limit) {
- unsigned const int more = LZ4_count(ip,
- (const BYTE *)source,
- matchlimit);
-
- matchCode += more;
- ip += more;
- }
- } else {
- matchCode = LZ4_count(ip + MINMATCH,
- match + MINMATCH, matchlimit);
- ip += MINMATCH + matchCode;
- }
-
- if (outputLimited &&
- /* Check output buffer overflow */
- (unlikely(op +
- (1 + LASTLITERALS) +
- (matchCode >> 8) > olimit)))
- return 0;
-
- if (matchCode >= ML_MASK) {
- *token += ML_MASK;
- matchCode -= ML_MASK;
- LZ4_write32(op, 0xFFFFFFFF);
-
- while (matchCode >= 4 * 255) {
- op += 4;
- LZ4_write32(op, 0xFFFFFFFF);
- matchCode -= 4 * 255;
- }
-
- op += matchCode / 255;
- *op++ = (BYTE)(matchCode % 255);
- } else
- *token += (BYTE)(matchCode);
- }
- anchor = ip;
+#include "lz4_deps.h"
+#include "upstream/lz4.c"
- /* Test end of chunk */
- if (ip > mflimit)
- break;
+/* Upstream's short names for these clash with <linux/minmax.h>. */
+#undef MIN
+#undef MAX
+#undef KB
+#undef MB
+#undef GB
- /* Fill table */
- LZ4_putPosition(ip - 2, dictPtr->hashTable, tableType, base);
-
- /* Test next position */
- match = LZ4_getPosition(ip, dictPtr->hashTable,
- tableType, base);
-
- if (dict == usingExtDict) {
- if (match < (const BYTE *)source) {
- refDelta = dictDelta;
- lowLimit = dictionary;
- } else {
- refDelta = 0;
- lowLimit = (const BYTE *)source;
- }
- }
-
- LZ4_putPosition(ip, dictPtr->hashTable, tableType, base);
-
- if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1)
- && (match + MAX_DISTANCE >= ip)
- && (LZ4_read32(match + refDelta) == LZ4_read32(ip))) {
- token = op++;
- *token = 0;
- goto _next_match;
- }
-
- /* Prepare next loop */
- forwardH = LZ4_hashPosition(++ip, tableType);
- }
-
-_last_literals:
- /* Encode Last Literals */
- {
- size_t const lastRun = (size_t)(iend - anchor);
-
- if ((outputLimited) &&
- /* Check output buffer overflow */
- ((op - (BYTE *)dest) + lastRun + 1 +
- ((lastRun + 255 - RUN_MASK) / 255) > (U32)maxOutputSize))
- return 0;
-
- if (lastRun >= RUN_MASK) {
- size_t accumulator = lastRun - RUN_MASK;
- *op++ = RUN_MASK << ML_BITS;
- for (; accumulator >= 255; accumulator -= 255)
- *op++ = 255;
- *op++ = (BYTE) accumulator;
- } else {
- *op++ = (BYTE)(lastRun << ML_BITS);
- }
-
- LZ4_memcpy(op, anchor, lastRun);
-
- op += lastRun;
- }
-
- /* End */
- return (int) (((char *)op) - dest);
-}
-
-static int LZ4_compress_fast_extState(
- void *state,
- const char *source,
- char *dest,
- int inputSize,
- int maxOutputSize,
- int acceleration)
-{
- LZ4_stream_t_internal *ctx = &((LZ4_stream_t *)state)->internal_donotuse;
-#if LZ4_ARCH64
- const tableType_t tableType = byU32;
-#else
- const tableType_t tableType = byPtr;
-#endif
-
- LZ4_resetStream((LZ4_stream_t *)state);
-
- if (acceleration < 1)
- acceleration = LZ4_ACCELERATION_DEFAULT;
+#include "lz4_kernel_api.h"
+#include <linux/export.h>
+#include <linux/module.h>
- if (maxOutputSize >= LZ4_COMPRESSBOUND(inputSize)) {
- if (inputSize < LZ4_64Klimit)
- return LZ4_compress_generic(ctx, source,
- dest, inputSize, 0,
- noLimit, byU16, noDict,
- noDictIssue, acceleration);
- else
- return LZ4_compress_generic(ctx, source,
- dest, inputSize, 0,
- noLimit, tableType, noDict,
- noDictIssue, acceleration);
- } else {
- if (inputSize < LZ4_64Klimit)
- return LZ4_compress_generic(ctx, source,
- dest, inputSize,
- maxOutputSize, limitedOutput, byU16, noDict,
- noDictIssue, acceleration);
- else
- return LZ4_compress_generic(ctx, source,
- dest, inputSize,
- maxOutputSize, limitedOutput, tableType, noDict,
- noDictIssue, acceleration);
- }
-}
+/* Catch any divergence from upstream's layout at build time. */
+static_assert(sizeof(LZ4_stream_t) == LZ4_STREAM_MINSIZE);
+static_assert(LZ4_STREAM_MINSIZE == 16416); /* LZ4_MEM_COMPRESS */
int LZ4_compress_fast(const char *source, char *dest, int inputSize,
- int maxOutputSize, int acceleration, void *wrkmem)
+ int maxOutputSize, int acceleration, void *wrkmem)
{
return LZ4_compress_fast_extState(wrkmem, source, dest, inputSize,
- maxOutputSize, acceleration);
+ maxOutputSize, acceleration);
}
EXPORT_SYMBOL(LZ4_compress_fast);
int LZ4_compress_default(const char *source, char *dest, int inputSize,
- int maxOutputSize, void *wrkmem)
+ int maxOutputSize, void *wrkmem)
{
- return LZ4_compress_fast(source, dest, inputSize,
- maxOutputSize, LZ4_ACCELERATION_DEFAULT, wrkmem);
+ return LZ4_compress_fast(source, dest, inputSize, maxOutputSize,
+ LZ4_ACCELERATION_DEFAULT, wrkmem);
}
EXPORT_SYMBOL(LZ4_compress_default);
-/*-******************************
- * *_destSize() variant
- ********************************/
-static int LZ4_compress_destSize_generic(
- LZ4_stream_t_internal * const ctx,
- const char * const src,
- char * const dst,
- int * const srcSizePtr,
- const int targetDstSize,
- const tableType_t tableType)
+int LZ4_compress_destSize(const char *source, char *dest, int *sourceSizePtr,
+ int targetDestSize, void *wrkmem)
{
- const BYTE *ip = (const BYTE *) src;
- const BYTE *base = (const BYTE *) src;
- const BYTE *lowLimit = (const BYTE *) src;
- const BYTE *anchor = ip;
- const BYTE * const iend = ip + *srcSizePtr;
- const BYTE * const mflimit = iend - MFLIMIT;
- const BYTE * const matchlimit = iend - LASTLITERALS;
-
- BYTE *op = (BYTE *) dst;
- BYTE * const oend = op + targetDstSize;
- BYTE * const oMaxLit = op + targetDstSize - 2 /* offset */
- - 8 /* because 8 + MINMATCH == MFLIMIT */ - 1 /* token */;
- BYTE * const oMaxMatch = op + targetDstSize
- - (LASTLITERALS + 1 /* token */);
- BYTE * const oMaxSeq = oMaxLit - 1 /* token */;
-
- U32 forwardH;
-
- /* Init conditions */
- /* Impossible to store anything */
- if (targetDstSize < 1)
- return 0;
- /* Unsupported input size, too large (or negative) */
- if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE)
- return 0;
- /* Size too large (not within 64K limit) */
- if ((tableType == byU16) && (*srcSizePtr >= LZ4_64Klimit))
- return 0;
- /* Input too small, no compression (all literals) */
- if (*srcSizePtr < LZ4_minLength)
- goto _last_literals;
-
- /* First Byte */
- *srcSizePtr = 0;
- LZ4_putPosition(ip, ctx->hashTable, tableType, base);
- ip++; forwardH = LZ4_hashPosition(ip, tableType);
-
- /* Main Loop */
- for ( ; ; ) {
- const BYTE *match;
- BYTE *token;
-
- /* Find a match */
- {
- const BYTE *forwardIp = ip;
- unsigned int step = 1;
- unsigned int searchMatchNb = 1 << LZ4_SKIPTRIGGER;
-
- do {
- U32 h = forwardH;
-
- ip = forwardIp;
- forwardIp += step;
- step = (searchMatchNb++ >> LZ4_SKIPTRIGGER);
-
- if (unlikely(forwardIp > mflimit))
- goto _last_literals;
-
- match = LZ4_getPositionOnHash(h, ctx->hashTable,
- tableType, base);
- forwardH = LZ4_hashPosition(forwardIp,
- tableType);
- LZ4_putPositionOnHash(ip, h,
- ctx->hashTable, tableType,
- base);
-
- } while (((tableType == byU16)
- ? 0
- : (match + MAX_DISTANCE < ip))
- || (LZ4_read32(match) != LZ4_read32(ip)));
- }
-
- /* Catch up */
- while ((ip > anchor)
- && (match > lowLimit)
- && (unlikely(ip[-1] == match[-1]))) {
- ip--;
- match--;
- }
-
- /* Encode Literal length */
- {
- unsigned int litLength = (unsigned int)(ip - anchor);
-
- token = op++;
- if (op + ((litLength + 240) / 255)
- + litLength > oMaxLit) {
- /* Not enough space for a last match */
- op--;
- goto _last_literals;
- }
- if (litLength >= RUN_MASK) {
- unsigned int len = litLength - RUN_MASK;
- *token = (RUN_MASK<<ML_BITS);
- for (; len >= 255; len -= 255)
- *op++ = 255;
- *op++ = (BYTE)len;
- } else
- *token = (BYTE)(litLength << ML_BITS);
-
- /* Copy Literals */
- LZ4_wildCopy(op, anchor, op + litLength);
- op += litLength;
- }
-
-_next_match:
- /* Encode Offset */
- LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
-
- /* Encode MatchLength */
- {
- size_t matchLength = LZ4_count(ip + MINMATCH,
- match + MINMATCH, matchlimit);
-
- if (op + ((matchLength + 240)/255) > oMaxMatch) {
- /* Match description too long : reduce it */
- matchLength = (15 - 1) + (oMaxMatch - op) * 255;
- }
- ip += MINMATCH + matchLength;
-
- if (matchLength >= ML_MASK) {
- *token += ML_MASK;
- matchLength -= ML_MASK;
- while (matchLength >= 255) {
- matchLength -= 255;
- *op++ = 255;
- }
- *op++ = (BYTE)matchLength;
- } else
- *token += (BYTE)(matchLength);
- }
-
- anchor = ip;
-
- /* Test end of block */
- if (ip > mflimit)
- break;
- if (op > oMaxSeq)
- break;
-
- /* Fill table */
- LZ4_putPosition(ip - 2, ctx->hashTable, tableType, base);
-
- /* Test next position */
- match = LZ4_getPosition(ip, ctx->hashTable, tableType, base);
- LZ4_putPosition(ip, ctx->hashTable, tableType, base);
-
- if ((match + MAX_DISTANCE >= ip)
- && (LZ4_read32(match) == LZ4_read32(ip))) {
- token = op++; *token = 0;
- goto _next_match;
- }
-
- /* Prepare next loop */
- forwardH = LZ4_hashPosition(++ip, tableType);
- }
-
-_last_literals:
- /* Encode Last Literals */
- {
- size_t lastRunSize = (size_t)(iend - anchor);
-
- if (op + 1 /* token */
- + ((lastRunSize + 240) / 255) /* litLength */
- + lastRunSize /* literals */ > oend) {
- /* adapt lastRunSize to fill 'dst' */
- lastRunSize = (oend - op) - 1;
- lastRunSize -= (lastRunSize + 240) / 255;
- }
- ip = anchor + lastRunSize;
-
- if (lastRunSize >= RUN_MASK) {
- size_t accumulator = lastRunSize - RUN_MASK;
-
- *op++ = RUN_MASK << ML_BITS;
- for (; accumulator >= 255; accumulator -= 255)
- *op++ = 255;
- *op++ = (BYTE) accumulator;
- } else {
- *op++ = (BYTE)(lastRunSize<<ML_BITS);
- }
- LZ4_memcpy(op, anchor, lastRunSize);
- op += lastRunSize;
- }
-
- /* End */
- *srcSizePtr = (int) (((const char *)ip) - src);
- return (int) (((char *)op) - dst);
-}
-
-static int LZ4_compress_destSize_extState(
- LZ4_stream_t *state,
- const char *src,
- char *dst,
- int *srcSizePtr,
- int targetDstSize)
-{
-#if LZ4_ARCH64
- const tableType_t tableType = byU32;
-#else
- const tableType_t tableType = byPtr;
-#endif
-
- LZ4_resetStream(state);
-
- if (targetDstSize >= LZ4_COMPRESSBOUND(*srcSizePtr)) {
- /* compression success is guaranteed */
- return LZ4_compress_fast_extState(
- state, src, dst, *srcSizePtr,
- targetDstSize, 1);
- } else {
- if (*srcSizePtr < LZ4_64Klimit)
- return LZ4_compress_destSize_generic(
- &state->internal_donotuse,
- src, dst, srcSizePtr,
- targetDstSize, byU16);
- else
- return LZ4_compress_destSize_generic(
- &state->internal_donotuse,
- src, dst, srcSizePtr,
- targetDstSize, tableType);
- }
-}
-
-
-int LZ4_compress_destSize(
- const char *src,
- char *dst,
- int *srcSizePtr,
- int targetDstSize,
- void *wrkmem)
-{
- return LZ4_compress_destSize_extState(wrkmem, src, dst, srcSizePtr,
- targetDstSize);
+ return LZ4_compress_destSize_extState(wrkmem, source, dest,
+ sourceSizePtr, targetDestSize,
+ LZ4_ACCELERATION_DEFAULT);
}
EXPORT_SYMBOL(LZ4_compress_destSize);
-/*-******************************
- * Streaming functions
- ********************************/
void LZ4_resetStream(LZ4_stream_t *LZ4_stream)
{
- memset(LZ4_stream, 0, sizeof(LZ4_stream_t));
+ __lz4_resetStream(LZ4_stream);
}
-int LZ4_loadDict(LZ4_stream_t *LZ4_dict,
- const char *dictionary, int dictSize)
+int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary, int dictSize)
{
- LZ4_stream_t_internal *dict = &LZ4_dict->internal_donotuse;
- const BYTE *p = (const BYTE *)dictionary;
- const BYTE * const dictEnd = p + dictSize;
- const BYTE *base;
-
- if ((dict->initCheck)
- || (dict->currentOffset > 1 * GB)) {
- /* Uninitialized structure, or reuse overflow */
- LZ4_resetStream(LZ4_dict);
- }
-
- if (dictSize < (int)HASH_UNIT) {
- dict->dictionary = NULL;
- dict->dictSize = 0;
- return 0;
- }
-
- if ((dictEnd - p) > 64 * KB)
- p = dictEnd - 64 * KB;
- dict->currentOffset += 64 * KB;
- base = p - dict->currentOffset;
- dict->dictionary = p;
- dict->dictSize = (U32)(dictEnd - p);
- dict->currentOffset += dict->dictSize;
-
- while (p <= dictEnd - HASH_UNIT) {
- LZ4_putPosition(p, dict->hashTable, byU32, base);
- p += 3;
- }
-
- return dict->dictSize;
+ return __lz4_loadDict(streamPtr, dictionary, dictSize);
}
EXPORT_SYMBOL(LZ4_loadDict);
-static void LZ4_renormDictT(LZ4_stream_t_internal *LZ4_dict,
- const BYTE *src)
-{
- if ((LZ4_dict->currentOffset > 0x80000000) ||
- ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) {
- /* address space overflow */
- /* rescale hash table */
- U32 const delta = LZ4_dict->currentOffset - 64 * KB;
- const BYTE *dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
- int i;
-
- for (i = 0; i < LZ4_HASH_SIZE_U32; i++) {
- if (LZ4_dict->hashTable[i] < delta)
- LZ4_dict->hashTable[i] = 0;
- else
- LZ4_dict->hashTable[i] -= delta;
- }
- LZ4_dict->currentOffset = 64 * KB;
- if (LZ4_dict->dictSize > 64 * KB)
- LZ4_dict->dictSize = 64 * KB;
- LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
- }
-}
-
-int LZ4_saveDict(LZ4_stream_t *LZ4_dict, char *safeBuffer, int dictSize)
+int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int dictSize)
{
- LZ4_stream_t_internal * const dict = &LZ4_dict->internal_donotuse;
- const BYTE * const previousDictEnd = dict->dictionary + dict->dictSize;
-
- if ((U32)dictSize > 64 * KB) {
- /* useless to define a dictionary > 64 * KB */
- dictSize = 64 * KB;
- }
- if ((U32)dictSize > dict->dictSize)
- dictSize = dict->dictSize;
-
- memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
-
- dict->dictionary = (const BYTE *)safeBuffer;
- dict->dictSize = (U32)dictSize;
-
- return dictSize;
+ return __lz4_saveDict(streamPtr, safeBuffer, dictSize);
}
EXPORT_SYMBOL(LZ4_saveDict);
-int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source,
- char *dest, int inputSize, int maxOutputSize, int acceleration)
+int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src,
+ char *dst, int srcSize, int maxDstSize,
+ int acceleration)
{
- LZ4_stream_t_internal *streamPtr = &LZ4_stream->internal_donotuse;
- const BYTE * const dictEnd = streamPtr->dictionary
- + streamPtr->dictSize;
-
- const BYTE *smallest = (const BYTE *) source;
-
- if (streamPtr->initCheck) {
- /* Uninitialized structure detected */
- return 0;
- }
-
- if ((streamPtr->dictSize > 0) && (smallest > dictEnd))
- smallest = dictEnd;
-
- LZ4_renormDictT(streamPtr, smallest);
-
- if (acceleration < 1)
- acceleration = LZ4_ACCELERATION_DEFAULT;
-
- /* Check overlapping input/dictionary space */
- {
- const BYTE *sourceEnd = (const BYTE *) source + inputSize;
-
- if ((sourceEnd > streamPtr->dictionary)
- && (sourceEnd < dictEnd)) {
- streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
- if (streamPtr->dictSize > 64 * KB)
- streamPtr->dictSize = 64 * KB;
- if (streamPtr->dictSize < 4)
- streamPtr->dictSize = 0;
- streamPtr->dictionary = dictEnd - streamPtr->dictSize;
- }
- }
-
- /* prefix mode : source data follows dictionary */
- if (dictEnd == (const BYTE *)source) {
- int result;
-
- if ((streamPtr->dictSize < 64 * KB) &&
- (streamPtr->dictSize < streamPtr->currentOffset)) {
- result = LZ4_compress_generic(
- streamPtr, source, dest, inputSize,
- maxOutputSize, limitedOutput, byU32,
- withPrefix64k, dictSmall, acceleration);
- } else {
- result = LZ4_compress_generic(
- streamPtr, source, dest, inputSize,
- maxOutputSize, limitedOutput, byU32,
- withPrefix64k, noDictIssue, acceleration);
- }
- streamPtr->dictSize += (U32)inputSize;
- streamPtr->currentOffset += (U32)inputSize;
- return result;
- }
-
- /* external dictionary mode */
- {
- int result;
-
- if ((streamPtr->dictSize < 64 * KB) &&
- (streamPtr->dictSize < streamPtr->currentOffset)) {
- result = LZ4_compress_generic(
- streamPtr, source, dest, inputSize,
- maxOutputSize, limitedOutput, byU32,
- usingExtDict, dictSmall, acceleration);
- } else {
- result = LZ4_compress_generic(
- streamPtr, source, dest, inputSize,
- maxOutputSize, limitedOutput, byU32,
- usingExtDict, noDictIssue, acceleration);
- }
- streamPtr->dictionary = (const BYTE *)source;
- streamPtr->dictSize = (U32)inputSize;
- streamPtr->currentOffset += (U32)inputSize;
- return result;
- }
+ return __lz4_compress_fast_continue(streamPtr, src, dst, srcSize,
+ maxDstSize, acceleration);
}
EXPORT_SYMBOL(LZ4_compress_fast_continue);
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH RFC 6/9] lib/lz4: switch the HC compressor to the vendored sources
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (3 preceding siblings ...)
2026-09-25 11:27 ` [PATCH RFC 5/9] lib/lz4: switch the compressor to the vendored sources Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 7/9] lib/lz4: switch the decompressor " Michal Wilczynski
` (5 subsequent siblings)
10 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
Replace the forked LZ4HC with thin entry points over the vendored
lz4hc.c.
The HC entry points clamp the level below LZ4HC_CLEVEL_OPT_MIN, since
upstream routes levels 10 and up to the optimal parser whose ~64K
workspace does not fit a kernel stack. Levels are clamped rather than
rejected so existing f2fs and zram settings keep working; they now
compress as level 9.
f2fs and zram both take user levels up to LZ4HC_MAX_CLEVEL, so
<linux/lz4.h> gains LZ4HC_CLAMP_CLEVEL and says what happens at or above
it. A later patch ties that constant to upstream's LZ4HC_CLEVEL_OPT_MIN
with a static_assert, once <linux/lz4.h> is in scope of these files.
Levels 1 and 2 change in the other direction. Upstream routes them
through its new lz4mid strategy: at a 4K block that is 26% faster for
10% and 19% worse ratio, and at 64K it is 83% and 90% faster for 14% and
26% worse. In the fork level 1 was only 10% faster than level 3 while
compressing 17% worse, so this is a better point on the curve rather
than a loss, but it is a change. f2fs rejects levels below
LZ4HC_MIN_CLEVEL, so only zram can select them; a caller that wants the
old ratio should ask for level 3.
As with LZ4_stream_t, LZ4_streamHC_t becomes an incomplete type, and the
macros that laid the forked structure out (LZ4HC_DICTIONARY_LOGSIZE,
LZ4HC_MAXD, LZ4HC_MAXD_MASK, LZ4HC_HASH_LOG, LZ4HC_HASHTABLESIZE,
LZ4HC_HASH_MASK, LZ4_STREAMHCSIZE, LZ4_STREAMHCSIZE_SIZET) go with it.
LZ4HC_MEM_COMPRESS grows from 262192 to upstream's LZ4_STREAMHC_MINSIZE,
262200: upstream's LZ4HC_CCtx_internal has fields the forked one does
not, most visibly the dictionary context pointer. It has to grow in the
same commit; an allocation eight bytes short of what the compressor
initialises would overrun zram's compress path. The size is
static_asserted against upstream's own LZ4_STREAMHC_MINSIZE, so a future
re-sync that changes it fails the build rather than the allocation.
lz4hc.c pulls in lz4.c for its common definitions, which include two
decoder tables used there only by the fast decode loop. On architectures
where that loop is off, W=1 reports them as unused. Silence that one
warning for this one object rather than edit the vendored file.
This retires one local patch:
commit b08918fb3f27 ("lz4: do not export static symbol")
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
drivers/block/zram/backend_lz4hc.c | 2 +-
include/linux/lz4.h | 53 +--
lib/lz4/Makefile | 4 +
lib/lz4/lz4hc_compress.c | 785 +++----------------------------------
4 files changed, 76 insertions(+), 768 deletions(-)
diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c
index d8aa01bb258fec760b597a88296dfaa4e0049693..894695753d99bf2fec7e191c4ec2fff489b5bddd 100644
--- a/drivers/block/zram/backend_lz4hc.c
+++ b/drivers/block/zram/backend_lz4hc.c
@@ -69,7 +69,7 @@ static int lz4hc_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
if (!zctx->dstrm)
goto error;
- zctx->cstrm = kzalloc_obj(*zctx->cstrm);
+ zctx->cstrm = kzalloc(LZ4HC_MEM_COMPRESS, GFP_KERNEL);
if (!zctx->cstrm)
goto error;
}
diff --git a/include/linux/lz4.h b/include/linux/lz4.h
index e96353a67d617a4d734cecaf3764814df692428b..0e617c096653ba122f466b019c68a30661e04989 100644
--- a/include/linux/lz4.h
+++ b/include/linux/lz4.h
@@ -59,19 +59,15 @@
#define LZ4HC_DEFAULT_CLEVEL 9
#define LZ4HC_MAX_CLEVEL 16
-#define LZ4HC_DICTIONARY_LOGSIZE 16
-#define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE)
-#define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1)
-#define LZ4HC_HASH_LOG (LZ4HC_DICTIONARY_LOGSIZE - 1)
-#define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG)
-#define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)
+/* Levels from here up select the optimal parser, whose ~64K workspace does
+ * not fit a kernel stack; lib/lz4 clamps them to LZ4HC_CLAMP_CLEVEL - 1.
+ * Anything up to LZ4HC_MAX_CLEVEL is still accepted, just no harder.
+ */
+#define LZ4HC_CLAMP_CLEVEL 10
/*-************************************************************************
* STREAMING CONSTANTS AND STRUCTURES
**************************************************************************/
-#define LZ4_STREAMHCSIZE 262192
-#define LZ4_STREAMHCSIZE_SIZET (262192 / sizeof(size_t))
-
#define LZ4_STREAMDECODESIZE_U64 4
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * \
sizeof(unsigned long long))
@@ -83,29 +79,10 @@
typedef union LZ4_stream_u LZ4_stream_t;
/*
- * LZ4_streamHC_t - information structure to track an LZ4HC stream.
+ * LZ4_streamHC_t - an LZ4HC stream. Incomplete: lib/lz4 owns the layout.
+ * Allocate LZ4HC_MEM_COMPRESS bytes and cast, do not sizeof().
*/
-typedef struct {
- unsigned int hashTable[LZ4HC_HASHTABLESIZE];
- unsigned short chainTable[LZ4HC_MAXD];
- /* next block to continue on current prefix */
- const unsigned char *end;
- /* All index relative to this position */
- const unsigned char *base;
- /* alternate base for extDict */
- const unsigned char *dictBase;
- /* below that point, need extDict */
- unsigned int dictLimit;
- /* below that point, no more dict */
- unsigned int lowLimit;
- /* index from which to continue dict update */
- unsigned int nextToUpdate;
- unsigned int compressionLevel;
-} LZ4HC_CCtx_internal;
-typedef union {
- size_t table[LZ4_STREAMHCSIZE_SIZET];
- LZ4HC_CCtx_internal internal_donotuse;
-} LZ4_streamHC_t;
+typedef union LZ4_streamHC_u LZ4_streamHC_t;
/*
* LZ4_streamDecode_t - information structure to track an
@@ -133,7 +110,7 @@ typedef union {
* buffer is rejected, and the stateless entry points cannot report that.
*/
#define LZ4_MEM_COMPRESS 16416
-#define LZ4HC_MEM_COMPRESS LZ4_STREAMHCSIZE
+#define LZ4HC_MEM_COMPRESS 262200
/*-************************************************************************
* Compression Functions
@@ -310,9 +287,9 @@ int LZ4_decompress_safe_partial(const char *source, char *dest,
* @srcSize: size of the input data. Max supported value is LZ4_MAX_INPUT_SIZE
* @dstCapacity: full or partial size of buffer 'dst',
* which must be already allocated
- * @compressionLevel: Recommended values are between 4 and 9, although any
- * value between 1 and LZ4HC_MAX_CLEVEL will work.
- * Values >LZ4HC_MAX_CLEVEL behave the same as 16.
+ * @compressionLevel: Recommended values are between 4 and 9. Levels of
+ * LZ4HC_CLAMP_CLEVEL and above are clamped to LZ4HC_CLAMP_CLEVEL - 1;
+ * see that macro.
* @wrkmem: address of the working memory.
* This requires 'wrkmem' of size LZ4HC_MEM_COMPRESS, aligned to 8 bytes.
*
@@ -328,9 +305,9 @@ int LZ4_compress_HC(const char *src, char *dst, int srcSize, int dstCapacity,
/**
* LZ4_resetStreamHC() - Init an allocated 'LZ4_streamHC_t' structure
* @streamHCPtr: pointer to the 'LZ4_streamHC_t' structure
- * @compressionLevel: Recommended values are between 4 and 9, although any
- * value between 1 and LZ4HC_MAX_CLEVEL will work.
- * Values >LZ4HC_MAX_CLEVEL behave the same as 16.
+ * @compressionLevel: Recommended values are between 4 and 9. Levels of
+ * LZ4HC_CLAMP_CLEVEL and above are clamped to LZ4HC_CLAMP_CLEVEL - 1;
+ * see that macro.
*
* An LZ4_streamHC_t structure can be allocated once
* and re-used multiple times.
diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile
index e9d83cff4ea4efe1097f54caba72e268cecb04af..9ac36ada805cc99d6db43d141394e51b4b1f7598 100644
--- a/lib/lz4/Makefile
+++ b/lib/lz4/Makefile
@@ -9,3 +9,7 @@ ccflags-y += -I $(src)/freestanding
obj-$(CONFIG_LZ4_COMPRESS) += lz4_compress.o
obj-$(CONFIG_LZ4HC_COMPRESS) += lz4hc_compress.o
obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o
+
+# lz4hc.c pulls in lz4.c's common definitions, which include two decoder
+# tables nothing here uses when LZ4_FAST_DEC_LOOP is off.
+CFLAGS_lz4hc_compress.o += $(call cc-disable-warning, unused-const-variable)
diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c
index 91936dc3d14bca31752a361693380aad8eb3b98a..6070719bab54e90a8a163c08842a5531d7b2b4ac 100644
--- a/lib/lz4/lz4hc_compress.c
+++ b/lib/lz4/lz4hc_compress.c
@@ -1,766 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
/*
- * LZ4 HC - High Compression Mode of LZ4
- * Copyright (C) 2011-2015, Yann Collet.
+ * Copyright (C) 2011 - 2016, Yann Collet.
+ * Copyright (C) 2016, Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
*
- * BSD 2 - Clause License (http://www.opensource.org/licenses/bsd - license.php)
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * You can contact the author at :
- * - LZ4 homepage : http://www.lz4.org
- * - LZ4 source repository : https://github.com/lz4/lz4
+ * LZ4 HC compressor -- kernel entry points
*
- * Changed for kernel usage by:
- * Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
+ * The compressor is upstream's, in the verbatim lz4hc.c included below.
+ * LZ4_compress_HC() takes the kernel's trailing wrkmem argument and forwards
+ * to LZ4_compress_HC_extStateHC(); the level-taking entry points clamp the
+ * level below LZ4HC_CLEVEL_OPT_MIN (see lz4hc_clamp_level()).
*/
-/*-************************************
- * Dependencies
- **************************************/
-#include "lz4defs.h"
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h> /* memset */
-
-/* *************************************
- * Local Constants and types
- ***************************************/
-
-#define OPTIMAL_ML (int)((ML_MASK - 1) + MINMATCH)
-
-#define HASH_FUNCTION(i) (((i) * 2654435761U) \
- >> ((MINMATCH*8) - LZ4HC_HASH_LOG))
-#define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */
-
-static U32 LZ4HC_hashPtr(const void *ptr)
-{
- return HASH_FUNCTION(LZ4_read32(ptr));
-}
-
-/**************************************
- * HC Compression
- **************************************/
-static void LZ4HC_init(LZ4HC_CCtx_internal *hc4, const BYTE *start)
-{
- memset((void *)hc4->hashTable, 0, sizeof(hc4->hashTable));
- memset(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
- hc4->nextToUpdate = 64 * KB;
- hc4->base = start - 64 * KB;
- hc4->end = start;
- hc4->dictBase = start - 64 * KB;
- hc4->dictLimit = 64 * KB;
- hc4->lowLimit = 64 * KB;
-}
-
-/* Update chains up to ip (excluded) */
-static FORCE_INLINE void LZ4HC_Insert(LZ4HC_CCtx_internal *hc4,
- const BYTE *ip)
-{
- U16 * const chainTable = hc4->chainTable;
- U32 * const hashTable = hc4->hashTable;
- const BYTE * const base = hc4->base;
- U32 const target = (U32)(ip - base);
- U32 idx = hc4->nextToUpdate;
-
- while (idx < target) {
- U32 const h = LZ4HC_hashPtr(base + idx);
- size_t delta = idx - hashTable[h];
-
- if (delta > MAX_DISTANCE)
- delta = MAX_DISTANCE;
-
- DELTANEXTU16(idx) = (U16)delta;
+#include "lz4_deps.h"
- hashTable[h] = idx;
- idx++;
- }
-
- hc4->nextToUpdate = target;
-}
-
-static FORCE_INLINE int LZ4HC_InsertAndFindBestMatch(
- LZ4HC_CCtx_internal *hc4, /* Index table will be updated */
- const BYTE *ip,
- const BYTE * const iLimit,
- const BYTE **matchpos,
- const int maxNbAttempts)
+/* lz4hc.c includes lz4.c with LZ4_COMMONDEFS_ONLY, which stops short of
+ * LZ4_compressBound(). Supply it for lz4hc.c's internal use.
+ */
+static int LZ4_compressBound(int isize)
{
- U16 * const chainTable = hc4->chainTable;
- U32 * const HashTable = hc4->hashTable;
- const BYTE * const base = hc4->base;
- const BYTE * const dictBase = hc4->dictBase;
- const U32 dictLimit = hc4->dictLimit;
- const U32 lowLimit = (hc4->lowLimit + 64 * KB > (U32)(ip - base))
- ? hc4->lowLimit
- : (U32)(ip - base) - (64 * KB - 1);
- U32 matchIndex;
- int nbAttempts = maxNbAttempts;
- size_t ml = 0;
-
- /* HC4 match finder */
- LZ4HC_Insert(hc4, ip);
- matchIndex = HashTable[LZ4HC_hashPtr(ip)];
-
- while ((matchIndex >= lowLimit)
- && (nbAttempts)) {
- nbAttempts--;
- if (matchIndex >= dictLimit) {
- const BYTE * const match = base + matchIndex;
-
- if (*(match + ml) == *(ip + ml)
- && (LZ4_read32(match) == LZ4_read32(ip))) {
- size_t const mlt = LZ4_count(ip + MINMATCH,
- match + MINMATCH, iLimit) + MINMATCH;
-
- if (mlt > ml) {
- ml = mlt;
- *matchpos = match;
- }
- }
- } else {
- const BYTE * const match = dictBase + matchIndex;
-
- if (LZ4_read32(match) == LZ4_read32(ip)) {
- size_t mlt;
- const BYTE *vLimit = ip
- + (dictLimit - matchIndex);
-
- if (vLimit > iLimit)
- vLimit = iLimit;
- mlt = LZ4_count(ip + MINMATCH,
- match + MINMATCH, vLimit) + MINMATCH;
- if ((ip + mlt == vLimit)
- && (vLimit < iLimit))
- mlt += LZ4_count(ip + mlt,
- base + dictLimit,
- iLimit);
- if (mlt > ml) {
- /* virtual matchpos */
- ml = mlt;
- *matchpos = base + matchIndex;
- }
- }
- }
- matchIndex -= DELTANEXTU16(matchIndex);
- }
-
- return (int)ml;
+ return LZ4_COMPRESSBOUND(isize);
}
-static FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch(
- LZ4HC_CCtx_internal *hc4,
- const BYTE * const ip,
- const BYTE * const iLowLimit,
- const BYTE * const iHighLimit,
- int longest,
- const BYTE **matchpos,
- const BYTE **startpos,
- const int maxNbAttempts)
-{
- U16 * const chainTable = hc4->chainTable;
- U32 * const HashTable = hc4->hashTable;
- const BYTE * const base = hc4->base;
- const U32 dictLimit = hc4->dictLimit;
- const BYTE * const lowPrefixPtr = base + dictLimit;
- const U32 lowLimit = (hc4->lowLimit + 64 * KB > (U32)(ip - base))
- ? hc4->lowLimit
- : (U32)(ip - base) - (64 * KB - 1);
- const BYTE * const dictBase = hc4->dictBase;
- U32 matchIndex;
- int nbAttempts = maxNbAttempts;
- int delta = (int)(ip - iLowLimit);
-
- /* First Match */
- LZ4HC_Insert(hc4, ip);
- matchIndex = HashTable[LZ4HC_hashPtr(ip)];
-
- while ((matchIndex >= lowLimit)
- && (nbAttempts)) {
- nbAttempts--;
- if (matchIndex >= dictLimit) {
- const BYTE *matchPtr = base + matchIndex;
+#include "upstream/lz4hc.c"
- if (*(iLowLimit + longest)
- == *(matchPtr - delta + longest)) {
- if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
- int mlt = MINMATCH + LZ4_count(
- ip + MINMATCH,
- matchPtr + MINMATCH,
- iHighLimit);
- int back = 0;
-
- while ((ip + back > iLowLimit)
- && (matchPtr + back > lowPrefixPtr)
- && (ip[back - 1] == matchPtr[back - 1]))
- back--;
-
- mlt -= back;
-
- if (mlt > longest) {
- longest = (int)mlt;
- *matchpos = matchPtr + back;
- *startpos = ip + back;
- }
- }
- }
- } else {
- const BYTE * const matchPtr = dictBase + matchIndex;
-
- if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
- size_t mlt;
- int back = 0;
- const BYTE *vLimit = ip + (dictLimit - matchIndex);
-
- if (vLimit > iHighLimit)
- vLimit = iHighLimit;
-
- mlt = LZ4_count(ip + MINMATCH,
- matchPtr + MINMATCH, vLimit) + MINMATCH;
-
- if ((ip + mlt == vLimit) && (vLimit < iHighLimit))
- mlt += LZ4_count(ip + mlt, base + dictLimit,
- iHighLimit);
- while ((ip + back > iLowLimit)
- && (matchIndex + back > lowLimit)
- && (ip[back - 1] == matchPtr[back - 1]))
- back--;
-
- mlt -= back;
-
- if ((int)mlt > longest) {
- longest = (int)mlt;
- *matchpos = base + matchIndex + back;
- *startpos = ip + back;
- }
- }
- }
-
- matchIndex -= DELTANEXTU16(matchIndex);
- }
-
- return longest;
-}
-
-static FORCE_INLINE int LZ4HC_encodeSequence(
- const BYTE **ip,
- BYTE **op,
- const BYTE **anchor,
- int matchLength,
- const BYTE * const match,
- limitedOutput_directive limitedOutputBuffer,
- BYTE *oend)
-{
- int length;
- BYTE *token;
-
- /* Encode Literal length */
- length = (int)(*ip - *anchor);
- token = (*op)++;
-
- if ((limitedOutputBuffer)
- && ((*op + (length>>8)
- + length + (2 + 1 + LASTLITERALS)) > oend)) {
- /* Check output limit */
- return 1;
- }
- if (length >= (int)RUN_MASK) {
- int len;
-
- *token = (RUN_MASK<<ML_BITS);
- len = length - RUN_MASK;
- for (; len > 254 ; len -= 255)
- *(*op)++ = 255;
- *(*op)++ = (BYTE)len;
- } else
- *token = (BYTE)(length<<ML_BITS);
-
- /* Copy Literals */
- LZ4_wildCopy(*op, *anchor, (*op) + length);
- *op += length;
-
- /* Encode Offset */
- LZ4_writeLE16(*op, (U16)(*ip - match));
- *op += 2;
-
- /* Encode MatchLength */
- length = (int)(matchLength - MINMATCH);
-
- if ((limitedOutputBuffer)
- && (*op + (length>>8)
- + (1 + LASTLITERALS) > oend)) {
- /* Check output limit */
- return 1;
- }
-
- if (length >= (int)ML_MASK) {
- *token += ML_MASK;
- length -= ML_MASK;
-
- for (; length > 509 ; length -= 510) {
- *(*op)++ = 255;
- *(*op)++ = 255;
- }
-
- if (length > 254) {
- length -= 255;
- *(*op)++ = 255;
- }
-
- *(*op)++ = (BYTE)length;
- } else
- *token += (BYTE)(length);
-
- /* Prepare next loop */
- *ip += matchLength;
- *anchor = *ip;
-
- return 0;
-}
+/* Upstream's short names for these clash with <linux/minmax.h>. */
+#undef MIN
+#undef MAX
+#undef KB
+#undef MB
+#undef GB
-static int LZ4HC_compress_generic(
- LZ4HC_CCtx_internal *const ctx,
- const char * const source,
- char * const dest,
- int const inputSize,
- int const maxOutputSize,
- int compressionLevel,
- limitedOutput_directive limit
- )
-{
- const BYTE *ip = (const BYTE *) source;
- const BYTE *anchor = ip;
- const BYTE * const iend = ip + inputSize;
- const BYTE * const mflimit = iend - MFLIMIT;
- const BYTE * const matchlimit = (iend - LASTLITERALS);
-
- BYTE *op = (BYTE *) dest;
- BYTE * const oend = op + maxOutputSize;
-
- unsigned int maxNbAttempts;
- int ml, ml2, ml3, ml0;
- const BYTE *ref = NULL;
- const BYTE *start2 = NULL;
- const BYTE *ref2 = NULL;
- const BYTE *start3 = NULL;
- const BYTE *ref3 = NULL;
- const BYTE *start0;
- const BYTE *ref0;
-
- /* init */
- if (compressionLevel > LZ4HC_MAX_CLEVEL)
- compressionLevel = LZ4HC_MAX_CLEVEL;
- if (compressionLevel < 1)
- compressionLevel = LZ4HC_DEFAULT_CLEVEL;
- maxNbAttempts = 1 << (compressionLevel - 1);
- ctx->end += inputSize;
-
- ip++;
-
- /* Main Loop */
- while (ip < mflimit) {
- ml = LZ4HC_InsertAndFindBestMatch(ctx, ip,
- matchlimit, (&ref), maxNbAttempts);
- if (!ml) {
- ip++;
- continue;
- }
-
- /* saved, in case we would skip too much */
- start0 = ip;
- ref0 = ref;
- ml0 = ml;
-
-_Search2:
- if (ip + ml < mflimit)
- ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
- ip + ml - 2, ip + 0,
- matchlimit, ml, &ref2,
- &start2, maxNbAttempts);
- else
- ml2 = ml;
-
- if (ml2 == ml) {
- /* No better match */
- if (LZ4HC_encodeSequence(&ip, &op,
- &anchor, ml, ref, limit, oend))
- return 0;
- continue;
- }
-
- if (start0 < ip) {
- if (start2 < ip + ml0) {
- /* empirical */
- ip = start0;
- ref = ref0;
- ml = ml0;
- }
- }
-
- /* Here, start0 == ip */
- if ((start2 - ip) < 3) {
- /* First Match too small : removed */
- ml = ml2;
- ip = start2;
- ref = ref2;
- goto _Search2;
- }
-
-_Search3:
- /*
- * Currently we have :
- * ml2 > ml1, and
- * ip1 + 3 <= ip2 (usually < ip1 + ml1)
- */
- if ((start2 - ip) < OPTIMAL_ML) {
- int correction;
- int new_ml = ml;
-
- if (new_ml > OPTIMAL_ML)
- new_ml = OPTIMAL_ML;
- if (ip + new_ml > start2 + ml2 - MINMATCH)
- new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
-
- correction = new_ml - (int)(start2 - ip);
-
- if (correction > 0) {
- start2 += correction;
- ref2 += correction;
- ml2 -= correction;
- }
- }
- /*
- * Now, we have start2 = ip + new_ml,
- * with new_ml = min(ml, OPTIMAL_ML = 18)
- */
-
- if (start2 + ml2 < mflimit)
- ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
- start2 + ml2 - 3, start2,
- matchlimit, ml2, &ref3, &start3,
- maxNbAttempts);
- else
- ml3 = ml2;
-
- if (ml3 == ml2) {
- /* No better match : 2 sequences to encode */
- /* ip & ref are known; Now for ml */
- if (start2 < ip + ml)
- ml = (int)(start2 - ip);
- /* Now, encode 2 sequences */
- if (LZ4HC_encodeSequence(&ip, &op, &anchor,
- ml, ref, limit, oend))
- return 0;
- ip = start2;
- if (LZ4HC_encodeSequence(&ip, &op, &anchor,
- ml2, ref2, limit, oend))
- return 0;
- continue;
- }
-
- if (start3 < ip + ml + 3) {
- /* Not enough space for match 2 : remove it */
- if (start3 >= (ip + ml)) {
- /* can write Seq1 immediately
- * ==> Seq2 is removed,
- * so Seq3 becomes Seq1
- */
- if (start2 < ip + ml) {
- int correction = (int)(ip + ml - start2);
-
- start2 += correction;
- ref2 += correction;
- ml2 -= correction;
- if (ml2 < MINMATCH) {
- start2 = start3;
- ref2 = ref3;
- ml2 = ml3;
- }
- }
-
- if (LZ4HC_encodeSequence(&ip, &op, &anchor,
- ml, ref, limit, oend))
- return 0;
- ip = start3;
- ref = ref3;
- ml = ml3;
-
- start0 = start2;
- ref0 = ref2;
- ml0 = ml2;
- goto _Search2;
- }
-
- start2 = start3;
- ref2 = ref3;
- ml2 = ml3;
- goto _Search3;
- }
-
- /*
- * OK, now we have 3 ascending matches;
- * let's write at least the first one
- * ip & ref are known; Now for ml
- */
- if (start2 < ip + ml) {
- if ((start2 - ip) < (int)ML_MASK) {
- int correction;
-
- if (ml > OPTIMAL_ML)
- ml = OPTIMAL_ML;
- if (ip + ml > start2 + ml2 - MINMATCH)
- ml = (int)(start2 - ip) + ml2 - MINMATCH;
- correction = ml - (int)(start2 - ip);
- if (correction > 0) {
- start2 += correction;
- ref2 += correction;
- ml2 -= correction;
- }
- } else
- ml = (int)(start2 - ip);
- }
- if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml,
- ref, limit, oend))
- return 0;
-
- ip = start2;
- ref = ref2;
- ml = ml2;
-
- start2 = start3;
- ref2 = ref3;
- ml2 = ml3;
-
- goto _Search3;
- }
-
- /* Encode Last Literals */
- {
- int lastRun = (int)(iend - anchor);
-
- if ((limit)
- && (((char *)op - dest) + lastRun + 1
- + ((lastRun + 255 - RUN_MASK)/255)
- > (U32)maxOutputSize)) {
- /* Check output limit */
- return 0;
- }
- if (lastRun >= (int)RUN_MASK) {
- *op++ = (RUN_MASK<<ML_BITS);
- lastRun -= RUN_MASK;
- for (; lastRun > 254 ; lastRun -= 255)
- *op++ = 255;
- *op++ = (BYTE) lastRun;
- } else
- *op++ = (BYTE)(lastRun<<ML_BITS);
- LZ4_memcpy(op, anchor, iend - anchor);
- op += iend - anchor;
- }
+#include "lz4_kernel_api.h"
+#include <linux/export.h>
+#include <linux/module.h>
- /* End */
- return (int) (((char *)op) - dest);
-}
+/* Catch any divergence from upstream's layout at build time. */
+static_assert(sizeof(LZ4_streamHC_t) == LZ4_STREAMHC_MINSIZE);
+static_assert(LZ4_STREAMHC_MINSIZE == 262200); /* LZ4HC_MEM_COMPRESS */
-static int LZ4_compress_HC_extStateHC(
- void *state,
- const char *src,
- char *dst,
- int srcSize,
- int maxDstSize,
- int compressionLevel)
+/* Levels >= LZ4HC_CLEVEL_OPT_MIN (10) reach the optimal parser, whose ~64K
+ * opt[] does not fit a kernel stack, so clamp them to 9. Clamp rather than
+ * reject so existing f2fs and zram settings keep working. Levels 3..9 are
+ * untouched; 1 and 2 are upstream's lz4mid, faster and weaker than the
+ * shallow hash chain the fork used for them.
+ */
+static int lz4hc_clamp_level(int compressionLevel)
{
- LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t *)state)->internal_donotuse;
+ if (compressionLevel >= LZ4HC_CLEVEL_OPT_MIN)
+ return LZ4HC_CLEVEL_OPT_MIN - 1;
- if (((size_t)(state)&(sizeof(void *) - 1)) != 0) {
- /* Error : state is not aligned
- * for pointers (32 or 64 bits)
- */
- return 0;
- }
-
- LZ4HC_init(ctx, (const BYTE *)src);
-
- if (maxDstSize < LZ4_compressBound(srcSize))
- return LZ4HC_compress_generic(ctx, src, dst,
- srcSize, maxDstSize, compressionLevel, limitedOutput);
- else
- return LZ4HC_compress_generic(ctx, src, dst,
- srcSize, maxDstSize, compressionLevel, noLimit);
+ return compressionLevel;
}
-int LZ4_compress_HC(const char *src, char *dst, int srcSize,
- int maxDstSize, int compressionLevel, void *wrkmem)
+int LZ4_compress_HC(const char *src, char *dst, int srcSize, int dstCapacity,
+ int compressionLevel, void *wrkmem)
{
- return LZ4_compress_HC_extStateHC(wrkmem, src, dst,
- srcSize, maxDstSize, compressionLevel);
+ return LZ4_compress_HC_extStateHC(wrkmem, src, dst, srcSize,
+ dstCapacity,
+ lz4hc_clamp_level(compressionLevel));
}
EXPORT_SYMBOL(LZ4_compress_HC);
-/**************************************
- * Streaming Functions
- **************************************/
-void LZ4_resetStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr, int compressionLevel)
+void LZ4_resetStreamHC(LZ4_streamHC_t *streamHCPtr, int compressionLevel)
{
- LZ4_streamHCPtr->internal_donotuse.base = NULL;
- LZ4_streamHCPtr->internal_donotuse.compressionLevel = (unsigned int)compressionLevel;
+ __lz4_resetStreamHC(streamHCPtr, lz4hc_clamp_level(compressionLevel));
}
EXPORT_SYMBOL(LZ4_resetStreamHC);
-int LZ4_loadDictHC(LZ4_streamHC_t *LZ4_streamHCPtr,
- const char *dictionary,
- int dictSize)
+int LZ4_loadDictHC(LZ4_streamHC_t *streamHCPtr, const char *dictionary,
+ int dictSize)
{
- LZ4HC_CCtx_internal *ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
-
- if (dictSize > 64 * KB) {
- dictionary += dictSize - 64 * KB;
- dictSize = 64 * KB;
- }
- LZ4HC_init(ctxPtr, (const BYTE *)dictionary);
- if (dictSize >= 4)
- LZ4HC_Insert(ctxPtr, (const BYTE *)dictionary + (dictSize - 3));
- ctxPtr->end = (const BYTE *)dictionary + dictSize;
- return dictSize;
+ return __lz4_loadDictHC(streamHCPtr, dictionary, dictSize);
}
EXPORT_SYMBOL(LZ4_loadDictHC);
-/* compression */
-
-static void LZ4HC_setExternalDict(
- LZ4HC_CCtx_internal *ctxPtr,
- const BYTE *newBlock)
-{
- if (ctxPtr->end >= ctxPtr->base + 4) {
- /* Referencing remaining dictionary content */
- LZ4HC_Insert(ctxPtr, ctxPtr->end - 3);
- }
-
- /*
- * Only one memory segment for extDict,
- * so any previous extDict is lost at this stage
- */
- ctxPtr->lowLimit = ctxPtr->dictLimit;
- ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
- ctxPtr->dictBase = ctxPtr->base;
- ctxPtr->base = newBlock - ctxPtr->dictLimit;
- ctxPtr->end = newBlock;
- /* match referencing will resume from there */
- ctxPtr->nextToUpdate = ctxPtr->dictLimit;
-}
-
-static int LZ4_compressHC_continue_generic(
- LZ4_streamHC_t *LZ4_streamHCPtr,
- const char *source,
- char *dest,
- int inputSize,
- int maxOutputSize,
- limitedOutput_directive limit)
-{
- LZ4HC_CCtx_internal *ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
-
- /* auto - init if forgotten */
- if (ctxPtr->base == NULL)
- LZ4HC_init(ctxPtr, (const BYTE *) source);
-
- /* Check overflow */
- if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 * GB) {
- size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base)
- - ctxPtr->dictLimit;
- if (dictSize > 64 * KB)
- dictSize = 64 * KB;
- LZ4_loadDictHC(LZ4_streamHCPtr,
- (const char *)(ctxPtr->end) - dictSize, (int)dictSize);
- }
-
- /* Check if blocks follow each other */
- if ((const BYTE *)source != ctxPtr->end)
- LZ4HC_setExternalDict(ctxPtr, (const BYTE *)source);
-
- /* Check overlapping input/dictionary space */
- {
- const BYTE *sourceEnd = (const BYTE *) source + inputSize;
- const BYTE * const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
- const BYTE * const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
-
- if ((sourceEnd > dictBegin)
- && ((const BYTE *)source < dictEnd)) {
- if (sourceEnd > dictEnd)
- sourceEnd = dictEnd;
- ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
-
- if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4)
- ctxPtr->lowLimit = ctxPtr->dictLimit;
- }
- }
-
- return LZ4HC_compress_generic(ctxPtr, source, dest,
- inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
-}
-
-int LZ4_compress_HC_continue(
- LZ4_streamHC_t *LZ4_streamHCPtr,
- const char *source,
- char *dest,
- int inputSize,
- int maxOutputSize)
+int LZ4_compress_HC_continue(LZ4_streamHC_t *streamHCPtr, const char *src,
+ char *dst, int srcSize, int maxDstSize)
{
- if (maxOutputSize < LZ4_compressBound(inputSize))
- return LZ4_compressHC_continue_generic(LZ4_streamHCPtr,
- source, dest, inputSize, maxOutputSize, limitedOutput);
- else
- return LZ4_compressHC_continue_generic(LZ4_streamHCPtr,
- source, dest, inputSize, maxOutputSize, noLimit);
+ return __lz4_compress_HC_continue(streamHCPtr, src, dst, srcSize,
+ maxDstSize);
}
EXPORT_SYMBOL(LZ4_compress_HC_continue);
-/* dictionary saving */
-
-int LZ4_saveDictHC(
- LZ4_streamHC_t *LZ4_streamHCPtr,
- char *safeBuffer,
- int dictSize)
+int LZ4_saveDictHC(LZ4_streamHC_t *streamHCPtr, char *safeBuffer,
+ int maxDictSize)
{
- LZ4HC_CCtx_internal *const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
- int const prefixSize = (int)(streamPtr->end
- - (streamPtr->base + streamPtr->dictLimit));
-
- if (dictSize > 64 * KB)
- dictSize = 64 * KB;
- if (dictSize < 4)
- dictSize = 0;
- if (dictSize > prefixSize)
- dictSize = prefixSize;
-
- memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
-
- {
- U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
-
- streamPtr->end = (const BYTE *)safeBuffer + dictSize;
- streamPtr->base = streamPtr->end - endIndex;
- streamPtr->dictLimit = endIndex - dictSize;
- streamPtr->lowLimit = endIndex - dictSize;
-
- if (streamPtr->nextToUpdate < streamPtr->dictLimit)
- streamPtr->nextToUpdate = streamPtr->dictLimit;
- }
- return dictSize;
+ return __lz4_saveDictHC(streamHCPtr, safeBuffer, maxDictSize);
}
EXPORT_SYMBOL(LZ4_saveDictHC);
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH RFC 7/9] lib/lz4: switch the decompressor to the vendored sources
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (4 preceding siblings ...)
2026-09-25 11:27 ` [PATCH RFC 6/9] lib/lz4: switch the HC " Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-28 4:16 ` Sergey Senozhatsky
2026-09-25 11:27 ` [PATCH RFC 8/9] lib/lz4: fold lz4_kernel_api.h into <linux/lz4.h> Michal Wilczynski
` (4 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
Replace the forked decompressor with thin entry points over the vendored
lz4.c. The API is already signature-compatible, so every export is a
plain forwarder. lz4defs.h has no users left and goes.
lib/decompress_unlz4.c still includes this file for the pre-boot
decompressor; the exports stay behind #ifndef STATIC.
That include is why LZ4_streamDecode_t is incomplete: under PREBOOT the
translation unit has both <linux/lz4.h> and upstream's lz4.h, so both
must name the same type. Both repeat upstream's forward declaration,
and the file builds without guards.
LZ4_streamDecode_t is the last of the three, so LZ4_STREAMDECODESIZE and
LZ4_STREAMDECODESIZE_U64 go and LZ4_MEM_DECOMPRESS takes over, 32 bytes.
LZ4_COMPRESSBOUND is likewise defined by both headers; guard it.
LZ4_compressBound() cannot be guarded, so drop the inline wrapper:
lib/decompress_unlz4.c was its only caller and uses the macro now.
This picks up upstream's decoder fixes since v1.8.3 and retires six
local patches:
commit 8cb5d7482810 ("lib/lz4: make arrays static const, reduces object code size")
commit b1a3e75e466d ("lz4: fix kernel decompression speed")
commit 89b158635ad7 ("lib/lz4: explicitly support in-place decompression")
commit 7fde9d6e839d ("lz4_decompress: declare LZ4_decompress_safe_withPrefix64k static")
commit eafc0a02391b ("lz4: fix LZ4_decompress_safe_partial read out of bound")
commit 2d8867f3e083 ("lib: make LZ4_decompress_safe_forceExtDict() static")
The decompression speed fix has an upstream equivalent, carried since
v1.9.3 as upstream commit fe2a1b3707d5
("Call LZ4_memcpy() instead of memcpy()").
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
drivers/block/zram/backend_lz4.c | 2 +-
drivers/block/zram/backend_lz4hc.c | 2 +-
include/linux/lz4.h | 51 +--
lib/decompress_unlz4.c | 4 +-
lib/lz4/lz4_decompress.c | 718 +++----------------------------------
lib/lz4/lz4defs.h | 247 -------------
6 files changed, 74 insertions(+), 950 deletions(-)
diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c
index 50265e3ce256490994cb6dae32a45da376e408e0..b9b8a5f678c155442fa3fd2c1984e45182e6fc38 100644
--- a/drivers/block/zram/backend_lz4.c
+++ b/drivers/block/zram/backend_lz4.c
@@ -84,7 +84,7 @@ static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
if (!zctx->mem)
goto error;
} else {
- zctx->dstrm = kzalloc_obj(*zctx->dstrm);
+ zctx->dstrm = kzalloc(LZ4_MEM_DECOMPRESS, GFP_KERNEL);
if (!zctx->dstrm)
goto error;
diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c
index 894695753d99bf2fec7e191c4ec2fff489b5bddd..7fabd0e6d66095d411007bec5eaa8e5f553b626d 100644
--- a/drivers/block/zram/backend_lz4hc.c
+++ b/drivers/block/zram/backend_lz4hc.c
@@ -65,7 +65,7 @@ static int lz4hc_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
if (!zctx->mem)
goto error;
} else {
- zctx->dstrm = kzalloc_obj(*zctx->dstrm);
+ zctx->dstrm = kzalloc(LZ4_MEM_DECOMPRESS, GFP_KERNEL);
if (!zctx->dstrm)
goto error;
diff --git a/include/linux/lz4.h b/include/linux/lz4.h
index 0e617c096653ba122f466b019c68a30661e04989..22adf26904754b3a274274d6b77955eb119e463f 100644
--- a/include/linux/lz4.h
+++ b/include/linux/lz4.h
@@ -48,10 +48,16 @@
* CONSTANTS
**************************************************************************/
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
+
+/* lib/decompress_unlz4.c sees this header and, under PREBOOT, upstream's
+ * lz4.h too; both define this identically.
+ */
+#ifndef LZ4_COMPRESSBOUND
#define LZ4_COMPRESSBOUND(isize) (\
(unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE \
? 0 \
: (isize) + ((isize)/255) + 16)
+#endif
#define LZ4_ACCELERATION_DEFAULT 1
@@ -66,12 +72,8 @@
#define LZ4HC_CLAMP_CLEVEL 10
/*-************************************************************************
- * STREAMING CONSTANTS AND STRUCTURES
+ * STREAMING STRUCTURES
**************************************************************************/
-#define LZ4_STREAMDECODESIZE_U64 4
-#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * \
- sizeof(unsigned long long))
-
/*
* LZ4_stream_t - an LZ4 stream. Incomplete: lib/lz4 owns the layout.
* Allocate LZ4_MEM_COMPRESS bytes and cast, do not sizeof().
@@ -85,21 +87,11 @@ typedef union LZ4_stream_u LZ4_stream_t;
typedef union LZ4_streamHC_u LZ4_streamHC_t;
/*
- * LZ4_streamDecode_t - information structure to track an
- * LZ4 stream during decompression.
- *
- * init this structure using LZ4_setStreamDecode (or memset()) before first use
+ * LZ4_streamDecode_t - an LZ4 stream during decompression. Incomplete:
+ * lib/lz4 owns the layout. Allocate LZ4_MEM_DECOMPRESS bytes and cast, do
+ * not sizeof(). Init with LZ4_setStreamDecode() (or zero it) before use.
*/
-typedef struct {
- const uint8_t *externalDict;
- size_t extDictSize;
- const uint8_t *prefixEnd;
- size_t prefixSize;
-} LZ4_streamDecode_t_internal;
-typedef union {
- unsigned long long table[LZ4_STREAMDECODESIZE_U64];
- LZ4_streamDecode_t_internal internal_donotuse;
-} LZ4_streamDecode_t;
+typedef union LZ4_streamDecode_u LZ4_streamDecode_t;
/*-************************************************************************
* SIZE OF STATE
@@ -111,23 +103,12 @@ typedef union {
*/
#define LZ4_MEM_COMPRESS 16416
#define LZ4HC_MEM_COMPRESS 262200
+#define LZ4_MEM_DECOMPRESS 32
/*-************************************************************************
* Compression Functions
**************************************************************************/
-/**
- * LZ4_compressBound() - Max. output size in worst case szenarios
- * @isize: Size of the input data
- *
- * Return: Max. size LZ4 may output in a "worst case" szenario
- * (data not compressible)
- */
-static inline int LZ4_compressBound(size_t isize)
-{
- return LZ4_COMPRESSBOUND(isize);
-}
-
/**
* LZ4_compress_default() - Compress data from source to dest
* @source: source address of the original data
@@ -141,7 +122,7 @@ static inline int LZ4_compressBound(size_t isize)
* Compresses 'sourceSize' bytes from buffer 'source'
* into already allocated 'dest' buffer of size 'maxOutputSize'.
* Compression is guaranteed to succeed if
- * 'maxOutputSize' >= LZ4_compressBound(inputSize).
+ * 'maxOutputSize' >= LZ4_COMPRESSBOUND(inputSize).
* It also runs faster, so it's a recommended setting.
* If the function cannot compress 'source' into a more limited 'dest' budget,
* compression stops *immediately*, and the function result is zero.
@@ -295,7 +276,7 @@ int LZ4_decompress_safe_partial(const char *source, char *dest,
*
* Compress data from 'src' into 'dst', using the more powerful
* but slower "HC" algorithm. Compression is guaranteed to succeed if
- * `dstCapacity >= LZ4_compressBound(srcSize)
+ * `dstCapacity >= LZ4_COMPRESSBOUND(srcSize)
*
* Return : the number of bytes written into 'dst' or 0 if compression fails.
*/
@@ -359,7 +340,7 @@ int LZ4_loadDictHC(LZ4_streamHC_t *streamHCPtr, const char *dictionary,
* (including initial dictionary when present) must remain accessible
* and unmodified during compression.
* 'dst' buffer should be sized to handle worst case scenarios, using
- * LZ4_compressBound(), to ensure operation success.
+ * LZ4_COMPRESSBOUND(), to ensure operation success.
* If, for any reason, previous data blocks can't be preserved unmodified
* in memory during next compression block,
* you must save it to a safer memory space, using LZ4_saveDictHC().
@@ -455,7 +436,7 @@ int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int dictSize);
* as dictionary to improve compression ratio.
* Important : Previous data blocks are assumed to still
* be present and unmodified !
- * If maxDstSize >= LZ4_compressBound(srcSize),
+ * If maxDstSize >= LZ4_COMPRESSBOUND(srcSize),
* compression is guaranteed to succeed, and runs faster.
*
* Return: Number of bytes written into buffer 'dst' or 0 if compression fails
diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c
index c0dbb3cea915eb91d8f4ac26c38c4785bbf19770..48ac767dbf68d69082dd00fa4970aaf50aa1db5c 100644
--- a/lib/decompress_unlz4.c
+++ b/lib/decompress_unlz4.c
@@ -69,7 +69,7 @@ STATIC inline int INIT unlz4(u8 *input, long in_len,
error("NULL input pointer and missing fill function");
goto exit_1;
} else {
- inp = large_malloc(LZ4_compressBound(uncomp_chunksize));
+ inp = large_malloc(LZ4_COMPRESSBOUND(uncomp_chunksize));
if (!inp) {
error("Could not allocate input buffer");
goto exit_1;
@@ -140,7 +140,7 @@ STATIC inline int INIT unlz4(u8 *input, long in_len,
inp += 4;
size -= 4;
} else {
- if (chunksize > LZ4_compressBound(uncomp_chunksize)) {
+ if (chunksize > LZ4_COMPRESSBOUND(uncomp_chunksize)) {
error("chunk length is longer than allocated");
goto exit_2;
}
diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c
index 3a2cd9acada4a09ef70a344090d48167c46088a1..68c8a87476df58fff48b1ffbeee8f2d3bbf743df 100644
--- a/lib/lz4/lz4_decompress.c
+++ b/lib/lz4/lz4_decompress.c
@@ -1,707 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
/*
- * LZ4 - Fast LZ compression algorithm
* Copyright (C) 2011 - 2016, Yann Collet.
- * BSD 2 - Clause License (http://www.opensource.org/licenses/bsd - license.php)
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * You can contact the author at :
- * - LZ4 homepage : http://www.lz4.org
- * - LZ4 source repository : https://github.com/lz4/lz4
+ * Copyright (C) 2016, Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
+ * Copyright (c) 2026 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
*
- * Changed for kernel usage by:
- * Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
+ * LZ4 decompressor -- kernel entry points
+ *
+ * The decompressor is upstream's, in the verbatim lz4.c included below. The
+ * API is signature-compatible, so every export is a plain forwarder. This
+ * file is also included by lib/decompress_unlz4.c for the pre-boot
+ * decompressor, which defines STATIC.
*/
-/*-************************************
- * Dependencies
- **************************************/
-#include "lz4defs.h"
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/unaligned.h>
+#include "lz4_deps.h"
+#include "upstream/lz4.c"
-/*-*****************************
- * Decompression functions
- *******************************/
+/* Upstream's short names for these clash with <linux/minmax.h>. */
+#undef MIN
+#undef MAX
+#undef KB
+#undef MB
+#undef GB
-#define DEBUGLOG(l, ...) {} /* disabled */
+#include "lz4_kernel_api.h"
-#ifndef assert
-#define assert(condition) ((void)0)
+#ifndef STATIC
+#include <linux/export.h>
+#include <linux/module.h>
#endif
-/*
- * LZ4_decompress_generic() :
- * This generic decompression function covers all use cases.
- * It shall be instantiated several times, using different sets of directives.
- * Note that it is important for performance that this function really get inlined,
- * in order to remove useless branches during compilation optimization.
- */
-static FORCE_INLINE int LZ4_decompress_generic(
- const char * const src,
- char * const dst,
- int srcSize,
- /*
- * If endOnInput == endOnInputSize,
- * this value is `dstCapacity`
- */
- int outputSize,
- /* endOnOutputSize, endOnInputSize */
- endCondition_directive endOnInput,
- /* full, partial */
- earlyEnd_directive partialDecoding,
- /* noDict, withPrefix64k, usingExtDict */
- dict_directive dict,
- /* always <= dst, == dst when no prefix */
- const BYTE * const lowPrefix,
- /* only if dict == usingExtDict */
- const BYTE * const dictStart,
- /* note : = 0 if noDict */
- const size_t dictSize
- )
-{
- const BYTE *ip = (const BYTE *) src;
- const BYTE * const iend = ip + srcSize;
-
- BYTE *op = (BYTE *) dst;
- BYTE * const oend = op + outputSize;
- BYTE *cpy;
-
- const BYTE * const dictEnd = (const BYTE *)dictStart + dictSize;
- static const unsigned int inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
- static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
-
- const int safeDecode = (endOnInput == endOnInputSize);
- const int checkOffset = ((safeDecode) && (dictSize < (int)(64 * KB)));
-
- /* Set up the "end" pointers for the shortcut. */
- const BYTE *const shortiend = iend -
- (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/;
- const BYTE *const shortoend = oend -
- (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/;
-
- DEBUGLOG(5, "%s (srcSize:%i, dstSize:%i)", __func__,
- srcSize, outputSize);
-
- /* Special cases */
- assert(lowPrefix <= op);
- assert(src != NULL);
-
- /* Empty output buffer */
- if ((endOnInput) && (unlikely(outputSize == 0)))
- return ((srcSize == 1) && (*ip == 0)) ? 0 : -1;
-
- if ((!endOnInput) && (unlikely(outputSize == 0)))
- return (*ip == 0 ? 1 : -1);
-
- if ((endOnInput) && unlikely(srcSize == 0))
- return -1;
-
- /* Main Loop : decode sequences */
- while (1) {
- size_t length;
- const BYTE *match;
- size_t offset;
-
- /* get literal length */
- unsigned int const token = *ip++;
- length = token>>ML_BITS;
-
- /* ip < iend before the increment */
- assert(!endOnInput || ip <= iend);
-
- /*
- * A two-stage shortcut for the most common case:
- * 1) If the literal length is 0..14, and there is enough
- * space, enter the shortcut and copy 16 bytes on behalf
- * of the literals (in the fast mode, only 8 bytes can be
- * safely copied this way).
- * 2) Further if the match length is 4..18, copy 18 bytes
- * in a similar manner; but we ensure that there's enough
- * space in the output for those 18 bytes earlier, upon
- * entering the shortcut (in other words, there is a
- * combined check for both stages).
- *
- * The & in the likely() below is intentionally not && so that
- * some compilers can produce better parallelized runtime code
- */
- if ((endOnInput ? length != RUN_MASK : length <= 8)
- /*
- * strictly "less than" on input, to re-enter
- * the loop with at least one byte
- */
- && likely((endOnInput ? ip < shortiend : 1) &
- (op <= shortoend))) {
- /* Copy the literals */
- LZ4_memcpy(op, ip, endOnInput ? 16 : 8);
- op += length; ip += length;
-
- /*
- * The second stage:
- * prepare for match copying, decode full info.
- * If it doesn't work out, the info won't be wasted.
- */
- length = token & ML_MASK; /* match length */
- offset = LZ4_readLE16(ip);
- ip += 2;
- match = op - offset;
- assert(match <= op); /* check overflow */
-
- /* Do not deal with overlapping matches. */
- if ((length != ML_MASK) &&
- (offset >= 8) &&
- (dict == withPrefix64k || match >= lowPrefix)) {
- /* Copy the match. */
- LZ4_memcpy(op + 0, match + 0, 8);
- LZ4_memcpy(op + 8, match + 8, 8);
- LZ4_memcpy(op + 16, match + 16, 2);
- op += length + MINMATCH;
- /* Both stages worked, load the next token. */
- continue;
- }
-
- /*
- * The second stage didn't work out, but the info
- * is ready. Propel it right to the point of match
- * copying.
- */
- goto _copy_match;
- }
-
- /* decode literal length */
- if (length == RUN_MASK) {
- unsigned int s;
-
- if (unlikely(endOnInput ? ip >= iend - RUN_MASK : 0)) {
- /* overflow detection */
- goto _output_error;
- }
- do {
- s = *ip++;
- length += s;
- } while (likely(endOnInput
- ? ip < iend - RUN_MASK
- : 1) & (s == 255));
-
- if ((safeDecode)
- && unlikely((uptrval)(op) +
- length < (uptrval)(op))) {
- /* overflow detection */
- goto _output_error;
- }
- if ((safeDecode)
- && unlikely((uptrval)(ip) +
- length < (uptrval)(ip))) {
- /* overflow detection */
- goto _output_error;
- }
- }
-
- /* copy literals */
- cpy = op + length;
- LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
-
- if (((endOnInput) && ((cpy > oend - MFLIMIT)
- || (ip + length > iend - (2 + 1 + LASTLITERALS))))
- || ((!endOnInput) && (cpy > oend - WILDCOPYLENGTH))) {
- if (partialDecoding) {
- if (cpy > oend) {
- /*
- * Partial decoding :
- * stop in the middle of literal segment
- */
- cpy = oend;
- length = oend - op;
- }
- if ((endOnInput)
- && (ip + length > iend)) {
- /*
- * Error :
- * read attempt beyond
- * end of input buffer
- */
- goto _output_error;
- }
- } else {
- if ((!endOnInput)
- && (cpy != oend)) {
- /*
- * Error :
- * block decoding must
- * stop exactly there
- */
- goto _output_error;
- }
- if ((endOnInput)
- && ((ip + length != iend)
- || (cpy > oend))) {
- /*
- * Error :
- * input must be consumed
- */
- goto _output_error;
- }
- }
-
- /*
- * supports overlapping memory regions; only matters
- * for in-place decompression scenarios
- */
- LZ4_memmove(op, ip, length);
- ip += length;
- op += length;
-
- /* Necessarily EOF when !partialDecoding.
- * When partialDecoding, it is EOF if we've either
- * filled the output buffer or
- * can't proceed with reading an offset for following match.
- */
- if (!partialDecoding || (cpy == oend) || (ip >= (iend - 2)))
- break;
- } else {
- /* may overwrite up to WILDCOPYLENGTH beyond cpy */
- LZ4_wildCopy(op, ip, cpy);
- ip += length;
- op = cpy;
- }
-
- /* get offset */
- offset = LZ4_readLE16(ip);
- ip += 2;
- match = op - offset;
-
- /* get matchlength */
- length = token & ML_MASK;
-
-_copy_match:
- if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) {
- /* Error : offset outside buffers */
- goto _output_error;
- }
-
- /* costs ~1%; silence an msan warning when offset == 0 */
- /*
- * note : when partialDecoding, there is no guarantee that
- * at least 4 bytes remain available in output buffer
- */
- if (!partialDecoding) {
- assert(oend > op);
- assert(oend - op >= 4);
-
- LZ4_write32(op, (U32)offset);
- }
-
- if (length == ML_MASK) {
- unsigned int s;
-
- do {
- s = *ip++;
-
- if ((endOnInput) && (ip > iend - LASTLITERALS))
- goto _output_error;
-
- length += s;
- } while (s == 255);
-
- if ((safeDecode)
- && unlikely(
- (uptrval)(op) + length < (uptrval)op)) {
- /* overflow detection */
- goto _output_error;
- }
- }
-
- length += MINMATCH;
-
- /* match starting within external dictionary */
- if ((dict == usingExtDict) && (match < lowPrefix)) {
- if (unlikely(op + length > oend - LASTLITERALS)) {
- /* doesn't respect parsing restriction */
- if (!partialDecoding)
- goto _output_error;
- length = min(length, (size_t)(oend - op));
- }
-
- if (length <= (size_t)(lowPrefix - match)) {
- /*
- * match fits entirely within external
- * dictionary : just copy
- */
- memmove(op, dictEnd - (lowPrefix - match),
- length);
- op += length;
- } else {
- /*
- * match stretches into both external
- * dictionary and current block
- */
- size_t const copySize = (size_t)(lowPrefix - match);
- size_t const restSize = length - copySize;
+static_assert(sizeof(LZ4_streamDecode_t) == LZ4_STREAMDECODE_MINSIZE);
+static_assert(LZ4_STREAMDECODE_MINSIZE == 32); /* LZ4_MEM_DECOMPRESS */
- LZ4_memcpy(op, dictEnd - copySize, copySize);
- op += copySize;
- if (restSize > (size_t)(op - lowPrefix)) {
- /* overlap copy */
- BYTE * const endOfMatch = op + restSize;
- const BYTE *copyFrom = lowPrefix;
-
- while (op < endOfMatch)
- *op++ = *copyFrom++;
- } else {
- LZ4_memcpy(op, lowPrefix, restSize);
- op += restSize;
- }
- }
- continue;
- }
-
- /* copy match within block */
- cpy = op + length;
-
- /*
- * partialDecoding :
- * may not respect endBlock parsing restrictions
- */
- assert(op <= oend);
- if (partialDecoding &&
- (cpy > oend - MATCH_SAFEGUARD_DISTANCE)) {
- size_t const mlen = min(length, (size_t)(oend - op));
- const BYTE * const matchEnd = match + mlen;
- BYTE * const copyEnd = op + mlen;
-
- if (matchEnd > op) {
- /* overlap copy */
- while (op < copyEnd)
- *op++ = *match++;
- } else {
- LZ4_memcpy(op, match, mlen);
- }
- op = copyEnd;
- if (op == oend)
- break;
- continue;
- }
-
- if (unlikely(offset < 8)) {
- op[0] = match[0];
- op[1] = match[1];
- op[2] = match[2];
- op[3] = match[3];
- match += inc32table[offset];
- LZ4_memcpy(op + 4, match, 4);
- match -= dec64table[offset];
- } else {
- LZ4_copy8(op, match);
- match += 8;
- }
-
- op += 8;
-
- if (unlikely(cpy > oend - MATCH_SAFEGUARD_DISTANCE)) {
- BYTE * const oCopyLimit = oend - (WILDCOPYLENGTH - 1);
-
- if (cpy > oend - LASTLITERALS) {
- /*
- * Error : last LASTLITERALS bytes
- * must be literals (uncompressed)
- */
- goto _output_error;
- }
-
- if (op < oCopyLimit) {
- LZ4_wildCopy(op, match, oCopyLimit);
- match += oCopyLimit - op;
- op = oCopyLimit;
- }
- while (op < cpy)
- *op++ = *match++;
- } else {
- LZ4_copy8(op, match);
- if (length > 16)
- LZ4_wildCopy(op + 8, match + 8, cpy);
- }
- op = cpy; /* wildcopy correction */
- }
-
- /* end of decoding */
- if (endOnInput) {
- /* Nb of output bytes decoded */
- return (int) (((char *)op) - dst);
- } else {
- /* Nb of input bytes read */
- return (int) (((const char *)ip) - src);
- }
-
- /* Overflow error detected */
-_output_error:
- return (int) (-(((const char *)ip) - src)) - 1;
-}
-
-int LZ4_decompress_safe(const char *source, char *dest,
- int compressedSize, int maxDecompressedSize)
+int LZ4_decompress_safe(const char *source, char *dest, int compressedSize,
+ int maxDecompressedSize)
{
- return LZ4_decompress_generic(source, dest,
- compressedSize, maxDecompressedSize,
- endOnInputSize, decode_full_block,
- noDict, (BYTE *)dest, NULL, 0);
+ return __lz4_decompress_safe(source, dest, compressedSize,
+ maxDecompressedSize);
}
-int LZ4_decompress_safe_partial(const char *src, char *dst,
- int compressedSize, int targetOutputSize, int dstCapacity)
+int LZ4_decompress_safe_partial(const char *source, char *dest,
+ int compressedSize, int targetOutputSize,
+ int maxDecompressedSize)
{
- dstCapacity = min(targetOutputSize, dstCapacity);
- return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,
- endOnInputSize, partial_decode,
- noDict, (BYTE *)dst, NULL, 0);
+ return __lz4_decompress_safe_partial(source, dest, compressedSize,
+ targetOutputSize,
+ maxDecompressedSize);
}
int LZ4_decompress_fast(const char *source, char *dest, int originalSize)
{
- return LZ4_decompress_generic(source, dest, 0, originalSize,
- endOnOutputSize, decode_full_block,
- withPrefix64k,
- (BYTE *)dest - 64 * KB, NULL, 0);
-}
-
-/* ===== Instantiate a few more decoding cases, used more than once. ===== */
-
-static int LZ4_decompress_safe_withPrefix64k(const char *source, char *dest,
- int compressedSize, int maxOutputSize)
-{
- return LZ4_decompress_generic(source, dest,
- compressedSize, maxOutputSize,
- endOnInputSize, decode_full_block,
- withPrefix64k,
- (BYTE *)dest - 64 * KB, NULL, 0);
+ return __lz4_decompress_fast(source, dest, originalSize);
}
-static int LZ4_decompress_safe_withSmallPrefix(const char *source, char *dest,
- int compressedSize,
- int maxOutputSize,
- size_t prefixSize)
-{
- return LZ4_decompress_generic(source, dest,
- compressedSize, maxOutputSize,
- endOnInputSize, decode_full_block,
- noDict,
- (BYTE *)dest - prefixSize, NULL, 0);
-}
-
-static int LZ4_decompress_safe_forceExtDict(const char *source, char *dest,
- int compressedSize, int maxOutputSize,
- const void *dictStart, size_t dictSize)
-{
- return LZ4_decompress_generic(source, dest,
- compressedSize, maxOutputSize,
- endOnInputSize, decode_full_block,
- usingExtDict, (BYTE *)dest,
- (const BYTE *)dictStart, dictSize);
-}
-
-static int LZ4_decompress_fast_extDict(const char *source, char *dest,
- int originalSize,
- const void *dictStart, size_t dictSize)
-{
- return LZ4_decompress_generic(source, dest,
- 0, originalSize,
- endOnOutputSize, decode_full_block,
- usingExtDict, (BYTE *)dest,
- (const BYTE *)dictStart, dictSize);
-}
-
-/*
- * The "double dictionary" mode, for use with e.g. ring buffers: the first part
- * of the dictionary is passed as prefix, and the second via dictStart + dictSize.
- * These routines are used only once, in LZ4_decompress_*_continue().
- */
-static FORCE_INLINE
-int LZ4_decompress_safe_doubleDict(const char *source, char *dest,
- int compressedSize, int maxOutputSize,
- size_t prefixSize,
- const void *dictStart, size_t dictSize)
-{
- return LZ4_decompress_generic(source, dest,
- compressedSize, maxOutputSize,
- endOnInputSize, decode_full_block,
- usingExtDict, (BYTE *)dest - prefixSize,
- (const BYTE *)dictStart, dictSize);
-}
-
-static FORCE_INLINE
-int LZ4_decompress_fast_doubleDict(const char *source, char *dest,
- int originalSize, size_t prefixSize,
- const void *dictStart, size_t dictSize)
-{
- return LZ4_decompress_generic(source, dest,
- 0, originalSize,
- endOnOutputSize, decode_full_block,
- usingExtDict, (BYTE *)dest - prefixSize,
- (const BYTE *)dictStart, dictSize);
-}
-
-/* ===== streaming decompression functions ===== */
-
int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode,
- const char *dictionary, int dictSize)
+ const char *dictionary, int dictSize)
{
- LZ4_streamDecode_t_internal *lz4sd =
- &LZ4_streamDecode->internal_donotuse;
-
- lz4sd->prefixSize = (size_t) dictSize;
- lz4sd->prefixEnd = (const BYTE *) dictionary + dictSize;
- lz4sd->externalDict = NULL;
- lz4sd->extDictSize = 0;
- return 1;
+ return __lz4_setStreamDecode(LZ4_streamDecode, dictionary, dictSize);
}
-/*
- * *_continue() :
- * These decoding functions allow decompression of multiple blocks
- * in "streaming" mode.
- * Previously decoded blocks must still be available at the memory
- * position where they were decoded.
- * If it's not possible, save the relevant part of
- * decoded data into a safe buffer,
- * and indicate where it stands using LZ4_setStreamDecode()
- */
int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode,
- const char *source, char *dest, int compressedSize, int maxOutputSize)
+ const char *source, char *dest,
+ int compressedSize, int maxDecompressedSize)
{
- LZ4_streamDecode_t_internal *lz4sd =
- &LZ4_streamDecode->internal_donotuse;
- int result;
-
- if (lz4sd->prefixSize == 0) {
- /* The first call, no dictionary yet. */
- assert(lz4sd->extDictSize == 0);
- result = LZ4_decompress_safe(source, dest,
- compressedSize, maxOutputSize);
- if (result <= 0)
- return result;
- lz4sd->prefixSize = result;
- lz4sd->prefixEnd = (BYTE *)dest + result;
- } else if (lz4sd->prefixEnd == (BYTE *)dest) {
- /* They're rolling the current segment. */
- if (lz4sd->prefixSize >= 64 * KB - 1)
- result = LZ4_decompress_safe_withPrefix64k(source, dest,
- compressedSize, maxOutputSize);
- else if (lz4sd->extDictSize == 0)
- result = LZ4_decompress_safe_withSmallPrefix(source,
- dest, compressedSize, maxOutputSize,
- lz4sd->prefixSize);
- else
- result = LZ4_decompress_safe_doubleDict(source, dest,
- compressedSize, maxOutputSize,
- lz4sd->prefixSize,
- lz4sd->externalDict, lz4sd->extDictSize);
- if (result <= 0)
- return result;
- lz4sd->prefixSize += result;
- lz4sd->prefixEnd += result;
- } else {
- /*
- * The buffer wraps around, or they're
- * switching to another buffer.
- */
- lz4sd->extDictSize = lz4sd->prefixSize;
- lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
- result = LZ4_decompress_safe_forceExtDict(source, dest,
- compressedSize, maxOutputSize,
- lz4sd->externalDict, lz4sd->extDictSize);
- if (result <= 0)
- return result;
- lz4sd->prefixSize = result;
- lz4sd->prefixEnd = (BYTE *)dest + result;
- }
-
- return result;
+ return __lz4_decompress_safe_continue(LZ4_streamDecode, source, dest,
+ compressedSize,
+ maxDecompressedSize);
}
int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode,
- const char *source, char *dest, int originalSize)
+ const char *source, char *dest,
+ int originalSize)
{
- LZ4_streamDecode_t_internal *lz4sd = &LZ4_streamDecode->internal_donotuse;
- int result;
-
- if (lz4sd->prefixSize == 0) {
- assert(lz4sd->extDictSize == 0);
- result = LZ4_decompress_fast(source, dest, originalSize);
- if (result <= 0)
- return result;
- lz4sd->prefixSize = originalSize;
- lz4sd->prefixEnd = (BYTE *)dest + originalSize;
- } else if (lz4sd->prefixEnd == (BYTE *)dest) {
- if (lz4sd->prefixSize >= 64 * KB - 1 ||
- lz4sd->extDictSize == 0)
- result = LZ4_decompress_fast(source, dest,
- originalSize);
- else
- result = LZ4_decompress_fast_doubleDict(source, dest,
- originalSize, lz4sd->prefixSize,
- lz4sd->externalDict, lz4sd->extDictSize);
- if (result <= 0)
- return result;
- lz4sd->prefixSize += originalSize;
- lz4sd->prefixEnd += originalSize;
- } else {
- lz4sd->extDictSize = lz4sd->prefixSize;
- lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
- result = LZ4_decompress_fast_extDict(source, dest,
- originalSize, lz4sd->externalDict, lz4sd->extDictSize);
- if (result <= 0)
- return result;
- lz4sd->prefixSize = originalSize;
- lz4sd->prefixEnd = (BYTE *)dest + originalSize;
- }
- return result;
+ return __lz4_decompress_fast_continue(LZ4_streamDecode, source, dest,
+ originalSize);
}
int LZ4_decompress_safe_usingDict(const char *source, char *dest,
- int compressedSize, int maxOutputSize,
+ int compressedSize, int maxDecompressedSize,
const char *dictStart, int dictSize)
{
- if (dictSize == 0)
- return LZ4_decompress_safe(source, dest,
- compressedSize, maxOutputSize);
- if (dictStart+dictSize == dest) {
- if (dictSize >= 64 * KB - 1)
- return LZ4_decompress_safe_withPrefix64k(source, dest,
- compressedSize, maxOutputSize);
- return LZ4_decompress_safe_withSmallPrefix(source, dest,
- compressedSize, maxOutputSize, dictSize);
- }
- return LZ4_decompress_safe_forceExtDict(source, dest,
- compressedSize, maxOutputSize, dictStart, dictSize);
+ return __lz4_decompress_safe_usingDict(source, dest, compressedSize,
+ maxDecompressedSize, dictStart,
+ dictSize);
}
int LZ4_decompress_fast_usingDict(const char *source, char *dest,
- int originalSize,
- const char *dictStart, int dictSize)
+ int originalSize, const char *dictStart,
+ int dictSize)
{
- if (dictSize == 0 || dictStart + dictSize == dest)
- return LZ4_decompress_fast(source, dest, originalSize);
-
- return LZ4_decompress_fast_extDict(source, dest, originalSize,
- dictStart, dictSize);
+ return __lz4_decompress_fast_usingDict(source, dest, originalSize,
+ dictStart, dictSize);
}
#ifndef STATIC
diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h
deleted file mode 100644
index 17277ec16919f3a554afc7d91ad515c493d745ca..0000000000000000000000000000000000000000
--- a/lib/lz4/lz4defs.h
+++ /dev/null
@@ -1,247 +0,0 @@
-#ifndef __LZ4DEFS_H__
-#define __LZ4DEFS_H__
-
-/*
- * lz4defs.h -- common and architecture specific defines for the kernel usage
-
- * LZ4 - Fast LZ compression algorithm
- * Copyright (C) 2011-2016, Yann Collet.
- * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * You can contact the author at :
- * - LZ4 homepage : http://www.lz4.org
- * - LZ4 source repository : https://github.com/lz4/lz4
- *
- * Changed for kernel usage by:
- * Sven Schmidt <4sschmid@informatik.uni-hamburg.de>
- */
-
-#include <linux/unaligned.h>
-
-#include <linux/bitops.h>
-#include <linux/string.h> /* memset, memcpy */
-#include <linux/lz4.h>
-
-#define FORCE_INLINE __always_inline
-
-/*-************************************
- * Basic Types
- **************************************/
-#include <linux/types.h>
-
-typedef uint8_t BYTE;
-typedef uint16_t U16;
-typedef uint32_t U32;
-typedef int32_t S32;
-typedef uint64_t U64;
-typedef uintptr_t uptrval;
-
-/*-************************************
- * Architecture specifics
- **************************************/
-#if defined(CONFIG_64BIT)
-#define LZ4_ARCH64 1
-#else
-#define LZ4_ARCH64 0
-#endif
-
-#if defined(__LITTLE_ENDIAN)
-#define LZ4_LITTLE_ENDIAN 1
-#else
-#define LZ4_LITTLE_ENDIAN 0
-#endif
-
-/*-************************************
- * Constants
- **************************************/
-#define MINMATCH 4
-
-#define WILDCOPYLENGTH 8
-#define LASTLITERALS 5
-#define MFLIMIT (WILDCOPYLENGTH + MINMATCH)
-/*
- * ensure it's possible to write 2 x wildcopyLength
- * without overflowing output buffer
- */
-#define MATCH_SAFEGUARD_DISTANCE ((2 * WILDCOPYLENGTH) - MINMATCH)
-
-/* Increase this value ==> compression run slower on incompressible data */
-#define LZ4_SKIPTRIGGER 6
-
-#define HASH_UNIT sizeof(size_t)
-
-#define KB (1 << 10)
-#define MB (1 << 20)
-#define GB (1U << 30)
-
-#define MAX_DISTANCE LZ4_DISTANCE_MAX
-#define STEPSIZE sizeof(size_t)
-
-#define ML_BITS 4
-#define ML_MASK ((1U << ML_BITS) - 1)
-#define RUN_BITS (8 - ML_BITS)
-#define RUN_MASK ((1U << RUN_BITS) - 1)
-
-/*-************************************
- * Reading and writing into memory
- **************************************/
-static FORCE_INLINE U16 LZ4_read16(const void *ptr)
-{
- return get_unaligned((const U16 *)ptr);
-}
-
-static FORCE_INLINE U32 LZ4_read32(const void *ptr)
-{
- return get_unaligned((const U32 *)ptr);
-}
-
-static FORCE_INLINE size_t LZ4_read_ARCH(const void *ptr)
-{
- return get_unaligned((const size_t *)ptr);
-}
-
-static FORCE_INLINE void LZ4_write16(void *memPtr, U16 value)
-{
- put_unaligned(value, (U16 *)memPtr);
-}
-
-static FORCE_INLINE void LZ4_write32(void *memPtr, U32 value)
-{
- put_unaligned(value, (U32 *)memPtr);
-}
-
-static FORCE_INLINE U16 LZ4_readLE16(const void *memPtr)
-{
- return get_unaligned_le16(memPtr);
-}
-
-static FORCE_INLINE void LZ4_writeLE16(void *memPtr, U16 value)
-{
- return put_unaligned_le16(value, memPtr);
-}
-
-/*
- * LZ4 relies on memcpy with a constant size being inlined. In freestanding
- * environments, the compiler can't assume the implementation of memcpy() is
- * standard compliant, so apply its specialized memcpy() inlining logic. When
- * possible, use __builtin_memcpy() to tell the compiler to analyze memcpy()
- * as-if it were standard compliant, so it can inline it in freestanding
- * environments. This is needed when decompressing the Linux Kernel, for example.
- */
-#define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size)
-#define LZ4_memmove(dst, src, size) __builtin_memmove(dst, src, size)
-
-static FORCE_INLINE void LZ4_copy8(void *dst, const void *src)
-{
-#if LZ4_ARCH64
- U64 a = get_unaligned((const U64 *)src);
-
- put_unaligned(a, (U64 *)dst);
-#else
- U32 a = get_unaligned((const U32 *)src);
- U32 b = get_unaligned((const U32 *)src + 1);
-
- put_unaligned(a, (U32 *)dst);
- put_unaligned(b, (U32 *)dst + 1);
-#endif
-}
-
-/*
- * customized variant of memcpy,
- * which can overwrite up to 7 bytes beyond dstEnd
- */
-static FORCE_INLINE void LZ4_wildCopy(void *dstPtr,
- const void *srcPtr, void *dstEnd)
-{
- BYTE *d = (BYTE *)dstPtr;
- const BYTE *s = (const BYTE *)srcPtr;
- BYTE *const e = (BYTE *)dstEnd;
-
- do {
- LZ4_copy8(d, s);
- d += 8;
- s += 8;
- } while (d < e);
-}
-
-static FORCE_INLINE unsigned int LZ4_NbCommonBytes(register size_t val)
-{
-#if LZ4_LITTLE_ENDIAN
- return __ffs(val) >> 3;
-#else
- return (BITS_PER_LONG - 1 - __fls(val)) >> 3;
-#endif
-}
-
-static FORCE_INLINE unsigned int LZ4_count(
- const BYTE *pIn,
- const BYTE *pMatch,
- const BYTE *pInLimit)
-{
- const BYTE *const pStart = pIn;
-
- while (likely(pIn < pInLimit - (STEPSIZE - 1))) {
- size_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
-
- if (!diff) {
- pIn += STEPSIZE;
- pMatch += STEPSIZE;
- continue;
- }
-
- pIn += LZ4_NbCommonBytes(diff);
-
- return (unsigned int)(pIn - pStart);
- }
-
-#if LZ4_ARCH64
- if ((pIn < (pInLimit - 3))
- && (LZ4_read32(pMatch) == LZ4_read32(pIn))) {
- pIn += 4;
- pMatch += 4;
- }
-#endif
-
- if ((pIn < (pInLimit - 1))
- && (LZ4_read16(pMatch) == LZ4_read16(pIn))) {
- pIn += 2;
- pMatch += 2;
- }
-
- if ((pIn < pInLimit) && (*pMatch == *pIn))
- pIn++;
-
- return (unsigned int)(pIn - pStart);
-}
-
-typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive;
-typedef enum { byPtr, byU32, byU16 } tableType_t;
-
-typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
-typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
-
-typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
-typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;
-
-#define LZ4_STATIC_ASSERT(c) BUILD_BUG_ON(!(c))
-
-#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH RFC 7/9] lib/lz4: switch the decompressor to the vendored sources
2026-09-25 11:27 ` [PATCH RFC 7/9] lib/lz4: switch the decompressor " Michal Wilczynski
@ 2026-09-28 4:16 ` Sergey Senozhatsky
2026-10-03 23:38 ` Michal Wilczynski
0 siblings, 1 reply; 25+ messages in thread
From: Sergey Senozhatsky @ 2026-09-28 4:16 UTC (permalink / raw)
To: Michal Wilczynski
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Sergey Senozhatsky, Jens Axboe, Andrew Morton,
linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
On (26/09/25 13:27), Michal Wilczynski wrote:
[..]
> -static FORCE_INLINE int LZ4_decompress_generic(
[..]
> - /* Necessarily EOF when !partialDecoding.
> - * When partialDecoding, it is EOF if we've either
> - * filled the output buffer or
> - * can't proceed with reading an offset for following match.
> - */
> - if (!partialDecoding || (cpy == oend) || (ip >= (iend - 2)))
> - break;
Worth noting, these lines are downstream commit eafc0a02391b
(lz4: fix LZ4_decompress_safe_partial read out of bound).
Is this intended or are we "loosing" some of the downstream fixes?
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH RFC 7/9] lib/lz4: switch the decompressor to the vendored sources
2026-09-28 4:16 ` Sergey Senozhatsky
@ 2026-10-03 23:38 ` Michal Wilczynski
0 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-10-03 23:38 UTC (permalink / raw)
To: Sergey Senozhatsky
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Jens Axboe, Andrew Morton, linux-kernel, llvm,
linux-arm-kernel, linux-mips, linux-parisc, linux-s390,
linux-block, Yann Collet, Nick Terrell, Gao Xiang, Chao Yu,
Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk, Jaehoon Chung,
Marek Szyprowski, linux-erofs, linux-f2fs-devel, linux-crypto
On 9/28/26 06:16, Sergey Senozhatsky wrote:
> On (26/09/25 13:27), Michal Wilczynski wrote:
> [..]
>> -static FORCE_INLINE int LZ4_decompress_generic(
> [..]
>> - /* Necessarily EOF when !partialDecoding.
>> - * When partialDecoding, it is EOF if we've either
>> - * filled the output buffer or
>> - * can't proceed with reading an offset for following match.
>> - */
>> - if (!partialDecoding || (cpy == oend) || (ip >= (iend - 2)))
>> - break;
>
> Worth noting, these lines are downstream commit eafc0a02391b
> (lz4: fix LZ4_decompress_safe_partial read out of bound).
>
> Is this intended or are we "loosing" some of the downstream fixes?
>
Yeah it's intended, eafc0a02391b was itself a backport of upstream
c5d6f8a8be39 which is in v1.9.3 and later; its own commit message links
it. The same check is at lib/lz4/upstream/lz4.c in this series.
And upstream's version also clamps a literal run that would read past
the end of the input, which the backport didn't take.
Best regards,
--
Michal Wilczynski <m.wilczynski@samsung.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH RFC 8/9] lib/lz4: fold lz4_kernel_api.h into <linux/lz4.h>
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (5 preceding siblings ...)
2026-09-25 11:27 ` [PATCH RFC 7/9] lib/lz4: switch the decompressor " Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-25 11:27 ` [PATCH RFC 9/9] MAINTAINERS: add an entry for the LZ4 compression library Michal Wilczynski
` (3 subsequent siblings)
10 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
lz4_kernel_api.h carried its own copy of the twenty public prototypes
because it could not include <linux/lz4.h>, which defined the stream
types that upstream's headers also define.
The types are incomplete now, so it can. Two prototype lists for one
ABI is a drift hazard: the entry points were built against one and their
callers against the other, so no compiler ever saw both, and MODVERSIONS
would not catch a mismatch either, since it hashes the exporter's view
only. Now there is one list.
It also puts the public constants in scope of the entry points, so the
size assertions can name them, and the HC level clamp can use
LZ4HC_CLAMP_CLEVEL, static_asserted equal to upstream's
LZ4HC_CLEVEL_OPT_MIN.
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
lib/lz4/lz4_compress.c | 2 +-
lib/lz4/lz4_decompress.c | 2 +-
lib/lz4/lz4_kernel_api.h | 71 +++---------------------------------------------
lib/lz4/lz4hc_compress.c | 8 ++++--
4 files changed, 11 insertions(+), 72 deletions(-)
diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c
index 19b877fc96d1dde6fd5ff832f79beca42d5b783b..40ebbc850f42f60ca2ddbcacd3b804cfde9e8d4e 100644
--- a/lib/lz4/lz4_compress.c
+++ b/lib/lz4/lz4_compress.c
@@ -29,7 +29,7 @@
/* Catch any divergence from upstream's layout at build time. */
static_assert(sizeof(LZ4_stream_t) == LZ4_STREAM_MINSIZE);
-static_assert(LZ4_STREAM_MINSIZE == 16416); /* LZ4_MEM_COMPRESS */
+static_assert(LZ4_STREAM_MINSIZE == LZ4_MEM_COMPRESS);
int LZ4_compress_fast(const char *source, char *dest, int inputSize,
int maxOutputSize, int acceleration, void *wrkmem)
diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c
index 68c8a87476df58fff48b1ffbeee8f2d3bbf743df..49e6f76af975435c10c387c09bb639525a89b5f9 100644
--- a/lib/lz4/lz4_decompress.c
+++ b/lib/lz4/lz4_decompress.c
@@ -31,7 +31,7 @@
#endif
static_assert(sizeof(LZ4_streamDecode_t) == LZ4_STREAMDECODE_MINSIZE);
-static_assert(LZ4_STREAMDECODE_MINSIZE == 32); /* LZ4_MEM_DECOMPRESS */
+static_assert(LZ4_STREAMDECODE_MINSIZE == LZ4_MEM_DECOMPRESS);
int LZ4_decompress_safe(const char *source, char *dest, int compressedSize,
int maxDecompressedSize)
diff --git a/lib/lz4/lz4_kernel_api.h b/lib/lz4/lz4_kernel_api.h
index 795434a64d2cb744c8ac8027d9ed59485ef6e7f3..9d21add27deb207ddba4d90fb36fb6cb62205ef9 100644
--- a/lib/lz4/lz4_kernel_api.h
+++ b/lib/lz4/lz4_kernel_api.h
@@ -3,19 +3,10 @@
* Copyright (c) 2026 Samsung Electronics Co., Ltd.
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
*
- * lz4_kernel_api.h -- the LZ4 API this directory exports
+ * lz4_kernel_api.h -- hand the LZ4 names back to the kernel
*
- * lz4_deps.h renames upstream's entry points to __lz4_* so that the kernel's
- * own definitions can use the real names; this header undoes that renaming
- * and declares what lib/lz4 exports.
- *
- * The same functions are declared to callers in <linux/lz4.h>, in terms of
- * opaque stream types. We cannot include that header here -- it and
- * upstream's lz4.h describe the same library and collide -- so the
- * declarations are repeated, expressed in upstream's own types. Keep the two
- * in step; <linux/lz4.h> is the one callers compile against.
- *
- * Include after upstream/lz4.c or upstream/lz4hc.c.
+ * Undo lz4_deps.h's renaming and pull in <linux/lz4.h>. Include after
+ * upstream/lz4.c or upstream/lz4hc.c.
*/
#undef LZ4_compress_fast
@@ -41,58 +32,4 @@
#undef LZ4_compress_HC_continue
#undef LZ4_saveDictHC
-/*
- * The objects that do not build lz4hc.c never see this type, and it is only
- * ever used through a pointer here. Upstream declares it the same way.
- */
-typedef union LZ4_streamHC_u LZ4_streamHC_t;
-
-/* Compression. wrkmem is LZ4_MEM_COMPRESS bytes, supplied by the caller. */
-int LZ4_compress_default(const char *source, char *dest, int inputSize,
- int maxOutputSize, void *wrkmem);
-int LZ4_compress_fast(const char *source, char *dest, int inputSize,
- int maxOutputSize, int acceleration, void *wrkmem);
-int LZ4_compress_destSize(const char *source, char *dest, int *sourceSizePtr,
- int targetDestSize, void *wrkmem);
-
-/* Streaming compression. */
-void LZ4_resetStream(LZ4_stream_t *LZ4_stream);
-int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary,
- int dictSize);
-int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int dictSize);
-int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src,
- char *dst, int srcSize, int maxDstSize,
- int acceleration);
-
-/* Decompression. */
-int LZ4_decompress_safe(const char *source, char *dest, int compressedSize,
- int maxDecompressedSize);
-int LZ4_decompress_safe_partial(const char *source, char *dest,
- int compressedSize, int targetOutputSize,
- int maxDecompressedSize);
-int LZ4_decompress_fast(const char *source, char *dest, int originalSize);
-int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode,
- const char *dictionary, int dictSize);
-int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode,
- const char *source, char *dest,
- int compressedSize, int maxDecompressedSize);
-int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode,
- const char *source, char *dest,
- int originalSize);
-int LZ4_decompress_safe_usingDict(const char *source, char *dest,
- int compressedSize, int maxDecompressedSize,
- const char *dictStart, int dictSize);
-int LZ4_decompress_fast_usingDict(const char *source, char *dest,
- int originalSize, const char *dictStart,
- int dictSize);
-
-/* HC compression. wrkmem is LZ4HC_MEM_COMPRESS bytes. */
-int LZ4_compress_HC(const char *src, char *dst, int srcSize, int dstCapacity,
- int compressionLevel, void *wrkmem);
-void LZ4_resetStreamHC(LZ4_streamHC_t *streamHCPtr, int compressionLevel);
-int LZ4_loadDictHC(LZ4_streamHC_t *streamHCPtr, const char *dictionary,
- int dictSize);
-int LZ4_compress_HC_continue(LZ4_streamHC_t *streamHCPtr, const char *src,
- char *dst, int srcSize, int maxDstSize);
-int LZ4_saveDictHC(LZ4_streamHC_t *streamHCPtr, char *safeBuffer,
- int maxDictSize);
+#include <linux/lz4.h>
diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c
index 6070719bab54e90a8a163c08842a5531d7b2b4ac..ad49a3509aaac25850c045347d588b9354a8ce18 100644
--- a/lib/lz4/lz4hc_compress.c
+++ b/lib/lz4/lz4hc_compress.c
@@ -38,7 +38,7 @@ static int LZ4_compressBound(int isize)
/* Catch any divergence from upstream's layout at build time. */
static_assert(sizeof(LZ4_streamHC_t) == LZ4_STREAMHC_MINSIZE);
-static_assert(LZ4_STREAMHC_MINSIZE == 262200); /* LZ4HC_MEM_COMPRESS */
+static_assert(LZ4_STREAMHC_MINSIZE == LZ4HC_MEM_COMPRESS);
/* Levels >= LZ4HC_CLEVEL_OPT_MIN (10) reach the optimal parser, whose ~64K
* opt[] does not fit a kernel stack, so clamp them to 9. Clamp rather than
@@ -46,10 +46,12 @@ static_assert(LZ4_STREAMHC_MINSIZE == 262200); /* LZ4HC_MEM_COMPRESS */
* untouched; 1 and 2 are upstream's lz4mid, faster and weaker than the
* shallow hash chain the fork used for them.
*/
+static_assert(LZ4HC_CLAMP_CLEVEL == LZ4HC_CLEVEL_OPT_MIN);
+
static int lz4hc_clamp_level(int compressionLevel)
{
- if (compressionLevel >= LZ4HC_CLEVEL_OPT_MIN)
- return LZ4HC_CLEVEL_OPT_MIN - 1;
+ if (compressionLevel >= LZ4HC_CLAMP_CLEVEL)
+ return LZ4HC_CLAMP_CLEVEL - 1;
return compressionLevel;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH RFC 9/9] MAINTAINERS: add an entry for the LZ4 compression library
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (6 preceding siblings ...)
2026-09-25 11:27 ` [PATCH RFC 8/9] lib/lz4: fold lz4_kernel_api.h into <linux/lz4.h> Michal Wilczynski
@ 2026-09-25 11:27 ` Michal Wilczynski
2026-09-25 21:39 ` Eric Biggers
2026-09-25 22:07 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Eric Biggers
` (2 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Michal Wilczynski @ 2026-09-25 11:27 UTC (permalink / raw)
To: Michal Wilczynski, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Russell King, Thomas Bogendoerfer,
James E.J. Bottomley, Helge Deller, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Minchan Kim, Sergey Senozhatsky, Jens Axboe,
Andrew Morton
Cc: linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
lib/lz4/ has never had one: get_maintainer.pl returns only the LKML
fallback for every file in it, including include/linux/lz4.h, which eight
subsystems build against.
This matters more now than it did. With the previous patches lib/lz4 is
vendored upstream sources, and someone has to bump them to new upstream
releases and decide what the kernel-side glue may do. I am willing to do
that, so add myself as its maintainer.
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index cc3cae2e378b34aeb705cef654c720ca9f2ba223..989e1b5fab21432dd7042d1e60c4bbad85beb925 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15606,6 +15606,12 @@ S: Supported
F: drivers/net/pcs/pcs-lynx.c
F: include/linux/pcs-lynx.h
+LZ4 COMPRESSION LIBRARY
+M: Michal Wilczynski <m.wilczynski@samsung.com>
+S: Maintained
+F: include/linux/lz4.h
+F: lib/lz4/
+
M68K ARCHITECTURE
M: Geert Uytterhoeven <geert@linux-m68k.org>
L: linux-m68k@lists.linux-m68k.org
--
2.34.1
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH RFC 9/9] MAINTAINERS: add an entry for the LZ4 compression library
2026-09-25 11:27 ` [PATCH RFC 9/9] MAINTAINERS: add an entry for the LZ4 compression library Michal Wilczynski
@ 2026-09-25 21:39 ` Eric Biggers
2026-10-03 22:45 ` Michal Wilczynski
0 siblings, 1 reply; 25+ messages in thread
From: Eric Biggers @ 2026-09-25 21:39 UTC (permalink / raw)
To: Michal Wilczynski
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Sergey Senozhatsky, Jens Axboe, Andrew Morton,
linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
On Fri, Sep 25, 2026 at 01:27:39PM +0200, Michal Wilczynski wrote:
> lib/lz4/ has never had one: get_maintainer.pl returns only the LKML
> fallback for every file in it, including include/linux/lz4.h, which eight
> subsystems build against.
>
> This matters more now than it did. With the previous patches lib/lz4 is
> vendored upstream sources, and someone has to bump them to new upstream
> releases and decide what the kernel-side glue may do. I am willing to do
> that, so add myself as its maintainer.
>
> Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index cc3cae2e378b34aeb705cef654c720ca9f2ba223..989e1b5fab21432dd7042d1e60c4bbad85beb925 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15606,6 +15606,12 @@ S: Supported
> F: drivers/net/pcs/pcs-lynx.c
> F: include/linux/pcs-lynx.h
>
> +LZ4 COMPRESSION LIBRARY
> +M: Michal Wilczynski <m.wilczynski@samsung.com>
> +S: Maintained
> +F: include/linux/lz4.h
> +F: lib/lz4/
> +
Should this entry cover lib/decompress_unlz4.c and
include/linux/decompress/unlz4.h as well?
- Eric
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH RFC 9/9] MAINTAINERS: add an entry for the LZ4 compression library
2026-09-25 21:39 ` Eric Biggers
@ 2026-10-03 22:45 ` Michal Wilczynski
0 siblings, 0 replies; 25+ messages in thread
From: Michal Wilczynski @ 2026-10-03 22:45 UTC (permalink / raw)
To: Eric Biggers
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Sergey Senozhatsky, Jens Axboe, Andrew Morton,
linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
On 9/25/26 23:39, Eric Biggers wrote:
> On Fri, Sep 25, 2026 at 01:27:39PM +0200, Michal Wilczynski wrote:
>> lib/lz4/ has never had one: get_maintainer.pl returns only the LKML
>> fallback for every file in it, including include/linux/lz4.h, which eight
>> subsystems build against.
>>
>> This matters more now than it did. With the previous patches lib/lz4 is
>> vendored upstream sources, and someone has to bump them to new upstream
>> releases and decide what the kernel-side glue may do. I am willing to do
>> that, so add myself as its maintainer.
>>
>> Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
>> ---
>> MAINTAINERS | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index cc3cae2e378b34aeb705cef654c720ca9f2ba223..989e1b5fab21432dd7042d1e60c4bbad85beb925 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -15606,6 +15606,12 @@ S: Supported
>> F: drivers/net/pcs/pcs-lynx.c
>> F: include/linux/pcs-lynx.h
>>
>> +LZ4 COMPRESSION LIBRARY
>> +M: Michal Wilczynski <m.wilczynski@samsung.com>
>> +S: Maintained
>> +F: include/linux/lz4.h
>> +F: lib/lz4/
>> +
>
> Should this entry cover lib/decompress_unlz4.c and
> include/linux/decompress/unlz4.h as well?
Yes I'll add both in v2.
Thanks a lot for looking at the series as a whole.
>
> - Eric
>
Best regards,
--
Michal Wilczynski <m.wilczynski@samsung.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (7 preceding siblings ...)
2026-09-25 11:27 ` [PATCH RFC 9/9] MAINTAINERS: add an entry for the LZ4 compression library Michal Wilczynski
@ 2026-09-25 22:07 ` Eric Biggers
[not found] ` <CGME20260925113452eucas1p170bfdb34dfbf670a14a6f8f0c2f5094a@eucas1p1.samsung.com>
2026-09-28 4:25 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Sergey Senozhatsky
10 siblings, 0 replies; 25+ messages in thread
From: Eric Biggers @ 2026-09-25 22:07 UTC (permalink / raw)
To: Michal Wilczynski
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Sergey Senozhatsky, Jens Axboe, Andrew Morton,
linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
On Fri, Sep 25, 2026 at 01:27:30PM +0200, Michal Wilczynski wrote:
> The in-kernel LZ4 is a fork. The decompressor was last synced with
> upstream v1.8.3 in 2018 and the compressor with v1.7.3 in 2017, both by
> hand. Upstream has made 488 commits against lib/ since, and the gap is
> maintained one cherry-pick at a time.
>
> That has left real bugs in place for example the forked
> LZ4_decompress_fast() has no bounds checks, so corrupted input runs off
> the output buffer in both directions.
>
> This series vendors the upstream sources unmodified and adapts them at
> build time, so a re-sync becomes a directory copy:
At a high level, this looks good to me, and it's similar to what was
done with zstd. I don't see any obvious issues with the integration.
There are disadvantages to directly integrating external projects like
this, vs. writing a small implementation from scratch for the kernel.
But the existing LZ4 code in the kernel isn't that, but rather a fork
from upstream anyway, and it's clearly not being maintained properly.
The upstream LZ4 codebase also already avoids many of the typical
incompatibilities with Linux kernel code that are often seen in
userspace projects (such as assuming FPU/SIMD/vector instructions can be
used at any time, or that the stack size is infinite, or that the C
standard library is available, or that it's reasonable to have hundreds
of files or 100MB of test data, etc.).
And writing properly optimized compression/decompression code is quite
difficult. So yes, syncing with the latest LZ4 upstream seems like the
right choice for the kernel.
- Eric
^ permalink raw reply [flat|nested] 25+ messages in thread[parent not found: <CGME20260925113452eucas1p170bfdb34dfbf670a14a6f8f0c2f5094a@eucas1p1.samsung.com>]
* Re: [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead
2026-09-25 11:27 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Michal Wilczynski
` (9 preceding siblings ...)
[not found] ` <CGME20260925113452eucas1p170bfdb34dfbf670a14a6f8f0c2f5094a@eucas1p1.samsung.com>
@ 2026-09-28 4:25 ` Sergey Senozhatsky
2026-09-28 8:27 ` Sergey Senozhatsky
10 siblings, 1 reply; 25+ messages in thread
From: Sergey Senozhatsky @ 2026-09-28 4:25 UTC (permalink / raw)
To: Michal Wilczynski
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Sergey Senozhatsky, Jens Axboe, Andrew Morton,
linux-kernel, llvm, linux-arm-kernel, linux-mips, linux-parisc,
linux-s390, linux-block, Yann Collet, Nick Terrell, Gao Xiang,
Chao Yu, Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk,
Jaehoon Chung, Marek Szyprowski, linux-erofs, linux-f2fs-devel,
linux-crypto
On (26/09/25 13:27), Michal Wilczynski wrote:
[..]
> Michal Wilczynski (9):
> lib/lz4: import upstream LZ4 sources verbatim
> lib/lz4: backport upstream's -Wmissing-prototypes fix
> lib/lz4: add the build environment for the vendored sources
> arch: boot: put the LZ4 freestanding headers on the decompressor path
> lib/lz4: switch the compressor to the vendored sources
> lib/lz4: switch the HC compressor to the vendored sources
> lib/lz4: switch the decompressor to the vendored sources
> lib/lz4: fold lz4_kernel_api.h into <linux/lz4.h>
> MAINTAINERS: add an entry for the LZ4 compression library
On my x86_64 build .text size change seems to be quite significant:
./scripts/bloat-o-meter lib/lz4/lz4_compress-old.ko lib/lz4/lz4_compress.ko
add/remove: 0/2 grow/shrink: 5/1 up/down: 8022/-1755 (6267)
Function old new delta
LZ4_compress_fast_continue 6028 10486 +4458
LZ4_compress_destSize 158 3112 +2954
LZ4_compress_fast_extState 4078 4597 +519
LZ4_saveDict 82 153 +71
__UNIQUE_ID_modinfo_466 52 72 +20
__pfx_LZ4_compress_destSize_generic 16 - -16
LZ4_loadDict 261 204 -57
LZ4_compress_destSize_generic 1682 - -1682
Total: Before=14756, After=21023, chg +42.47%
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead
2026-09-28 4:25 ` [PATCH RFC 0/9] lib/lz4: stop forking upstream LZ4, vendor it instead Sergey Senozhatsky
@ 2026-09-28 8:27 ` Sergey Senozhatsky
0 siblings, 0 replies; 25+ messages in thread
From: Sergey Senozhatsky @ 2026-09-28 8:27 UTC (permalink / raw)
To: Michal Wilczynski
Cc: Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Russell King, Thomas Bogendoerfer, James E.J. Bottomley,
Helge Deller, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Minchan Kim, Jens Axboe, Andrew Morton, linux-kernel, llvm,
linux-arm-kernel, linux-mips, linux-parisc, linux-s390,
linux-block, Yann Collet, Nick Terrell, Gao Xiang, Chao Yu,
Jaegeuk Kim, Herbert Xu, Phillip Lougher, Sungguk, Jaehoon Chung,
Marek Szyprowski, linux-erofs, linux-f2fs-devel, linux-crypto,
Sergey Senozhatsky
On (26/09/28 13:25), Sergey Senozhatsky wrote:
> On my x86_64 build .text size change seems to be quite significant:
>
> ./scripts/bloat-o-meter lib/lz4/lz4_compress-old.ko lib/lz4/lz4_compress.ko
> add/remove: 0/2 grow/shrink: 5/1 up/down: 8022/-1755 (6267)
> Function old new delta
> LZ4_compress_fast_continue 6028 10486 +4458
> LZ4_compress_destSize 158 3112 +2954
> LZ4_compress_fast_extState 4078 4597 +519
> LZ4_saveDict 82 153 +71
> __UNIQUE_ID_modinfo_466 52 72 +20
> __pfx_LZ4_compress_destSize_generic 16 - -16
> LZ4_loadDict 261 204 -57
> LZ4_compress_destSize_generic 1682 - -1682
> Total: Before=14756, After=21023, chg +42.47%
D'oh you actually point that out in the commit message, sorry for the noise.
^ permalink raw reply [flat|nested] 25+ messages in thread