summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-01-17 19:29:32 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-01-17 19:29:32 -0800
commite84d960149e71e8d5e4db69775ce31305898ed0c (patch)
tree31b2c53d1e93ec99c216a27dfc6d64a39468a09b
parent47622aa8b66c8fb2af4aff584c3c7c17ca0686ea (diff)
parent437cc6057e01d98ee124496f045ede36224af326 (diff)
Merge tag 'for-6.19-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - with large folios in use, fix partial incorrect update of a reflinked range - fix potential deadlock in iget when lookup fails and eviction is needed - in send, validate inline extent type while detecting file holes - fix memory leak after an error when creating a space info - remove zone statistics from sysfs again, the output size limitations make it unusable, we'll do it in another way in another release - test fixes: - return proper error codes from block remapping tests - fix tree root leaks in qgroup tests after errors * tag 'for-6.19-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: remove zoned statistics from sysfs btrfs: fix memory leaks in create_space_info() error paths btrfs: invalidate pages instead of truncate after reflinking btrfs: update the Kconfig string for CONFIG_BTRFS_EXPERIMENTAL btrfs: send: check for inline extents in range_is_hole_in_parent() btrfs: tests: fix return 0 on rmap test failure btrfs: tests: fix root tree leak in btrfs_test_qgroups() btrfs: release path before iget_failed() in btrfs_read_locked_inode()
-rw-r--r--fs/btrfs/Kconfig6
-rw-r--r--fs/btrfs/inode.c9
-rw-r--r--fs/btrfs/reflink.c23
-rw-r--r--fs/btrfs/send.c2
-rw-r--r--fs/btrfs/space-info.c8
-rw-r--r--fs/btrfs/sysfs.c52
-rw-r--r--fs/btrfs/tests/extent-map-tests.c3
-rw-r--r--fs/btrfs/tests/qgroup-tests.c6
8 files changed, 41 insertions, 68 deletions
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 4438637c8900..6d6fc85835d4 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -115,6 +115,10 @@ config BTRFS_EXPERIMENTAL
- extent tree v2 - complex rework of extent tracking
- - large folio support
+ - large folio and block size (> page size) support
+
+ - shutdown ioctl and auto-degradation support
+
+ - asynchronous checksum generation for data writes
If unsure, say N.
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d2b302ac6af9..a2b5b440637e 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4180,6 +4180,15 @@ cache_acl:
return 0;
out:
+ /*
+ * We may have a read locked leaf and iget_failed() triggers inode
+ * eviction which needs to release the delayed inode and that needs
+ * to lock the delayed inode's mutex. This can cause a ABBA deadlock
+ * with a task running delayed items, as that require first locking
+ * the delayed inode's mutex and then modifying its subvolume btree.
+ * So release the path before iget_failed().
+ */
+ btrfs_release_path(path);
iget_failed(vfs_inode);
return ret;
}
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
index b5fe95baf92e..58dc3e5057ce 100644
--- a/fs/btrfs/reflink.c
+++ b/fs/btrfs/reflink.c
@@ -705,7 +705,6 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
struct inode *src = file_inode(file_src);
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
int ret;
- int wb_ret;
u64 len = olen;
u64 bs = fs_info->sectorsize;
u64 end;
@@ -750,25 +749,29 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
btrfs_lock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);
ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);
+ if (ret < 0)
+ return ret;
/*
* We may have copied an inline extent into a page of the destination
- * range, so wait for writeback to complete before truncating pages
+ * range, so wait for writeback to complete before invalidating pages
* from the page cache. This is a rare case.
*/
- wb_ret = btrfs_wait_ordered_range(BTRFS_I(inode), destoff, len);
- ret = ret ? ret : wb_ret;
+ ret = btrfs_wait_ordered_range(BTRFS_I(inode), destoff, len);
+ if (ret < 0)
+ return ret;
+
/*
- * Truncate page cache pages so that future reads will see the cloned
- * data immediately and not the previous data.
+ * Invalidate page cache so that future reads will see the cloned data
+ * immediately and not the previous data.
*/
- truncate_inode_pages_range(&inode->i_data,
- round_down(destoff, PAGE_SIZE),
- round_up(destoff + len, PAGE_SIZE) - 1);
+ ret = filemap_invalidate_inode(inode, false, destoff, end);
+ if (ret < 0)
+ return ret;
btrfs_btree_balance_dirty(fs_info);
- return ret;
+ return 0;
}
static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 2522faa97478..d8127a7120c2 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -6383,6 +6383,8 @@ static int range_is_hole_in_parent(struct send_ctx *sctx,
extent_end = btrfs_file_extent_end(path);
if (extent_end <= start)
goto next;
+ if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE)
+ return 0;
if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0) {
search_start = extent_end;
goto next;
diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c
index 6babbe333741..3f08e450f796 100644
--- a/fs/btrfs/space-info.c
+++ b/fs/btrfs/space-info.c
@@ -306,18 +306,22 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags)
0);
if (ret)
- return ret;
+ goto out_free;
}
ret = btrfs_sysfs_add_space_info_type(space_info);
if (ret)
- return ret;
+ goto out_free;
list_add(&space_info->list, &info->space_info);
if (flags & BTRFS_BLOCK_GROUP_DATA)
info->data_sinfo = space_info;
return ret;
+
+out_free:
+ kfree(space_info);
+ return ret;
}
int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 1f64c132b387..4b3c2acac51a 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -26,7 +26,6 @@
#include "misc.h"
#include "fs.h"
#include "accessors.h"
-#include "zoned.h"
/*
* Structure name Path
@@ -1189,56 +1188,6 @@ static ssize_t btrfs_commit_stats_store(struct kobject *kobj,
}
BTRFS_ATTR_RW(, commit_stats, btrfs_commit_stats_show, btrfs_commit_stats_store);
-static ssize_t btrfs_zoned_stats_show(struct kobject *kobj,
- struct kobj_attribute *a, char *buf)
-{
- struct btrfs_fs_info *fs_info = to_fs_info(kobj);
- struct btrfs_block_group *bg;
- size_t ret = 0;
-
-
- if (!btrfs_is_zoned(fs_info))
- return ret;
-
- spin_lock(&fs_info->zone_active_bgs_lock);
- ret += sysfs_emit_at(buf, ret, "active block-groups: %zu\n",
- list_count_nodes(&fs_info->zone_active_bgs));
- spin_unlock(&fs_info->zone_active_bgs_lock);
-
- mutex_lock(&fs_info->reclaim_bgs_lock);
- spin_lock(&fs_info->unused_bgs_lock);
- ret += sysfs_emit_at(buf, ret, "\treclaimable: %zu\n",
- list_count_nodes(&fs_info->reclaim_bgs));
- ret += sysfs_emit_at(buf, ret, "\tunused: %zu\n",
- list_count_nodes(&fs_info->unused_bgs));
- spin_unlock(&fs_info->unused_bgs_lock);
- mutex_unlock(&fs_info->reclaim_bgs_lock);
-
- ret += sysfs_emit_at(buf, ret, "\tneed reclaim: %s\n",
- str_true_false(btrfs_zoned_should_reclaim(fs_info)));
-
- if (fs_info->data_reloc_bg)
- ret += sysfs_emit_at(buf, ret,
- "data relocation block-group: %llu\n",
- fs_info->data_reloc_bg);
- if (fs_info->treelog_bg)
- ret += sysfs_emit_at(buf, ret,
- "tree-log block-group: %llu\n",
- fs_info->treelog_bg);
-
- spin_lock(&fs_info->zone_active_bgs_lock);
- ret += sysfs_emit_at(buf, ret, "active zones:\n");
- list_for_each_entry(bg, &fs_info->zone_active_bgs, active_bg_list) {
- ret += sysfs_emit_at(buf, ret,
- "\tstart: %llu, wp: %llu used: %llu, reserved: %llu, unusable: %llu\n",
- bg->start, bg->alloc_offset, bg->used,
- bg->reserved, bg->zone_unusable);
- }
- spin_unlock(&fs_info->zone_active_bgs_lock);
- return ret;
-}
-BTRFS_ATTR(, zoned_stats, btrfs_zoned_stats_show);
-
static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
@@ -1651,7 +1600,6 @@ static const struct attribute *btrfs_attrs[] = {
BTRFS_ATTR_PTR(, bg_reclaim_threshold),
BTRFS_ATTR_PTR(, commit_stats),
BTRFS_ATTR_PTR(, temp_fsid),
- BTRFS_ATTR_PTR(, zoned_stats),
#ifdef CONFIG_BTRFS_EXPERIMENTAL
BTRFS_ATTR_PTR(, offload_csum),
#endif
diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c
index 0b9f25dd1a68..aabf825e8d7b 100644
--- a/fs/btrfs/tests/extent-map-tests.c
+++ b/fs/btrfs/tests/extent-map-tests.c
@@ -1059,6 +1059,7 @@ static int test_rmap_block(struct btrfs_fs_info *fs_info,
if (out_stripe_len != BTRFS_STRIPE_LEN) {
test_err("calculated stripe length doesn't match");
+ ret = -EINVAL;
goto out;
}
@@ -1066,12 +1067,14 @@ static int test_rmap_block(struct btrfs_fs_info *fs_info,
for (i = 0; i < out_ndaddrs; i++)
test_msg("mapped %llu", logical[i]);
test_err("unexpected number of mapped addresses: %d", out_ndaddrs);
+ ret = -EINVAL;
goto out;
}
for (i = 0; i < out_ndaddrs; i++) {
if (logical[i] != test->mapped_logical[i]) {
test_err("unexpected logical address mapped");
+ ret = -EINVAL;
goto out;
}
}
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index e9124605974b..0fcc31beeffe 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -517,11 +517,11 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID;
root->fs_info->fs_root = tmp_root;
ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
+ btrfs_put_root(tmp_root);
if (ret) {
test_err("couldn't insert fs root %d", ret);
goto out;
}
- btrfs_put_root(tmp_root);
tmp_root = btrfs_alloc_dummy_root(fs_info);
if (IS_ERR(tmp_root)) {
@@ -532,11 +532,11 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID;
ret = btrfs_insert_fs_root(root->fs_info, tmp_root);
+ btrfs_put_root(tmp_root);
if (ret) {
- test_err("couldn't insert fs root %d", ret);
+ test_err("couldn't insert subvolume root %d", ret);
goto out;
}
- btrfs_put_root(tmp_root);
test_msg("running qgroup tests");
ret = test_no_shared_qgroup(root, sectorsize, nodesize);