diff options
author | Adam Borowski <kilobyte@angband.pl> | 2017-09-15 17:36:59 +0200 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-04-05 19:25:35 +0200 |
commit | e37739baf4015e21148f04725765686362ca1150 (patch) | |
tree | dbab26134d439cc967671b4a45d2ded240ca843b /fs | |
parent | 57599c7e7722daf5f8c2dba4b0e4628f5c500771 (diff) | |
download | linux-next-e37739baf4015e21148f04725765686362ca1150.tar.gz |
btrfs: allow setting zstd level
Capped at 15 because of currently used encoding, which is also a reasonable
limit because highest levels shine only on blocks much bigger than btrfs'
128KB.
Memory is allocated for the biggest supported level rather than for
what is actually used.
Signed-off-by: Adam Borowski <kilobyte@angband.pl>
[ refresh after changes in previous patch ]
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/compression.c | 21 | ||||
-rw-r--r-- | fs/btrfs/props.c | 2 | ||||
-rw-r--r-- | fs/btrfs/super.c | 3 | ||||
-rw-r--r-- | fs/btrfs/zstd.c | 19 |
4 files changed, 33 insertions, 12 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 562c3e633403..d22041a40881 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -1621,12 +1621,23 @@ out: unsigned int btrfs_compress_str2level(const char *str) { - if (strncmp(str, "zlib", 4) != 0) + long level; + int max; + + if (strncmp(str, "zlib", 4) == 0) + max = 9; + else if (strncmp(str, "zstd", 4) == 0) + max = 15; // encoded on 4 bits, real max is 22 + else return 0; - /* Accepted form: zlib:1 up to zlib:9 and nothing left after the number */ - if (str[4] == ':' && '1' <= str[5] && str[5] <= '9' && str[6] == 0) - return str[5] - '0'; + /* Accepted form: zxxx:1 up to zxxx:9 and nothing left after the number */ + str += 4; + if (*str == ':') + str++; + + if (kstrtoul(str, 10, &level)) + return BTRFS_ZLIB_DEFAULT_LEVEL; - return BTRFS_ZLIB_DEFAULT_LEVEL; + return (level > max) ? BTRFS_ZLIB_DEFAULT_LEVEL : level; } diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c index 5859f7d3cf3e..93f4fe25fdf1 100644 --- a/fs/btrfs/props.c +++ b/fs/btrfs/props.c @@ -407,7 +407,7 @@ static int prop_compression_apply(struct inode *inode, type = BTRFS_COMPRESS_LZO; else if (!strncmp("zlib", value, 4)) type = BTRFS_COMPRESS_ZLIB; - else if (!strncmp("zstd", value, len)) + else if (!strncmp("zstd", value, 4)) type = BTRFS_COMPRESS_ZSTD; else return -EINVAL; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 170baef49fae..fa1420a3f0cf 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -556,9 +556,10 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, btrfs_clear_opt(info->mount_opt, NODATASUM); btrfs_set_fs_incompat(info, COMPRESS_LZO); no_compress = 0; - } else if (strcmp(args[0].from, "zstd") == 0) { + } else if (strncmp(args[0].from, "zstd", 4) == 0) { compress_type = "zstd"; info->compress_type = BTRFS_COMPRESS_ZSTD; + info->compress_level = btrfs_compress_str2level(args[0].from); btrfs_set_opt(info->mount_opt, COMPRESS); btrfs_clear_opt(info->mount_opt, NODATACOW); btrfs_clear_opt(info->mount_opt, NODATASUM); diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c index 01a4eab602a3..eb3e39012658 100644 --- a/fs/btrfs/zstd.c +++ b/fs/btrfs/zstd.c @@ -26,11 +26,14 @@ #define ZSTD_BTRFS_MAX_WINDOWLOG 17 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG) #define ZSTD_BTRFS_DEFAULT_LEVEL 3 +// Max supported by the algorithm is 22, but gains for small blocks (128KB) +// are limited, thus we cap at 15. +#define ZSTD_BTRFS_MAX_LEVEL 15 -static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len) +static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len, int level) { - ZSTD_parameters params = ZSTD_getParams(ZSTD_BTRFS_DEFAULT_LEVEL, - src_len, 0); + ZSTD_parameters params = ZSTD_getParams(level, src_len, 0); + BUG_ON(level > ZSTD_maxCLevel()); if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG) params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG; @@ -45,6 +48,7 @@ struct workspace { struct list_head list; ZSTD_inBuffer in_buf; ZSTD_outBuffer out_buf; + int level; }; static void zstd_free_workspace(struct list_head *ws) @@ -59,7 +63,8 @@ static void zstd_free_workspace(struct list_head *ws) static struct list_head *zstd_alloc_workspace(void) { ZSTD_parameters params = - zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT); + zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT, + ZSTD_BTRFS_MAX_LEVEL); struct workspace *workspace; workspace = kzalloc(sizeof(*workspace), GFP_KERNEL); @@ -101,7 +106,7 @@ static int zstd_compress_pages(struct list_head *ws, unsigned long len = *total_out; const unsigned long nr_dest_pages = *out_pages; unsigned long max_out = nr_dest_pages * PAGE_SIZE; - ZSTD_parameters params = zstd_get_btrfs_parameters(len); + ZSTD_parameters params = zstd_get_btrfs_parameters(len, workspace->level); *out_pages = 0; *total_out = 0; @@ -427,6 +432,10 @@ finish: static void zstd_set_level(struct list_head *ws, unsigned int type) { + struct workspace *workspace = list_entry(ws, struct workspace, list); + unsigned level = (type & 0xF0) >> 4; + + workspace->level = level > 0 ? level : ZSTD_BTRFS_DEFAULT_LEVEL; } const struct btrfs_compress_op btrfs_zstd_compress = { |