fs: btrfs: add zstd decompression support
authorMarek Behún <marek.behun@nic.cz>
Mon, 29 Apr 2019 20:40:45 +0000 (22:40 +0200)
committerTom Rini <trini@konsulko.com>
Sun, 5 May 2019 12:48:50 +0000 (08:48 -0400)
This adds decompression support for Zstandard, which has been included
in Linux btrfs driver for some time.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
fs/btrfs/Kconfig
fs/btrfs/btrfs_tree.h
fs/btrfs/compression.c

index 22909d9..f302b1f 100644 (file)
@@ -2,6 +2,7 @@ config FS_BTRFS
        bool "Enable BTRFS filesystem support"
        select CRC32C
        select LZO
+       select ZSTD
        select RBTREE
        help
          This provides a single-device read-only BTRFS support. BTRFS is a
index f90fbb2..aa0f3d6 100644 (file)
@@ -647,8 +647,9 @@ enum btrfs_compression_type {
        BTRFS_COMPRESS_NONE  = 0,
        BTRFS_COMPRESS_ZLIB  = 1,
        BTRFS_COMPRESS_LZO   = 2,
-       BTRFS_COMPRESS_TYPES = 2,
-       BTRFS_COMPRESS_LAST  = 3,
+       BTRFS_COMPRESS_ZSTD  = 3,
+       BTRFS_COMPRESS_TYPES = 3,
+       BTRFS_COMPRESS_LAST  = 4,
 };
 
 struct btrfs_file_extent_item {
index e5601b8..346875d 100644 (file)
@@ -6,7 +6,9 @@
  */
 
 #include "btrfs.h"
+#include <malloc.h>
 #include <linux/lzo.h>
+#include <linux/zstd.h>
 #include <u-boot/zlib.h>
 #include <asm/unaligned.h>
 
@@ -108,6 +110,61 @@ static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)
        return res;
 }
 
+#define ZSTD_BTRFS_MAX_WINDOWLOG 17
+#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
+
+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;
+
+       out_buf.dst = dbuf;
+       out_buf.pos = 0;
+       out_buf.size = 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;
+}
+
 u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
 {
        u32 res;
@@ -126,6 +183,8 @@ u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
                return decompress_zlib(cbuf, clen, dbuf, dlen);
        case BTRFS_COMPRESS_LZO:
                return decompress_lzo(cbuf, clen, dbuf, dlen);
+       case BTRFS_COMPRESS_ZSTD:
+               return decompress_zstd(cbuf, clen, dbuf, dlen);
        default:
                printf("%s: Unsupported compression in extent: %i\n", __func__,
                       type);