aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorYan, Zheng <zheng.yan@oracle.com>2009-10-09 09:25:16 -0400
committerChris Mason <chris.mason@oracle.com>2009-10-09 09:25:16 -0400
commit94fcca9f8999e7828d5f4dc181daa39cad2af38a (patch)
tree68842517a4d10d080bc4f70abae19e480d2ac049 /fs/btrfs
parentefefb1438be269897585934fc6c05deb4dfa01ce (diff)
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent-tree.c82
1 files changed, 53 insertions, 29 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 53026806ae9e..4aedbff36b8f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4911,6 +4911,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
4911 u64 bytenr; 4911 u64 bytenr;
4912 u64 generation; 4912 u64 generation;
4913 u64 refs; 4913 u64 refs;
4914 u64 flags;
4914 u64 last = 0; 4915 u64 last = 0;
4915 u32 nritems; 4916 u32 nritems;
4916 u32 blocksize; 4917 u32 blocksize;
@@ -4948,15 +4949,19 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
4948 generation <= root->root_key.offset) 4949 generation <= root->root_key.offset)
4949 continue; 4950 continue;
4950 4951
4952 /* We don't lock the tree block, it's OK to be racy here */
4953 ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
4954 &refs, &flags);
4955 BUG_ON(ret);
4956 BUG_ON(refs == 0);
4957
4951 if (wc->stage == DROP_REFERENCE) { 4958 if (wc->stage == DROP_REFERENCE) {
4952 ret = btrfs_lookup_extent_info(trans, root,
4953 bytenr, blocksize,
4954 &refs, NULL);
4955 BUG_ON(ret);
4956 BUG_ON(refs == 0);
4957 if (refs == 1) 4959 if (refs == 1)
4958 goto reada; 4960 goto reada;
4959 4961
4962 if (wc->level == 1 &&
4963 (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF))
4964 continue;
4960 if (!wc->update_ref || 4965 if (!wc->update_ref ||
4961 generation <= root->root_key.offset) 4966 generation <= root->root_key.offset)
4962 continue; 4967 continue;
@@ -4965,6 +4970,10 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
4965 &wc->update_progress); 4970 &wc->update_progress);
4966 if (ret < 0) 4971 if (ret < 0)
4967 continue; 4972 continue;
4973 } else {
4974 if (wc->level == 1 &&
4975 (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF))
4976 continue;
4968 } 4977 }
4969reada: 4978reada:
4970 ret = readahead_tree_block(root, bytenr, blocksize, 4979 ret = readahead_tree_block(root, bytenr, blocksize,
@@ -4988,7 +4997,7 @@ reada:
4988static noinline int walk_down_proc(struct btrfs_trans_handle *trans, 4997static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
4989 struct btrfs_root *root, 4998 struct btrfs_root *root,
4990 struct btrfs_path *path, 4999 struct btrfs_path *path,
4991 struct walk_control *wc) 5000 struct walk_control *wc, int lookup_info)
4992{ 5001{
4993 int level = wc->level; 5002 int level = wc->level;
4994 struct extent_buffer *eb = path->nodes[level]; 5003 struct extent_buffer *eb = path->nodes[level];
@@ -5003,8 +5012,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
5003 * when reference count of tree block is 1, it won't increase 5012 * when reference count of tree block is 1, it won't increase
5004 * again. once full backref flag is set, we never clear it. 5013 * again. once full backref flag is set, we never clear it.
5005 */ 5014 */
5006 if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) || 5015 if (lookup_info &&
5007 (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) { 5016 ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) ||
5017 (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag)))) {
5008 BUG_ON(!path->locks[level]); 5018 BUG_ON(!path->locks[level]);
5009 ret = btrfs_lookup_extent_info(trans, root, 5019 ret = btrfs_lookup_extent_info(trans, root,
5010 eb->start, eb->len, 5020 eb->start, eb->len,
@@ -5065,7 +5075,7 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
5065static noinline int do_walk_down(struct btrfs_trans_handle *trans, 5075static noinline int do_walk_down(struct btrfs_trans_handle *trans,
5066 struct btrfs_root *root, 5076 struct btrfs_root *root,
5067 struct btrfs_path *path, 5077 struct btrfs_path *path,
5068 struct walk_control *wc) 5078 struct walk_control *wc, int *lookup_info)
5069{ 5079{
5070 u64 bytenr; 5080 u64 bytenr;
5071 u64 generation; 5081 u64 generation;
@@ -5085,8 +5095,10 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
5085 * for the subtree 5095 * for the subtree
5086 */ 5096 */
5087 if (wc->stage == UPDATE_BACKREF && 5097 if (wc->stage == UPDATE_BACKREF &&
5088 generation <= root->root_key.offset) 5098 generation <= root->root_key.offset) {
5099 *lookup_info = 1;
5089 return 1; 5100 return 1;
5101 }
5090 5102
5091 bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]); 5103 bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
5092 blocksize = btrfs_level_size(root, level - 1); 5104 blocksize = btrfs_level_size(root, level - 1);
@@ -5099,14 +5111,19 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
5099 btrfs_tree_lock(next); 5111 btrfs_tree_lock(next);
5100 btrfs_set_lock_blocking(next); 5112 btrfs_set_lock_blocking(next);
5101 5113
5102 if (wc->stage == DROP_REFERENCE) { 5114 ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
5103 ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize, 5115 &wc->refs[level - 1],
5104 &wc->refs[level - 1], 5116 &wc->flags[level - 1]);
5105 &wc->flags[level - 1]); 5117 BUG_ON(ret);
5106 BUG_ON(ret); 5118 BUG_ON(wc->refs[level - 1] == 0);
5107 BUG_ON(wc->refs[level - 1] == 0); 5119 *lookup_info = 0;
5108 5120
5121 if (wc->stage == DROP_REFERENCE) {
5109 if (wc->refs[level - 1] > 1) { 5122 if (wc->refs[level - 1] > 1) {
5123 if (level == 1 &&
5124 (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
5125 goto skip;
5126
5110 if (!wc->update_ref || 5127 if (!wc->update_ref ||
5111 generation <= root->root_key.offset) 5128 generation <= root->root_key.offset)
5112 goto skip; 5129 goto skip;
@@ -5120,12 +5137,17 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
5120 wc->stage = UPDATE_BACKREF; 5137 wc->stage = UPDATE_BACKREF;
5121 wc->shared_level = level - 1; 5138 wc->shared_level = level - 1;
5122 } 5139 }
5140 } else {
5141 if (level == 1 &&
5142 (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
5143 goto skip;
5123 } 5144 }
5124 5145
5125 if (!btrfs_buffer_uptodate(next, generation)) { 5146 if (!btrfs_buffer_uptodate(next, generation)) {
5126 btrfs_tree_unlock(next); 5147 btrfs_tree_unlock(next);
5127 free_extent_buffer(next); 5148 free_extent_buffer(next);
5128 next = NULL; 5149 next = NULL;
5150 *lookup_info = 1;
5129 } 5151 }
5130 5152
5131 if (!next) { 5153 if (!next) {
@@ -5148,21 +5170,22 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
5148skip: 5170skip:
5149 wc->refs[level - 1] = 0; 5171 wc->refs[level - 1] = 0;
5150 wc->flags[level - 1] = 0; 5172 wc->flags[level - 1] = 0;
5173 if (wc->stage == DROP_REFERENCE) {
5174 if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
5175 parent = path->nodes[level]->start;
5176 } else {
5177 BUG_ON(root->root_key.objectid !=
5178 btrfs_header_owner(path->nodes[level]));
5179 parent = 0;
5180 }
5151 5181
5152 if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) { 5182 ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
5153 parent = path->nodes[level]->start; 5183 root->root_key.objectid, level - 1, 0);
5154 } else { 5184 BUG_ON(ret);
5155 BUG_ON(root->root_key.objectid !=
5156 btrfs_header_owner(path->nodes[level]));
5157 parent = 0;
5158 } 5185 }
5159
5160 ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
5161 root->root_key.objectid, level - 1, 0);
5162 BUG_ON(ret);
5163
5164 btrfs_tree_unlock(next); 5186 btrfs_tree_unlock(next);
5165 free_extent_buffer(next); 5187 free_extent_buffer(next);
5188 *lookup_info = 1;
5166 return 1; 5189 return 1;
5167} 5190}
5168 5191
@@ -5276,6 +5299,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
5276 struct walk_control *wc) 5299 struct walk_control *wc)
5277{ 5300{
5278 int level = wc->level; 5301 int level = wc->level;
5302 int lookup_info = 1;
5279 int ret; 5303 int ret;
5280 5304
5281 while (level >= 0) { 5305 while (level >= 0) {
@@ -5283,14 +5307,14 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
5283 btrfs_header_nritems(path->nodes[level])) 5307 btrfs_header_nritems(path->nodes[level]))
5284 break; 5308 break;
5285 5309
5286 ret = walk_down_proc(trans, root, path, wc); 5310 ret = walk_down_proc(trans, root, path, wc, lookup_info);
5287 if (ret > 0) 5311 if (ret > 0)
5288 break; 5312 break;
5289 5313
5290 if (level == 0) 5314 if (level == 0)
5291 break; 5315 break;
5292 5316
5293 ret = do_walk_down(trans, root, path, wc); 5317 ret = do_walk_down(trans, root, path, wc, &lookup_info);
5294 if (ret > 0) { 5318 if (ret > 0) {
5295 path->slots[level]++; 5319 path->slots[level]++;
5296 continue; 5320 continue;