Skip to content

Commit 986e984

Browse files
author
Kent Overstreet
committed
bcachefs: Compression levels
This allows including a compression level when specifying a compression type, e.g. compression=zstd:15 Values from 1 through 15 indicate compression levels, 0 or unspecified indicates the default. For LZ4, values 3-15 specify that the HC algorithm should be used. Note that for compatibility, extents themselves only include the compression type, not the compression level. This means that specifying the same compression algorithm but different compression levels for the compression and background_compression options will have no effect. XXX: perhaps we could add a warning for this Signed-off-by: Kent Overstreet <[email protected]>
1 parent e86e912 commit 986e984

File tree

10 files changed

+174
-57
lines changed

10 files changed

+174
-57
lines changed

fs/bcachefs/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ config BCACHEFS_FS
99
select FS_POSIX_ACL
1010
select LZ4_COMPRESS
1111
select LZ4_DECOMPRESS
12+
select LZ4HC_COMPRESS
13+
select LZ4HC_DECOMPRESS
1214
select ZLIB_DEFLATE
1315
select ZLIB_INFLATE
1416
select ZSTD_COMPRESS

fs/bcachefs/checksum.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,6 @@ static inline enum bch_csum_type bch2_meta_checksum_type(struct bch_fs *c)
120120
return bch2_csum_opt_to_type(c->opts.metadata_checksum, false);
121121
}
122122

123-
static const unsigned bch2_compression_opt_to_type[] = {
124-
#define x(t, n) [BCH_COMPRESSION_OPT_##t] = BCH_COMPRESSION_TYPE_##t,
125-
BCH_COMPRESSION_OPTS()
126-
#undef x
127-
};
128-
129123
static inline bool bch2_checksum_type_valid(const struct bch_fs *c,
130124
unsigned type)
131125
{

fs/bcachefs/compress.c

Lines changed: 121 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -296,21 +296,32 @@ static int attempt_compress(struct bch_fs *c,
296296
void *workspace,
297297
void *dst, size_t dst_len,
298298
void *src, size_t src_len,
299-
enum bch_compression_type compression_type)
299+
struct bch_compression_opt compression)
300300
{
301-
switch (compression_type) {
302-
case BCH_COMPRESSION_TYPE_lz4: {
303-
int len = src_len;
304-
int ret = LZ4_compress_destSize(
305-
src, dst,
306-
&len, dst_len,
307-
workspace);
308-
309-
if (len < src_len)
310-
return -len;
301+
enum bch_compression_type compression_type =
302+
__bch2_compression_opt_to_type[compression.type];
311303

312-
return ret;
313-
}
304+
switch (compression_type) {
305+
case BCH_COMPRESSION_TYPE_lz4:
306+
if (compression.level < LZ4HC_MIN_CLEVEL) {
307+
int len = src_len;
308+
int ret = LZ4_compress_destSize(
309+
src, dst,
310+
&len, dst_len,
311+
workspace);
312+
if (len < src_len)
313+
return -len;
314+
315+
return ret;
316+
} else {
317+
int ret = LZ4_compress_HC(
318+
src, dst,
319+
src_len, dst_len,
320+
compression.level,
321+
workspace);
322+
323+
return ret ?: -1;
324+
}
314325
case BCH_COMPRESSION_TYPE_gzip: {
315326
z_stream strm = {
316327
.next_in = src,
@@ -320,7 +331,11 @@ static int attempt_compress(struct bch_fs *c,
320331
};
321332

322333
zlib_set_workspace(&strm, workspace);
323-
zlib_deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
334+
zlib_deflateInit2(&strm,
335+
compression.level
336+
? clamp_t(unsigned, compression.level,
337+
Z_BEST_SPEED, Z_BEST_COMPRESSION)
338+
: Z_DEFAULT_COMPRESSION,
324339
Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL,
325340
Z_DEFAULT_STRATEGY);
326341

@@ -333,8 +348,14 @@ static int attempt_compress(struct bch_fs *c,
333348
return strm.total_out;
334349
}
335350
case BCH_COMPRESSION_TYPE_zstd: {
351+
/*
352+
* rescale:
353+
* zstd max compression level is 22, our max level is 15
354+
*/
355+
unsigned level = min((compression.level * 3) / 2, zstd_max_clevel());
356+
ZSTD_parameters params = zstd_get_params(level, c->opts.encoded_extent_max);
336357
ZSTD_CCtx *ctx = zstd_init_cctx(workspace,
337-
zstd_cctx_workspace_bound(&c->zstd_params.cParams));
358+
zstd_cctx_workspace_bound(&params.cParams));
338359

339360
/*
340361
* ZSTD requires that when we decompress we pass in the exact
@@ -365,10 +386,12 @@ static int attempt_compress(struct bch_fs *c,
365386
static unsigned __bio_compress(struct bch_fs *c,
366387
struct bio *dst, size_t *dst_len,
367388
struct bio *src, size_t *src_len,
368-
enum bch_compression_type compression_type)
389+
struct bch_compression_opt compression)
369390
{
370391
struct bbuf src_data = { NULL }, dst_data = { NULL };
371392
void *workspace;
393+
enum bch_compression_type compression_type =
394+
__bch2_compression_opt_to_type[compression.type];
372395
unsigned pad;
373396
int ret = 0;
374397

@@ -400,7 +423,7 @@ static unsigned __bio_compress(struct bch_fs *c,
400423
ret = attempt_compress(c, workspace,
401424
dst_data.b, *dst_len,
402425
src_data.b, *src_len,
403-
compression_type);
426+
compression);
404427
if (ret > 0) {
405428
*dst_len = ret;
406429
ret = 0;
@@ -447,34 +470,34 @@ static unsigned __bio_compress(struct bch_fs *c,
447470
BUG_ON(!*src_len || *src_len > src->bi_iter.bi_size);
448471
BUG_ON(*dst_len & (block_bytes(c) - 1));
449472
BUG_ON(*src_len & (block_bytes(c) - 1));
473+
ret = compression_type;
450474
out:
451475
bio_unmap_or_unbounce(c, src_data);
452476
bio_unmap_or_unbounce(c, dst_data);
453-
return compression_type;
477+
return ret;
454478
err:
455-
compression_type = BCH_COMPRESSION_TYPE_incompressible;
479+
ret = BCH_COMPRESSION_TYPE_incompressible;
456480
goto out;
457481
}
458482

459483
unsigned bch2_bio_compress(struct bch_fs *c,
460484
struct bio *dst, size_t *dst_len,
461485
struct bio *src, size_t *src_len,
462-
unsigned compression_type)
486+
unsigned compression_opt)
463487
{
464488
unsigned orig_dst = dst->bi_iter.bi_size;
465489
unsigned orig_src = src->bi_iter.bi_size;
490+
unsigned compression_type;
466491

467492
/* Don't consume more than BCH_ENCODED_EXTENT_MAX from @src: */
468493
src->bi_iter.bi_size = min_t(unsigned, src->bi_iter.bi_size,
469494
c->opts.encoded_extent_max);
470495
/* Don't generate a bigger output than input: */
471496
dst->bi_iter.bi_size = min(dst->bi_iter.bi_size, src->bi_iter.bi_size);
472497

473-
if (compression_type == BCH_COMPRESSION_TYPE_lz4_old)
474-
compression_type = BCH_COMPRESSION_TYPE_lz4;
475-
476498
compression_type =
477-
__bio_compress(c, dst, dst_len, src, src_len, compression_type);
499+
__bio_compress(c, dst, dst_len, src, src_len,
500+
bch2_compression_decode(compression_opt));
478501

479502
dst->bi_iter.bi_size = orig_dst;
480503
src->bi_iter.bi_size = orig_src;
@@ -521,8 +544,10 @@ static int __bch2_check_set_has_compressed_data(struct bch_fs *c, u64 f)
521544
}
522545

523546
int bch2_check_set_has_compressed_data(struct bch_fs *c,
524-
unsigned compression_type)
547+
unsigned compression_opt)
525548
{
549+
unsigned compression_type = bch2_compression_decode(compression_opt).type;
550+
526551
BUG_ON(compression_type >= ARRAY_SIZE(bch2_compression_opt_to_feature));
527552

528553
return compression_type
@@ -546,14 +571,16 @@ static int __bch2_fs_compress_init(struct bch_fs *c, u64 features)
546571
{
547572
size_t decompress_workspace_size = 0;
548573
bool decompress_workspace_needed;
549-
ZSTD_parameters params = zstd_get_params(0, c->opts.encoded_extent_max);
574+
ZSTD_parameters params = zstd_get_params(zstd_max_clevel(),
575+
c->opts.encoded_extent_max);
550576
struct {
551-
unsigned feature;
552-
unsigned type;
553-
size_t compress_workspace;
554-
size_t decompress_workspace;
577+
unsigned feature;
578+
enum bch_compression_type type;
579+
size_t compress_workspace;
580+
size_t decompress_workspace;
555581
} compression_types[] = {
556-
{ BCH_FEATURE_lz4, BCH_COMPRESSION_TYPE_lz4, LZ4_MEM_COMPRESS, 0 },
582+
{ BCH_FEATURE_lz4, BCH_COMPRESSION_TYPE_lz4,
583+
max_t(size_t, LZ4_MEM_COMPRESS, LZ4HC_MEM_COMPRESS) },
557584
{ BCH_FEATURE_gzip, BCH_COMPRESSION_TYPE_gzip,
558585
zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL),
559586
zlib_inflate_workspacesize(), },
@@ -612,16 +639,74 @@ static int __bch2_fs_compress_init(struct bch_fs *c, u64 features)
612639
return 0;
613640
}
614641

642+
static u64 compression_opt_to_feature(unsigned v)
643+
{
644+
unsigned type = bch2_compression_decode(v).type;
645+
return 1ULL << bch2_compression_opt_to_feature[type];
646+
}
647+
615648
int bch2_fs_compress_init(struct bch_fs *c)
616649
{
617650
u64 f = c->sb.features;
618651

619-
if (c->opts.compression)
620-
f |= 1ULL << bch2_compression_opt_to_feature[c->opts.compression];
621-
622-
if (c->opts.background_compression)
623-
f |= 1ULL << bch2_compression_opt_to_feature[c->opts.background_compression];
652+
f |= compression_opt_to_feature(c->opts.compression);
653+
f |= compression_opt_to_feature(c->opts.background_compression);
624654

625655
return __bch2_fs_compress_init(c, f);
656+
}
657+
658+
int bch2_opt_compression_parse(struct bch_fs *c, const char *_val, u64 *res,
659+
struct printbuf *err)
660+
{
661+
char *val = kstrdup(_val, GFP_KERNEL);
662+
char *p = val, *type_str, *level_str;
663+
struct bch_compression_opt opt = { 0 };
664+
int ret;
665+
666+
if (!val)
667+
return -ENOMEM;
668+
669+
type_str = strsep(&p, ":");
670+
level_str = p;
671+
672+
ret = match_string(bch2_compression_opts, -1, type_str);
673+
if (ret < 0 && err)
674+
prt_str(err, "invalid compression type");
675+
if (ret < 0)
676+
goto err;
677+
678+
opt.type = ret;
679+
680+
if (level_str) {
681+
unsigned level;
682+
683+
ret = kstrtouint(level_str, 10, &level);
684+
if (!ret && !opt.type && level)
685+
ret = -EINVAL;
686+
if (!ret && level > 15)
687+
ret = -EINVAL;
688+
if (ret < 0 && err)
689+
prt_str(err, "invalid compression level");
690+
if (ret < 0)
691+
goto err;
692+
693+
opt.level = level;
694+
}
695+
696+
*res = bch2_compression_encode(opt);
697+
err:
698+
kfree(val);
699+
return ret;
700+
}
701+
702+
void bch2_opt_compression_to_text(struct printbuf *out,
703+
struct bch_fs *c,
704+
struct bch_sb *sb,
705+
u64 v)
706+
{
707+
struct bch_compression_opt opt = bch2_compression_decode(v);
626708

709+
prt_str(out, bch2_compression_opts[opt.type]);
710+
if (opt.level)
711+
prt_printf(out, ":%u", opt.level);
627712
}

fs/bcachefs/compress.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@
44

55
#include "extents_types.h"
66

7+
struct bch_compression_opt {
8+
u8 type:4,
9+
level:4;
10+
};
11+
12+
static inline struct bch_compression_opt bch2_compression_decode(unsigned v)
13+
{
14+
return (struct bch_compression_opt) {
15+
.type = v & 15,
16+
.level = v >> 4,
17+
};
18+
}
19+
20+
static inline unsigned bch2_compression_encode(struct bch_compression_opt opt)
21+
{
22+
return opt.type|(opt.level << 4);
23+
}
24+
25+
static const unsigned __bch2_compression_opt_to_type[] = {
26+
#define x(t, n) [BCH_COMPRESSION_OPT_##t] = BCH_COMPRESSION_TYPE_##t,
27+
BCH_COMPRESSION_OPTS()
28+
#undef x
29+
};
30+
31+
static inline enum bch_compression_type bch2_compression_opt_to_type(unsigned v)
32+
{
33+
return __bch2_compression_opt_to_type[bch2_compression_decode(v).type];
34+
}
35+
736
int bch2_bio_uncompress_inplace(struct bch_fs *, struct bio *,
837
struct bch_extent_crc_unpacked *);
938
int bch2_bio_uncompress(struct bch_fs *, struct bio *, struct bio *,
@@ -15,4 +44,12 @@ int bch2_check_set_has_compressed_data(struct bch_fs *, unsigned);
1544
void bch2_fs_compress_exit(struct bch_fs *);
1645
int bch2_fs_compress_init(struct bch_fs *);
1746

47+
int bch2_opt_compression_parse(struct bch_fs *, const char *, u64 *, struct printbuf *);
48+
void bch2_opt_compression_to_text(struct printbuf *, struct bch_fs *, struct bch_sb *, u64);
49+
50+
#define bch2_opt_compression (struct bch_opt_fn) { \
51+
.parse = bch2_opt_compression_parse, \
52+
.to_text = bch2_opt_compression_to_text, \
53+
}
54+
1855
#endif /* _BCACHEFS_COMPRESS_H */

fs/bcachefs/data_update.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,7 @@ int bch2_data_update_init(struct btree_trans *trans,
455455
BCH_WRITE_DATA_ENCODED|
456456
BCH_WRITE_MOVE|
457457
m->data_opts.write_flags;
458-
m->op.compression_type =
459-
bch2_compression_opt_to_type[io_opts.background_compression ?:
460-
io_opts.compression];
458+
m->op.compression_opt = io_opts.background_compression ?: io_opts.compression;
461459
m->op.watermark = m->data_opts.btree_insert_flags & BCH_WATERMARK_MASK;
462460

463461
bkey_for_each_ptr(ptrs, ptr)

fs/bcachefs/io.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,7 @@ static enum prep_encoded_ret {
10781078
/* Can we just write the entire extent as is? */
10791079
if (op->crc.uncompressed_size == op->crc.live_size &&
10801080
op->crc.compressed_size <= wp->sectors_free &&
1081-
(op->crc.compression_type == op->compression_type ||
1081+
(op->crc.compression_type == bch2_compression_opt_to_type(op->compression_opt) ||
10821082
op->incompressible)) {
10831083
if (!crc_is_compressed(op->crc) &&
10841084
op->csum_type != op->crc.csum_type &&
@@ -1126,7 +1126,7 @@ static enum prep_encoded_ret {
11261126
/*
11271127
* If we want to compress the data, it has to be decrypted:
11281128
*/
1129-
if ((op->compression_type ||
1129+
if ((op->compression_opt ||
11301130
bch2_csum_type_is_encryption(op->crc.csum_type) !=
11311131
bch2_csum_type_is_encryption(op->csum_type)) &&
11321132
bch2_write_decrypt(op))
@@ -1173,7 +1173,7 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
11731173
}
11741174

11751175
if (ec_buf ||
1176-
op->compression_type ||
1176+
op->compression_opt ||
11771177
(op->csum_type &&
11781178
!(op->flags & BCH_WRITE_PAGES_STABLE)) ||
11791179
(bch2_csum_type_is_encryption(op->csum_type) &&
@@ -1196,16 +1196,16 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp,
11961196
dst->bi_iter.bi_size < c->opts.encoded_extent_max)
11971197
break;
11981198

1199-
BUG_ON(op->compression_type &&
1199+
BUG_ON(op->compression_opt &&
12001200
(op->flags & BCH_WRITE_DATA_ENCODED) &&
12011201
bch2_csum_type_is_encryption(op->crc.csum_type));
1202-
BUG_ON(op->compression_type && !bounce);
1202+
BUG_ON(op->compression_opt && !bounce);
12031203

12041204
crc.compression_type = op->incompressible
12051205
? BCH_COMPRESSION_TYPE_incompressible
1206-
: op->compression_type
1206+
: op->compression_opt
12071207
? bch2_bio_compress(c, dst, &dst_len, src, &src_len,
1208-
op->compression_type)
1208+
op->compression_opt)
12091209
: 0;
12101210
if (!crc_is_compressed(crc)) {
12111211
dst_len = min(dst->bi_iter.bi_size, src->bi_iter.bi_size);

fs/bcachefs/io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c,
8686
op->written = 0;
8787
op->error = 0;
8888
op->csum_type = bch2_data_checksum_type(c, opts);
89-
op->compression_type = bch2_compression_opt_to_type[opts.compression];
89+
op->compression_opt = opts.compression;
9090
op->nr_replicas = 0;
9191
op->nr_replicas_required = c->opts.data_replicas_required;
9292
op->watermark = BCH_WATERMARK_normal;

0 commit comments

Comments
 (0)