diff -urdN linux-5.4.18/Documentation/lzip.txt linux-5.4.18.new/Documentation/lzip.txt
--- linux-5.4.18/Documentation/lzip.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.4.18.new/Documentation/lzip.txt	2020-02-10 15:55:57.000000000 +0100
@@ -0,0 +1,59 @@
+==============================
+Lzip data compression in Linux
+==============================
+
+Introduction
+============
+
+Lzip is a lossless data compressor with a user interface similar to the
+one of gzip or bzip2. Lzip can compress about as fast as gzip (lzip -0)
+or compress most files more than bzip2 (lzip -9). Decompression speed is
+intermediate between gzip and bzip2. Lzip implements the LZMA algorithm.
+
+Lzip has been designed, written and tested with great care to be the
+standard general-purpose compressor for unix-like systems. The lzip
+format is as simple as possible (but not simpler). It provides accurate
+and robust 3 factor integrity checking.
+
+Learn more about lzip at http://www.nongnu.org/lzip/lzip.html
+
+Lzip related components in the kernel
+=====================================
+
+The lzip_decompress module in lib/lzip_decompress.c provides a versatile
+lzip decompression function able to do buffer to buffer decompression or
+stream decompression with fill and flush callback functions. The usage
+of the function is documented in include/linux/lzip.h.
+
+For decompressing the kernel image, initramfs, and initrd, there is a
+wrapper function in lib/decompress_lunzip.c providing the same common
+interface as the other decompress_*.c files, which is defined in
+include/linux/decompress/generic.h.
+
+For kernel makefiles, two commands are provided in scripts/Makefile.lib
+for use with $(call if_changed). The kernel image must be compressed
+with $(call if_changed,klzip) which will append a four-byte trailer
+containing the size of the uncompressed data, which is needed by the
+boot code. Other things should be compressed with $(call if_changed,lzip).
+
+Testing
+=======
+
+Lzip-compressed kernel images of multiple linux versions since 2.6.30.10
+have been built and tested, even on machines as modest as an AMD 486-DX2
+at 66 MHz with 64 MiB of RAM. In the worst case (on the slow machine
+above), lzip just increased the boot time a 15% compared with gzip. On
+more modern machines, lzip may boot slightly faster than gzip. It just
+takes 0.2 seconds for lzip to decompress vmlinuz-4.4.16 on my machine.
+
+Decompression time is usually a small fraction of the total boot time.
+For example, using lz4 on a desktop machine in order to save 0.05
+seconds of a total boot time of 20 seconds is probably not worth the
+increased image size.
+
+Xlunzip is a test tool for the lzip_decompress module. It is similar to
+lunzip, but it uses the lzip_decompress module as a backend. The xlunzip
+home page is at http://www.nongnu.org/lzip/xlunzip.html
+
+Author: Antonio Diaz Diaz
+Updated: 2018-12-09
diff -urdN linux-5.4.18/Makefile linux-5.4.18.new/Makefile
--- linux-5.4.18/Makefile	2020-02-05 23:18:13.000000000 +0100
+++ linux-5.4.18.new/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -972,14 +972,17 @@
 export mod_strip_cmd
 
 # CONFIG_MODULE_COMPRESS, if defined, will cause module to be compressed
-# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP
-# or CONFIG_MODULE_COMPRESS_XZ.
+# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP,
+# CONFIG_MODULE_COMPRESS_LZIP or CONFIG_MODULE_COMPRESS_XZ.
 
 mod_compress_cmd = true
 ifdef CONFIG_MODULE_COMPRESS
   ifdef CONFIG_MODULE_COMPRESS_GZIP
     mod_compress_cmd = gzip -n -f
   endif # CONFIG_MODULE_COMPRESS_GZIP
+  ifdef CONFIG_MODULE_COMPRESS_LZIP
+    mod_compress_cmd = lzip -f
+  endif # CONFIG_MODULE_COMPRESS_LZIP
   ifdef CONFIG_MODULE_COMPRESS_XZ
     mod_compress_cmd = xz -f
   endif # CONFIG_MODULE_COMPRESS_XZ
diff -urdN linux-5.4.18/arch/arm/Kconfig linux-5.4.18.new/arch/arm/Kconfig
--- linux-5.4.18/arch/arm/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/arm/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -91,6 +91,7 @@
 	select HAVE_IRQ_TIME_ACCOUNTING
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZ4
+	select HAVE_KERNEL_LZIP
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_LZO
 	select HAVE_KERNEL_XZ
diff -urdN linux-5.4.18/arch/arm/boot/compressed/Makefile linux-5.4.18.new/arch/arm/boot/compressed/Makefile
--- linux-5.4.18/arch/arm/boot/compressed/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/arm/boot/compressed/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -71,6 +71,7 @@
 CPPFLAGS_vmlinux.lds := -DTEXT_START="$(ZTEXTADDR)" -DBSS_START="$(ZBSSADDR)"
 
 compress-$(CONFIG_KERNEL_GZIP) = gzip
+compress-$(CONFIG_KERNEL_LZIP) = klzip
 compress-$(CONFIG_KERNEL_LZO)  = lzo
 compress-$(CONFIG_KERNEL_LZMA) = lzma
 compress-$(CONFIG_KERNEL_XZ)   = xzkern
diff -urdN linux-5.4.18/arch/arm/boot/compressed/decompress.c linux-5.4.18.new/arch/arm/boot/compressed/decompress.c
--- linux-5.4.18/arch/arm/boot/compressed/decompress.c	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/arm/boot/compressed/decompress.c	2020-02-10 15:55:57.000000000 +0100
@@ -38,6 +38,10 @@
 #include "../../../../lib/decompress_inflate.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZIP
+#include "../../../../lib/decompress_lunzip.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZO
 #include "../../../../lib/decompress_unlzo.c"
 #endif
diff -urdN linux-5.4.18/arch/sh/Kconfig linux-5.4.18.new/arch/sh/Kconfig
--- linux-5.4.18/arch/sh/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/sh/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -23,6 +23,7 @@
 	select HAVE_KERNEL_GZIP
 	select CPU_NO_EFFICIENT_FFS
 	select HAVE_KERNEL_BZIP2
+	select HAVE_KERNEL_LZIP
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_XZ
 	select HAVE_KERNEL_LZO
diff -urdN linux-5.4.18/arch/sh/Makefile linux-5.4.18.new/arch/sh/Makefile
--- linux-5.4.18/arch/sh/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/sh/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -209,9 +209,9 @@
 libs-$(CONFIG_SUPERH32)		:= arch/sh/lib/	$(libs-y)
 libs-$(CONFIG_SUPERH64)		:= arch/sh/lib64/ $(libs-y)
 
-BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.xz uImage.lzo \
-	       uImage.srec uImage.bin zImage vmlinux.bin vmlinux.srec \
-	       romImage
+BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lz uImage.lzma uImage.xz \
+	       uImage.lzo uImage.srec uImage.bin zImage vmlinux.bin \
+	       vmlinux.srec romImage
 PHONY += $(BOOT_TARGETS)
 
 all: $(notdir $(KBUILD_IMAGE))
@@ -241,6 +241,7 @@
 	@echo '  uImage.bin	           - Kernel-only image for U-Boot (bin)'
 	@echo '* uImage.gz	           - Kernel-only image for U-Boot (gzip)'
 	@echo '  uImage.bz2	           - Kernel-only image for U-Boot (bzip2)'
+	@echo '  uImage.lz	           - Kernel-only image for U-Boot (lzip)'
 	@echo '  uImage.lzma	           - Kernel-only image for U-Boot (lzma)'
 	@echo '  uImage.xz	           - Kernel-only image for U-Boot (xz)'
 	@echo '  uImage.lzo	           - Kernel-only image for U-Boot (lzo)'
diff -urdN linux-5.4.18/arch/sh/boot/Makefile linux-5.4.18.new/arch/sh/boot/Makefile
--- linux-5.4.18/arch/sh/boot/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/sh/boot/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -22,14 +22,15 @@
 suffix-y := bin
 suffix-$(CONFIG_KERNEL_GZIP)	:= gz
 suffix-$(CONFIG_KERNEL_BZIP2)	:= bz2
+suffix-$(CONFIG_KERNEL_LZIP)	:= lz
 suffix-$(CONFIG_KERNEL_LZMA)	:= lzma
 suffix-$(CONFIG_KERNEL_XZ)	:= xz
 suffix-$(CONFIG_KERNEL_LZO)	:= lzo
 
 targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz \
-	   uImage.bz2 uImage.lzma uImage.xz uImage.lzo uImage.bin
-extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
-	   vmlinux.bin.xz vmlinux.bin.lzo
+	   uImage.bz2 uImage.lz uImage.lzma uImage.xz uImage.lzo uImage.bin
+extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lz \
+	   vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo
 subdir- := compressed romimage
 
 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
@@ -71,6 +72,9 @@
 $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,bzip2)
 
+$(obj)/vmlinux.bin.lz: $(obj)/vmlinux.bin FORCE
+	$(call if_changed,klzip)
+
 $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,lzma)
 
@@ -86,6 +90,9 @@
 $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz
 	$(call if_changed,uimage,gzip)
 
+$(obj)/uImage.lz: $(obj)/vmlinux.bin.lz
+	$(call if_changed,uimage,lzip)
+
 $(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma
 	$(call if_changed,uimage,lzma)
 
diff -urdN linux-5.4.18/arch/sh/boot/compressed/Makefile linux-5.4.18.new/arch/sh/boot/compressed/Makefile
--- linux-5.4.18/arch/sh/boot/compressed/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/sh/boot/compressed/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -5,10 +5,9 @@
 # create a compressed vmlinux image from the original vmlinux
 #
 
-targets		:= vmlinux vmlinux.bin vmlinux.bin.gz \
-		   vmlinux.bin.bz2 vmlinux.bin.lzma \
-		   vmlinux.bin.xz vmlinux.bin.lzo \
-		   head_$(BITS).o misc.o piggy.o
+targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
+	   vmlinux.bin.lz vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo \
+	   head_$(BITS).o misc.o piggy.o
 
 OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o
 
@@ -66,6 +65,8 @@
 	$(call if_changed,gzip)
 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lz: $(vmlinux.bin.all-y) FORCE
+	$(call if_changed,klzip)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,lzma)
 $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
diff -urdN linux-5.4.18/arch/sh/boot/compressed/misc.c linux-5.4.18.new/arch/sh/boot/compressed/misc.c
--- linux-5.4.18/arch/sh/boot/compressed/misc.c	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/sh/boot/compressed/misc.c	2020-02-10 15:55:57.000000000 +0100
@@ -58,6 +58,10 @@
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZIP
+#include "../../../../lib/decompress_lunzip.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZMA
 #include "../../../../lib/decompress_unlzma.c"
 #endif
diff -urdN linux-5.4.18/arch/x86/Kconfig linux-5.4.18.new/arch/x86/Kconfig
--- linux-5.4.18/arch/x86/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/x86/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -176,6 +176,7 @@
 	select HAVE_KERNEL_BZIP2
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZ4
+	select HAVE_KERNEL_LZIP
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_LZO
 	select HAVE_KERNEL_XZ
diff -urdN linux-5.4.18/arch/x86/boot/compressed/Makefile linux-5.4.18.new/arch/x86/boot/compressed/Makefile
--- linux-5.4.18/arch/x86/boot/compressed/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/x86/boot/compressed/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -23,8 +23,8 @@
 # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
 KCOV_INSTRUMENT		:= n
 
-targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
-	vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
+targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lz \
+	   vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
 
 KBUILD_CFLAGS := -m$(BITS) -O2
 KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
@@ -136,6 +136,8 @@
 	$(call if_changed,gzip)
 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lz: $(vmlinux.bin.all-y) FORCE
+	$(call if_changed,klzip)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,lzma)
 $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
@@ -147,6 +149,7 @@
 
 suffix-$(CONFIG_KERNEL_GZIP)	:= gz
 suffix-$(CONFIG_KERNEL_BZIP2)	:= bz2
+suffix-$(CONFIG_KERNEL_LZIP)	:= lz
 suffix-$(CONFIG_KERNEL_LZMA)	:= lzma
 suffix-$(CONFIG_KERNEL_XZ)	:= xz
 suffix-$(CONFIG_KERNEL_LZO) 	:= lzo
diff -urdN linux-5.4.18/arch/x86/boot/compressed/misc.c linux-5.4.18.new/arch/x86/boot/compressed/misc.c
--- linux-5.4.18/arch/x86/boot/compressed/misc.c	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/arch/x86/boot/compressed/misc.c	2020-02-10 15:55:57.000000000 +0100
@@ -62,6 +62,10 @@
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZIP
+#include "../../../../lib/decompress_lunzip.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZMA
 #include "../../../../lib/decompress_unlzma.c"
 #endif
diff -urdN linux-5.4.18/fs/squashfs/Kconfig linux-5.4.18.new/fs/squashfs/Kconfig
--- linux-5.4.18/fs/squashfs/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/fs/squashfs/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -5,7 +5,7 @@
 	help
 	  Saying Y here includes support for SquashFS 4.0 (a Compressed
 	  Read-Only File System).  Squashfs is a highly compressed read-only
-	  filesystem for Linux.  It uses zlib, lzo or xz compression to
+	  filesystem for Linux.  It uses zlib, lzip, lzo or xz compression to
 	  compress both files, inodes and directories.  Inodes in the system
 	  are very small and all blocks are packed to minimise data overhead.
 	  Block sizes greater than 4K are supported up to a maximum of 1 Mbytes
@@ -135,6 +135,21 @@
 	  file systems will be readable without selecting this option.
 
 	  If unsure, say N.
+
+config SQUASHFS_LZIP
+	bool "Include support for LZIP compressed file systems"
+	depends on SQUASHFS
+	select LZIP_DECOMPRESS
+	help
+	  Saying Y here includes support for reading Squashfs file systems
+	  compressed with LZIP compression.  LZIP gives better compression
+	  than the default zlib compression, at the expense of greater CPU
+	  and memory overhead.
+
+	  LZIP is not the standard compression used in Squashfs and so most
+	  file systems will be readable without selecting this option.
+
+	  If unsure, say N.
 
 config SQUASHFS_LZO
 	bool "Include support for LZO compressed file systems"
diff -urdN linux-5.4.18/fs/squashfs/Makefile linux-5.4.18.new/fs/squashfs/Makefile
--- linux-5.4.18/fs/squashfs/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/fs/squashfs/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -13,6 +13,7 @@
 squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o
 squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o
 squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o
+squashfs-$(CONFIG_SQUASHFS_LZIP) += lzip_wrapper.o
 squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
 squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
 squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o
diff -urdN linux-5.4.18/fs/squashfs/decompressor.c linux-5.4.18.new/fs/squashfs/decompressor.c
--- linux-5.4.18/fs/squashfs/decompressor.c	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/fs/squashfs/decompressor.c	2020-02-10 15:55:57.000000000 +0100
@@ -34,6 +34,12 @@
 };
 #endif
 
+#ifndef CONFIG_SQUASHFS_LZIP
+static const struct squashfs_decompressor squashfs_lzip_comp_ops = {
+	NULL, NULL, NULL, NULL, LZIP_COMPRESSION, "lzip", 0
+};
+#endif
+
 #ifndef CONFIG_SQUASHFS_LZO
 static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
 	NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
@@ -65,6 +71,7 @@
 static const struct squashfs_decompressor *decompressor[] = {
 	&squashfs_zlib_comp_ops,
 	&squashfs_lz4_comp_ops,
+	&squashfs_lzip_comp_ops,
 	&squashfs_lzo_comp_ops,
 	&squashfs_xz_comp_ops,
 	&squashfs_lzma_unsupported_comp_ops,
diff -urdN linux-5.4.18/fs/squashfs/decompressor.h linux-5.4.18.new/fs/squashfs/decompressor.h
--- linux-5.4.18/fs/squashfs/decompressor.h	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/fs/squashfs/decompressor.h	2020-02-10 15:55:57.000000000 +0100
@@ -37,6 +37,10 @@
 extern const struct squashfs_decompressor squashfs_lz4_comp_ops;
 #endif
 
+#ifdef CONFIG_SQUASHFS_LZIP
+extern const struct squashfs_decompressor squashfs_lzip_comp_ops;
+#endif
+
 #ifdef CONFIG_SQUASHFS_LZO
 extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
 #endif
diff -urdN linux-5.4.18/fs/squashfs/lzip_wrapper.c linux-5.4.18.new/fs/squashfs/lzip_wrapper.c
--- linux-5.4.18/fs/squashfs/lzip_wrapper.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.4.18.new/fs/squashfs/lzip_wrapper.c	2020-02-10 15:55:57.000000000 +0100
@@ -0,0 +1,129 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2014
+ * Phillip Lougher <phillip@squashfs.org.uk>
+ * Copyright (C) 2018-2020 Antonio Diaz Diaz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * lzip_wrapper.c
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/lzip.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs.h"
+#include "decompressor.h"
+#include "page_actor.h"
+
+struct squashfs_lzip {
+	void *input;
+	void *output;
+};
+
+
+static void *lzip_init(struct squashfs_sb_info *msblk, void *buff)
+{
+	int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
+	struct squashfs_lzip *stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (stream == NULL)
+		goto failed;
+	stream->input = vmalloc(block_size);
+	if (stream->input == NULL)
+		goto failed2;
+	stream->output = vmalloc(block_size);
+	if (stream->output == NULL)
+		goto failed3;
+
+	return stream;
+
+failed3:
+	vfree(stream->input);
+failed2:
+	kfree(stream);
+failed:
+	ERROR("Failed to initialise LZIP decompressor\n");
+	return ERR_PTR(-ENOMEM);
+}
+
+
+static void lzip_free(void *strm)
+{
+	struct squashfs_lzip *stream = strm;
+
+	if (stream) {
+		vfree(stream->input);
+		vfree(stream->output);
+	}
+	kfree(stream);
+}
+
+
+static int lzip_uncompress(struct squashfs_sb_info *msblk, void *strm,
+	struct buffer_head **bh, int b, int offset, int length,
+	struct squashfs_page_actor *output)
+{
+	struct squashfs_lzip *stream = strm;
+	void *buff = stream->input, *data;
+	long out_pos;
+	int avail, i, bytes = length, res;
+
+	for (i = 0; i < b; i++) {
+		avail = min(bytes, msblk->devblksize - offset);
+		memcpy(buff, bh[i]->b_data + offset, avail);
+		buff += avail;
+		bytes -= avail;
+		offset = 0;
+		put_bh(bh[i]);
+	}
+
+	res = lzip_decompress(stream->input, length, 0, 0, stream->output,
+				output->length, 0, &out_pos);
+	if (res < 0) {
+		ERROR("LZIP error code %d\n", res);
+		return -EIO;
+	}
+	bytes = out_pos;
+	data = squashfs_first_page(output);
+	buff = stream->output;
+	while (data) {
+		if (bytes <= PAGE_SIZE) {
+			memcpy(data, buff, bytes);
+			break;
+		}
+		memcpy(data, buff, PAGE_SIZE);
+		buff += PAGE_SIZE;
+		bytes -= PAGE_SIZE;
+		data = squashfs_next_page(output);
+	}
+	squashfs_finish_page(output);
+
+	return out_pos;
+}
+
+
+const struct squashfs_decompressor squashfs_lzip_comp_ops = {
+	.init = lzip_init,
+	.free = lzip_free,
+	.decompress = lzip_uncompress,
+	.id = LZIP_COMPRESSION,
+	.name = "lzip",
+	.supported = 1
+};
diff -urdN linux-5.4.18/fs/squashfs/squashfs_fs.h linux-5.4.18.new/fs/squashfs/squashfs_fs.h
--- linux-5.4.18/fs/squashfs/squashfs_fs.h	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/fs/squashfs/squashfs_fs.h	2020-02-10 15:55:57.000000000 +0100
@@ -235,6 +235,7 @@
 #define XZ_COMPRESSION		4
 #define LZ4_COMPRESSION		5
 #define ZSTD_COMPRESSION	6
+#define LZIP_COMPRESSION	7
 
 struct squashfs_super_block {
 	__le32			s_magic;
diff -urdN linux-5.4.18/include/linux/decompress/lunzip.h linux-5.4.18.new/include/linux/decompress/lunzip.h
--- linux-5.4.18/include/linux/decompress/lunzip.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.4.18.new/include/linux/decompress/lunzip.h	2020-02-10 15:55:57.000000000 +0100
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LINUX_DECOMPRESS_LUNZIP_H
+#define LINUX_DECOMPRESS_LUNZIP_H
+
+int lunzip(unsigned char *inbuf, long in_len,
+	   long (*fill)(void*, unsigned long),
+	   long (*flush)(void*, unsigned long),
+	   unsigned char *outbuf,
+	   long *in_posp,
+	   void (*error)(char *x));
+#endif
diff -urdN linux-5.4.18/include/linux/lzip.h linux-5.4.18.new/include/linux/lzip.h
--- linux-5.4.18/include/linux/lzip.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.4.18.new/include/linux/lzip.h	2020-02-10 15:55:57.000000000 +0100
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LZIP_H__
+#define __LZIP_H__
+/*
+ * LZIP decompressor
+ *
+ * Copyright (C) 2016-2020 Antonio Diaz Diaz.
+ */
+
+/* Return values (< 0 = Error) */
+enum {
+	LZIP_OOM_INBUF     = -1,
+	LZIP_HEADER1_EOF   = -2,
+	LZIP_HEADER2_EOF   = -3,
+	LZIP_BAD_MAGIC1    = -4,
+	LZIP_BAD_MAGIC2    = -5,
+	LZIP_BAD_VERSION   = -6,
+	LZIP_BAD_DICT_SIZE = -7,
+	LZIP_OOM_OUTBUF    = -8,
+	LZIP_WRITE_ERROR   = -9,
+	LZIP_BAD_DATA      = -10,
+	LZIP_DATA_EOF      = -11,
+	LZIP_BAD_CRC       = -12
+};
+
+int lzip_decompress(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp, long *out_posp);
+
+/* inbuf    - input buffer. If null or in_len <= 0, fill must be non-null
+ * in_len   - len of pre-read data in inbuf if inbuf is non-null
+ * fill     - if non-null, function to fill inbuf when empty
+ * flush    - if non-null, function to write out outbuf when full
+ * outbuf   - output buffer. If null or out_size <= 0, flush must be non-null
+ * out_size - size of outbuf if outbuf is non-null
+ * in_posp  - if non-null, the number of bytes consumed will be returned here
+ * out_posp - if non-null, the number of bytes produced will be returned here
+ *
+ * fill will be called (repeatedly) to read data. in_len bytes will be read
+ * per call (or 16384 bytes per call if inbuf is null or in_len <= 0).
+ *
+ * If flush is null, outbuf must be large enough to buffer all the expected
+ * output. Else the flush function will be called to flush the output buffer
+ * at the appropriate time (stream dependent).
+ * If out_size > 0 but is not large enough to buffer all the expected output,
+ * it must be at least as large as the dictionary size of the data.
+ *
+ * inbuf and outbuf may overlap (in-place decompression).
+ */
+
+#endif
diff -urdN linux-5.4.18/init/Kconfig linux-5.4.18.new/init/Kconfig
--- linux-5.4.18/init/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/init/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -181,6 +181,9 @@
 config HAVE_KERNEL_BZIP2
 	bool
 
+config HAVE_KERNEL_LZIP
+	bool
+
 config HAVE_KERNEL_LZMA
 	bool
 
@@ -199,7 +202,7 @@
 choice
 	prompt "Kernel compression mode"
 	default KERNEL_GZIP
-	depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_UNCOMPRESSED
+	depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZIP || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_UNCOMPRESSED
 	help
 	  The linux kernel is a kind of self-extracting executable.
 	  Several compression algorithms are available, which differ
@@ -235,6 +238,15 @@
 	  Bzip2 uses a large amount of memory. For modern kernels you
 	  will need at least 8MB RAM or more for booting.
 
+config KERNEL_LZIP
+	bool "Lzip"
+	depends on HAVE_KERNEL_LZIP
+	help
+	  Lzip's compression ratio is better than that of gzip and bzip2.
+	  Decompression speed is between gzip and bzip2.  Compression can
+	  be as fast as gzip or slower than bzip2 depending on compression
+	  level.  Lzip can produce a kernel about a 16% smaller than gzip.
+
 config KERNEL_LZMA
 	bool "LZMA"
 	depends on HAVE_KERNEL_LZMA
@@ -2135,8 +2147,8 @@
 	bool "Compress modules on installation"
 	help
 
-	  Compresses kernel modules when 'make modules_install' is run; gzip or
-	  xz depending on "Compression algorithm" below.
+	  Compresses kernel modules when 'make modules_install' is run; gzip,
+	  lzip, or xz are used depending on "Compression algorithm" below.
 
 	  module-init-tools MAY support gzip, and kmod MAY support gzip and xz.
 
@@ -2158,11 +2170,14 @@
 	  This determines which sort of compression will be used during
 	  'make modules_install'.
 
-	  GZIP (default) and XZ are supported.
+	  GZIP (default), LZIP, and XZ are supported.
 
 config MODULE_COMPRESS_GZIP
 	bool "GZIP"
 
+config MODULE_COMPRESS_LZIP
+	bool "LZIP"
+
 config MODULE_COMPRESS_XZ
 	bool "XZ"
 
diff -urdN linux-5.4.18/init/do_mounts_rd.c linux-5.4.18.new/init/do_mounts_rd.c
--- linux-5.4.18/init/do_mounts_rd.c	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/init/do_mounts_rd.c	2020-02-10 15:55:57.000000000 +0100
@@ -49,6 +49,7 @@
  *	squashfs
  *	gzip
  *	bzip2
+ *	lzip
  *	lzma
  *	xz
  *	lzo
diff -urdN linux-5.4.18/lib/Kconfig linux-5.4.18.new/lib/Kconfig
--- linux-5.4.18/lib/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/lib/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -278,6 +278,12 @@
 	tristate
 	select BITREVERSE
 
+config LZIP_DECOMPRESS
+	tristate "LZIP decompression support"
+	help
+	  LZMA compression algorithm is supported using the .lz file format.
+	  See Documentation/lzip.txt for more information.
+
 config LZO_COMPRESS
 	tristate
 
@@ -314,6 +320,10 @@
 config DECOMPRESS_BZIP2
 	tristate
 
+config DECOMPRESS_LZIP
+	select LZIP_DECOMPRESS
+	tristate
+
 config DECOMPRESS_LZMA
 	tristate
 
diff -urdN linux-5.4.18/lib/Makefile linux-5.4.18.new/lib/Makefile
--- linux-5.4.18/lib/Makefile	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/lib/Makefile	2020-02-10 15:55:57.000000000 +0100
@@ -141,6 +141,7 @@
 obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
 obj-$(CONFIG_BCH) += bch.o
+obj-$(CONFIG_LZIP_DECOMPRESS) += lzip_decompress.o
 obj-$(CONFIG_LZO_COMPRESS) += lzo/
 obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
 obj-$(CONFIG_LZ4_COMPRESS) += lz4/
@@ -153,6 +154,7 @@
 
 lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
 lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+lib-$(CONFIG_DECOMPRESS_LZIP) += decompress_lunzip.o
 lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o
 lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o
 lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o
diff -urdN linux-5.4.18/lib/decompress.c linux-5.4.18.new/lib/decompress.c
--- linux-5.4.18/lib/decompress.c	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/lib/decompress.c	2020-02-10 15:55:57.000000000 +0100
@@ -8,6 +8,7 @@
 #include <linux/decompress/generic.h>
 
 #include <linux/decompress/bunzip2.h>
+#include <linux/decompress/lunzip.h>
 #include <linux/decompress/unlzma.h>
 #include <linux/decompress/unxz.h>
 #include <linux/decompress/inflate.h>
@@ -25,6 +26,9 @@
 #ifndef CONFIG_DECOMPRESS_BZIP2
 # define bunzip2 NULL
 #endif
+#ifndef CONFIG_DECOMPRESS_LZIP
+# define lunzip NULL
+#endif
 #ifndef CONFIG_DECOMPRESS_LZMA
 # define unlzma NULL
 #endif
@@ -48,6 +52,7 @@
 	{ {0x1f, 0x8b}, "gzip", gunzip },
 	{ {0x1f, 0x9e}, "gzip", gunzip },
 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
+	{ {0x4c, 0x5a}, "lzip", lunzip },
 	{ {0x5d, 0x00}, "lzma", unlzma },
 	{ {0xfd, 0x37}, "xz", unxz },
 	{ {0x89, 0x4c}, "lzo", unlzo },
diff -urdN linux-5.4.18/lib/decompress_lunzip.c linux-5.4.18.new/lib/decompress_lunzip.c
--- linux-5.4.18/lib/decompress_lunzip.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.4.18.new/lib/decompress_lunzip.c	2020-02-10 15:55:57.000000000 +0100
@@ -0,0 +1,100 @@
+/*
+ * Wrapper for decompressing LZIP-compressed kernel, initramfs, and initrd
+ *
+ * Copyright (C) 2016-2020 Antonio Diaz Diaz.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#ifdef STATIC
+#define PREBOOT
+#include "lzip_decompress.c"
+#else
+#include <linux/lzip.h>
+#include <linux/decompress/lunzip.h>
+#include <linux/decompress/mm.h>
+#endif
+
+STATIC int INIT __lunzip(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp, long *out_posp,
+			void (*error)(char *x))
+{
+	const int retval = lzip_decompress(inbuf, in_len, fill, flush,
+					outbuf, out_size, in_posp, out_posp);
+	switch (retval) {
+	case 0: break;
+	case LZIP_OOM_INBUF:
+		error("Out of memory while allocating input buffer.");
+		break;
+	case LZIP_HEADER1_EOF:
+		error("File ends unexpectedly at member header.");
+		break;
+	case LZIP_HEADER2_EOF:
+		error("Truncated header in multimember file.");
+		break;
+	case LZIP_BAD_MAGIC1:
+		error("Bad magic number (file not in lzip format).");
+		break;
+	case LZIP_BAD_MAGIC2:
+		error("Corrupt header in multimember file.");
+		break;
+	case LZIP_BAD_VERSION:
+		error("Version of lzip member format not supported.");
+		break;
+	case LZIP_BAD_DICT_SIZE:
+		error("Invalid dictionary size in member header.");
+		break;
+	case LZIP_OOM_OUTBUF:
+		error("Out of memory while allocating output buffer.");
+		break;
+	case LZIP_WRITE_ERROR:
+		error("Write error.");
+		break;
+	case LZIP_BAD_DATA:
+		error("LZIP-compressed data is corrupt.");
+		break;
+	case LZIP_DATA_EOF:
+		error("LZIP-compressed data ends unexpectedly.");
+		break;
+	case LZIP_BAD_CRC:
+		error("CRC mismatch in LZIP-compressed data.");
+		break;
+	default:
+		error("Bug in the LZIP decompressor.");
+	}
+	return retval;
+}
+
+#ifndef PREBOOT
+/* decompress_fn (see include/linux/decompress/generic.h) should have an
+ * out_size argument to prevent overflowing outbuf in case of corruption
+ * of the compressed data.
+ */
+STATIC int INIT lunzip(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf,
+			long *in_posp,
+			void (*error)(char *x))
+{
+	return __lunzip(inbuf, in_len, fill, flush, outbuf, LONG_MAX,
+			in_posp, 0, error);
+}
+#else
+STATIC int INIT __decompress(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp,
+			void (*error)(char *x))
+{
+/* Some archs pass out_size = 0 (to mean unlimited size), which is unsafe
+ * in case of corruption of the compressed data.
+ */
+	return __lunzip(inbuf, in_len - 4, fill, flush, outbuf,
+			out_size ? out_size : LONG_MAX, in_posp, 0, error);
+}
+#endif
diff -urdN linux-5.4.18/lib/lzip_decompress.c linux-5.4.18.new/lib/lzip_decompress.c
--- linux-5.4.18/lib/lzip_decompress.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.4.18.new/lib/lzip_decompress.c	2020-02-10 16:58:14.000000000 +0100
@@ -0,0 +1,877 @@
+/*
+ * LZIP decompressor
+ *
+ * Copyright (C) 2016-2020 Antonio Diaz Diaz.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include <linux/module.h>
+#include <linux/lzip.h>
+#include <linux/decompress/mm.h>
+
+/*
+ * STATIC_RW_DATA is used in the pre-boot environment on some architectures.
+ * See include/linux/decompress/mm.h for details.
+ */
+#ifndef STATIC_RW_DATA
+#define STATIC_RW_DATA static
+#endif
+
+typedef int State;
+
+enum { states = 12 };
+
+static inline bool St_is_char(const State st) { return st < 7; }
+
+static inline State St_set_char(const State st)
+{
+	STATIC_RW_DATA const State next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
+	return next[st];
+}
+
+static inline State St_set_match(const State st)
+{
+	return ((st < 7) ? 7 : 10);
+}
+
+static inline State St_set_rep(const State st)
+{
+	return ((st < 7) ? 8 : 11);
+}
+
+static inline State St_set_short_rep(const State st)
+{
+	return ((st < 7) ? 9 : 11);
+}
+
+
+enum {
+	min_dictionary_bits = 12,
+	min_dictionary_size = 1 << min_dictionary_bits,
+	max_dictionary_bits = 29,
+	max_dictionary_size = 1 << max_dictionary_bits,
+	literal_context_bits = 3,
+	pos_state_bits = 2,
+	pos_states = 1 << pos_state_bits,
+	pos_state_mask = pos_states - 1,
+
+	len_states = 4,
+	dis_slot_bits = 6,
+	start_dis_model = 4,
+	end_dis_model = 14,
+	modeled_distances = 1 << (end_dis_model / 2),	/* 128 */
+	dis_align_bits = 4,
+	dis_align_size = 1 << dis_align_bits,
+
+	len_low_bits = 3,
+	len_mid_bits = 3,
+	len_high_bits = 8,
+	len_low_symbols = 1 << len_low_bits,
+	len_mid_symbols = 1 << len_mid_bits,
+	len_high_symbols = 1 << len_high_bits,
+	max_len_symbols = len_low_symbols + len_mid_symbols + len_high_symbols,
+
+	min_match_len = 2,					/* must be 2 */
+	max_match_len = min_match_len + max_len_symbols - 1,	/* 273 */
+	min_match_len_limit = 5
+};
+
+static inline int get_len_state(const int len)
+{
+	return min(len - min_match_len, len_states - 1);
+}
+
+static inline int get_lit_state(const uint8_t prev_byte)
+{
+	return prev_byte >> (8 - literal_context_bits);
+}
+
+
+enum { bit_model_move_bits = 5,
+	bit_model_total_bits = 11,
+	bit_model_total = 1 << bit_model_total_bits
+};
+
+typedef int Bit_model;
+
+static inline void Bm_init(Bit_model * const probability)
+{
+	*probability = bit_model_total / 2;
+}
+
+static inline void Bm_array_init(Bit_model bm[], const int size)
+{
+	int i;
+
+	for (i = 0; i < size; ++i)
+		Bm_init(&bm[i]);
+}
+
+struct Len_model {
+	Bit_model choice1;
+	Bit_model choice2;
+	Bit_model bm_low[pos_states][len_low_symbols];
+	Bit_model bm_mid[pos_states][len_mid_symbols];
+	Bit_model bm_high[len_high_symbols];
+};
+
+static inline void Lm_init(struct Len_model * const lm)
+{
+	Bm_init(&lm->choice1);
+	Bm_init(&lm->choice2);
+	Bm_array_init(lm->bm_low[0], pos_states * len_low_symbols);
+	Bm_array_init(lm->bm_mid[0], pos_states * len_mid_symbols);
+	Bm_array_init(lm->bm_high, len_high_symbols);
+}
+
+
+/* Table of CRCs of all 8-bit messages. */
+STATIC_RW_DATA const uint32_t crc32[256] =
+  {
+  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
+
+
+static inline void CRC32_update_buf(uint32_t * const crc,
+					const uint8_t * const buffer,
+					const long size)
+{
+	long i;
+	uint32_t c = *crc;
+
+	for (i = 0; i < size; ++i)
+		c = crc32[(c^buffer[i])&0xFF] ^ (c >> 8);
+	*crc = c;
+}
+
+
+STATIC_RW_DATA const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */
+
+typedef uint8_t Lzip_header[6];		/* 0-3 magic bytes */
+					/*   4 version */
+					/*   5 coded_dict_size */
+enum { Lh_size = 6 };
+
+static inline bool Lh_verify_magic(const Lzip_header data)
+{
+	int i;
+
+	for (i = 0; i < 4; ++i)
+		if (data[i] != lzip_magic[i])
+			return false;
+	return true;
+}
+
+/* detect (truncated) header */
+static inline bool Lh_verify_prefix(const Lzip_header data, const int sz)
+{
+	int i;
+	for (i = 0; i < sz && i < 4; ++i)
+		if (data[i] != lzip_magic[i])
+			return false;
+	return (sz > 0);
+}
+
+/* detect corrupt header */
+static inline bool Lh_verify_corrupt(const Lzip_header data)
+{
+	int matches = 0;
+	int i;
+	for (i = 0; i < 4; ++i)
+		if (data[i] == lzip_magic[i])
+			++matches;
+	return (matches > 1 && matches < 4);
+}
+
+static inline bool Lh_verify_version(const Lzip_header data)
+{
+	return (data[4] == 1);
+}
+
+static inline unsigned Lh_get_dictionary_size(const Lzip_header data)
+{
+	unsigned sz = (1 << (data[5] & 0x1F));
+
+	if (sz > min_dictionary_size)
+		sz -= (sz / 16) * ((data[5] >> 5) & 7);
+	return sz;
+}
+
+
+typedef uint8_t Lzip_trailer[20];
+			/*  0-3  CRC32 of the uncompressed data */
+			/*  4-11 size of the uncompressed data */
+			/* 12-19 member size including header and trailer */
+enum { Lt_size = 20 };
+
+static inline unsigned Lt_get_data_crc(const Lzip_trailer data)
+{
+	unsigned tmp = 0;
+	int i;
+
+	for (i = 3; i >= 0; --i) {
+		tmp <<= 8;
+		tmp += data[i];
+	}
+	return tmp;
+}
+
+static inline unsigned long long Lt_get_data_size(const Lzip_trailer data)
+{
+	unsigned long long tmp = 0;
+	int i;
+
+	for (i = 11; i >= 4; --i) {
+		tmp <<= 8;
+		tmp += data[i];
+	}
+	return tmp;
+}
+
+static inline unsigned long long Lt_get_member_size(const Lzip_trailer data)
+{
+	unsigned long long tmp = 0;
+	int i;
+
+	for (i = 19; i >= 12; --i) {
+		tmp <<= 8;
+		tmp += data[i];
+	}
+	return tmp;
+}
+
+
+struct Range_decoder {
+	unsigned long long partial_member_pos;
+	uint8_t *buffer;	/* input buffer */
+	long buffer_size;
+	long pos;		/* current pos in buffer */
+	long stream_pos;	/* when reached, a new block must be read */
+	uint32_t code;
+	uint32_t range;
+	long (*fill)(void*, unsigned long);
+	bool at_stream_end;
+	bool buffer_given;
+};
+
+
+static bool Rd_read_block(struct Range_decoder * const rdec)
+{
+	if (!rdec->at_stream_end) {
+		rdec->stream_pos = rdec->fill ?
+			rdec->fill(rdec->buffer, rdec->buffer_size) : 0;
+		rdec->at_stream_end = (rdec->stream_pos < rdec->buffer_size);
+		rdec->partial_member_pos += rdec->pos;
+		rdec->pos = 0;
+	}
+	return rdec->pos < rdec->stream_pos;
+}
+
+
+static inline bool Rd_init(struct Range_decoder * const rdec,
+				uint8_t * const inbuf, const long in_len,
+				long (*fill)(void*, unsigned long))
+{
+	rdec->partial_member_pos = 0;
+	rdec->buffer_given = (inbuf && in_len > 0);
+	rdec->buffer_size = rdec->buffer_given ? in_len : 16384;
+	rdec->buffer = rdec->buffer_given ? inbuf : malloc(rdec->buffer_size);
+	if (!rdec->buffer)
+		return false;
+	rdec->pos = 0;
+	rdec->stream_pos = rdec->buffer_given ? in_len : 0;
+	rdec->code = 0;
+	rdec->range = 0xFFFFFFFFU;
+	rdec->fill = fill;
+	rdec->at_stream_end = false;
+	return true;
+}
+
+static inline void Rd_free(struct Range_decoder * const rdec)
+{
+	if (!rdec->buffer_given)
+		free(rdec->buffer);
+}
+
+static inline bool Rd_finished(struct Range_decoder * const rdec)
+{
+	return rdec->pos >= rdec->stream_pos && !Rd_read_block(rdec);
+}
+
+static inline unsigned long long
+Rd_member_position(const struct Range_decoder * const rdec)
+{
+	return rdec->partial_member_pos + rdec->pos;
+}
+
+static inline void Rd_reset_member_position(struct Range_decoder * const rdec)
+{
+	rdec->partial_member_pos = 0; rdec->partial_member_pos -= rdec->pos;
+}
+
+static inline uint8_t Rd_get_byte(struct Range_decoder * const rdec)
+{
+	/* 0xFF avoids decoder error if member is truncated at EOS marker */
+	if (Rd_finished(rdec))
+		return 0xFF;
+	return rdec->buffer[rdec->pos++];
+}
+
+static inline void Rd_load(struct Range_decoder * const rdec)
+{
+	int i;
+
+	rdec->code = 0;
+	for (i = 0; i < 5; ++i)
+		rdec->code = (rdec->code << 8) | Rd_get_byte(rdec);
+	rdec->range = 0xFFFFFFFFU;
+}
+
+static inline void Rd_normalize(struct Range_decoder * const rdec)
+{
+	if (rdec->range <= 0x00FFFFFFU) {
+		rdec->range <<= 8;
+		rdec->code = (rdec->code << 8) | Rd_get_byte(rdec);
+	}
+}
+
+static inline unsigned Rd_decode(struct Range_decoder * const rdec,
+				const int num_bits)
+{
+	unsigned symbol = 0;
+	int i;
+
+	for (i = num_bits; i > 0; --i) {
+		bool bit;
+
+		Rd_normalize(rdec);
+		rdec->range >>= 1;
+		/* symbol <<= 1; */
+		/* if(rdec->code >= rdec->range) { rdec->code -= rdec->range; symbol |= 1; } */
+		bit = (rdec->code >= rdec->range);
+		symbol <<= 1; symbol += bit;
+		rdec->code -= rdec->range & (0U - bit);
+	}
+	return symbol;
+}
+
+static inline unsigned Rd_decode_bit(struct Range_decoder * const rdec,
+					Bit_model * const probability)
+{
+	uint32_t bound;
+
+	Rd_normalize(rdec);
+	bound = (rdec->range >> bit_model_total_bits) * *probability;
+	if (rdec->code < bound) {
+		rdec->range = bound;
+		*probability += (bit_model_total - *probability) >> bit_model_move_bits;
+		return 0;
+	} else {
+		rdec->range -= bound;
+		rdec->code -= bound;
+		*probability -= *probability >> bit_model_move_bits;
+		return 1;
+	}
+}
+
+static inline unsigned Rd_decode_tree3(struct Range_decoder * const rdec,
+					Bit_model bm[])
+{
+	unsigned symbol = 2 | Rd_decode_bit(rdec, &bm[1]);
+
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	return symbol & 7;
+}
+
+static inline unsigned Rd_decode_tree6(struct Range_decoder * const rdec,
+					Bit_model bm[])
+{
+	unsigned symbol = 2 | Rd_decode_bit(rdec, &bm[1]);
+
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	return symbol & 0x3F;
+}
+
+static inline unsigned Rd_decode_tree8(struct Range_decoder * const rdec,
+					Bit_model bm[])
+{
+	unsigned symbol = 1;
+	int i;
+
+	for (i = 0; i < 8; ++i)
+		symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	return symbol & 0xFF;
+}
+
+static inline unsigned
+Rd_decode_tree_reversed(struct Range_decoder * const rdec,
+			Bit_model bm[], const int num_bits)
+{
+	unsigned model = 1;
+	unsigned symbol = 0;
+	int i;
+
+	for (i = 0; i < num_bits; ++i) {
+		const unsigned bit = Rd_decode_bit(rdec, &bm[model]);
+
+		model <<= 1; model += bit;
+		symbol |= (bit << i);
+	}
+	return symbol;
+}
+
+static inline unsigned
+Rd_decode_tree_reversed4(struct Range_decoder * const rdec, Bit_model bm[])
+{
+	unsigned symbol = Rd_decode_bit(rdec, &bm[1]);
+
+	symbol += Rd_decode_bit( rdec, &bm[2+symbol] ) << 1;
+	symbol += Rd_decode_bit( rdec, &bm[4+symbol] ) << 2;
+	symbol += Rd_decode_bit( rdec, &bm[8+symbol] ) << 3;
+	return symbol;
+}
+
+static inline unsigned Rd_decode_matched(struct Range_decoder * const rdec,
+					Bit_model bm[], unsigned match_byte)
+{
+	unsigned symbol = 1;
+	unsigned mask = 0x100;
+
+	while (true) {
+		const unsigned match_bit = (match_byte <<= 1) & mask;
+		const unsigned bit = Rd_decode_bit(rdec, &bm[symbol+match_bit+mask]);
+
+		symbol <<= 1; symbol += bit;
+		if (symbol > 0xFF)
+			return symbol & 0xFF;
+		mask &= ~(match_bit ^ (bit << 8));	/* if( match_bit != bit ) mask = 0; */
+	}
+}
+
+static inline unsigned Rd_decode_len(struct Range_decoder * const rdec,
+						struct Len_model * const lm,
+						const int pos_state)
+{
+	if (Rd_decode_bit(rdec, &lm->choice1) == 0)
+		return Rd_decode_tree3(rdec, lm->bm_low[pos_state]);
+	if (Rd_decode_bit(rdec, &lm->choice2) == 0)
+		return len_low_symbols +
+			Rd_decode_tree3(rdec, lm->bm_mid[pos_state]);
+	return len_low_symbols + len_mid_symbols +
+		Rd_decode_tree8(rdec, lm->bm_high);
+}
+
+
+struct LZ_decoder {
+	unsigned long long partial_data_pos;
+	struct Range_decoder *rdec;
+	/* Don't move bm_* to LZd_decode_member; makes frame too large. */
+	Bit_model bm_literal[1 << literal_context_bits][0x300];
+	Bit_model bm_match[states][pos_states];
+	Bit_model bm_rep[states];
+	Bit_model bm_rep0[states];
+	Bit_model bm_rep1[states];
+	Bit_model bm_rep2[states];
+	Bit_model bm_len[states][pos_states];
+	Bit_model bm_dis_slot[len_states][1 << dis_slot_bits];
+	Bit_model bm_dis[modeled_distances-end_dis_model+1];
+	Bit_model bm_align[dis_align_size];
+	struct Len_model match_len_model;
+	struct Len_model rep_len_model;
+
+	unsigned long buffer_size;
+	unsigned dictionary_size;
+	uint8_t *buffer;	/* output buffer */
+	unsigned long pos;	/* current pos in buffer */
+	unsigned long stream_pos;	/* first byte not yet written to file */
+	uint32_t crc;
+	long (*flush)(void*, unsigned long);
+	bool pos_wrapped;
+	bool buffer_given;
+	bool write_error;
+};
+
+static void LZd_flush_data(struct LZ_decoder * const d)
+{
+	if (d->pos > d->stream_pos) {
+		const long size = d->pos - d->stream_pos;
+
+		CRC32_update_buf(&d->crc, d->buffer + d->stream_pos, size);
+		if ((d->flush &&
+		     d->flush(d->buffer + d->stream_pos, size) != size) ||
+		    (!d->flush && d->pos_wrapped))
+			d->write_error = true;
+		if (d->pos >= d->buffer_size) {
+			d->partial_data_pos += d->pos;
+			d->pos = 0;
+			d->pos_wrapped = true;
+		}
+		d->stream_pos = d->pos;
+	}
+}
+
+static inline uint8_t LZd_peek_prev(const struct LZ_decoder * const d)
+{
+	if (d->pos > 0)
+		return d->buffer[d->pos-1];
+	if (d->pos_wrapped)
+		return d->buffer[d->buffer_size-1];
+	return 0;			/* prev_byte of first byte */
+}
+
+static inline uint8_t LZd_peek(const struct LZ_decoder * const d,
+				const unsigned distance)
+{
+	const unsigned long i = ((d->pos > distance) ? 0 : d->buffer_size) +
+				d->pos - distance - 1;
+	return d->buffer[i];
+}
+
+static inline void LZd_put_byte(struct LZ_decoder * const d, const uint8_t b)
+{
+	d->buffer[d->pos] = b;
+	if (++d->pos >= d->buffer_size)
+		LZd_flush_data(d);
+}
+
+static inline void LZd_copy_block(struct LZ_decoder * const d,
+				const unsigned distance, unsigned len)
+{
+	unsigned long lpos = d->pos, i = lpos - distance - 1;
+	bool fast, fast2;
+
+	if (lpos > distance) {
+		fast = (len < d->buffer_size - lpos);
+		fast2 = (fast && len <= lpos - i);
+	} else {
+		i += d->buffer_size;
+		fast = (len < d->buffer_size - i);	/* (i == pos) may happen */
+		fast2 = (fast && len <= i - lpos);
+	}
+	if (fast) {				/* no wrap */
+		d->pos += len;
+		if (fast2)			/* no wrap, no overlap */
+			memcpy(d->buffer + lpos, d->buffer + i, len);
+		else
+			for (; len > 0; --len)
+				d->buffer[lpos++] = d->buffer[i++];
+	} else
+		for (; len > 0; --len) {
+			d->buffer[d->pos] = d->buffer[i];
+			if (++d->pos >= d->buffer_size)
+				LZd_flush_data(d);
+			if (++i >= d->buffer_size)
+				i = 0;
+		}
+}
+
+static inline bool LZd_init(struct LZ_decoder * const d,
+			struct Range_decoder * const rde,
+			const unsigned dict_size, uint8_t * const outbuf,
+			long out_size, long (*flush)(void*, unsigned long))
+{
+	d->partial_data_pos = 0;
+	d->rdec = rde;
+	Bm_array_init(d->bm_literal[0], (1 << literal_context_bits) * 0x300);
+	Bm_array_init(d->bm_match[0], states * pos_states);
+	Bm_array_init(d->bm_rep, states);
+	Bm_array_init(d->bm_rep0, states);
+	Bm_array_init(d->bm_rep1, states);
+	Bm_array_init(d->bm_rep2, states);
+	Bm_array_init(d->bm_len[0], states * pos_states);
+	Bm_array_init(d->bm_dis_slot[0], len_states * (1 << dis_slot_bits));
+	Bm_array_init(d->bm_dis, modeled_distances - end_dis_model + 1);
+	Bm_array_init(d->bm_align, dis_align_size);
+	Lm_init(&d->match_len_model);
+	Lm_init(&d->rep_len_model);
+
+	d->buffer_given = (outbuf && out_size > 0);
+	d->buffer_size = d->buffer_given ? (unsigned long)out_size : dict_size;
+	d->dictionary_size = min_t(unsigned long, d->buffer_size, dict_size);
+	d->buffer = d->buffer_given ? outbuf : large_malloc(d->buffer_size);
+	if (!d->buffer)
+		return false;
+	d->pos = 0;
+	d->stream_pos = 0;
+	d->crc = 0xFFFFFFFFU;
+	d->flush = flush;
+	d->pos_wrapped = false;
+	d->write_error = false;
+	/* prev_byte of first byte; also for LZd_peek( 0 ) on corrupt file */
+	if (!d->buffer_given)		/* inbuf and outbuf may overlap */
+		d->buffer[d->buffer_size-1] = 0;
+	return true;
+}
+
+static inline void LZd_free(struct LZ_decoder * const d)
+{
+	if (!d->buffer_given)
+		large_free(d->buffer);
+}
+
+static inline unsigned LZd_crc(const struct LZ_decoder * const d)
+{
+	return d->crc ^ 0xFFFFFFFFU;
+}
+
+static inline unsigned long long
+LZd_data_position(const struct LZ_decoder * const d)
+{
+	return d->partial_data_pos + d->pos;
+}
+
+
+static bool LZd_verify_trailer(struct LZ_decoder * const d)
+{
+	Lzip_trailer trailer;
+	int i = 0;
+
+	while (i < Lt_size)
+		trailer[i++] = Rd_get_byte(d->rdec);
+
+	return (Lt_get_data_crc(trailer) == LZd_crc(d) &&
+		Lt_get_data_size(trailer) == LZd_data_position(d) &&
+		Lt_get_member_size(trailer) == Rd_member_position(d->rdec));
+}
+
+
+/* Return value: 0 = OK, < 0 = error (see include/linux/lzip.h). */
+static int LZd_decode_member(struct LZ_decoder * const d)
+{
+	struct Range_decoder * const rdec = d->rdec;
+	unsigned rep0 = 0;	/* rep[0-3] latest four distances */
+	unsigned rep1 = 0;	/* used for efficient coding of */
+	unsigned rep2 = 0;	/* repeated distances */
+	unsigned rep3 = 0;
+	State state = 0;
+
+	Rd_load(rdec);
+	while (!Rd_finished(rdec)) {
+		int len;
+		const int pos_state = LZd_data_position(d) & pos_state_mask;
+
+		if (Rd_decode_bit(rdec, &d->bm_match[state][pos_state]) == 0) {
+			/* literal byte */
+			Bit_model * const bm = d->bm_literal[get_lit_state(LZd_peek_prev(d))];
+
+			if (St_is_char(state)) {
+				state -= (state < 4) ? state : 3;
+				LZd_put_byte(d, Rd_decode_tree8(rdec, bm));
+			} else {
+				state -= (state < 10) ? 3 : 6;
+				LZd_put_byte(d, Rd_decode_matched(rdec, bm, LZd_peek(d, rep0)));
+			}
+		continue;
+		}
+		/* match or repeated match */
+		if (Rd_decode_bit(rdec, &d->bm_rep[state]) != 0) {
+			if (Rd_decode_bit(rdec, &d->bm_rep0[state]) == 0) {
+				if (Rd_decode_bit(rdec, &d->bm_len[state][pos_state]) == 0) {
+					state = St_set_short_rep(state);
+					LZd_put_byte(d, LZd_peek(d, rep0));
+					continue;
+				}
+			} else {
+				unsigned distance;
+
+				if (Rd_decode_bit(rdec, &d->bm_rep1[state]) == 0)
+					distance = rep1;
+				else {
+					if (Rd_decode_bit(rdec, &d->bm_rep2[state]) == 0)
+						distance = rep2;
+					else {
+						distance = rep3;
+						rep3 = rep2;
+					}
+					rep2 = rep1;
+				}
+				rep1 = rep0;
+				rep0 = distance;
+			}
+			state = St_set_rep(state);
+			len = min_match_len + Rd_decode_len(rdec, &d->rep_len_model, pos_state);
+		} else {			/* match */
+			unsigned distance;
+
+			len = min_match_len + Rd_decode_len(rdec, &d->match_len_model, pos_state);
+			distance = Rd_decode_tree6(rdec, d->bm_dis_slot[get_len_state(len)]);
+			if (distance >= start_dis_model) {
+				const unsigned dis_slot = distance;
+				const int direct_bits = (dis_slot >> 1) - 1;
+
+				distance = (2 | (dis_slot & 1)) << direct_bits;
+				if (dis_slot < end_dis_model)
+					distance += Rd_decode_tree_reversed(rdec,
+						d->bm_dis + (distance - dis_slot), direct_bits);
+				else {
+					distance +=
+					  Rd_decode(rdec, direct_bits - dis_align_bits) << dis_align_bits;
+					distance += Rd_decode_tree_reversed4(rdec, d->bm_align);
+					if (distance == 0xFFFFFFFFU) {	/* marker found */
+						Rd_normalize(rdec);
+						LZd_flush_data(d);
+						if (d->write_error)
+							return LZIP_WRITE_ERROR;
+						if (len == min_match_len) {	/* End Of Stream marker */
+							if (LZd_verify_trailer(d))
+								return 0;
+							else
+								return LZIP_BAD_CRC;
+						}
+						if (len == min_match_len + 1) {	/* Sync Flush marker */
+							Rd_load(rdec);
+							continue;
+						}
+						return LZIP_BAD_DATA;	/* unknown marker */
+					}
+				}
+			}
+			rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance;
+			state = St_set_match(state);
+			if (rep0 >= d->dictionary_size ||
+			   (rep0 >= d->pos && !d->pos_wrapped)) {
+				LZd_flush_data(d);
+				return LZIP_BAD_DATA;
+			}
+		}
+		LZd_copy_block(d, rep0, len);
+	}
+	LZd_flush_data(d);
+	return LZIP_DATA_EOF;
+}
+
+
+int lzip_decompress(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp, long *out_posp)
+{
+	unsigned char *outptr = outbuf;
+	struct Range_decoder rdec;
+	struct LZ_decoder *decoder = 0;
+	int retval = 0;
+	bool first_member;
+
+	if (in_posp)
+		*in_posp = 0;
+	if (out_posp)
+		*out_posp = 0;
+
+	if (!Rd_init(&rdec, inbuf, in_len, fill))
+		return LZIP_OOM_INBUF;
+
+	for (first_member = true;; first_member = false) {
+		long data_pos;
+		int size;
+		unsigned dictionary_size;
+		Lzip_header header;
+
+		Rd_reset_member_position(&rdec);
+		for (size = 0; size < Lh_size && !Rd_finished(&rdec); ++size)
+			header[size] = Rd_get_byte(&rdec);
+		if (Rd_finished(&rdec)) {	/* End Of File */
+			if (first_member)
+				retval = LZIP_HEADER1_EOF;
+			else if (Lh_verify_prefix(header, size))
+				retval = LZIP_HEADER2_EOF;
+			break;
+		}
+		if (!Lh_verify_magic(header)) {
+			if (first_member)
+				retval = LZIP_BAD_MAGIC1;
+			else if (Lh_verify_corrupt(header))
+				retval = LZIP_BAD_MAGIC2;
+			break;
+		}
+		if (!Lh_verify_version(header)) {
+			retval = LZIP_BAD_VERSION;
+			break;
+		}
+		dictionary_size = Lh_get_dictionary_size(header);
+		if (dictionary_size < min_dictionary_size ||
+		    dictionary_size > max_dictionary_size) {
+			retval = LZIP_BAD_DICT_SIZE;
+			break;
+		}
+
+		if (!decoder)
+			decoder = malloc(sizeof *decoder);
+		if (!decoder || !LZd_init(decoder, &rdec, dictionary_size,
+					outptr, out_size, flush)) {
+			retval = LZIP_OOM_OUTBUF;
+			break;
+		}
+		retval = LZd_decode_member(decoder);
+		if (in_posp)
+			*in_posp += Rd_member_position(&rdec);
+		data_pos = LZd_data_position(decoder);
+		if (outptr)
+			outptr += data_pos;
+		if (out_posp)
+			*out_posp += data_pos;
+		if (out_size > 0)
+			out_size -= data_pos;
+		LZd_free(decoder);
+		if (retval != 0)
+			break;
+	}
+	if (decoder)
+		free(decoder);
+	Rd_free(&rdec);
+	return retval;
+}
+
+#ifndef STATIC
+EXPORT_SYMBOL_GPL(lzip_decompress);
+#endif
+MODULE_DESCRIPTION("LZIP Decompressor");
+MODULE_AUTHOR("Antonio Diaz Diaz <antonio@gnu.org>");
+MODULE_LICENSE("GPL");
diff -urdN linux-5.4.18/scripts/Makefile.lib linux-5.4.18.new/scripts/Makefile.lib
--- linux-5.4.18/scripts/Makefile.lib	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/scripts/Makefile.lib	2020-02-10 15:55:57.000000000 +0100
@@ -338,6 +338,18 @@
 quiet_cmd_bzip2 = BZIP2   $@
       cmd_bzip2 = { cat $(real-prereqs) | bzip2 -9; $(size_append); } > $@
 
+# Lzip
+# ---------------------------------------------------------------------------
+# The .lz format has the uncompressed size available at the end of the
+# file, but at offset (member_size - 16). So we append a gzip-style size.
+# Use klzip to compress the kernel image and lzip to compress other things.
+
+quiet_cmd_klzip = LZIP    $@
+      cmd_klzip = { cat $(real-prereqs) | lzip -9; $(size_append); } > $@
+
+quiet_cmd_lzip = LZIP    $@
+      cmd_lzip = cat $(real-prereqs) | lzip -9 > $@
+
 # Lzma
 # ---------------------------------------------------------------------------
 
diff -urdN linux-5.4.18/scripts/extract-ikconfig linux-5.4.18.new/scripts/extract-ikconfig
--- linux-5.4.18/scripts/extract-ikconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/scripts/extract-ikconfig	2020-02-10 15:55:57.000000000 +0100
@@ -59,6 +59,7 @@
 try_decompress '\037\213\010' xy    gunzip
 try_decompress '\3757zXZ\000' abcde unxz
 try_decompress 'BZh'          xy    bunzip2
+try_decompress 'LZIP'         xyz   'lzip -d'
 try_decompress '\135\0\0\0'   xxx   unlzma
 try_decompress '\211\114\132' xy    'lzop -d'
 try_decompress '\002\041\114\030' xyy 'lz4 -d -l'
diff -urdN linux-5.4.18/scripts/extract-vmlinux linux-5.4.18.new/scripts/extract-vmlinux
--- linux-5.4.18/scripts/extract-vmlinux	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/scripts/extract-vmlinux	2020-02-10 15:55:57.000000000 +0100
@@ -52,6 +52,7 @@
 try_decompress '\037\213\010' xy    gunzip
 try_decompress '\3757zXZ\000' abcde unxz
 try_decompress 'BZh'          xy    bunzip2
+try_decompress 'LZIP'         xyz   'lzip -d'
 try_decompress '\135\0\0\0'   xxx   unlzma
 try_decompress '\211\114\132' xy    'lzop -d'
 try_decompress '\002!L\030'   xxx   'lz4 -d'
diff -urdN linux-5.4.18/scripts/package/buildtar linux-5.4.18.new/scripts/package/buildtar
--- linux-5.4.18/scripts/package/buildtar	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/scripts/package/buildtar	2020-02-10 15:55:57.000000000 +0100
@@ -35,6 +35,10 @@
 		opts=--bzip2
 		tarball=${tarball}.bz2
 		;;
+	tarlz-pkg)
+		opts=--lzip
+		tarball=${tarball}.lz
+		;;
 	tarxz-pkg)
 		opts=--xz
 		tarball=${tarball}.xz
diff -urdN linux-5.4.18/scripts/patch-kernel linux-5.4.18.new/scripts/patch-kernel
--- linux-5.4.18/scripts/patch-kernel	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/scripts/patch-kernel	2020-02-10 15:55:57.000000000 +0100
@@ -117,6 +117,10 @@
 		ext=".bz2"
 		name="bzip2"
 		uncomp="bunzip2 -dc"
+  elif [ -r ${filebase}.lz ]; then
+		ext=".lz"
+		name="lzip"
+		uncomp="lzip -dc"
   elif [ -r ${filebase}.xz ]; then
                 ext=".xz"
                 name="xz"
diff -urdN linux-5.4.18/tools/testing/selftests/gen_kselftest_tar.sh linux-5.4.18.new/tools/testing/selftests/gen_kselftest_tar.sh
--- linux-5.4.18/tools/testing/selftests/gen_kselftest_tar.sh	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/tools/testing/selftests/gen_kselftest_tar.sh	2020-02-10 15:55:57.000000000 +0100
@@ -27,6 +27,10 @@
 				copts="cvjf"
 				ext=".tar.bz2"
 				;;
+			tarlz)
+				copts="cv --lzip -f"
+				ext=".tar.lz"
+				;;
 			tarxz)
 				copts="cvJf"
 				ext=".tar.xz"
diff -urdN linux-5.4.18/usr/.gitignore linux-5.4.18.new/usr/.gitignore
--- linux-5.4.18/usr/.gitignore	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/usr/.gitignore	2020-02-10 15:55:57.000000000 +0100
@@ -5,5 +5,6 @@
 initramfs_data.cpio
 initramfs_data.cpio.gz
 initramfs_data.cpio.bz2
+initramfs_data.cpio.lz
 initramfs_data.cpio.lzma
 initramfs_list
diff -urdN linux-5.4.18/usr/Kconfig linux-5.4.18.new/usr/Kconfig
--- linux-5.4.18/usr/Kconfig	2020-02-05 22:22:53.000000000 +0100
+++ linux-5.4.18.new/usr/Kconfig	2020-02-10 15:55:57.000000000 +0100
@@ -70,6 +70,15 @@
 	  Support loading of a bzip2 encoded initial ramdisk or cpio buffer
 	  If unsure, say N.
 
+config RD_LZIP
+	bool "Support initial ramdisk/ramfs compressed using lzip"
+	default y
+	depends on BLK_DEV_INITRD
+	select DECOMPRESS_LZIP
+	help
+	  Support loading of a lzip encoded initial ramdisk or cpio buffer.
+	  If unsure, say N.
+
 config RD_LZMA
 	bool "Support initial ramdisk/ramfs compressed using LZMA"
 	default y
@@ -165,6 +174,18 @@
 	  If you choose this, keep in mind that you need to have the bzip2 tool
 	  available to be able to compress the initram.
 
+config INITRAMFS_COMPRESSION_LZIP
+	bool "Lzip"
+	depends on RD_LZIP
+	help
+	  Lzip's compression ratio is better than that of gzip and bzip2.
+	  Decompression speed is between gzip and bzip2.  Compression can
+	  be as fast as gzip or slower than bzip2 depending on compression
+	  level.  Lzip can produce a initramfs about a 16% smaller than gzip.
+
+	  If you choose this, keep in mind that you need to have the lzip tool
+	  available to be able to compress the initram.
+
 config INITRAMFS_COMPRESSION_LZMA
 	bool "LZMA"
 	depends on RD_LZMA
@@ -222,12 +243,14 @@
 	default ""      if INITRAMFS_COMPRESSION_NONE
 	default ".gz"   if INITRAMFS_COMPRESSION_GZIP
 	default ".bz2"  if INITRAMFS_COMPRESSION_BZIP2
+	default ".lz"   if INITRAMFS_COMPRESSION_LZIP
 	default ".lzma" if INITRAMFS_COMPRESSION_LZMA
 	default ".xz"   if INITRAMFS_COMPRESSION_XZ
 	default ".lzo"  if INITRAMFS_COMPRESSION_LZO
 	default ".lz4"  if INITRAMFS_COMPRESSION_LZ4
 	default ".gz"   if RD_GZIP
 	default ".lz4"  if RD_LZ4
+	default ".lz"   if RD_LZIP
 	default ".lzo"  if RD_LZO
 	default ".xz"   if RD_XZ
 	default ".lzma" if RD_LZMA
