diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 28 |
1 files changed, 17 insertions, 11 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c81e14162ef1..4a40282b45f7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -95,6 +95,7 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf) | |||
95 | int btrfs_finish_extent_commit(struct btrfs_root *root) | 95 | int btrfs_finish_extent_commit(struct btrfs_root *root) |
96 | { | 96 | { |
97 | unsigned long gang[8]; | 97 | unsigned long gang[8]; |
98 | u64 first = 0; | ||
98 | int ret; | 99 | int ret; |
99 | int i; | 100 | int i; |
100 | 101 | ||
@@ -104,11 +105,13 @@ int btrfs_finish_extent_commit(struct btrfs_root *root) | |||
104 | ARRAY_SIZE(gang)); | 105 | ARRAY_SIZE(gang)); |
105 | if (!ret) | 106 | if (!ret) |
106 | break; | 107 | break; |
108 | if (!first) | ||
109 | first = gang[0]; | ||
107 | for (i = 0; i < ret; i++) { | 110 | for (i = 0; i < ret; i++) { |
108 | radix_tree_delete(&root->pinned_radix, gang[i]); | 111 | radix_tree_delete(&root->pinned_radix, gang[i]); |
109 | } | 112 | } |
110 | } | 113 | } |
111 | root->last_insert.objectid = 0; | 114 | root->last_insert.objectid = first; |
112 | root->last_insert.offset = 0; | 115 | root->last_insert.offset = 0; |
113 | return 0; | 116 | return 0; |
114 | } | 117 | } |
@@ -140,7 +143,8 @@ static int finish_current_insert(struct btrfs_root *extent_root) | |||
140 | /* | 143 | /* |
141 | * remove an extent from the root, returns 0 on success | 144 | * remove an extent from the root, returns 0 on success |
142 | */ | 145 | */ |
143 | static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | 146 | static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks, |
147 | int pin) | ||
144 | { | 148 | { |
145 | struct btrfs_path path; | 149 | struct btrfs_path path; |
146 | struct btrfs_key key; | 150 | struct btrfs_key key; |
@@ -150,6 +154,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
150 | struct btrfs_key ins; | 154 | struct btrfs_key ins; |
151 | u32 refs; | 155 | u32 refs; |
152 | 156 | ||
157 | BUG_ON(pin && num_blocks != 1); | ||
153 | key.objectid = blocknr; | 158 | key.objectid = blocknr; |
154 | key.flags = 0; | 159 | key.flags = 0; |
155 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 160 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
@@ -170,7 +175,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
170 | refs = btrfs_extent_refs(ei) - 1; | 175 | refs = btrfs_extent_refs(ei) - 1; |
171 | btrfs_set_extent_refs(ei, refs); | 176 | btrfs_set_extent_refs(ei, refs); |
172 | if (refs == 0) { | 177 | if (refs == 0) { |
173 | if (!root->ref_cows) { | 178 | if (pin) { |
174 | int err; | 179 | int err; |
175 | radix_tree_preload(GFP_KERNEL); | 180 | radix_tree_preload(GFP_KERNEL); |
176 | err = radix_tree_insert(&extent_root->pinned_radix, | 181 | err = radix_tree_insert(&extent_root->pinned_radix, |
@@ -179,8 +184,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
179 | radix_tree_preload_end(); | 184 | radix_tree_preload_end(); |
180 | } | 185 | } |
181 | ret = btrfs_del_item(extent_root, &path); | 186 | ret = btrfs_del_item(extent_root, &path); |
182 | if (root != extent_root && | 187 | if (!pin && extent_root->last_insert.objectid > blocknr) |
183 | extent_root->last_insert.objectid > blocknr) | ||
184 | extent_root->last_insert.objectid = blocknr; | 188 | extent_root->last_insert.objectid = blocknr; |
185 | if (ret) | 189 | if (ret) |
186 | BUG(); | 190 | BUG(); |
@@ -208,7 +212,8 @@ static int del_pending_extents(struct btrfs_root *extent_root) | |||
208 | if (!ret) | 212 | if (!ret) |
209 | break; | 213 | break; |
210 | for (i = 0; i < ret; i++) { | 214 | for (i = 0; i < ret; i++) { |
211 | ret = __free_extent(extent_root, gang[i]->blocknr, 1); | 215 | ret = __free_extent(extent_root, |
216 | gang[i]->blocknr, 1, 1); | ||
212 | radix_tree_tag_clear(&extent_root->cache_radix, | 217 | radix_tree_tag_clear(&extent_root->cache_radix, |
213 | gang[i]->blocknr, | 218 | gang[i]->blocknr, |
214 | CTREE_EXTENT_PENDING_DEL); | 219 | CTREE_EXTENT_PENDING_DEL); |
@@ -230,7 +235,8 @@ static int run_pending(struct btrfs_root *extent_root) | |||
230 | /* | 235 | /* |
231 | * remove an extent from the root, returns 0 on success | 236 | * remove an extent from the root, returns 0 on success |
232 | */ | 237 | */ |
233 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | 238 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks, |
239 | int pin) | ||
234 | { | 240 | { |
235 | struct btrfs_root *extent_root = root->extent_root; | 241 | struct btrfs_root *extent_root = root->extent_root; |
236 | struct btrfs_buffer *t; | 242 | struct btrfs_buffer *t; |
@@ -243,7 +249,7 @@ int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
243 | CTREE_EXTENT_PENDING_DEL); | 249 | CTREE_EXTENT_PENDING_DEL); |
244 | return 0; | 250 | return 0; |
245 | } | 251 | } |
246 | ret = __free_extent(root, blocknr, num_blocks); | 252 | ret = __free_extent(root, blocknr, num_blocks, pin); |
247 | pending_ret = run_pending(root->extent_root); | 253 | pending_ret = run_pending(root->extent_root); |
248 | return ret ? ret : pending_ret; | 254 | return ret ? ret : pending_ret; |
249 | } | 255 | } |
@@ -451,7 +457,7 @@ static int walk_down_tree(struct btrfs_root *root, | |||
451 | ret = lookup_block_ref(root, blocknr, &refs); | 457 | ret = lookup_block_ref(root, blocknr, &refs); |
452 | if (refs != 1 || *level == 1) { | 458 | if (refs != 1 || *level == 1) { |
453 | path->slots[*level]++; | 459 | path->slots[*level]++; |
454 | ret = btrfs_free_extent(root, blocknr, 1); | 460 | ret = btrfs_free_extent(root, blocknr, 1, 1); |
455 | BUG_ON(ret); | 461 | BUG_ON(ret); |
456 | continue; | 462 | continue; |
457 | } | 463 | } |
@@ -464,7 +470,7 @@ static int walk_down_tree(struct btrfs_root *root, | |||
464 | path->slots[*level] = 0; | 470 | path->slots[*level] = 0; |
465 | } | 471 | } |
466 | out: | 472 | out: |
467 | ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1); | 473 | ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1, 1); |
468 | btrfs_block_release(root, path->nodes[*level]); | 474 | btrfs_block_release(root, path->nodes[*level]); |
469 | path->nodes[*level] = NULL; | 475 | path->nodes[*level] = NULL; |
470 | *level += 1; | 476 | *level += 1; |
@@ -492,7 +498,7 @@ static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, | |||
492 | return 0; | 498 | return 0; |
493 | } else { | 499 | } else { |
494 | ret = btrfs_free_extent(root, | 500 | ret = btrfs_free_extent(root, |
495 | path->nodes[*level]->blocknr, 1); | 501 | path->nodes[*level]->blocknr, 1, 1); |
496 | btrfs_block_release(root, path->nodes[*level]); | 502 | btrfs_block_release(root, path->nodes[*level]); |
497 | path->nodes[*level] = NULL; | 503 | path->nodes[*level] = NULL; |
498 | *level = i + 1; | 504 | *level = i + 1; |