btrfs_mkdir
[linux-2.6-block.git] / fs / btrfs / extent-tree.c
CommitLineData
2e635a27
CM
1#include <linux/module.h>
2#include <linux/radix-tree.h>
fec577fb
CM
3#include "ctree.h"
4#include "disk-io.h"
5#include "print-tree.h"
e089f05c 6#include "transaction.h"
fec577fb 7
e089f05c
CM
8static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
9 *orig_root, u64 num_blocks, u64 search_start, u64
10 search_end, struct btrfs_key *ins);
11static int finish_current_insert(struct btrfs_trans_handle *trans, struct
12 btrfs_root *extent_root);
e20d96d6
CM
13static int del_pending_extents(struct btrfs_trans_handle *trans, struct
14 btrfs_root *extent_root);
fec577fb
CM
15/*
16 * pending extents are blocks that we're trying to allocate in the extent
17 * map while trying to grow the map because of other allocations. To avoid
18 * recursing, they are tagged in the radix tree and cleaned up after
19 * other allocations are done. The pending tag is also used in the same
20 * manner for deletes.
21 */
037e6390 22#define CTREE_EXTENT_PENDING_DEL 0
e20d96d6 23#define CTREE_EXTENT_PINNED 1
fec577fb 24
e089f05c
CM
25static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
26 *root, u64 blocknr)
02217ed2 27{
234b63a0 28 struct btrfs_path path;
02217ed2 29 int ret;
e2fa7227 30 struct btrfs_key key;
234b63a0
CM
31 struct btrfs_leaf *l;
32 struct btrfs_extent_item *item;
e2fa7227 33 struct btrfs_key ins;
cf27e1ee 34 u32 refs;
037e6390 35
9f5fae2f
CM
36 find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
37 &ins);
234b63a0 38 btrfs_init_path(&path);
02217ed2
CM
39 key.objectid = blocknr;
40 key.flags = 0;
62e2749e 41 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
02217ed2 42 key.offset = 1;
9f5fae2f
CM
43 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
44 0, 1);
a28ec197
CM
45 if (ret != 0)
46 BUG();
02217ed2 47 BUG_ON(ret != 0);
e20d96d6 48 l = btrfs_buffer_leaf(path.nodes[0]);
4beb1b8b 49 item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
cf27e1ee
CM
50 refs = btrfs_extent_refs(item);
51 btrfs_set_extent_refs(item, refs + 1);
d5719762 52 mark_buffer_dirty(path.nodes[0]);
a28ec197 53
9f5fae2f
CM
54 btrfs_release_path(root->fs_info->extent_root, &path);
55 finish_current_insert(trans, root->fs_info->extent_root);
e20d96d6 56 del_pending_extents(trans, root->fs_info->extent_root);
02217ed2
CM
57 return 0;
58}
59
e089f05c
CM
60static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
61 *root, u64 blocknr, u32 *refs)
a28ec197 62{
234b63a0 63 struct btrfs_path path;
a28ec197 64 int ret;
e2fa7227 65 struct btrfs_key key;
234b63a0
CM
66 struct btrfs_leaf *l;
67 struct btrfs_extent_item *item;
68 btrfs_init_path(&path);
a28ec197 69 key.objectid = blocknr;
a28ec197 70 key.offset = 1;
62e2749e
CM
71 key.flags = 0;
72 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
9f5fae2f
CM
73 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
74 0, 0);
a28ec197
CM
75 if (ret != 0)
76 BUG();
e20d96d6 77 l = btrfs_buffer_leaf(path.nodes[0]);
4beb1b8b 78 item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
cf27e1ee 79 *refs = btrfs_extent_refs(item);
9f5fae2f 80 btrfs_release_path(root->fs_info->extent_root, &path);
a28ec197
CM
81 return 0;
82}
83
e089f05c 84int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
e20d96d6 85 struct buffer_head *buf)
02217ed2
CM
86{
87 u64 blocknr;
e20d96d6 88 struct btrfs_node *buf_node;
02217ed2 89 int i;
a28ec197 90
3768f368 91 if (!root->ref_cows)
a28ec197 92 return 0;
e20d96d6
CM
93 buf_node = btrfs_buffer_node(buf);
94 if (btrfs_is_leaf(buf_node))
a28ec197
CM
95 return 0;
96
e20d96d6
CM
97 for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
98 blocknr = btrfs_node_blockptr(buf_node, i);
e089f05c 99 inc_block_ref(trans, root, blocknr);
02217ed2
CM
100 }
101 return 0;
102}
103
e089f05c
CM
104int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
105 btrfs_root *root)
a28ec197 106{
d5719762 107 struct buffer_head *gang[8];
88fd146c 108 u64 first = 0;
a28ec197
CM
109 int ret;
110 int i;
111
112 while(1) {
e20d96d6 113 ret = radix_tree_gang_lookup_tag(&root->fs_info->pinned_radix,
9f5fae2f 114 (void **)gang, 0,
e20d96d6
CM
115 ARRAY_SIZE(gang),
116 CTREE_EXTENT_PINNED);
a28ec197
CM
117 if (!ret)
118 break;
88fd146c 119 if (!first)
d5719762 120 first = gang[0]->b_blocknr;
0579da42 121 for (i = 0; i < ret; i++) {
9f5fae2f 122 radix_tree_delete(&root->fs_info->pinned_radix,
d5719762
CM
123 gang[i]->b_blocknr);
124 brelse(gang[i]);
0579da42 125 }
a28ec197 126 }
d5719762
CM
127 if (root->fs_info->last_insert.objectid > first)
128 root->fs_info->last_insert.objectid = first;
9f5fae2f 129 root->fs_info->last_insert.offset = 0;
a28ec197
CM
130 return 0;
131}
132
e089f05c
CM
133static int finish_current_insert(struct btrfs_trans_handle *trans, struct
134 btrfs_root *extent_root)
037e6390 135{
e2fa7227 136 struct btrfs_key ins;
234b63a0 137 struct btrfs_extent_item extent_item;
037e6390
CM
138 int i;
139 int ret;
1261ec42
CM
140 u64 super_blocks_used;
141 struct btrfs_fs_info *info = extent_root->fs_info;
037e6390 142
cf27e1ee
CM
143 btrfs_set_extent_refs(&extent_item, 1);
144 btrfs_set_extent_owner(&extent_item,
e20d96d6 145 btrfs_header_parentid(btrfs_buffer_header(extent_root->node)));
037e6390
CM
146 ins.offset = 1;
147 ins.flags = 0;
62e2749e 148 btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
037e6390 149
9f5fae2f
CM
150 for (i = 0; i < extent_root->fs_info->current_insert.flags; i++) {
151 ins.objectid = extent_root->fs_info->current_insert.objectid +
152 i;
1261ec42
CM
153 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
154 btrfs_set_super_blocks_used(info->disk_super,
155 super_blocks_used + 1);
e089f05c
CM
156 ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
157 sizeof(extent_item));
037e6390
CM
158 BUG_ON(ret);
159 }
9f5fae2f 160 extent_root->fs_info->current_insert.offset = 0;
037e6390
CM
161 return 0;
162}
163
e20d96d6
CM
164static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag)
165{
166 int err;
d5719762 167 struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr);
78fae27e 168 struct btrfs_header *header;
d5719762 169 BUG_ON(!bh);
78fae27e
CM
170
171 header = btrfs_buffer_header(bh);
172 if (btrfs_header_generation(header) ==
173 root->fs_info->running_transaction->transid) {
174 return 0;
175 }
176
e20d96d6 177 err = radix_tree_insert(&root->fs_info->pinned_radix,
d5719762 178 blocknr, bh);
d561c025
CM
179 if (err && err != -EEXIST) {
180 BUG();
e20d96d6 181 return err;
d561c025 182 }
78fae27e
CM
183 if (err == -EEXIST)
184 brelse(bh);
e20d96d6
CM
185 radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr,
186 tag);
187 return 0;
188}
189
fec577fb 190/*
a28ec197 191 * remove an extent from the root, returns 0 on success
fec577fb 192 */
e089f05c 193static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
78fae27e 194 *root, u64 blocknr, u64 num_blocks, int pin)
a28ec197 195{
234b63a0 196 struct btrfs_path path;
e2fa7227 197 struct btrfs_key key;
1261ec42
CM
198 struct btrfs_fs_info *info = root->fs_info;
199 struct btrfs_root *extent_root = info->extent_root;
a28ec197 200 int ret;
234b63a0 201 struct btrfs_extent_item *ei;
e2fa7227 202 struct btrfs_key ins;
cf27e1ee 203 u32 refs;
037e6390 204
a28ec197
CM
205 key.objectid = blocknr;
206 key.flags = 0;
62e2749e 207 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
a28ec197
CM
208 key.offset = num_blocks;
209
e089f05c 210 find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
234b63a0 211 btrfs_init_path(&path);
e089f05c 212 ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1);
a28ec197 213 if (ret) {
2e635a27 214 printk("failed to find %Lu\n", key.objectid);
234b63a0 215 btrfs_print_tree(extent_root, extent_root->node);
2e635a27 216 printk("failed to find %Lu\n", key.objectid);
a28ec197
CM
217 BUG();
218 }
e20d96d6 219 ei = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
123abc88 220 struct btrfs_extent_item);
a28ec197 221 BUG_ON(ei->refs == 0);
cf27e1ee
CM
222 refs = btrfs_extent_refs(ei) - 1;
223 btrfs_set_extent_refs(ei, refs);
224 if (refs == 0) {
1261ec42 225 u64 super_blocks_used;
78fae27e
CM
226
227 if (pin) {
228 ret = pin_down_block(root, blocknr,
229 CTREE_EXTENT_PINNED);
230 BUG_ON(ret);
231 }
232
1261ec42
CM
233 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
234 btrfs_set_super_blocks_used(info->disk_super,
235 super_blocks_used - num_blocks);
e089f05c 236 ret = btrfs_del_item(trans, extent_root, &path);
78fae27e 237 if (extent_root->fs_info->last_insert.objectid > blocknr)
9f5fae2f 238 extent_root->fs_info->last_insert.objectid = blocknr;
a28ec197
CM
239 if (ret)
240 BUG();
241 }
d5719762 242 mark_buffer_dirty(path.nodes[0]);
234b63a0 243 btrfs_release_path(extent_root, &path);
e089f05c 244 finish_current_insert(trans, extent_root);
a28ec197
CM
245 return ret;
246}
247
a28ec197
CM
248/*
249 * find all the blocks marked as pending in the radix tree and remove
250 * them from the extent map
251 */
e089f05c
CM
252static int del_pending_extents(struct btrfs_trans_handle *trans, struct
253 btrfs_root *extent_root)
a28ec197
CM
254{
255 int ret;
e20d96d6
CM
256 int wret;
257 int err = 0;
d5719762 258 struct buffer_head *gang[4];
a28ec197 259 int i;
e20d96d6 260 struct radix_tree_root *radix = &extent_root->fs_info->pinned_radix;
a28ec197
CM
261
262 while(1) {
9f5fae2f 263 ret = radix_tree_gang_lookup_tag(
e20d96d6 264 &extent_root->fs_info->pinned_radix,
9f5fae2f
CM
265 (void **)gang, 0,
266 ARRAY_SIZE(gang),
267 CTREE_EXTENT_PENDING_DEL);
a28ec197
CM
268 if (!ret)
269 break;
270 for (i = 0; i < ret; i++) {
d5719762
CM
271 radix_tree_tag_set(radix, gang[i]->b_blocknr,
272 CTREE_EXTENT_PINNED);
273 radix_tree_tag_clear(radix, gang[i]->b_blocknr,
9f5fae2f 274 CTREE_EXTENT_PENDING_DEL);
d5719762 275 wret = __free_extent(trans, extent_root,
78fae27e 276 gang[i]->b_blocknr, 1, 0);
e20d96d6
CM
277 if (wret)
278 err = wret;
fec577fb
CM
279 }
280 }
e20d96d6 281 return err;
fec577fb
CM
282}
283
284/*
285 * remove an extent from the root, returns 0 on success
286 */
e089f05c
CM
287int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
288 *root, u64 blocknr, u64 num_blocks, int pin)
fec577fb 289{
9f5fae2f 290 struct btrfs_root *extent_root = root->fs_info->extent_root;
e20d96d6 291 struct buffer_head *t;
fec577fb
CM
292 int pending_ret;
293 int ret;
a28ec197 294
fec577fb 295 if (root == extent_root) {
a28ec197 296 t = find_tree_block(root, blocknr);
e20d96d6 297 pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL);
fec577fb
CM
298 return 0;
299 }
78fae27e 300 ret = __free_extent(trans, root, blocknr, num_blocks, pin);
e20d96d6 301 pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
fec577fb
CM
302 return ret ? ret : pending_ret;
303}
304
305/*
306 * walks the btree of allocated extents and find a hole of a given size.
307 * The key ins is changed to record the hole:
308 * ins->objectid == block start
62e2749e 309 * ins->flags = BTRFS_EXTENT_ITEM_KEY
fec577fb
CM
310 * ins->offset == number of blocks
311 * Any available blocks before search_start are skipped.
312 */
e089f05c
CM
313static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
314 *orig_root, u64 num_blocks, u64 search_start, u64
315 search_end, struct btrfs_key *ins)
fec577fb 316{
234b63a0 317 struct btrfs_path path;
e2fa7227 318 struct btrfs_key key;
fec577fb
CM
319 int ret;
320 u64 hole_size = 0;
321 int slot = 0;
e20d96d6 322 u64 last_block = 0;
037e6390 323 u64 test_block;
fec577fb 324 int start_found;
234b63a0 325 struct btrfs_leaf *l;
9f5fae2f 326 struct btrfs_root * root = orig_root->fs_info->extent_root;
0579da42 327 int total_needed = num_blocks;
e20d96d6 328 int level;
fec577fb 329
e20d96d6
CM
330 level = btrfs_header_level(btrfs_buffer_header(root->node));
331 total_needed += (level + 1) * 3;
9f5fae2f
CM
332 if (root->fs_info->last_insert.objectid > search_start)
333 search_start = root->fs_info->last_insert.objectid;
62e2749e
CM
334
335 ins->flags = 0;
336 btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
337
fec577fb 338check_failed:
234b63a0 339 btrfs_init_path(&path);
fec577fb
CM
340 ins->objectid = search_start;
341 ins->offset = 0;
fec577fb 342 start_found = 0;
e089f05c 343 ret = btrfs_search_slot(trans, root, ins, &path, 0, 0);
0f70abe2
CM
344 if (ret < 0)
345 goto error;
aa5d6bed 346
0579da42
CM
347 if (path.slots[0] > 0)
348 path.slots[0]--;
349
fec577fb 350 while (1) {
e20d96d6 351 l = btrfs_buffer_leaf(path.nodes[0]);
fec577fb 352 slot = path.slots[0];
7518a238 353 if (slot >= btrfs_header_nritems(&l->header)) {
234b63a0 354 ret = btrfs_next_leaf(root, &path);
fec577fb
CM
355 if (ret == 0)
356 continue;
0f70abe2
CM
357 if (ret < 0)
358 goto error;
fec577fb
CM
359 if (!start_found) {
360 ins->objectid = search_start;
037e6390 361 ins->offset = (u64)-1;
fec577fb
CM
362 start_found = 1;
363 goto check_pending;
364 }
365 ins->objectid = last_block > search_start ?
366 last_block : search_start;
037e6390 367 ins->offset = (u64)-1;
fec577fb
CM
368 goto check_pending;
369 }
e2fa7227
CM
370 btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
371 if (key.objectid >= search_start) {
fec577fb 372 if (start_found) {
0579da42
CM
373 if (last_block < search_start)
374 last_block = search_start;
e2fa7227 375 hole_size = key.objectid - last_block;
037e6390 376 if (hole_size > total_needed) {
fec577fb 377 ins->objectid = last_block;
037e6390 378 ins->offset = hole_size;
fec577fb
CM
379 goto check_pending;
380 }
0579da42 381 }
fec577fb 382 }
0579da42 383 start_found = 1;
e2fa7227 384 last_block = key.objectid + key.offset;
fec577fb
CM
385 path.slots[0]++;
386 }
387 // FIXME -ENOSPC
388check_pending:
389 /* we have to make sure we didn't find an extent that has already
390 * been allocated by the map tree or the original allocation
391 */
234b63a0 392 btrfs_release_path(root, &path);
fec577fb 393 BUG_ON(ins->objectid < search_start);
037e6390
CM
394 for (test_block = ins->objectid;
395 test_block < ins->objectid + total_needed; test_block++) {
9f5fae2f
CM
396 if (radix_tree_lookup(&root->fs_info->pinned_radix,
397 test_block)) {
037e6390 398 search_start = test_block + 1;
fec577fb
CM
399 goto check_failed;
400 }
401 }
9f5fae2f
CM
402 BUG_ON(root->fs_info->current_insert.offset);
403 root->fs_info->current_insert.offset = total_needed - num_blocks;
404 root->fs_info->current_insert.objectid = ins->objectid + num_blocks;
405 root->fs_info->current_insert.flags = 0;
406 root->fs_info->last_insert.objectid = ins->objectid;
037e6390 407 ins->offset = num_blocks;
fec577fb 408 return 0;
0f70abe2 409error:
234b63a0 410 btrfs_release_path(root, &path);
0f70abe2 411 return ret;
fec577fb
CM
412}
413
fec577fb
CM
414/*
415 * finds a free extent and does all the dirty work required for allocation
416 * returns the key for the extent through ins, and a tree buffer for
417 * the first block of the extent through buf.
418 *
419 * returns 0 if everything worked, non-zero otherwise.
420 */
e089f05c
CM
421static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
422 *root, u64 num_blocks, u64 search_start, u64
423 search_end, u64 owner, struct btrfs_key *ins)
fec577fb
CM
424{
425 int ret;
426 int pending_ret;
1261ec42
CM
427 u64 super_blocks_used;
428 struct btrfs_fs_info *info = root->fs_info;
429 struct btrfs_root *extent_root = info->extent_root;
234b63a0 430 struct btrfs_extent_item extent_item;
037e6390 431
cf27e1ee
CM
432 btrfs_set_extent_refs(&extent_item, 1);
433 btrfs_set_extent_owner(&extent_item, owner);
fec577fb 434
037e6390 435 if (root == extent_root) {
9f5fae2f 436 BUG_ON(extent_root->fs_info->current_insert.offset == 0);
037e6390 437 BUG_ON(num_blocks != 1);
9f5fae2f
CM
438 BUG_ON(extent_root->fs_info->current_insert.flags ==
439 extent_root->fs_info->current_insert.offset);
037e6390 440 ins->offset = 1;
9f5fae2f
CM
441 ins->objectid = extent_root->fs_info->current_insert.objectid +
442 extent_root->fs_info->current_insert.flags++;
fec577fb
CM
443 return 0;
444 }
e089f05c 445 ret = find_free_extent(trans, root, num_blocks, search_start,
037e6390
CM
446 search_end, ins);
447 if (ret)
448 return ret;
fec577fb 449
1261ec42
CM
450 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
451 btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
452 num_blocks);
e089f05c
CM
453 ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
454 sizeof(extent_item));
037e6390 455
e089f05c 456 finish_current_insert(trans, extent_root);
e20d96d6 457 pending_ret = del_pending_extents(trans, extent_root);
037e6390
CM
458 if (ret)
459 return ret;
460 if (pending_ret)
461 return pending_ret;
462 return 0;
fec577fb
CM
463}
464
465/*
466 * helper function to allocate a block for a given tree
467 * returns the tree buffer or NULL.
468 */
e20d96d6 469struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
e089f05c 470 struct btrfs_root *root)
fec577fb 471{
e2fa7227 472 struct btrfs_key ins;
fec577fb 473 int ret;
e20d96d6 474 struct buffer_head *buf;
fec577fb 475
e089f05c 476 ret = alloc_extent(trans, root, 1, 0, (unsigned long)-1,
e20d96d6 477 btrfs_header_parentid(btrfs_buffer_header(root->node)), &ins);
fec577fb
CM
478 if (ret) {
479 BUG();
480 return NULL;
481 }
037e6390 482 buf = find_tree_block(root, ins.objectid);
df2ce34c 483 set_buffer_uptodate(buf);
fec577fb
CM
484 return buf;
485}
a28ec197 486
9aca1d51
CM
487/*
488 * helper function for drop_snapshot, this walks down the tree dropping ref
489 * counts as it goes.
490 */
e089f05c
CM
491static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
492 *root, struct btrfs_path *path, int *level)
20524f02 493{
e20d96d6
CM
494 struct buffer_head *next;
495 struct buffer_head *cur;
20524f02
CM
496 u64 blocknr;
497 int ret;
498 u32 refs;
499
e20d96d6 500 ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr,
e089f05c 501 &refs);
20524f02
CM
502 BUG_ON(ret);
503 if (refs > 1)
504 goto out;
9aca1d51
CM
505 /*
506 * walk down to the last node level and free all the leaves
507 */
20524f02
CM
508 while(*level > 0) {
509 cur = path->nodes[*level];
7518a238 510 if (path->slots[*level] >=
e20d96d6 511 btrfs_header_nritems(btrfs_buffer_header(cur)))
20524f02 512 break;
e20d96d6
CM
513 blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
514 path->slots[*level]);
e089f05c 515 ret = lookup_block_ref(trans, root, blocknr, &refs);
20524f02
CM
516 if (refs != 1 || *level == 1) {
517 path->slots[*level]++;
e089f05c 518 ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
20524f02
CM
519 BUG_ON(ret);
520 continue;
521 }
522 BUG_ON(ret);
523 next = read_tree_block(root, blocknr);
83e15a28 524 if (path->nodes[*level-1])
234b63a0 525 btrfs_block_release(root, path->nodes[*level-1]);
20524f02 526 path->nodes[*level-1] = next;
e20d96d6 527 *level = btrfs_header_level(btrfs_buffer_header(next));
20524f02
CM
528 path->slots[*level] = 0;
529 }
530out:
e20d96d6
CM
531 ret = btrfs_free_extent(trans, root, path->nodes[*level]->b_blocknr,
532 1, 1);
234b63a0 533 btrfs_block_release(root, path->nodes[*level]);
20524f02
CM
534 path->nodes[*level] = NULL;
535 *level += 1;
536 BUG_ON(ret);
537 return 0;
538}
539
9aca1d51
CM
540/*
541 * helper for dropping snapshots. This walks back up the tree in the path
542 * to find the first node higher up where we haven't yet gone through
543 * all the slots
544 */
e089f05c
CM
545static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
546 *root, struct btrfs_path *path, int *level)
20524f02
CM
547{
548 int i;
549 int slot;
550 int ret;
234b63a0 551 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
20524f02 552 slot = path->slots[i];
e20d96d6
CM
553 if (slot < btrfs_header_nritems(
554 btrfs_buffer_header(path->nodes[i])) - 1) {
20524f02
CM
555 path->slots[i]++;
556 *level = i;
557 return 0;
558 } else {
e089f05c 559 ret = btrfs_free_extent(trans, root,
e20d96d6 560 path->nodes[*level]->b_blocknr,
e089f05c 561 1, 1);
234b63a0 562 btrfs_block_release(root, path->nodes[*level]);
83e15a28 563 path->nodes[*level] = NULL;
20524f02
CM
564 *level = i + 1;
565 BUG_ON(ret);
566 }
567 }
568 return 1;
569}
570
9aca1d51
CM
571/*
572 * drop the reference count on the tree rooted at 'snap'. This traverses
573 * the tree freeing any blocks that have a ref count of zero after being
574 * decremented.
575 */
e089f05c 576int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
e20d96d6 577 *root, struct buffer_head *snap)
20524f02 578{
3768f368 579 int ret = 0;
9aca1d51 580 int wret;
20524f02 581 int level;
234b63a0 582 struct btrfs_path path;
20524f02
CM
583 int i;
584 int orig_level;
585
234b63a0 586 btrfs_init_path(&path);
20524f02 587
e20d96d6 588 level = btrfs_header_level(btrfs_buffer_header(snap));
20524f02
CM
589 orig_level = level;
590 path.nodes[level] = snap;
591 path.slots[level] = 0;
592 while(1) {
e089f05c 593 wret = walk_down_tree(trans, root, &path, &level);
9aca1d51 594 if (wret > 0)
20524f02 595 break;
9aca1d51
CM
596 if (wret < 0)
597 ret = wret;
598
e089f05c 599 wret = walk_up_tree(trans, root, &path, &level);
9aca1d51 600 if (wret > 0)
20524f02 601 break;
9aca1d51
CM
602 if (wret < 0)
603 ret = wret;
20524f02 604 }
83e15a28
CM
605 for (i = 0; i <= orig_level; i++) {
606 if (path.nodes[i]) {
234b63a0 607 btrfs_block_release(root, path.nodes[i]);
83e15a28 608 }
20524f02 609 }
9aca1d51 610 return ret;
20524f02 611}