diff options
Diffstat (limited to 'fs/btrfs/compression.c')
-rw-r--r-- | fs/btrfs/compression.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 346875d45a..b1884fc15e 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -9,39 +9,47 @@ #include <malloc.h> #include <linux/lzo.h> #include <linux/zstd.h> +#include <linux/compat.h> #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; + u32 tot_len, tot_in, 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; + tot_in = 0; + cbuf += LZO_LEN; + clen -= LZO_LEN; + tot_len -= LZO_LEN; + tot_in += 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) { + u32 rem_page; + 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); + tot_in += (LZO_LEN + in_len); out_len = dlen; ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len); @@ -54,6 +62,18 @@ 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. + */ + rem_page = PAGE_SIZE - (tot_in % PAGE_SIZE); + if (rem_page < LZO_LEN) { + cbuf += rem_page; + tot_in += rem_page; + clen -= rem_page; + tot_len -= rem_page; + } } return res; |