Commit 372800cb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:

 - fix potential NULL pointer dereference when replaying tree log after
   an error

 - release path before initializing extent tree to avoid potential
   deadlock when allocating new inode

 - on filesystems with block size > page size
    - fix potential read out of bounds during encoded read of an inline
      extent
    - only enforce free space tree if v1 cache is required

 - print correct tree id in error message

* tag 'for-6.19-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: show correct warning if can't read data reloc tree
  btrfs: fix NULL pointer dereference in do_abort_log_replay()
  btrfs: force free space tree for bs > ps cases
  btrfs: only enforce free space tree if v1 cache is required for bs < ps cases
  btrfs: release path before initializing extent tree in btrfs_read_locked_inode()
  btrfs: avoid access-beyond-folio for bs > ps encoded writes
parents 4d6fe1dd 2bb83bc4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2255,6 +2255,7 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
				 BTRFS_DATA_RELOC_TREE_OBJECTID, true);
	if (IS_ERR(root)) {
		if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) {
			location.objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
			ret = PTR_ERR(root);
			goto out;
		}
+32 −9
Original line number Diff line number Diff line
@@ -481,13 +481,15 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
	ASSERT(size <= sectorsize);

	/*
	 * The compressed size also needs to be no larger than a sector.
	 * That's also why we only need one page as the parameter.
	 * The compressed size also needs to be no larger than a page.
	 * That's also why we only need one folio as the parameter.
	 */
	if (compressed_folio)
	if (compressed_folio) {
		ASSERT(compressed_size <= sectorsize);
	else
		ASSERT(compressed_size <= PAGE_SIZE);
	} else {
		ASSERT(compressed_size == 0);
	}

	if (compressed_size && compressed_folio)
		cur_size = compressed_size;
@@ -574,6 +576,18 @@ static bool can_cow_file_range_inline(struct btrfs_inode *inode,
	if (offset != 0)
		return false;

	/*
	 * Even for bs > ps cases, cow_file_range_inline() can only accept a
	 * single folio.
	 *
	 * This can be problematic and cause access beyond page boundary if a
	 * page sized folio is passed into that function.
	 * And encoded write is doing exactly that.
	 * So here limits the inlined extent size to PAGE_SIZE.
	 */
	if (size > PAGE_SIZE || compressed_size > PAGE_SIZE)
		return false;

	/* Inline extents are limited to sectorsize. */
	if (size > fs_info->sectorsize)
		return false;
@@ -4034,11 +4048,6 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path
	btrfs_set_inode_mapping_order(inode);

cache_index:
	ret = btrfs_init_file_extent_tree(inode);
	if (ret)
		goto out;
	btrfs_inode_set_file_extent_range(inode, 0,
			round_up(i_size_read(vfs_inode), fs_info->sectorsize));
	/*
	 * If we were modified in the current generation and evicted from memory
	 * and then re-read we need to do a full sync since we don't have any
@@ -4125,6 +4134,20 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path
				  btrfs_ino(inode), btrfs_root_id(root), ret);
	}

	/*
	 * We don't need the path anymore, so release it to avoid holding a read
	 * lock on a leaf while calling btrfs_init_file_extent_tree(), which can
	 * allocate memory that triggers reclaim (GFP_KERNEL) and cause a locking
	 * dependency.
	 */
	btrfs_release_path(path);

	ret = btrfs_init_file_extent_tree(inode);
	if (ret)
		goto out;
	btrfs_inode_set_file_extent_range(inode, 0,
			  round_up(i_size_read(vfs_inode), fs_info->sectorsize));

	if (!maybe_acls)
		cache_no_acl(vfs_inode);

+5 −7
Original line number Diff line number Diff line
@@ -736,15 +736,13 @@ bool btrfs_check_options(const struct btrfs_fs_info *info,
 */
void btrfs_set_free_space_cache_settings(struct btrfs_fs_info *fs_info)
{
	if (fs_info->sectorsize < PAGE_SIZE) {
		btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
		if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
	if (fs_info->sectorsize != PAGE_SIZE && btrfs_test_opt(fs_info, SPACE_CACHE)) {
		btrfs_info(fs_info,
			   "forcing free space tree for sector size %u with page size %lu",
			   fs_info->sectorsize, PAGE_SIZE);
		btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE);
		btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE);
	}
	}

	/*
	 * At this point our mount options are populated, so we only mess with
+1 −1
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ static void do_abort_log_replay(struct walk_control *wc, const char *function,

	btrfs_abort_transaction(wc->trans, error);

	if (wc->subvol_path->nodes[0]) {
	if (wc->subvol_path && wc->subvol_path->nodes[0]) {
		btrfs_crit(fs_info,
			   "subvolume (root %llu) leaf currently being processed:",
			   btrfs_root_id(wc->root));