diff options
| -rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 41 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 12 | ||||
| -rw-r--r-- | fs/btrfs/tree-log.c | 2 |
4 files changed, 39 insertions, 17 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 89149fac804c..d8ca5b6e88e0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -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; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 599c03a1c573..d2b302ac6af9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -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 @@ cache_acl: 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); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 1999533b52be..af56fdbba65d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -736,14 +736,12 @@ 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) { + 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); - if (!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) { - btrfs_info(fs_info, - "forcing free space tree for sector size %u with page size %lu", - fs_info->sectorsize, PAGE_SIZE); - btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE); - } + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE); } /* diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5831754bb01c..2d9d38b82daa 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -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)); |
