/*
* BTRFS filesystem implementation for U-Boot
*
- * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
+ * 2017 Marek BehĂșn, CZ.NIC, kabel@kernel.org
*/
#include "btrfs.h"
+#include <abuf.h>
+#include <log.h>
#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);
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;
while (stream.total_in < clen) {
stream.next_in = cbuf + stream.total_in;
stream.avail_in = min((u32) (clen - stream.total_in),
- (u32) btrfs_info.sb.sectorsize);
+ current_fs_info->sectorsize);
ret = inflate(&stream, Z_NO_FLUSH);
if (ret != Z_OK)
static u32 decompress_zstd(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
{
- ZSTD_DStream *dstream;
- ZSTD_inBuffer in_buf;
- ZSTD_outBuffer out_buf;
- void *workspace;
- size_t wsize;
- u32 res = -1;
-
- wsize = ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT);
- workspace = malloc(wsize);
- if (!workspace) {
- debug("%s: cannot allocate workspace of size %zu\n", __func__,
- wsize);
- return -1;
- }
-
- dstream = ZSTD_initDStream(ZSTD_BTRFS_MAX_INPUT, workspace, wsize);
- if (!dstream) {
- printf("%s: ZSTD_initDStream failed\n", __func__);
- goto err_free;
- }
-
- in_buf.src = cbuf;
- in_buf.pos = 0;
- in_buf.size = clen;
+ struct abuf in, out;
- out_buf.dst = dbuf;
- out_buf.pos = 0;
- out_buf.size = dlen;
+ abuf_init_set(&in, (u8 *)cbuf, clen);
+ abuf_init_set(&out, dbuf, dlen);
- while (1) {
- size_t ret;
-
- ret = ZSTD_decompressStream(dstream, &out_buf, &in_buf);
- if (ZSTD_isError(ret)) {
- printf("%s: ZSTD_decompressStream error %d\n", __func__,
- ZSTD_getErrorCode(ret));
- goto err_free;
- }
-
- if (in_buf.pos >= clen || !ret)
- break;
- }
-
- res = out_buf.pos;
-
-err_free:
- free(workspace);
- return res;
+ return zstd_decompress(&in, &out);
}
u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)