aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c253
-rw-r--r--fs/btrfs/transaction.c3
2 files changed, 207 insertions, 49 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 9bcb9c09c3b8..8fc922982183 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4886,19 +4886,90 @@ struct walk_control {
4886 int shared_level; 4886 int shared_level;
4887 int update_ref; 4887 int update_ref;
4888 int keep_locks; 4888 int keep_locks;
4889 int reada_slot;
4890 int reada_count;
4889}; 4891};
4890 4892
4891#define DROP_REFERENCE 1 4893#define DROP_REFERENCE 1
4892#define UPDATE_BACKREF 2 4894#define UPDATE_BACKREF 2
4893 4895
4896static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
4897 struct btrfs_root *root,
4898 struct walk_control *wc,
4899 struct btrfs_path *path)
4900{
4901 u64 bytenr;
4902 u64 generation;
4903 u64 refs;
4904 u64 last = 0;
4905 u32 nritems;
4906 u32 blocksize;
4907 struct btrfs_key key;
4908 struct extent_buffer *eb;
4909 int ret;
4910 int slot;
4911 int nread = 0;
4912
4913 if (path->slots[wc->level] < wc->reada_slot) {
4914 wc->reada_count = wc->reada_count * 2 / 3;
4915 wc->reada_count = max(wc->reada_count, 2);
4916 } else {
4917 wc->reada_count = wc->reada_count * 3 / 2;
4918 wc->reada_count = min_t(int, wc->reada_count,
4919 BTRFS_NODEPTRS_PER_BLOCK(root));
4920 }
4921
4922 eb = path->nodes[wc->level];
4923 nritems = btrfs_header_nritems(eb);
4924 blocksize = btrfs_level_size(root, wc->level - 1);
4925
4926 for (slot = path->slots[wc->level]; slot < nritems; slot++) {
4927 if (nread >= wc->reada_count)
4928 break;
4929
4930 cond_resched();
4931 bytenr = btrfs_node_blockptr(eb, slot);
4932 generation = btrfs_node_ptr_generation(eb, slot);
4933
4934 if (slot == path->slots[wc->level])
4935 goto reada;
4936
4937 if (wc->stage == UPDATE_BACKREF &&
4938 generation <= root->root_key.offset)
4939 continue;
4940
4941 if (wc->stage == DROP_REFERENCE) {
4942 ret = btrfs_lookup_extent_info(trans, root,
4943 bytenr, blocksize,
4944 &refs, NULL);
4945 BUG_ON(ret);
4946 BUG_ON(refs == 0);
4947 if (refs == 1)
4948 goto reada;
4949
4950 if (!wc->update_ref ||
4951 generation <= root->root_key.offset)
4952 continue;
4953 btrfs_node_key_to_cpu(eb, &key, slot);
4954 ret = btrfs_comp_cpu_keys(&key,
4955 &wc->update_progress);
4956 if (ret < 0)
4957 continue;
4958 }
4959reada:
4960 ret = readahead_tree_block(root, bytenr, blocksize,
4961 generation);
4962 if (ret)
4963 break;
4964 last = bytenr + blocksize;
4965 nread++;
4966 }
4967 wc->reada_slot = slot;
4968}
4969
4894/* 4970/*
4895 * hepler to process tree block while walking down the tree. 4971 * hepler to process tree block while walking down the tree.
4896 * 4972 *
4897 * when wc->stage == DROP_REFERENCE, this function checks
4898 * reference count of the block. if the block is shared and
4899 * we need update back refs for the subtree rooted at the
4900 * block, this function changes wc->stage to UPDATE_BACKREF
4901 *
4902 * when wc->stage == UPDATE_BACKREF, this function updates 4973 * when wc->stage == UPDATE_BACKREF, this function updates
4903 * back refs for pointers in the block. 4974 * back refs for pointers in the block.
4904 * 4975 *
@@ -4911,7 +4982,6 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
4911{ 4982{
4912 int level = wc->level; 4983 int level = wc->level;
4913 struct extent_buffer *eb = path->nodes[level]; 4984 struct extent_buffer *eb = path->nodes[level];
4914 struct btrfs_key key;
4915 u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF; 4985 u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF;
4916 int ret; 4986 int ret;
4917 4987
@@ -4934,21 +5004,6 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
4934 BUG_ON(wc->refs[level] == 0); 5004 BUG_ON(wc->refs[level] == 0);
4935 } 5005 }
4936 5006
4937 if (wc->stage == DROP_REFERENCE &&
4938 wc->update_ref && wc->refs[level] > 1) {
4939 BUG_ON(eb == root->node);
4940 BUG_ON(path->slots[level] > 0);
4941 if (level == 0)
4942 btrfs_item_key_to_cpu(eb, &key, path->slots[level]);
4943 else
4944 btrfs_node_key_to_cpu(eb, &key, path->slots[level]);
4945 if (btrfs_header_owner(eb) == root->root_key.objectid &&
4946 btrfs_comp_cpu_keys(&key, &wc->update_progress) >= 0) {
4947 wc->stage = UPDATE_BACKREF;
4948 wc->shared_level = level;
4949 }
4950 }
4951
4952 if (wc->stage == DROP_REFERENCE) { 5007 if (wc->stage == DROP_REFERENCE) {
4953 if (wc->refs[level] > 1) 5008 if (wc->refs[level] > 1)
4954 return 1; 5009 return 1;
@@ -4985,6 +5040,123 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
4985} 5040}
4986 5041
4987/* 5042/*
5043 * hepler to process tree block pointer.
5044 *
5045 * when wc->stage == DROP_REFERENCE, this function checks
5046 * reference count of the block pointed to. if the block
5047 * is shared and we need update back refs for the subtree
5048 * rooted at the block, this function changes wc->stage to
5049 * UPDATE_BACKREF. if the block is shared and there is no
5050 * need to update back, this function drops the reference
5051 * to the block.
5052 *
5053 * NOTE: return value 1 means we should stop walking down.
5054 */
5055static noinline int do_walk_down(struct btrfs_trans_handle *trans,
5056 struct btrfs_root *root,
5057 struct btrfs_path *path,
5058 struct walk_control *wc)
5059{
5060 u64 bytenr;
5061 u64 generation;
5062 u64 parent;
5063 u32 blocksize;
5064 struct btrfs_key key;
5065 struct extent_buffer *next;
5066 int level = wc->level;
5067 int reada = 0;
5068 int ret = 0;
5069
5070 generation = btrfs_node_ptr_generation(path->nodes[level],
5071 path->slots[level]);
5072 /*
5073 * if the lower level block was created before the snapshot
5074 * was created, we know there is no need to update back refs
5075 * for the subtree
5076 */
5077 if (wc->stage == UPDATE_BACKREF &&
5078 generation <= root->root_key.offset)
5079 return 1;
5080
5081 bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
5082 blocksize = btrfs_level_size(root, level - 1);
5083
5084 next = btrfs_find_tree_block(root, bytenr, blocksize);
5085 if (!next) {
5086 next = btrfs_find_create_tree_block(root, bytenr, blocksize);
5087 reada = 1;
5088 }
5089 btrfs_tree_lock(next);
5090 btrfs_set_lock_blocking(next);
5091
5092 if (wc->stage == DROP_REFERENCE) {
5093 ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
5094 &wc->refs[level - 1],
5095 &wc->flags[level - 1]);
5096 BUG_ON(ret);
5097 BUG_ON(wc->refs[level - 1] == 0);
5098
5099 if (wc->refs[level - 1] > 1) {
5100 if (!wc->update_ref ||
5101 generation <= root->root_key.offset)
5102 goto skip;
5103
5104 btrfs_node_key_to_cpu(path->nodes[level], &key,
5105 path->slots[level]);
5106 ret = btrfs_comp_cpu_keys(&key, &wc->update_progress);
5107 if (ret < 0)
5108 goto skip;
5109
5110 wc->stage = UPDATE_BACKREF;
5111 wc->shared_level = level - 1;
5112 }
5113 }
5114
5115 if (!btrfs_buffer_uptodate(next, generation)) {
5116 btrfs_tree_unlock(next);
5117 free_extent_buffer(next);
5118 next = NULL;
5119 }
5120
5121 if (!next) {
5122 if (reada && level == 1)
5123 reada_walk_down(trans, root, wc, path);
5124 next = read_tree_block(root, bytenr, blocksize, generation);
5125 btrfs_tree_lock(next);
5126 btrfs_set_lock_blocking(next);
5127 }
5128
5129 level--;
5130 BUG_ON(level != btrfs_header_level(next));
5131 path->nodes[level] = next;
5132 path->slots[level] = 0;
5133 path->locks[level] = 1;
5134 wc->level = level;
5135 if (wc->level == 1)
5136 wc->reada_slot = 0;
5137 return 0;
5138skip:
5139 wc->refs[level - 1] = 0;
5140 wc->flags[level - 1] = 0;
5141
5142 if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
5143 parent = path->nodes[level]->start;
5144 } else {
5145 BUG_ON(root->root_key.objectid !=
5146 btrfs_header_owner(path->nodes[level]));
5147 parent = 0;
5148 }
5149
5150 ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
5151 root->root_key.objectid, level - 1, 0);
5152 BUG_ON(ret);
5153
5154 btrfs_tree_unlock(next);
5155 free_extent_buffer(next);
5156 return 1;
5157}
5158
5159/*
4988 * hepler to process tree block while walking up the tree. 5160 * hepler to process tree block while walking up the tree.
4989 * 5161 *
4990 * when wc->stage == DROP_REFERENCE, this function drops 5162 * when wc->stage == DROP_REFERENCE, this function drops
@@ -5011,7 +5183,6 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
5011 if (level < wc->shared_level) 5183 if (level < wc->shared_level)
5012 goto out; 5184 goto out;
5013 5185
5014 BUG_ON(wc->refs[level] <= 1);
5015 ret = find_next_key(path, level + 1, &wc->update_progress); 5186 ret = find_next_key(path, level + 1, &wc->update_progress);
5016 if (ret > 0) 5187 if (ret > 0)
5017 wc->update_ref = 0; 5188 wc->update_ref = 0;
@@ -5042,8 +5213,6 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
5042 path->locks[level] = 0; 5213 path->locks[level] = 0;
5043 return 1; 5214 return 1;
5044 } 5215 }
5045 } else {
5046 BUG_ON(level != 0);
5047 } 5216 }
5048 } 5217 }
5049 5218
@@ -5096,17 +5265,13 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
5096 struct btrfs_path *path, 5265 struct btrfs_path *path,
5097 struct walk_control *wc) 5266 struct walk_control *wc)
5098{ 5267{
5099 struct extent_buffer *next;
5100 struct extent_buffer *cur;
5101 u64 bytenr;
5102 u64 ptr_gen;
5103 u32 blocksize;
5104 int level = wc->level; 5268 int level = wc->level;
5105 int ret; 5269 int ret;
5106 5270
5107 while (level >= 0) { 5271 while (level >= 0) {
5108 cur = path->nodes[level]; 5272 if (path->slots[level] >=
5109 BUG_ON(path->slots[level] >= btrfs_header_nritems(cur)); 5273 btrfs_header_nritems(path->nodes[level]))
5274 break;
5110 5275
5111 ret = walk_down_proc(trans, root, path, wc); 5276 ret = walk_down_proc(trans, root, path, wc);
5112 if (ret > 0) 5277 if (ret > 0)
@@ -5115,20 +5280,12 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
5115 if (level == 0) 5280 if (level == 0)
5116 break; 5281 break;
5117 5282
5118 bytenr = btrfs_node_blockptr(cur, path->slots[level]); 5283 ret = do_walk_down(trans, root, path, wc);
5119 blocksize = btrfs_level_size(root, level - 1); 5284 if (ret > 0) {
5120 ptr_gen = btrfs_node_ptr_generation(cur, path->slots[level]); 5285 path->slots[level]++;
5121 5286 continue;
5122 next = read_tree_block(root, bytenr, blocksize, ptr_gen); 5287 }
5123 btrfs_tree_lock(next); 5288 level = wc->level;
5124 btrfs_set_lock_blocking(next);
5125
5126 level--;
5127 BUG_ON(level != btrfs_header_level(next));
5128 path->nodes[level] = next;
5129 path->slots[level] = 0;
5130 path->locks[level] = 1;
5131 wc->level = level;
5132 } 5289 }
5133 return 0; 5290 return 0;
5134} 5291}
@@ -5218,9 +5375,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
5218 err = ret; 5375 err = ret;
5219 goto out; 5376 goto out;
5220 } 5377 }
5221 btrfs_node_key_to_cpu(path->nodes[level], &key, 5378 WARN_ON(ret > 0);
5222 path->slots[level]);
5223 WARN_ON(memcmp(&key, &wc->update_progress, sizeof(key)));
5224 5379
5225 /* 5380 /*
5226 * unlock our path, this is safe because only this 5381 * unlock our path, this is safe because only this
@@ -5255,6 +5410,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
5255 wc->stage = DROP_REFERENCE; 5410 wc->stage = DROP_REFERENCE;
5256 wc->update_ref = update_ref; 5411 wc->update_ref = update_ref;
5257 wc->keep_locks = 0; 5412 wc->keep_locks = 0;
5413 wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
5258 5414
5259 while (1) { 5415 while (1) {
5260 ret = walk_down_tree(trans, root, path, wc); 5416 ret = walk_down_tree(trans, root, path, wc);
@@ -5361,6 +5517,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
5361 wc->stage = DROP_REFERENCE; 5517 wc->stage = DROP_REFERENCE;
5362 wc->update_ref = 0; 5518 wc->update_ref = 0;
5363 wc->keep_locks = 1; 5519 wc->keep_locks = 1;
5520 wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
5364 5521
5365 while (1) { 5522 while (1) {
5366 wret = walk_down_tree(trans, root, path, wc); 5523 wret = walk_down_tree(trans, root, path, wc);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 6ed6186f51cd..94f816cb6e35 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -720,7 +720,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
720 memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); 720 memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));
721 721
722 key.objectid = objectid; 722 key.objectid = objectid;
723 key.offset = 0; 723 /* record when the snapshot was created in key.offset */
724 key.offset = trans->transid;
724 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); 725 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
725 726
726 old = btrfs_lock_root_node(root); 727 old = btrfs_lock_root_node(root);