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()
This commit is contained in:
Linus Torvalds
2026-01-17 19:29:32 -08:00
8 changed files with 41 additions and 68 deletions

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);