From 83e726623000d76b4986db591994a2f495d42c53d393d7c5066df9edc036aca9 Mon Sep 17 00:00:00 2001 From: Guillaume GARDET 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 +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 +Signed-off-by: Matthias Brugger +--- + 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 + #include + ++/* 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 +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 +Signed-off-by: Matthias Brugger +--- + 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 + #include + #include ++#include + #include + #include + +@@ -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 + +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 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