diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-20 14:57:09 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-20 14:57:09 -0800 |
| commit | b3f1da2a4d851b8e1ccf932e52c6772fe2253a47 (patch) | |
| tree | 6e307f51e8fc402284da126257489a5293ca2706 | |
| parent | 233a0c0f4498309f98d98a4b6543fa05a12d9587 (diff) | |
| parent | ecb7c2484cfc83a93658907580035a8adf1e0a92 (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.c | 8 | ||||
| -rw-r--r-- | fs/btrfs/block-group.c | 10 | ||||
| -rw-r--r-- | fs/btrfs/block-rsv.c | 7 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 10 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 15 | ||||
| -rw-r--r-- | fs/btrfs/qgroup.c | 11 | ||||
| -rw-r--r-- | fs/btrfs/root-tree.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/transaction.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/verity.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 10 |
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); |
