Skip to content

Commit d8ba2a9

Browse files
josefbacikkdave
authored andcommitted
btrfs: get correct owning_root when dropping snapshot
Dave reported a bug where we were aborting the transaction while trying to cleanup the squota reservation for an extent. This turned out to be because we're doing btrfs_header_owner(next) in do_walk_down when we decide to free the block. However in this code block we haven't explicitly read next, so it could be stale. We would then get whatever garbage happened to be in the pages at this point. The commit that introduced that is "btrfs: track owning root in btrfs_ref". Fix this by saving the owner_root when we do the btrfs_lookup_extent_info(). We always do this in do_walk_down, it is how we make the decision of whether or not to delete the block. This is cheap because we've already done the extent item lookup at this point, so it's straightforward to just grab the owner root as well. Then we can use this when deleting the metadata block without needing to force a read of the extent buffer to find the owner. This fixes the problem that Dave reported. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 776a838 commit d8ba2a9

3 files changed

Lines changed: 20 additions & 10 deletions

File tree

fs/btrfs/ctree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
421421
if (btrfs_block_can_be_shared(root, buf)) {
422422
ret = btrfs_lookup_extent_info(trans, fs_info, buf->start,
423423
btrfs_header_level(buf), 1,
424-
&refs, &flags);
424+
&refs, &flags, NULL);
425425
if (ret)
426426
return ret;
427427
if (unlikely(refs == 0)) {

fs/btrfs/extent-tree.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
102102
*/
103103
int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
104104
struct btrfs_fs_info *fs_info, u64 bytenr,
105-
u64 offset, int metadata, u64 *refs, u64 *flags)
105+
u64 offset, int metadata, u64 *refs, u64 *flags,
106+
u64 *owning_root)
106107
{
107108
struct btrfs_root *extent_root;
108109
struct btrfs_delayed_ref_head *head;
@@ -114,6 +115,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
114115
u32 item_size;
115116
u64 num_refs;
116117
u64 extent_flags;
118+
u64 owner = 0;
117119
int ret;
118120

119121
/*
@@ -167,6 +169,8 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
167169
struct btrfs_extent_item);
168170
num_refs = btrfs_extent_refs(leaf, ei);
169171
extent_flags = btrfs_extent_flags(leaf, ei);
172+
owner = btrfs_get_extent_owner_root(fs_info, leaf,
173+
path->slots[0]);
170174
} else {
171175
ret = -EUCLEAN;
172176
btrfs_err(fs_info,
@@ -226,6 +230,8 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
226230
*refs = num_refs;
227231
if (flags)
228232
*flags = extent_flags;
233+
if (owning_root)
234+
*owning_root = owner;
229235
out_free:
230236
btrfs_free_path(path);
231237
return ret;
@@ -5234,7 +5240,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
52345240
/* We don't lock the tree block, it's OK to be racy here */
52355241
ret = btrfs_lookup_extent_info(trans, fs_info, bytenr,
52365242
wc->level - 1, 1, &refs,
5237-
&flags);
5243+
&flags, NULL);
52385244
/* We don't care about errors in readahead. */
52395245
if (ret < 0)
52405246
continue;
@@ -5301,7 +5307,8 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
53015307
ret = btrfs_lookup_extent_info(trans, fs_info,
53025308
eb->start, level, 1,
53035309
&wc->refs[level],
5304-
&wc->flags[level]);
5310+
&wc->flags[level],
5311+
NULL);
53055312
BUG_ON(ret == -ENOMEM);
53065313
if (ret)
53075314
return ret;
@@ -5391,6 +5398,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
53915398
u64 bytenr;
53925399
u64 generation;
53935400
u64 parent;
5401+
u64 owner_root = 0;
53945402
struct btrfs_tree_parent_check check = { 0 };
53955403
struct btrfs_key key;
53965404
struct btrfs_ref ref = { 0 };
@@ -5434,7 +5442,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
54345442

54355443
ret = btrfs_lookup_extent_info(trans, fs_info, bytenr, level - 1, 1,
54365444
&wc->refs[level - 1],
5437-
&wc->flags[level - 1]);
5445+
&wc->flags[level - 1],
5446+
&owner_root);
54385447
if (ret < 0)
54395448
goto out_unlock;
54405449

@@ -5567,8 +5576,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
55675576
find_next_key(path, level, &wc->drop_progress);
55685577

55695578
btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
5570-
fs_info->nodesize, parent,
5571-
btrfs_header_owner(next));
5579+
fs_info->nodesize, parent, owner_root);
55725580
btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid,
55735581
0, false);
55745582
ret = btrfs_free_extent(trans, &ref);
@@ -5635,7 +5643,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
56355643
ret = btrfs_lookup_extent_info(trans, fs_info,
56365644
eb->start, level, 1,
56375645
&wc->refs[level],
5638-
&wc->flags[level]);
5646+
&wc->flags[level],
5647+
NULL);
56395648
if (ret < 0) {
56405649
btrfs_tree_unlock_rw(eb, path->locks[level]);
56415650
path->locks[level] = 0;
@@ -5880,7 +5889,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
58805889
ret = btrfs_lookup_extent_info(trans, fs_info,
58815890
path->nodes[level]->start,
58825891
level, 1, &wc->refs[level],
5883-
&wc->flags[level]);
5892+
&wc->flags[level], NULL);
58845893
if (ret < 0) {
58855894
err = ret;
58865895
goto out_end_trans;

fs/btrfs/extent-tree.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ u64 btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
9999
int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len);
100100
int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
101101
struct btrfs_fs_info *fs_info, u64 bytenr,
102-
u64 offset, int metadata, u64 *refs, u64 *flags);
102+
u64 offset, int metadata, u64 *refs, u64 *flags,
103+
u64 *owner_root);
103104
int btrfs_pin_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num,
104105
int reserved);
105106
int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,

0 commit comments

Comments
 (0)