From 83e726623000d76b4986db591994a2f495d42c53d393d7c5066df9edc036aca9 Mon Sep 17 00:00:00 2001
From: Guillaume GARDET <guillaume.gardet@opensuse.org>
Date: Thu, 19 Mar 2020 17:05:15 +0000
Subject: [PATCH] Accepting request 786526 from hardware:boot:staging

OBS-URL: https://build.opensuse.org/request/show/786526
OBS-URL: https://build.opensuse.org/package/show/hardware:boot/u-boot?expand=0&rev=88
---
 ...-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch |  66 ++++++++++
 ...-uboot-fs-btrfs-Fix-LZO-false-decomp.patch | 124 ++++++++++++++++++
 u-boot.changes                                |   9 ++
 u-boot.spec                                   |   2 +
 4 files changed, 201 insertions(+)
 create mode 100644 0019-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch
 create mode 100644 0020-uboot-fs-btrfs-Fix-LZO-false-decomp.patch

diff --git a/0019-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch b/0019-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch
new file mode 100644
index 0000000..6944d25
--- /dev/null
+++ b/0019-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch
@@ -0,0 +1,66 @@
+From 528169a95fac4edbc0935796d919876b1c64b204 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 19 Mar 2020 20:30:05 +0800
+Subject: [PATCH] uboot: fs/btrfs: Use LZO_LEN to replace immediate number
+
+Just a cleanup. The immediate number makes my eye hurt.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ fs/btrfs/compression.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
+index 346875d45a..4ef44ce114 100644
+--- a/fs/btrfs/compression.c
++++ b/fs/btrfs/compression.c
+@@ -12,36 +12,38 @@
+ #include <u-boot/zlib.h>
+ #include <asm/unaligned.h>
+ 
++/* Header for each segment, LE32, recording the compressed size */
++#define LZO_LEN		4
+ static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
+ {
+ 	u32 tot_len, in_len, res;
+ 	size_t out_len;
+ 	int ret;
+ 
+-	if (clen < 4)
++	if (clen < LZO_LEN)
+ 		return -1;
+ 
+ 	tot_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
+-	cbuf += 4;
+-	clen -= 4;
+-	tot_len -= 4;
++	cbuf += LZO_LEN;
++	clen -= LZO_LEN;
++	tot_len -= LZO_LEN;
+ 
+ 	if (tot_len == 0 && dlen)
+ 		return -1;
+-	if (tot_len < 4)
++	if (tot_len < LZO_LEN)
+ 		return -1;
+ 
+ 	res = 0;
+ 
+-	while (tot_len > 4) {
++	while (tot_len > LZO_LEN) {
+ 		in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
+-		cbuf += 4;
+-		clen -= 4;
++		cbuf += LZO_LEN;
++		clen -= LZO_LEN;
+ 
+-		if (in_len > clen || tot_len < 4 + in_len)
++		if (in_len > clen || tot_len < LZO_LEN + in_len)
+ 			return -1;
+ 
+-		tot_len -= 4 + in_len;
++		tot_len -= (LZO_LEN + in_len);
+ 
+ 		out_len = dlen;
+ 		ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);
diff --git a/0020-uboot-fs-btrfs-Fix-LZO-false-decomp.patch b/0020-uboot-fs-btrfs-Fix-LZO-false-decomp.patch
new file mode 100644
index 0000000..300f6cb
--- /dev/null
+++ b/0020-uboot-fs-btrfs-Fix-LZO-false-decomp.patch
@@ -0,0 +1,124 @@
+From a6aa59c7e4daef9ba202eb260daf23c4c5de63c1 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 19 Mar 2020 20:30:06 +0800
+Subject: [PATCH] uboot: fs/btrfs: Fix LZO false decompression error caused by
+ pending zero
+
+[BUG]
+For certain btrfs files with compressed file extent, uboot will fail to
+load it:
+
+  btrfs_read_extent_reg: disk_bytenr=14229504 disk_len=73728 offset=0 nr_bytes=131
+  072
+  decompress_lzo: tot_len=70770
+  decompress_lzo: in_len=1389
+  decompress_lzo: in_len=2400
+  decompress_lzo: in_len=3002
+  decompress_lzo: in_len=1379
+  decompress_lzo: in_len=88539136
+  decompress_lzo: header error, in_len=88539136 clen=65534 tot_len=62580
+
+NOTE: except the last line, all other lines are debug output.
+
+[CAUSE]
+Btrfs lzo compression uses its own format to record compressed size
+(segmant header, LE32).
+
+However to make decompression easier, we never put such segment header
+across page boundary.
+
+In above case, the xxd dump of the lzo compressed data looks like this:
+
+00001fe0: 4cdc 02fc 0bfd 02c0 dc02 0d13 0100 0001  L...............
+00001ff0: 0000 0008 0300 0000 0000 0011 0000|0000  ................
+00002000: 4705 0000 0001 cc02 0000 0000 0000 1e01  G...............
+
+'|' is the "expected" segment header start position.
+
+But in that page, there are only 2 bytes left, can't contain the 4 bytes
+segment header.
+
+So btrfs compression will skip that 2 bytes, put the segment header in
+next page directly.
+
+Uboot doesn't have such check, and read the header with 2 bytes offset,
+result 0x05470000 (88539136), other than the expected result
+0x00000547 (1351), resulting above error.
+
+[FIX]
+Follow the btrfs-progs restore implementation, by introducing tot_in to
+record total processed bytes (including headers), and do proper page
+boundary skip to fix it.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+---
+ fs/btrfs/compression.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
+index 4ef44ce114..2a6ac8bb10 100644
+--- a/fs/btrfs/compression.c
++++ b/fs/btrfs/compression.c
+@@ -9,6 +9,7 @@
+ #include <malloc.h>
+ #include <linux/lzo.h>
+ #include <linux/zstd.h>
++#include <linux/compat.h>
+ #include <u-boot/zlib.h>
+ #include <asm/unaligned.h>
+ 
+@@ -17,6 +18,7 @@
+ static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
+ {
+ 	u32 tot_len, in_len, res;
++	u32 tot_in = 0;
+ 	size_t out_len;
+ 	int ret;
+ 
+@@ -27,6 +29,7 @@ static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
+ 	cbuf += LZO_LEN;
+ 	clen -= LZO_LEN;
+ 	tot_len -= LZO_LEN;
++	tot_in += LZO_LEN;
+ 
+ 	if (tot_len == 0 && dlen)
+ 		return -1;
+@@ -36,6 +39,9 @@ static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
+ 	res = 0;
+ 
+ 	while (tot_len > LZO_LEN) {
++		size_t mod_page;
++		size_t rem_page;
++
+ 		in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
+ 		cbuf += LZO_LEN;
+ 		clen -= LZO_LEN;
+@@ -44,6 +50,7 @@ static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
+ 			return -1;
+ 
+ 		tot_len -= (LZO_LEN + in_len);
++		tot_in += (LZO_LEN + in_len);
+ 
+ 		out_len = dlen;
+ 		ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);
+@@ -56,6 +63,19 @@ static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
+ 		dlen -= out_len;
+ 
+ 		res += out_len;
++
++		/*
++		 * If the 4 bytes header does not fit to the rest of the page we
++		 * have to move to next one, or we read some garbage.
++		 */
++		mod_page = tot_in % PAGE_SIZE;
++		rem_page = PAGE_SIZE - mod_page;
++		if (rem_page < LZO_LEN) {
++			cbuf += rem_page;
++			tot_in += rem_page;
++			clen -= rem_page;
++			tot_len -= rem_page;
++		}
+ 	}
+ 
+ 	return res;
diff --git a/u-boot.changes b/u-boot.changes
index a3ae0e4..96b542e 100644
--- a/u-boot.changes
+++ b/u-boot.changes
@@ -1,3 +1,12 @@
+-------------------------------------------------------------------
+Thu Mar 19 14:15:58 UTC 2020 - Matthias Brugger <mbrugger@suse.com>
+
+Fix BTRFS access with LZO compression enabled (bsc#1166468)
+Patch queue updated from git://github.com/openSUSE/u-boot.git tumbleweed-2020.01
+* Patches added:
+  0019-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch
+  0020-uboot-fs-btrfs-Fix-LZO-false-decomp.patch
+
 -------------------------------------------------------------------
 Fri Feb 21 12:43:10 UTC 2020 - Matthias Brugger <mbrugger@suse.com>
 
diff --git a/u-boot.spec b/u-boot.spec
index 264f2a5..38cba42 100644
--- a/u-boot.spec
+++ b/u-boot.spec
@@ -219,6 +219,8 @@ Patch0015:      0015-configs-Re-sync-with-CONFIG_DISTRO_.patch
 Patch0016:      0016-configs-am335x_evm-disable-BTRFS.patch
 Patch0017:      0017-net-phy-Fix-overlong-PHY-timeout.patch
 Patch0018:      0018-net-bcmgenet-Don-t-set-ID_MODE_DIS-.patch
+Patch0019:      0019-uboot-fs-btrfs-Use-LZO_LEN-to-repla.patch
+Patch0020:      0020-uboot-fs-btrfs-Fix-LZO-false-decomp.patch
 # Patches: end
 BuildRequires:  bc
 BuildRequires:  bison