Btrfs: optimize back reference update during btrfs_drop_snapshot

This patch reading level 0 tree blocks that already use full backrefs.

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Yan, Zheng 2009-10-09 09:25:16 -04:00 committed by Chris Mason
parent efefb1438b
commit 94fcca9f89

View File

@ -4911,6 +4911,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
u64 bytenr; u64 bytenr;
u64 generation; u64 generation;
u64 refs; u64 refs;
u64 flags;
u64 last = 0; u64 last = 0;
u32 nritems; u32 nritems;
u32 blocksize; u32 blocksize;
@ -4948,15 +4949,19 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
generation <= root->root_key.offset) generation <= root->root_key.offset)
continue; continue;
/* We don't lock the tree block, it's OK to be racy here */
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
&refs, &flags);
BUG_ON(ret);
BUG_ON(refs == 0);
if (wc->stage == DROP_REFERENCE) { if (wc->stage == DROP_REFERENCE) {
ret = btrfs_lookup_extent_info(trans, root,
bytenr, blocksize,
&refs, NULL);
BUG_ON(ret);
BUG_ON(refs == 0);
if (refs == 1) if (refs == 1)
goto reada; goto reada;
if (wc->level == 1 &&
(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF))
continue;
if (!wc->update_ref || if (!wc->update_ref ||
generation <= root->root_key.offset) generation <= root->root_key.offset)
continue; continue;
@ -4965,6 +4970,10 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
&wc->update_progress); &wc->update_progress);
if (ret < 0) if (ret < 0)
continue; continue;
} else {
if (wc->level == 1 &&
(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF))
continue;
} }
reada: reada:
ret = readahead_tree_block(root, bytenr, blocksize, ret = readahead_tree_block(root, bytenr, blocksize,
@ -4988,7 +4997,7 @@ reada:
static noinline int walk_down_proc(struct btrfs_trans_handle *trans, static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_path *path,
struct walk_control *wc) struct walk_control *wc, int lookup_info)
{ {
int level = wc->level; int level = wc->level;
struct extent_buffer *eb = path->nodes[level]; struct extent_buffer *eb = path->nodes[level];
@ -5003,8 +5012,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
* when reference count of tree block is 1, it won't increase * when reference count of tree block is 1, it won't increase
* again. once full backref flag is set, we never clear it. * again. once full backref flag is set, we never clear it.
*/ */
if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) || if (lookup_info &&
(wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) { ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) ||
(wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag)))) {
BUG_ON(!path->locks[level]); BUG_ON(!path->locks[level]);
ret = btrfs_lookup_extent_info(trans, root, ret = btrfs_lookup_extent_info(trans, root,
eb->start, eb->len, eb->start, eb->len,
@ -5065,7 +5075,7 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
static noinline int do_walk_down(struct btrfs_trans_handle *trans, static noinline int do_walk_down(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_path *path,
struct walk_control *wc) struct walk_control *wc, int *lookup_info)
{ {
u64 bytenr; u64 bytenr;
u64 generation; u64 generation;
@ -5085,8 +5095,10 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
* for the subtree * for the subtree
*/ */
if (wc->stage == UPDATE_BACKREF && if (wc->stage == UPDATE_BACKREF &&
generation <= root->root_key.offset) generation <= root->root_key.offset) {
*lookup_info = 1;
return 1; return 1;
}
bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]); bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
blocksize = btrfs_level_size(root, level - 1); blocksize = btrfs_level_size(root, level - 1);
@ -5099,14 +5111,19 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
btrfs_tree_lock(next); btrfs_tree_lock(next);
btrfs_set_lock_blocking(next); btrfs_set_lock_blocking(next);
if (wc->stage == DROP_REFERENCE) { ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize, &wc->refs[level - 1],
&wc->refs[level - 1], &wc->flags[level - 1]);
&wc->flags[level - 1]); BUG_ON(ret);
BUG_ON(ret); BUG_ON(wc->refs[level - 1] == 0);
BUG_ON(wc->refs[level - 1] == 0); *lookup_info = 0;
if (wc->stage == DROP_REFERENCE) {
if (wc->refs[level - 1] > 1) { if (wc->refs[level - 1] > 1) {
if (level == 1 &&
(wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
goto skip;
if (!wc->update_ref || if (!wc->update_ref ||
generation <= root->root_key.offset) generation <= root->root_key.offset)
goto skip; goto skip;
@ -5120,12 +5137,17 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
wc->stage = UPDATE_BACKREF; wc->stage = UPDATE_BACKREF;
wc->shared_level = level - 1; wc->shared_level = level - 1;
} }
} else {
if (level == 1 &&
(wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
goto skip;
} }
if (!btrfs_buffer_uptodate(next, generation)) { if (!btrfs_buffer_uptodate(next, generation)) {
btrfs_tree_unlock(next); btrfs_tree_unlock(next);
free_extent_buffer(next); free_extent_buffer(next);
next = NULL; next = NULL;
*lookup_info = 1;
} }
if (!next) { if (!next) {
@ -5148,21 +5170,22 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
skip: skip:
wc->refs[level - 1] = 0; wc->refs[level - 1] = 0;
wc->flags[level - 1] = 0; wc->flags[level - 1] = 0;
if (wc->stage == DROP_REFERENCE) {
if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
parent = path->nodes[level]->start;
} else {
BUG_ON(root->root_key.objectid !=
btrfs_header_owner(path->nodes[level]));
parent = 0;
}
if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) { ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
parent = path->nodes[level]->start; root->root_key.objectid, level - 1, 0);
} else { BUG_ON(ret);
BUG_ON(root->root_key.objectid !=
btrfs_header_owner(path->nodes[level]));
parent = 0;
} }
ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
root->root_key.objectid, level - 1, 0);
BUG_ON(ret);
btrfs_tree_unlock(next); btrfs_tree_unlock(next);
free_extent_buffer(next); free_extent_buffer(next);
*lookup_info = 1;
return 1; return 1;
} }
@ -5276,6 +5299,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
struct walk_control *wc) struct walk_control *wc)
{ {
int level = wc->level; int level = wc->level;
int lookup_info = 1;
int ret; int ret;
while (level >= 0) { while (level >= 0) {
@ -5283,14 +5307,14 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
btrfs_header_nritems(path->nodes[level])) btrfs_header_nritems(path->nodes[level]))
break; break;
ret = walk_down_proc(trans, root, path, wc); ret = walk_down_proc(trans, root, path, wc, lookup_info);
if (ret > 0) if (ret > 0)
break; break;
if (level == 0) if (level == 0)
break; break;
ret = do_walk_down(trans, root, path, wc); ret = do_walk_down(trans, root, path, wc, &lookup_info);
if (ret > 0) { if (ret > 0) {
path->slots[level]++; path->slots[level]++;
continue; continue;