summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAdam Borowski <kilobyte@angband.pl>2017-09-15 17:36:59 +0200
committerDavid Sterba <dsterba@suse.com>2018-04-05 19:25:35 +0200
commite37739baf4015e21148f04725765686362ca1150 (patch)
treedbab26134d439cc967671b4a45d2ded240ca843b /fs
parent57599c7e7722daf5f8c2dba4b0e4628f5c500771 (diff)
downloadlinux-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.c21
-rw-r--r--fs/btrfs/props.c2
-rw-r--r--fs/btrfs/super.c3
-rw-r--r--fs/btrfs/zstd.c19
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 = {