summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-03-03 09:08:00 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-03-03 09:08:00 -0800
commitc44db6c820140ffbc0e293a34c6a6de4b363422b (patch)
treee5ff2c89969c7582f09fde3b7dd918117ff11a5d
parentaf4e9ef3d78420feb8fe58cd9a1ab80c501b3c08 (diff)
parentf8db8009ea65297dba7786668d4561f6dbd99678 (diff)
Merge tag 'for-7.0-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "One-liner or short fixes for minor/moderate problems reported recently: - fixes or level adjustments of error messages - fix leaked transaction handles after aborted transactions, when using the remap tree feature - fix a few leaked chunk maps after errors - fix leaked page array in io_uring encoded read if an error occurs and the 'finished' is not called - fix double release of reserved extents when doing a range COW - don't commit super block when the filesystem is in shutdown state - fix squota accounting condition when checking members vs parent usage - other error handling fixes" * tag 'for-7.0-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: check block group lookup in remove_range_from_remap_tree() btrfs: fix transaction handle leaks in btrfs_last_identity_remap_gone() btrfs: fix chunk map leak in btrfs_map_block() after btrfs_translate_remap() btrfs: fix chunk map leak in btrfs_map_block() after btrfs_chunk_map_num_copies() btrfs: fix compat mask in error messages in btrfs_check_features() btrfs: print correct subvol num if active swapfile prevents deletion btrfs: fix warning in scrub_verify_one_metadata() btrfs: fix objectid value in error message in check_extent_data_ref() btrfs: fix incorrect key offset in error message in check_dev_extent_item() btrfs: fix error message order of parameters in btrfs_delete_delayed_dir_index() btrfs: don't commit the super block when unmounting a shutdown filesystem btrfs: free pages on error in btrfs_uring_read_extent() btrfs: fix referenced/exclusive check in squota_check_parent_usage() btrfs: remove pointless WARN_ON() in cache_save_setup() btrfs: convert log messages to error level in btrfs_replay_log() btrfs: remove btrfs_handle_fs_error() after failure to recover log trees btrfs: remove redundant warning message in btrfs_check_uuid_tree() btrfs: change warning messages to error level in open_ctree() btrfs: fix a double release on reserved extents in cow_one_range() btrfs: handle discard errors in in btrfs_finish_extent_commit()
-rw-r--r--fs/btrfs/block-group.c1
-rw-r--r--fs/btrfs/delayed-inode.c2
-rw-r--r--fs/btrfs/disk-io.c36
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/inode.c19
-rw-r--r--fs/btrfs/ioctl.c7
-rw-r--r--fs/btrfs/qgroup.c2
-rw-r--r--fs/btrfs/relocation.c6
-rw-r--r--fs/btrfs/scrub.c2
-rw-r--r--fs/btrfs/tree-checker.c4
-rw-r--r--fs/btrfs/volumes.c8
11 files changed, 67 insertions, 28 deletions
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index c284f48cfae4..2a886bece810 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -3340,7 +3340,6 @@ again:
btrfs_abort_transaction(trans, ret);
goto out_put;
}
- WARN_ON(ret);
/* We've already setup this transaction, go ahead and exit */
if (block_group->cache_generation == trans->transid &&
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index d97bbbd045e0..56ff8afe9a22 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1657,7 +1657,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
if (unlikely(ret)) {
btrfs_err(trans->fs_info,
"failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %d",
- index, btrfs_root_id(node->root), node->inode_id, ret);
+ btrfs_root_id(node->root), node->inode_id, index, ret);
btrfs_delayed_item_release_metadata(dir->root, item);
btrfs_release_delayed_item(item);
}
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index f6fa15a1193f..e4fad777b034 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1994,7 +1994,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
int level = btrfs_super_log_root_level(disk_super);
if (unlikely(fs_devices->rw_devices == 0)) {
- btrfs_warn(fs_info, "log replay required on RO media");
+ btrfs_err(fs_info, "log replay required on RO media");
return -EIO;
}
@@ -2008,9 +2008,9 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
check.owner_root = BTRFS_TREE_LOG_OBJECTID;
log_tree_root->node = read_tree_block(fs_info, bytenr, &check);
if (IS_ERR(log_tree_root->node)) {
- btrfs_warn(fs_info, "failed to read log tree");
ret = PTR_ERR(log_tree_root->node);
log_tree_root->node = NULL;
+ btrfs_err(fs_info, "failed to read log tree with error: %d", ret);
btrfs_put_root(log_tree_root);
return ret;
}
@@ -2023,9 +2023,9 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
/* returns with log_tree_root freed on success */
ret = btrfs_recover_log_trees(log_tree_root);
btrfs_put_root(log_tree_root);
- if (ret) {
- btrfs_handle_fs_error(fs_info, ret,
- "Failed to recover log tree");
+ if (unlikely(ret)) {
+ ASSERT(BTRFS_FS_ERROR(fs_info) != 0);
+ btrfs_err(fs_info, "failed to recover log trees with error: %d", ret);
return ret;
}
@@ -2972,7 +2972,6 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid");
if (IS_ERR(task)) {
/* fs_info->update_uuid_tree_gen remains 0 in all error case */
- btrfs_warn(fs_info, "failed to start uuid_rescan task");
up(&fs_info->uuid_tree_rescan_sem);
return PTR_ERR(task);
}
@@ -3188,7 +3187,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
if (incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP) {
btrfs_err(fs_info,
"cannot mount because of unknown incompat features (0x%llx)",
- incompat);
+ incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP);
return -EINVAL;
}
@@ -3220,7 +3219,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
if (compat_ro_unsupp && is_rw_mount) {
btrfs_err(fs_info,
"cannot mount read-write because of unknown compat_ro features (0x%llx)",
- compat_ro);
+ compat_ro_unsupp);
return -EINVAL;
}
@@ -3233,7 +3232,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
!btrfs_test_opt(fs_info, NOLOGREPLAY)) {
btrfs_err(fs_info,
"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
- compat_ro);
+ compat_ro_unsupp);
return -EINVAL;
}
@@ -3642,7 +3641,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
fs_info->fs_root = btrfs_get_fs_root(fs_info, BTRFS_FS_TREE_OBJECTID, true);
if (IS_ERR(fs_info->fs_root)) {
ret = PTR_ERR(fs_info->fs_root);
- btrfs_warn(fs_info, "failed to read fs tree: %d", ret);
+ btrfs_err(fs_info, "failed to read fs tree: %d", ret);
fs_info->fs_root = NULL;
goto fail_qgroup;
}
@@ -3663,8 +3662,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
btrfs_info(fs_info, "checking UUID tree");
ret = btrfs_check_uuid_tree(fs_info);
if (ret) {
- btrfs_warn(fs_info,
- "failed to check the UUID tree: %d", ret);
+ btrfs_err(fs_info, "failed to check the UUID tree: %d", ret);
close_ctree(fs_info);
return ret;
}
@@ -4399,9 +4397,17 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
*/
btrfs_flush_workqueue(fs_info->delayed_workers);
- ret = btrfs_commit_super(fs_info);
- if (ret)
- btrfs_err(fs_info, "commit super ret %d", ret);
+ /*
+ * If the filesystem is shutdown, then an attempt to commit the
+ * super block (or any write) will just fail. Since we freeze
+ * the filesystem before shutting it down, the filesystem is in
+ * a consistent state and we don't need to commit super blocks.
+ */
+ if (!btrfs_is_shutdown(fs_info)) {
+ ret = btrfs_commit_super(fs_info);
+ if (ret)
+ btrfs_err(fs_info, "commit super block returned %d", ret);
+ }
}
kthread_stop(fs_info->transaction_kthread);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 03cf9f242c70..b0d9baf5b412 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2933,9 +2933,15 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
while (!TRANS_ABORTED(trans) && cached_state) {
struct extent_state *next_state;
- if (btrfs_test_opt(fs_info, DISCARD_SYNC))
+ if (btrfs_test_opt(fs_info, DISCARD_SYNC)) {
ret = btrfs_discard_extent(fs_info, start,
end + 1 - start, NULL, true);
+ if (ret) {
+ btrfs_warn(fs_info,
+ "discard failed for extent [%llu, %llu]: errno=%d %s",
+ start, end, ret, btrfs_decode_error(ret));
+ }
+ }
next_state = btrfs_next_extent_state(unpin, cached_state);
btrfs_clear_extent_dirty(unpin, start, end, &cached_state);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6efb543f1c24..a11fcc9e9f50 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1392,10 +1392,25 @@ static int cow_one_range(struct btrfs_inode *inode, struct folio *locked_folio,
return ret;
free_reserved:
+ /*
+ * If we have reserved an extent for the current range and failed to
+ * create the respective extent map or ordered extent, it means that
+ * when we reserved the extent we decremented the extent's size from
+ * the data space_info's bytes_may_use counter and
+ * incremented the space_info's bytes_reserved counter by the same
+ * amount.
+ *
+ * We must make sure extent_clear_unlock_delalloc() does not try
+ * to decrement again the data space_info's bytes_may_use counter, which
+ * will be handled by btrfs_free_reserved_extent().
+ *
+ * Therefore we do not pass it the flag EXTENT_CLEAR_DATA_RESV, but only
+ * EXTENT_CLEAR_META_RESV.
+ */
extent_clear_unlock_delalloc(inode, file_offset, cur_end, locked_folio, cached,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW |
- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
+ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV,
PAGE_UNLOCK | PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK);
btrfs_qgroup_free_data(inode, NULL, file_offset, cur_len, NULL);
@@ -4764,7 +4779,7 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
spin_unlock(&dest->root_item_lock);
btrfs_warn(fs_info,
"attempt to delete subvolume %llu with active swapfile",
- btrfs_root_id(root));
+ btrfs_root_id(dest));
ret = -EPERM;
goto out_up_write;
}
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index ae2173235c4d..a1fd44c44ecf 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -4581,7 +4581,7 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
{
struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
struct extent_io_tree *io_tree = &inode->io_tree;
- struct page **pages;
+ struct page **pages = NULL;
struct btrfs_uring_priv *priv = NULL;
unsigned long nr_pages;
int ret;
@@ -4639,6 +4639,11 @@ out_fail:
btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
kfree(priv);
+ for (int i = 0; i < nr_pages; i++) {
+ if (pages[i])
+ __free_page(pages[i]);
+ }
+ kfree(pages);
return ret;
}
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 3cdd9755dc52..3b2a6517d0b5 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -370,7 +370,7 @@ static bool squota_check_parent_usage(struct btrfs_fs_info *fs_info, struct btrf
nr_members++;
}
mismatch = (parent->excl != excl_sum || parent->rfer != rfer_sum ||
- parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != excl_cmpr_sum);
+ parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != rfer_cmpr_sum);
WARN(mismatch,
"parent squota qgroup %hu/%llu has mismatched usage from its %d members. "
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 95db7c48fbad..a330d8624b83 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -4723,6 +4723,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
ret = btrfs_remove_dev_extents(trans, chunk_map);
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
return ret;
}
@@ -4732,6 +4733,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
if (unlikely(ret)) {
mutex_unlock(&trans->fs_info->chunk_mutex);
btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
return ret;
}
}
@@ -4750,6 +4752,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
ret = remove_chunk_stripes(trans, chunk_map, path);
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
return ret;
}
@@ -5982,6 +5985,9 @@ static int remove_range_from_remap_tree(struct btrfs_trans_handle *trans,
struct btrfs_block_group *dest_bg;
dest_bg = btrfs_lookup_block_group(fs_info, new_addr);
+ if (unlikely(!dest_bg))
+ return -EUCLEAN;
+
adjust_block_group_remap_bytes(trans, dest_bg, -overlap_length);
btrfs_put_block_group(dest_bg);
ret = btrfs_add_to_free_space_tree(trans,
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 81022d912abb..bc94bbc00772 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -743,7 +743,7 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
btrfs_warn_rl(fs_info,
"scrub: tree block %llu mirror %u has bad fsid, has %pU want %pU",
logical, stripe->mirror_num,
- header->fsid, fs_info->fs_devices->fsid);
+ header->fsid, fs_info->fs_devices->metadata_uuid);
return;
}
if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 452394b34d01..ac4c4573ee39 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1740,7 +1740,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
objectid > BTRFS_LAST_FREE_OBJECTID)) {
extent_err(leaf, slot,
"invalid extent data backref objectid value %llu",
- root);
+ objectid);
return -EUCLEAN;
}
if (unlikely(!IS_ALIGNED(offset, leaf->fs_info->sectorsize))) {
@@ -1921,7 +1921,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf,
if (unlikely(prev_key->offset + prev_len > key->offset)) {
generic_err(leaf, slot,
"dev extent overlap, prev offset %llu len %llu current offset %llu",
- prev_key->objectid, prev_len, key->offset);
+ prev_key->offset, prev_len, key->offset);
return -EUCLEAN;
}
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6fb0c4cd50ff..648bb09fc416 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6907,7 +6907,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
ret = btrfs_translate_remap(fs_info, &new_logical, length);
if (ret)
- return ret;
+ goto out;
if (new_logical != logical) {
btrfs_free_chunk_map(map);
@@ -6921,8 +6921,10 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
}
num_copies = btrfs_chunk_map_num_copies(map);
- if (io_geom.mirror_num > num_copies)
- return -EINVAL;
+ if (io_geom.mirror_num > num_copies) {
+ ret = -EINVAL;
+ goto out;
+ }
map_offset = logical - map->start;
io_geom.raid56_full_stripe_start = (u64)-1;