From b287adb628223810c78703e6bcad624944dde679 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Thu, 14 Nov 2024 23:03:40 -0500 Subject: [PATCH 096/233] bcachefs: Don't BUG_ON() when superblock feature wasn't set for compressed data Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit We don't allocate the mempools for compression/decompression unless we need them - but that means there's an inconsistency to check for. Reported-by: syzbot+cb3fbcfb417448cfd278@syzkaller.appspotmail.com Signed-off-by: Kent Overstreet Signed-off-by: Alexander Miroshnichenko --- fs/bcachefs/compress.c | 29 +++++++++++++++++++++++++++-- fs/bcachefs/errcode.h | 1 + fs/bcachefs/opts.c | 2 +- fs/bcachefs/opts.h | 1 + fs/bcachefs/sb-errors_format.h | 4 +++- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/fs/bcachefs/compress.c b/fs/bcachefs/compress.c index 2813e4556f0d..f99ff1819597 100644 --- a/fs/bcachefs/compress.c +++ b/fs/bcachefs/compress.c @@ -2,7 +2,9 @@ #include "bcachefs.h" #include "checksum.h" #include "compress.h" +#include "error.h" #include "extents.h" +#include "opts.h" #include "super-io.h" #include @@ -178,7 +180,16 @@ static int __bio_uncompress(struct bch_fs *c, struct bio *src, enum bch_compression_opts opt = bch2_compression_type_to_opt(crc.compression_type); mempool_t *workspace_pool = &c->compress_workspace[opt]; - BUG_ON(!mempool_initialized(workspace_pool)); + if (unlikely(!mempool_initialized(workspace_pool))) { + if (fsck_err(c, compression_type_not_marked_in_sb, + "compression type %s set but not marked in superblock", + __bch2_compression_types[crc.compression_type])) + ret = bch2_check_set_has_compressed_data(c, opt); + else + ret = -BCH_ERR_compression_workspace_not_initialized; + if (ret) + goto out; + } src_data = bio_map_or_bounce(c, src, READ); @@ -234,6 +245,7 @@ static int __bio_uncompress(struct bch_fs *c, struct bio *src, BUG(); } ret = 0; +fsck_err: out: bio_unmap_or_unbounce(c, src_data); return ret; @@ -420,7 +432,17 @@ static unsigned __bio_compress(struct bch_fs *c, BUG_ON(compression.type >= BCH_COMPRESSION_OPT_NR); mempool_t *workspace_pool = &c->compress_workspace[compression.type]; - BUG_ON(!mempool_initialized(workspace_pool)); + if (unlikely(!mempool_initialized(workspace_pool))) { + if (fsck_err(c, compression_opt_not_marked_in_sb, + "compression opt %s set but not marked in superblock", + bch2_compression_opts[compression.type])) { + ret = bch2_check_set_has_compressed_data(c, compression.type); + if (ret) /* memory allocation failure, don't compress */ + return 0; + } else { + return 0; + } + } /* If it's only one block, don't bother trying to compress: */ if (src->bi_iter.bi_size <= c->opts.block_size) @@ -502,6 +524,9 @@ static unsigned __bio_compress(struct bch_fs *c, err: ret = BCH_COMPRESSION_TYPE_incompressible; goto out; +fsck_err: + ret = 0; + goto out; } unsigned bch2_bio_compress(struct bch_fs *c, diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h index 3affdafc2c04..2dda7f962e5b 100644 --- a/fs/bcachefs/errcode.h +++ b/fs/bcachefs/errcode.h @@ -54,6 +54,7 @@ x(ENOMEM, ENOMEM_compression_bounce_read_init) \ x(ENOMEM, ENOMEM_compression_bounce_write_init) \ x(ENOMEM, ENOMEM_compression_workspace_init) \ + x(EIO, compression_workspace_not_initialized) \ x(ENOMEM, ENOMEM_bucket_gens) \ x(ENOMEM, ENOMEM_buckets_nouse) \ x(ENOMEM, ENOMEM_usage_init) \ diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c index 0ba58d74c21f..6772faf385a5 100644 --- a/fs/bcachefs/opts.c +++ b/fs/bcachefs/opts.c @@ -54,7 +54,7 @@ const char * const __bch2_csum_opts[] = { NULL }; -static const char * const __bch2_compression_types[] = { +const char * const __bch2_compression_types[] = { BCH_COMPRESSION_TYPES() NULL }; diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h index 6b29339ea725..ea69099e681d 100644 --- a/fs/bcachefs/opts.h +++ b/fs/bcachefs/opts.h @@ -17,6 +17,7 @@ extern const char * const bch2_sb_features[]; extern const char * const bch2_sb_compat[]; extern const char * const __bch2_btree_ids[]; extern const char * const __bch2_csum_opts[]; +extern const char * const __bch2_compression_types[]; extern const char * const bch2_compression_opts[]; extern const char * const __bch2_str_hash_types[]; extern const char * const bch2_str_hash_opts[]; diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h index f2b38493356d..d5b18ff1645c 100644 --- a/fs/bcachefs/sb-errors_format.h +++ b/fs/bcachefs/sb-errors_format.h @@ -305,7 +305,9 @@ enum bch_fsck_flags { x(accounting_key_replicas_devs_unsorted, 280, FSCK_AUTOFIX) \ x(accounting_key_version_0, 282, FSCK_AUTOFIX) \ x(logged_op_but_clean, 283, FSCK_AUTOFIX) \ - x(MAX, 295, 0) + x(compression_opt_not_marked_in_sb, 295, FSCK_AUTOFIX) \ + x(compression_type_not_marked_in_sb, 296, FSCK_AUTOFIX) \ + x(MAX, 297, 0) enum bch_sb_error_id { #define x(t, n, ...) BCH_FSCK_ERR_##t = n, -- 2.45.2