summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/backref.c28
-rw-r--r--fs/btrfs/block-group.c36
-rw-r--r--fs/btrfs/compression.c11
-rw-r--r--fs/btrfs/disk-io.c20
-rw-r--r--fs/btrfs/extent-tree.c98
-rw-r--r--fs/btrfs/file-item.c7
-rw-r--r--fs/btrfs/free-space-tree.c9
-rw-r--r--fs/btrfs/inode.c25
-rw-r--r--fs/btrfs/ioctl.c12
-rw-r--r--fs/btrfs/lzo.c4
-rw-r--r--fs/btrfs/qgroup.c8
-rw-r--r--fs/btrfs/raid56.c12
-rw-r--r--fs/btrfs/relocation.c39
-rw-r--r--fs/btrfs/tree-checker.c17
-rw-r--r--fs/btrfs/tree-log.c21
-rw-r--r--fs/btrfs/volumes.c25
-rw-r--r--fs/btrfs/zoned.c7
-rw-r--r--fs/btrfs/zstd.c2
18 files changed, 341 insertions, 40 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index af98421e7922..0428557fd77b 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -1393,6 +1393,13 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx,
.indirect_missing_keys = PREFTREE_INIT
};
+ if (unlikely(!root)) {
+ btrfs_err(ctx->fs_info,
+ "missing extent root for extent at bytenr %llu",
+ ctx->bytenr);
+ return -EUCLEAN;
+ }
+
/* Roots ulist is not needed when using a sharedness check context. */
if (sc)
ASSERT(ctx->roots == NULL);
@@ -2204,6 +2211,13 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
struct btrfs_extent_item *ei;
struct btrfs_key key;
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ logical);
+ return -EUCLEAN;
+ }
+
key.objectid = logical;
if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
key.type = BTRFS_METADATA_ITEM_KEY;
@@ -2851,6 +2865,13 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
struct btrfs_key key;
int ret;
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
key.type = BTRFS_METADATA_ITEM_KEY;
key.offset = (u64)-1;
@@ -2987,6 +3008,13 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
/* We're at keyed items, there is no inline item, go to the next one */
extent_root = btrfs_extent_root(iter->fs_info, iter->bytenr);
+ if (unlikely(!extent_root)) {
+ btrfs_err(iter->fs_info,
+ "missing extent root for extent at bytenr %llu",
+ iter->bytenr);
+ return -EUCLEAN;
+ }
+
ret = btrfs_next_item(extent_root, iter->path);
if (ret)
return ret;
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 2a886bece810..ebf5079096af 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -739,6 +739,12 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
last = max_t(u64, block_group->start, BTRFS_SUPER_INFO_OFFSET);
extent_root = btrfs_extent_root(fs_info, last);
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for block group at offset %llu",
+ block_group->start);
+ return -EUCLEAN;
+ }
#ifdef CONFIG_BTRFS_DEBUG
/*
@@ -1061,6 +1067,11 @@ static int remove_block_group_item(struct btrfs_trans_handle *trans,
int ret;
root = btrfs_block_group_root(fs_info);
+ if (unlikely(!root)) {
+ btrfs_err(fs_info, "missing block group root");
+ return -EUCLEAN;
+ }
+
key.objectid = block_group->start;
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
key.offset = block_group->length;
@@ -1349,6 +1360,11 @@ struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
struct btrfs_chunk_map *map;
unsigned int num_items;
+ if (unlikely(!root)) {
+ btrfs_err(fs_info, "missing block group root");
+ return ERR_PTR(-EUCLEAN);
+ }
+
map = btrfs_find_chunk_map(fs_info, chunk_offset, 1);
ASSERT(map != NULL);
ASSERT(map->start == chunk_offset);
@@ -2140,6 +2156,11 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info,
int ret;
struct btrfs_key found_key;
+ if (unlikely(!root)) {
+ btrfs_err(fs_info, "missing block group root");
+ return -EUCLEAN;
+ }
+
btrfs_for_each_slot(root, key, &found_key, path, ret) {
if (found_key.objectid >= key->objectid &&
found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
@@ -2713,6 +2734,11 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans,
size_t size;
int ret;
+ if (unlikely(!root)) {
+ btrfs_err(fs_info, "missing block group root");
+ return -EUCLEAN;
+ }
+
spin_lock(&block_group->lock);
btrfs_set_stack_block_group_v2_used(&bgi, block_group->used);
btrfs_set_stack_block_group_v2_chunk_objectid(&bgi, block_group->global_root_id);
@@ -3048,6 +3074,11 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
int ret;
bool dirty_bg_running;
+ if (unlikely(!root)) {
+ btrfs_err(fs_info, "missing block group root");
+ return -EUCLEAN;
+ }
+
/*
* This can only happen when we are doing read-only scrub on read-only
* mount.
@@ -3192,6 +3223,11 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
u64 used, remap_bytes;
u32 identity_remap_count;
+ if (unlikely(!root)) {
+ btrfs_err(fs_info, "missing block group root");
+ return -EUCLEAN;
+ }
+
/*
* Block group items update can be triggered out of commit transaction
* critical section, thus we need a consistent view of used bytes.
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 790518a8c803..85199944c1eb 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -320,10 +320,16 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
ASSERT(IS_ALIGNED(ordered->file_offset, fs_info->sectorsize));
ASSERT(IS_ALIGNED(ordered->num_bytes, fs_info->sectorsize));
- ASSERT(cb->writeback);
+ /*
+ * This flag determines if we should clear the writeback flag from the
+ * page cache. But this function is only utilized by encoded writes, it
+ * never goes through the page cache.
+ */
+ ASSERT(!cb->writeback);
cb->start = ordered->file_offset;
cb->len = ordered->num_bytes;
+ ASSERT(cb->bbio.bio.bi_iter.bi_size == ordered->disk_num_bytes);
cb->compressed_len = ordered->disk_num_bytes;
cb->bbio.bio.bi_iter.bi_sector = ordered->disk_bytenr >> SECTOR_SHIFT;
cb->bbio.ordered = ordered;
@@ -345,8 +351,7 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
cb = alloc_compressed_bio(inode, start, REQ_OP_WRITE, end_bbio_compressed_write);
cb->start = start;
cb->len = len;
- cb->writeback = true;
-
+ cb->writeback = false;
return cb;
}
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 407830d86d0d..01f2dbb69832 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1591,7 +1591,7 @@ static int find_newest_super_backup(struct btrfs_fs_info *info)
* this will bump the backup pointer by one when it is
* done
*/
-static void backup_super_roots(struct btrfs_fs_info *info)
+static int backup_super_roots(struct btrfs_fs_info *info)
{
const int next_backup = info->backup_root_index;
struct btrfs_root_backup *root_backup;
@@ -1623,6 +1623,15 @@ static void backup_super_roots(struct btrfs_fs_info *info)
struct btrfs_root *extent_root = btrfs_extent_root(info, 0);
struct btrfs_root *csum_root = btrfs_csum_root(info, 0);
+ if (unlikely(!extent_root)) {
+ btrfs_err(info, "missing extent root for extent at bytenr 0");
+ return -EUCLEAN;
+ }
+ if (unlikely(!csum_root)) {
+ btrfs_err(info, "missing csum root for extent at bytenr 0");
+ return -EUCLEAN;
+ }
+
btrfs_set_backup_extent_root(root_backup,
extent_root->node->start);
btrfs_set_backup_extent_root_gen(root_backup,
@@ -1670,6 +1679,8 @@ static void backup_super_roots(struct btrfs_fs_info *info)
memcpy(&info->super_copy->super_roots,
&info->super_for_commit->super_roots,
sizeof(*root_backup) * BTRFS_NUM_BACKUP_ROOTS);
+
+ return 0;
}
/*
@@ -4051,8 +4062,11 @@ int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors)
* not from fsync where the tree roots in fs_info have not
* been consistent on disk.
*/
- if (max_mirrors == 0)
- backup_super_roots(fs_info);
+ if (max_mirrors == 0) {
+ ret = backup_super_roots(fs_info);
+ if (ret < 0)
+ return ret;
+ }
sb = fs_info->super_for_commit;
dev_item = &sb->dev_item;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b0d9baf5b412..85ee5c79759d 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -75,6 +75,12 @@ int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
struct btrfs_key key;
BTRFS_PATH_AUTO_FREE(path);
+ if (unlikely(!root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu", start);
+ return -EUCLEAN;
+ }
+
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
@@ -131,6 +137,12 @@ search_again:
key.offset = offset;
extent_root = btrfs_extent_root(fs_info, bytenr);
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
if (ret < 0)
return ret;
@@ -436,6 +448,12 @@ static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans,
int recow;
int ret;
+ if (unlikely(!root)) {
+ btrfs_err(trans->fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
if (parent) {
key.type = BTRFS_SHARED_DATA_REF_KEY;
@@ -510,6 +528,12 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans,
u32 num_refs;
int ret;
+ if (unlikely(!root)) {
+ btrfs_err(trans->fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
if (node->parent) {
key.type = BTRFS_SHARED_DATA_REF_KEY;
@@ -668,6 +692,12 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans,
struct btrfs_key key;
int ret;
+ if (unlikely(!root)) {
+ btrfs_err(trans->fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
if (parent) {
key.type = BTRFS_SHARED_BLOCK_REF_KEY;
@@ -692,6 +722,12 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans,
struct btrfs_key key;
int ret;
+ if (unlikely(!root)) {
+ btrfs_err(trans->fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
if (node->parent) {
key.type = BTRFS_SHARED_BLOCK_REF_KEY;
@@ -782,6 +818,12 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
bool skinny_metadata = btrfs_fs_incompat(fs_info, SKINNY_METADATA);
int needed;
+ if (unlikely(!root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes;
@@ -1680,6 +1722,12 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
}
root = btrfs_extent_root(fs_info, key.objectid);
+ if (unlikely(!root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ key.objectid);
+ return -EUCLEAN;
+ }
again:
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) {
@@ -1926,8 +1974,15 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root;
csum_root = btrfs_csum_root(fs_info, head->bytenr);
- ret = btrfs_del_csums(trans, csum_root, head->bytenr,
- head->num_bytes);
+ if (unlikely(!csum_root)) {
+ btrfs_err(fs_info,
+ "missing csum root for extent at bytenr %llu",
+ head->bytenr);
+ ret = -EUCLEAN;
+ } else {
+ ret = btrfs_del_csums(trans, csum_root, head->bytenr,
+ head->num_bytes);
+ }
}
}
@@ -2379,6 +2434,12 @@ static noinline int check_committed_ref(struct btrfs_inode *inode,
int type;
int ret;
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
+
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = (u64)-1;
@@ -3093,6 +3154,15 @@ static int do_free_extent_accounting(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root;
csum_root = btrfs_csum_root(trans->fs_info, bytenr);
+ if (unlikely(!csum_root)) {
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ btrfs_err(trans->fs_info,
+ "missing csum root for extent at bytenr %llu",
+ bytenr);
+ return ret;
+ }
+
ret = btrfs_del_csums(trans, csum_root, bytenr, num_bytes);
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
@@ -3222,7 +3292,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 delayed_ref_root = href->owning_root;
extent_root = btrfs_extent_root(info, bytenr);
- ASSERT(extent_root);
+ if (unlikely(!extent_root)) {
+ btrfs_err(info,
+ "missing extent root for extent at bytenr %llu", bytenr);
+ return -EUCLEAN;
+ }
path = btrfs_alloc_path();
if (!path)
@@ -4939,11 +5013,18 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
size += btrfs_extent_inline_ref_size(BTRFS_EXTENT_OWNER_REF_KEY);
size += btrfs_extent_inline_ref_size(type);
+ extent_root = btrfs_extent_root(fs_info, ins->objectid);
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ ins->objectid);
+ return -EUCLEAN;
+ }
+
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- extent_root = btrfs_extent_root(fs_info, ins->objectid);
ret = btrfs_insert_empty_item(trans, extent_root, path, ins, size);
if (ret) {
btrfs_free_path(path);
@@ -5019,11 +5100,18 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
size += sizeof(*block_info);
}
+ extent_root = btrfs_extent_root(fs_info, extent_key.objectid);
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ extent_key.objectid);
+ return -EUCLEAN;
+ }
+
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- extent_root = btrfs_extent_root(fs_info, extent_key.objectid);
ret = btrfs_insert_empty_item(trans, extent_root, path, &extent_key,
size);
if (ret) {
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 927324a2175a..ed8ecf44fbd0 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -308,6 +308,13 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info,
/* Current item doesn't contain the desired range, search again */
btrfs_release_path(path);
csum_root = btrfs_csum_root(fs_info, disk_bytenr);
+ if (unlikely(!csum_root)) {
+ btrfs_err(fs_info,
+ "missing csum root for extent at bytenr %llu",
+ disk_bytenr);
+ return -EUCLEAN;
+ }
+
item = btrfs_lookup_csum(NULL, csum_root, path, disk_bytenr, 0);
if (IS_ERR(item)) {
ret = PTR_ERR(item);
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index ecddfca92b2b..9efd1ec90f03 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1073,6 +1073,14 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
if (ret)
return ret;
+ extent_root = btrfs_extent_root(trans->fs_info, block_group->start);
+ if (unlikely(!extent_root)) {
+ btrfs_err(trans->fs_info,
+ "missing extent root for block group at offset %llu",
+ block_group->start);
+ return -EUCLEAN;
+ }
+
mutex_lock(&block_group->free_space_lock);
/*
@@ -1086,7 +1094,6 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0;
- extent_root = btrfs_extent_root(trans->fs_info, key.objectid);
ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0);
if (ret < 0)
goto out_locked;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a6da98435ef7..f643a0520872 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2012,6 +2012,13 @@ static int can_nocow_file_extent(struct btrfs_path *path,
*/
csum_root = btrfs_csum_root(root->fs_info, io_start);
+ if (unlikely(!csum_root)) {
+ btrfs_err(root->fs_info,
+ "missing csum root for extent at bytenr %llu", io_start);
+ ret = -EUCLEAN;
+ goto out;
+ }
+
ret = btrfs_lookup_csums_list(csum_root, io_start,
io_start + args->file_extent.num_bytes - 1,
NULL, nowait);
@@ -2749,10 +2756,17 @@ static int add_pending_csums(struct btrfs_trans_handle *trans,
int ret;
list_for_each_entry(sum, list, list) {
- trans->adding_csums = true;
- if (!csum_root)
+ if (!csum_root) {
csum_root = btrfs_csum_root(trans->fs_info,
sum->logical);
+ if (unlikely(!csum_root)) {
+ btrfs_err(trans->fs_info,
+ "missing csum root for extent at bytenr %llu",
+ sum->logical);
+ return -EUCLEAN;
+ }
+ }
+ trans->adding_csums = true;
ret = btrfs_csum_file_blocks(trans, csum_root, sum);
trans->adding_csums = false;
if (ret)
@@ -9874,6 +9888,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
int compression;
size_t orig_count;
const u32 min_folio_size = btrfs_min_folio_size(fs_info);
+ const u32 blocksize = fs_info->sectorsize;
u64 start, end;
u64 num_bytes, ram_bytes, disk_num_bytes;
struct btrfs_key ins;
@@ -9984,9 +9999,9 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
ret = -EFAULT;
goto out_cb;
}
- if (bytes < min_folio_size)
- folio_zero_range(folio, bytes, min_folio_size - bytes);
- ret = bio_add_folio(&cb->bbio.bio, folio, folio_size(folio), 0);
+ if (!IS_ALIGNED(bytes, blocksize))
+ folio_zero_range(folio, bytes, round_up(bytes, blocksize) - bytes);
+ ret = bio_add_folio(&cb->bbio.bio, folio, round_up(bytes, blocksize), 0);
if (unlikely(!ret)) {
folio_put(folio);
ret = -EINVAL;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index b805dd9227ef..d75d31b606e4 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3617,7 +3617,8 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
}
}
- trans = btrfs_join_transaction(root);
+ /* 2 BTRFS_QGROUP_RELATION_KEY items. */
+ trans = btrfs_start_transaction(root, 2);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
@@ -3689,7 +3690,11 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
goto out;
}
- trans = btrfs_join_transaction(root);
+ /*
+ * 1 BTRFS_QGROUP_INFO_KEY item.
+ * 1 BTRFS_QGROUP_LIMIT_KEY item.
+ */
+ trans = btrfs_start_transaction(root, 2);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
@@ -3738,7 +3743,8 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
goto drop_write;
}
- trans = btrfs_join_transaction(root);
+ /* 1 BTRFS_QGROUP_LIMIT_KEY item. */
+ trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 049a940ba449..79642e02181b 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -429,7 +429,7 @@ static void copy_compressed_segment(struct compressed_bio *cb,
int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
{
struct workspace *workspace = list_entry(ws, struct workspace, list);
- const struct btrfs_fs_info *fs_info = cb->bbio.inode->root->fs_info;
+ struct btrfs_fs_info *fs_info = cb->bbio.inode->root->fs_info;
const u32 sectorsize = fs_info->sectorsize;
struct folio_iter fi;
char *kaddr;
@@ -447,7 +447,7 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
/* There must be a compressed folio and matches the sectorsize. */
if (unlikely(!fi.folio))
return -EINVAL;
- ASSERT(folio_size(fi.folio) == sectorsize);
+ ASSERT(folio_size(fi.folio) == btrfs_min_folio_size(fs_info));
kaddr = kmap_local_folio(fi.folio, 0);
len_in = read_compress_length(kaddr);
kunmap_local(kaddr);
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 3b2a6517d0b5..41589ce66371 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -3739,6 +3739,14 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
mutex_lock(&fs_info->qgroup_rescan_lock);
extent_root = btrfs_extent_root(fs_info,
fs_info->qgroup_rescan_progress.objectid);
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ fs_info->qgroup_rescan_progress.objectid);
+ mutex_unlock(&fs_info->qgroup_rescan_lock);
+ return -EUCLEAN;
+ }
+
ret = btrfs_search_slot_for_read(extent_root,
&fs_info->qgroup_rescan_progress,
path, 1, 0);
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index b4511f560e92..02105d68accb 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -2297,8 +2297,7 @@ void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc,
static void fill_data_csums(struct btrfs_raid_bio *rbio)
{
struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
- struct btrfs_root *csum_root = btrfs_csum_root(fs_info,
- rbio->bioc->full_stripe_logical);
+ struct btrfs_root *csum_root;
const u64 start = rbio->bioc->full_stripe_logical;
const u32 len = (rbio->nr_data * rbio->stripe_nsectors) <<
fs_info->sectorsize_bits;
@@ -2331,6 +2330,15 @@ static void fill_data_csums(struct btrfs_raid_bio *rbio)
goto error;
}
+ csum_root = btrfs_csum_root(fs_info, rbio->bioc->full_stripe_logical);
+ if (unlikely(!csum_root)) {
+ btrfs_err(fs_info,
+ "missing csum root for extent at bytenr %llu",
+ rbio->bioc->full_stripe_logical);
+ ret = -EUCLEAN;
+ goto error;
+ }
+
ret = btrfs_lookup_csums_bitmap(csum_root, NULL, start, start + len - 1,
rbio->csum_buf, rbio->csum_bitmap);
if (ret < 0)
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index b2343aed7a5d..033f74fd6225 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -4185,6 +4185,8 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
dest_addr = ins.objectid;
dest_length = ins.offset;
+ dest_bg = btrfs_lookup_block_group(fs_info, dest_addr);
+
if (!is_data && !IS_ALIGNED(dest_length, fs_info->nodesize)) {
u64 new_length = ALIGN_DOWN(dest_length, fs_info->nodesize);
@@ -4295,15 +4297,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
if (unlikely(ret))
goto end;
- dest_bg = btrfs_lookup_block_group(fs_info, dest_addr);
-
adjust_block_group_remap_bytes(trans, dest_bg, dest_length);
mutex_lock(&dest_bg->free_space_lock);
bg_needs_free_space = test_bit(BLOCK_GROUP_FLAG_NEEDS_FREE_SPACE,
&dest_bg->runtime_flags);
mutex_unlock(&dest_bg->free_space_lock);
- btrfs_put_block_group(dest_bg);
if (bg_needs_free_space) {
ret = btrfs_add_block_group_free_space(trans, dest_bg);
@@ -4333,13 +4332,13 @@ end:
btrfs_end_transaction(trans);
}
} else {
- dest_bg = btrfs_lookup_block_group(fs_info, dest_addr);
btrfs_free_reserved_bytes(dest_bg, dest_length, 0);
- btrfs_put_block_group(dest_bg);
ret = btrfs_commit_transaction(trans);
}
+ btrfs_put_block_group(dest_bg);
+
return ret;
}
@@ -4954,6 +4953,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
struct btrfs_space_info *sinfo = src_bg->space_info;
extent_root = btrfs_extent_root(fs_info, src_bg->start);
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for block group at offset %llu",
+ src_bg->start);
+ return -EUCLEAN;
+ }
trans = btrfs_start_transaction(extent_root, 0);
if (IS_ERR(trans))
@@ -5306,6 +5311,13 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start,
int ret;
bool bg_is_ro = false;
+ if (unlikely(!extent_root)) {
+ btrfs_err(fs_info,
+ "missing extent root for block group at offset %llu",
+ group_start);
+ return -EUCLEAN;
+ }
+
/*
* This only gets set if we had a half-deleted snapshot on mount. We
* cannot allow relocation to start while we're still trying to clean up
@@ -5536,12 +5548,17 @@ int btrfs_recover_relocation(struct btrfs_fs_info *fs_info)
goto out;
}
+ rc->extent_root = btrfs_extent_root(fs_info, 0);
+ if (unlikely(!rc->extent_root)) {
+ btrfs_err(fs_info, "missing extent root for extent at bytenr 0");
+ ret = -EUCLEAN;
+ goto out;
+ }
+
ret = reloc_chunk_start(fs_info);
if (ret < 0)
goto out_end;
- rc->extent_root = btrfs_extent_root(fs_info, 0);
-
set_reloc_control(rc);
trans = btrfs_join_transaction(rc->extent_root);
@@ -5636,6 +5653,14 @@ int btrfs_reloc_clone_csums(struct btrfs_ordered_extent *ordered)
LIST_HEAD(list);
int ret;
+ if (unlikely(!csum_root)) {
+ btrfs_mark_ordered_extent_error(ordered);
+ btrfs_err(fs_info,
+ "missing csum root for extent at bytenr %llu",
+ disk_bytenr);
+ return -EUCLEAN;
+ }
+
ret = btrfs_lookup_csums_list(csum_root, disk_bytenr,
disk_bytenr + ordered->num_bytes - 1,
&list, false);
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 516ef62c8f43..b4e114efff45 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1288,6 +1288,23 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
btrfs_root_drop_level(&ri), BTRFS_MAX_LEVEL - 1);
return -EUCLEAN;
}
+ /*
+ * If drop_progress.objectid is non-zero, a btrfs_drop_snapshot() was
+ * interrupted and the resume point was recorded in drop_progress and
+ * drop_level. In that case drop_level must be >= 1: level 0 is the
+ * leaf level and drop_snapshot never saves a checkpoint there (it
+ * only records checkpoints at internal node levels in DROP_REFERENCE
+ * stage). A zero drop_level combined with a non-zero drop_progress
+ * objectid indicates on-disk corruption and would cause a BUG_ON in
+ * merge_reloc_root() and btrfs_drop_snapshot() at mount time.
+ */
+ if (unlikely(btrfs_disk_key_objectid(&ri.drop_progress) != 0 &&
+ btrfs_root_drop_level(&ri) == 0)) {
+ generic_err(leaf, slot,
+ "invalid root drop_level 0 with non-zero drop_progress objectid %llu",
+ btrfs_disk_key_objectid(&ri.drop_progress));
+ return -EUCLEAN;
+ }
/* Flags check */
if (unlikely(btrfs_root_flags(&ri) & ~valid_root_flags)) {
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 552fef3c385a..ab0d460c7139 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -984,6 +984,13 @@ static noinline int replay_one_extent(struct walk_control *wc)
sums = list_first_entry(&ordered_sums, struct btrfs_ordered_sum, list);
csum_root = btrfs_csum_root(fs_info, sums->logical);
+ if (unlikely(!csum_root)) {
+ btrfs_err(fs_info,
+ "missing csum root for extent at bytenr %llu",
+ sums->logical);
+ ret = -EUCLEAN;
+ }
+
if (!ret) {
ret = btrfs_del_csums(trans, csum_root, sums->logical,
sums->len);
@@ -4890,6 +4897,13 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
}
csum_root = btrfs_csum_root(trans->fs_info, disk_bytenr);
+ if (unlikely(!csum_root)) {
+ btrfs_err(trans->fs_info,
+ "missing csum root for extent at bytenr %llu",
+ disk_bytenr);
+ return -EUCLEAN;
+ }
+
disk_bytenr += extent_offset;
ret = btrfs_lookup_csums_list(csum_root, disk_bytenr,
disk_bytenr + extent_num_bytes - 1,
@@ -5086,6 +5100,13 @@ static int log_extent_csums(struct btrfs_trans_handle *trans,
/* block start is already adjusted for the file extent offset. */
block_start = btrfs_extent_map_block_start(em);
csum_root = btrfs_csum_root(trans->fs_info, block_start);
+ if (unlikely(!csum_root)) {
+ btrfs_err(trans->fs_info,
+ "missing csum root for extent at bytenr %llu",
+ block_start);
+ return -EUCLEAN;
+ }
+
ret = btrfs_lookup_csums_list(csum_root, block_start + csum_offset,
block_start + csum_offset + csum_len - 1,
&ordered_sums, false);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index be8975ef8b24..ab51e6ecfdef 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4277,20 +4277,29 @@ static int balance_remap_chunks(struct btrfs_fs_info *fs_info, struct btrfs_path
end:
while (!list_empty(chunks)) {
bool is_unused;
+ struct btrfs_block_group *bg;
rci = list_first_entry(chunks, struct remap_chunk_info, list);
- spin_lock(&rci->bg->lock);
- is_unused = !btrfs_is_block_group_used(rci->bg);
- spin_unlock(&rci->bg->lock);
+ bg = rci->bg;
+ if (bg) {
+ /*
+ * This is a bit racy and the 'used' status can change
+ * but this is not a problem as later functions will
+ * verify it again.
+ */
+ spin_lock(&bg->lock);
+ is_unused = !btrfs_is_block_group_used(bg);
+ spin_unlock(&bg->lock);
- if (is_unused)
- btrfs_mark_bg_unused(rci->bg);
+ if (is_unused)
+ btrfs_mark_bg_unused(bg);
- if (rci->made_ro)
- btrfs_dec_block_group_ro(rci->bg);
+ if (rci->made_ro)
+ btrfs_dec_block_group_ro(bg);
- btrfs_put_block_group(rci->bg);
+ btrfs_put_block_group(bg);
+ }
list_del(&rci->list);
kfree(rci);
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 817ca4fb9efa..0cd7fd3fcfa3 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -1261,6 +1261,13 @@ static int calculate_alloc_pointer(struct btrfs_block_group *cache,
key.offset = 0;
root = btrfs_extent_root(fs_info, key.objectid);
+ if (unlikely(!root)) {
+ btrfs_err(fs_info,
+ "missing extent root for extent at bytenr %llu",
+ key.objectid);
+ return -EUCLEAN;
+ }
+
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
/* We should not find the exact match */
if (unlikely(!ret))
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
index 6f076fa8f3f9..3e847b91dae3 100644
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -600,7 +600,7 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
bio_first_folio(&fi, &cb->bbio.bio, 0);
if (unlikely(!fi.folio))
return -EINVAL;
- ASSERT(folio_size(fi.folio) == blocksize);
+ ASSERT(folio_size(fi.folio) == min_folio_size);
stream = zstd_init_dstream(
ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);