summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-20 14:57:09 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-20 14:57:09 -0800
commitb3f1da2a4d851b8e1ccf932e52c6772fe2253a47 (patch)
tree6e307f51e8fc402284da126257489a5293ca2706
parent233a0c0f4498309f98d98a4b6543fa05a12d9587 (diff)
parentecb7c2484cfc83a93658907580035a8adf1e0a92 (diff)
Merge tag 'for-7.0-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - multiple error handling fixes of unexpected conditions - reset block group size class once it becomes empty so that its class can be changed - error message level adjustments - fixes of returned error values - use correct block reserve for delayed refs * tag 'for-7.0-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix invalid leaf access in btrfs_quota_enable() if ref key not found btrfs: fix lost error return in btrfs_find_orphan_roots() btrfs: fix lost return value on error in finish_verity() btrfs: change unaligned root messages to error level in btrfs_validate_super() btrfs: use the correct type to initialize block reserve for delayed refs btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure() btrfs: reset block group size class when it becomes empty btrfs: replace BUG() with error handling in __btrfs_balance() btrfs: handle unexpected exact match in btrfs_set_inode_index_count()
-rw-r--r--fs/btrfs/bio.c8
-rw-r--r--fs/btrfs/block-group.c10
-rw-r--r--fs/btrfs/block-rsv.c7
-rw-r--r--fs/btrfs/disk-io.c10
-rw-r--r--fs/btrfs/inode.c15
-rw-r--r--fs/btrfs/qgroup.c11
-rw-r--r--fs/btrfs/root-tree.c2
-rw-r--r--fs/btrfs/transaction.c2
-rw-r--r--fs/btrfs/verity.c2
-rw-r--r--fs/btrfs/volumes.c10
10 files changed, 56 insertions, 21 deletions
diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
index 0a69e09bfe28..4a1528803ff7 100644
--- a/fs/btrfs/bio.c
+++ b/fs/btrfs/bio.c
@@ -934,7 +934,6 @@ int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 fileoff,
struct bio *bio = NULL;
int ret = 0;
- ASSERT(!(fs_info->sb->s_flags & SB_RDONLY));
BUG_ON(!mirror_num);
/* Basic alignment checks. */
@@ -946,6 +945,13 @@ int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 fileoff,
ASSERT(step <= length);
ASSERT(is_power_of_2(step));
+ /*
+ * The fs either mounted RO or hit critical errors, no need
+ * to continue repairing.
+ */
+ if (unlikely(sb_rdonly(fs_info->sb)))
+ return 0;
+
if (btrfs_repair_one_zone(fs_info, logical))
return 0;
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 3186ed4fd26d..5f76683b3f21 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -3760,6 +3760,14 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)
return ret;
}
+static void btrfs_maybe_reset_size_class(struct btrfs_block_group *bg)
+{
+ lockdep_assert_held(&bg->lock);
+ if (btrfs_block_group_should_use_size_class(bg) &&
+ bg->used == 0 && bg->reserved == 0)
+ bg->size_class = BTRFS_BG_SZ_NONE;
+}
+
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, bool alloc)
{
@@ -3824,6 +3832,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
old_val -= num_bytes;
cache->used = old_val;
cache->pinned += num_bytes;
+ btrfs_maybe_reset_size_class(cache);
btrfs_space_info_update_bytes_pinned(space_info, num_bytes);
space_info->bytes_used -= num_bytes;
space_info->disk_used -= num_bytes * factor;
@@ -3952,6 +3961,7 @@ void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, u64 num_bytes,
spin_lock(&cache->lock);
bg_ro = cache->ro;
cache->reserved -= num_bytes;
+ btrfs_maybe_reset_size_class(cache);
if (is_delalloc)
cache->delalloc_bytes -= num_bytes;
spin_unlock(&cache->lock);
diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
index e823230c09b7..93c371db8731 100644
--- a/fs/btrfs/block-rsv.c
+++ b/fs/btrfs/block-rsv.c
@@ -276,10 +276,11 @@ u64 btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *target = NULL;
/*
- * If we are a delayed block reserve then push to the global rsv,
- * otherwise dump into the global delayed reserve if it is not full.
+ * If we are a delayed refs block reserve then push to the global
+ * reserve, otherwise dump into the global delayed refs reserve if it is
+ * not full.
*/
- if (block_rsv->type == BTRFS_BLOCK_RSV_DELOPS)
+ if (block_rsv->type == BTRFS_BLOCK_RSV_DELREFS)
target = global_rsv;
else if (block_rsv != global_rsv && !btrfs_block_rsv_full(delayed_rsv))
target = delayed_rsv;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 20c405a4789d..13e400046c87 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2416,18 +2416,18 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info,
/* Root alignment check */
if (!IS_ALIGNED(btrfs_super_root(sb), sectorsize)) {
- btrfs_warn(fs_info, "tree_root block unaligned: %llu",
- btrfs_super_root(sb));
+ btrfs_err(fs_info, "tree_root block unaligned: %llu",
+ btrfs_super_root(sb));
ret = -EINVAL;
}
if (!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize)) {
- btrfs_warn(fs_info, "chunk_root block unaligned: %llu",
+ btrfs_err(fs_info, "chunk_root block unaligned: %llu",
btrfs_super_chunk_root(sb));
ret = -EINVAL;
}
if (!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize)) {
- btrfs_warn(fs_info, "log_root block unaligned: %llu",
- btrfs_super_log_root(sb));
+ btrfs_err(fs_info, "log_root block unaligned: %llu",
+ btrfs_super_log_root(sb));
ret = -EINVAL;
}
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 845164485a00..5bbbce2224a1 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6146,9 +6146,18 @@ static int btrfs_set_inode_index_count(struct btrfs_inode *inode)
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
return ret;
- /* FIXME: we should be able to handle this */
- if (ret == 0)
- return ret;
+
+ if (unlikely(ret == 0)) {
+ /*
+ * Key with offset -1 found, there would have to exist a dir
+ * index item with such offset, but this is out of the valid
+ * range.
+ */
+ btrfs_err(root->fs_info,
+ "unexpected exact match for DIR_INDEX key, inode %llu",
+ btrfs_ino(inode));
+ return -EUCLEAN;
+ }
if (path->slots[0] == 0) {
inode->index_cnt = BTRFS_DIR_START_INDEX;
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index f53c313ab6e4..38adadb936dc 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1169,11 +1169,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
}
if (ret > 0) {
/*
- * Shouldn't happen, but in case it does we
- * don't need to do the btrfs_next_item, just
- * continue.
+ * Shouldn't happen because the key should still
+ * be there (return 0), but in case it does it
+ * means we have reached the end of the tree -
+ * there are no more leaves with items that have
+ * a key greater than or equals to @found_key,
+ * so just stop the search loop.
*/
- continue;
+ break;
}
}
ret = btrfs_next_item(tree_root, path);
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 37a4173c0a0b..d85a09ae1733 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -257,7 +257,7 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info)
root = btrfs_get_fs_root(fs_info, root_objectid, false);
ret = PTR_ERR_OR_ZERO(root);
if (ret && ret != -ENOENT) {
- break;
+ return ret;
} else if (ret == -ENOENT) {
struct btrfs_trans_handle *trans;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 0b2498749b1e..463238ca8a4d 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -726,7 +726,7 @@ again:
h->type = type;
INIT_LIST_HEAD(&h->new_bgs);
- btrfs_init_metadata_block_rsv(fs_info, &h->delayed_rsv, BTRFS_BLOCK_RSV_DELOPS);
+ btrfs_init_metadata_block_rsv(fs_info, &h->delayed_rsv, BTRFS_BLOCK_RSV_DELREFS);
smp_mb();
if (cur_trans->state >= TRANS_STATE_COMMIT_START &&
diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c
index d12537a212e9..0062b3a55781 100644
--- a/fs/btrfs/verity.c
+++ b/fs/btrfs/verity.c
@@ -552,7 +552,7 @@ static int finish_verity(struct btrfs_inode *inode, const void *desc,
btrfs_set_fs_compat_ro(root->fs_info, VERITY);
end_trans:
btrfs_end_transaction(trans);
- return 0;
+ return ret;
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f281d113519b..50f7aae70418 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4367,8 +4367,14 @@ again:
* this shouldn't happen, it means the last relocate
* failed
*/
- if (ret == 0)
- BUG(); /* FIXME break ? */
+ if (unlikely(ret == 0)) {
+ btrfs_err(fs_info,
+ "unexpected exact match of CHUNK_ITEM in chunk tree, offset 0x%llx",
+ key.offset);
+ mutex_unlock(&fs_info->reclaim_bgs_lock);
+ ret = -EUCLEAN;
+ goto error;
+ }
ret = btrfs_previous_item(chunk_root, path, 0,
BTRFS_CHUNK_ITEM_KEY);