Btrfs: very minimal locking
[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
CM
167 struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr);
168 BUG_ON(!bh);
e20d96d6 169 err = radix_tree_insert(&root->fs_info->pinned_radix,
d5719762 170 blocknr, bh);
d561c025
CM
171 if (err && err != -EEXIST) {
172 BUG();
e20d96d6 173 return err;
d561c025 174 }
e20d96d6
CM
175 radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr,
176 tag);
177 return 0;
178}
179
fec577fb 180/*
a28ec197 181 * remove an extent from the root, returns 0 on success
fec577fb 182 */
e089f05c 183static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
e20d96d6 184 *root, u64 blocknr, u64 num_blocks)
a28ec197 185{
234b63a0 186 struct btrfs_path path;
e2fa7227 187 struct btrfs_key key;
1261ec42
CM
188 struct btrfs_fs_info *info = root->fs_info;
189 struct btrfs_root *extent_root = info->extent_root;
a28ec197 190 int ret;
234b63a0 191 struct btrfs_extent_item *ei;
e2fa7227 192 struct btrfs_key ins;
cf27e1ee 193 u32 refs;
037e6390 194
a28ec197
CM
195 key.objectid = blocknr;
196 key.flags = 0;
62e2749e 197 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
a28ec197
CM
198 key.offset = num_blocks;
199
e089f05c 200 find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
234b63a0 201 btrfs_init_path(&path);
e089f05c 202 ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1);
a28ec197 203 if (ret) {
2e635a27 204 printk("failed to find %Lu\n", key.objectid);
234b63a0 205 btrfs_print_tree(extent_root, extent_root->node);
2e635a27 206 printk("failed to find %Lu\n", key.objectid);
a28ec197
CM
207 BUG();
208 }
e20d96d6 209 ei = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
123abc88 210 struct btrfs_extent_item);
a28ec197 211 BUG_ON(ei->refs == 0);
cf27e1ee
CM
212 refs = btrfs_extent_refs(ei) - 1;
213 btrfs_set_extent_refs(ei, refs);
214 if (refs == 0) {
1261ec42 215 u64 super_blocks_used;
1261ec42
CM
216 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
217 btrfs_set_super_blocks_used(info->disk_super,
218 super_blocks_used - num_blocks);
e089f05c 219 ret = btrfs_del_item(trans, extent_root, &path);
e20d96d6 220 if (extent_root->fs_info->last_insert.objectid >
9f5fae2f
CM
221 blocknr)
222 extent_root->fs_info->last_insert.objectid = blocknr;
a28ec197
CM
223 if (ret)
224 BUG();
225 }
d5719762 226 mark_buffer_dirty(path.nodes[0]);
234b63a0 227 btrfs_release_path(extent_root, &path);
e089f05c 228 finish_current_insert(trans, extent_root);
a28ec197
CM
229 return ret;
230}
231
a28ec197
CM
232/*
233 * find all the blocks marked as pending in the radix tree and remove
234 * them from the extent map
235 */
e089f05c
CM
236static int del_pending_extents(struct btrfs_trans_handle *trans, struct
237 btrfs_root *extent_root)
a28ec197
CM
238{
239 int ret;
e20d96d6
CM
240 int wret;
241 int err = 0;
d5719762 242 struct buffer_head *gang[4];
a28ec197 243 int i;
e20d96d6 244 struct radix_tree_root *radix = &extent_root->fs_info->pinned_radix;
a28ec197
CM
245
246 while(1) {
9f5fae2f 247 ret = radix_tree_gang_lookup_tag(
e20d96d6 248 &extent_root->fs_info->pinned_radix,
9f5fae2f
CM
249 (void **)gang, 0,
250 ARRAY_SIZE(gang),
251 CTREE_EXTENT_PENDING_DEL);
a28ec197
CM
252 if (!ret)
253 break;
254 for (i = 0; i < ret; i++) {
d5719762
CM
255 radix_tree_tag_set(radix, gang[i]->b_blocknr,
256 CTREE_EXTENT_PINNED);
257 radix_tree_tag_clear(radix, gang[i]->b_blocknr,
9f5fae2f 258 CTREE_EXTENT_PENDING_DEL);
d5719762
CM
259 wret = __free_extent(trans, extent_root,
260 gang[i]->b_blocknr, 1);
e20d96d6
CM
261 if (wret)
262 err = wret;
fec577fb
CM
263 }
264 }
e20d96d6 265 return err;
fec577fb
CM
266}
267
268/*
269 * remove an extent from the root, returns 0 on success
270 */
e089f05c
CM
271int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
272 *root, u64 blocknr, u64 num_blocks, int pin)
fec577fb 273{
9f5fae2f 274 struct btrfs_root *extent_root = root->fs_info->extent_root;
e20d96d6 275 struct buffer_head *t;
fec577fb
CM
276 int pending_ret;
277 int ret;
a28ec197 278
fec577fb 279 if (root == extent_root) {
a28ec197 280 t = find_tree_block(root, blocknr);
e20d96d6 281 pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL);
fec577fb
CM
282 return 0;
283 }
e20d96d6
CM
284 if (pin) {
285 ret = pin_down_block(root, blocknr, CTREE_EXTENT_PINNED);
286 BUG_ON(ret);
287 }
288 ret = __free_extent(trans, root, blocknr, num_blocks);
289 pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
fec577fb
CM
290 return ret ? ret : pending_ret;
291}
292
293/*
294 * walks the btree of allocated extents and find a hole of a given size.
295 * The key ins is changed to record the hole:
296 * ins->objectid == block start
62e2749e 297 * ins->flags = BTRFS_EXTENT_ITEM_KEY
fec577fb
CM
298 * ins->offset == number of blocks
299 * Any available blocks before search_start are skipped.
300 */
e089f05c
CM
301static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
302 *orig_root, u64 num_blocks, u64 search_start, u64
303 search_end, struct btrfs_key *ins)
fec577fb 304{
234b63a0 305 struct btrfs_path path;
e2fa7227 306 struct btrfs_key key;
fec577fb
CM
307 int ret;
308 u64 hole_size = 0;
309 int slot = 0;
e20d96d6 310 u64 last_block = 0;
037e6390 311 u64 test_block;
fec577fb 312 int start_found;
234b63a0 313 struct btrfs_leaf *l;
9f5fae2f 314 struct btrfs_root * root = orig_root->fs_info->extent_root;
0579da42 315 int total_needed = num_blocks;
e20d96d6 316 int level;
fec577fb 317
e20d96d6
CM
318 level = btrfs_header_level(btrfs_buffer_header(root->node));
319 total_needed += (level + 1) * 3;
9f5fae2f
CM
320 if (root->fs_info->last_insert.objectid > search_start)
321 search_start = root->fs_info->last_insert.objectid;
62e2749e
CM
322
323 ins->flags = 0;
324 btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
325
fec577fb 326check_failed:
234b63a0 327 btrfs_init_path(&path);
fec577fb
CM
328 ins->objectid = search_start;
329 ins->offset = 0;
fec577fb 330 start_found = 0;
e089f05c 331 ret = btrfs_search_slot(trans, root, ins, &path, 0, 0);
0f70abe2
CM
332 if (ret < 0)
333 goto error;
aa5d6bed 334
0579da42
CM
335 if (path.slots[0] > 0)
336 path.slots[0]--;
337
fec577fb 338 while (1) {
e20d96d6 339 l = btrfs_buffer_leaf(path.nodes[0]);
fec577fb 340 slot = path.slots[0];
7518a238 341 if (slot >= btrfs_header_nritems(&l->header)) {
234b63a0 342 ret = btrfs_next_leaf(root, &path);
fec577fb
CM
343 if (ret == 0)
344 continue;
0f70abe2
CM
345 if (ret < 0)
346 goto error;
fec577fb
CM
347 if (!start_found) {
348 ins->objectid = search_start;
037e6390 349 ins->offset = (u64)-1;
fec577fb
CM
350 start_found = 1;
351 goto check_pending;
352 }
353 ins->objectid = last_block > search_start ?
354 last_block : search_start;
037e6390 355 ins->offset = (u64)-1;
fec577fb
CM
356 goto check_pending;
357 }
e2fa7227
CM
358 btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
359 if (key.objectid >= search_start) {
fec577fb 360 if (start_found) {
0579da42
CM
361 if (last_block < search_start)
362 last_block = search_start;
e2fa7227 363 hole_size = key.objectid - last_block;
037e6390 364 if (hole_size > total_needed) {
fec577fb 365 ins->objectid = last_block;
037e6390 366 ins->offset = hole_size;
fec577fb
CM
367 goto check_pending;
368 }
0579da42 369 }
fec577fb 370 }
0579da42 371 start_found = 1;
e2fa7227 372 last_block = key.objectid + key.offset;
fec577fb
CM
373 path.slots[0]++;
374 }
375 // FIXME -ENOSPC
376check_pending:
377 /* we have to make sure we didn't find an extent that has already
378 * been allocated by the map tree or the original allocation
379 */
234b63a0 380 btrfs_release_path(root, &path);
fec577fb 381 BUG_ON(ins->objectid < search_start);
037e6390
CM
382 for (test_block = ins->objectid;
383 test_block < ins->objectid + total_needed; test_block++) {
9f5fae2f
CM
384 if (radix_tree_lookup(&root->fs_info->pinned_radix,
385 test_block)) {
037e6390 386 search_start = test_block + 1;
fec577fb
CM
387 goto check_failed;
388 }
389 }
9f5fae2f
CM
390 BUG_ON(root->fs_info->current_insert.offset);
391 root->fs_info->current_insert.offset = total_needed - num_blocks;
392 root->fs_info->current_insert.objectid = ins->objectid + num_blocks;
393 root->fs_info->current_insert.flags = 0;
394 root->fs_info->last_insert.objectid = ins->objectid;
037e6390 395 ins->offset = num_blocks;
fec577fb 396 return 0;
0f70abe2 397error:
234b63a0 398 btrfs_release_path(root, &path);
0f70abe2 399 return ret;
fec577fb
CM
400}
401
fec577fb
CM
402/*
403 * finds a free extent and does all the dirty work required for allocation
404 * returns the key for the extent through ins, and a tree buffer for
405 * the first block of the extent through buf.
406 *
407 * returns 0 if everything worked, non-zero otherwise.
408 */
e089f05c
CM
409static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
410 *root, u64 num_blocks, u64 search_start, u64
411 search_end, u64 owner, struct btrfs_key *ins)
fec577fb
CM
412{
413 int ret;
414 int pending_ret;
1261ec42
CM
415 u64 super_blocks_used;
416 struct btrfs_fs_info *info = root->fs_info;
417 struct btrfs_root *extent_root = info->extent_root;
234b63a0 418 struct btrfs_extent_item extent_item;
037e6390 419
cf27e1ee
CM
420 btrfs_set_extent_refs(&extent_item, 1);
421 btrfs_set_extent_owner(&extent_item, owner);
fec577fb 422
037e6390 423 if (root == extent_root) {
9f5fae2f 424 BUG_ON(extent_root->fs_info->current_insert.offset == 0);
037e6390 425 BUG_ON(num_blocks != 1);
9f5fae2f
CM
426 BUG_ON(extent_root->fs_info->current_insert.flags ==
427 extent_root->fs_info->current_insert.offset);
037e6390 428 ins->offset = 1;
9f5fae2f
CM
429 ins->objectid = extent_root->fs_info->current_insert.objectid +
430 extent_root->fs_info->current_insert.flags++;
fec577fb
CM
431 return 0;
432 }
e089f05c 433 ret = find_free_extent(trans, root, num_blocks, search_start,
037e6390
CM
434 search_end, ins);
435 if (ret)
436 return ret;
fec577fb 437
1261ec42
CM
438 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
439 btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
440 num_blocks);
e089f05c
CM
441 ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
442 sizeof(extent_item));
037e6390 443
e089f05c 444 finish_current_insert(trans, extent_root);
e20d96d6 445 pending_ret = del_pending_extents(trans, extent_root);
037e6390
CM
446 if (ret)
447 return ret;
448 if (pending_ret)
449 return pending_ret;
450 return 0;
fec577fb
CM
451}
452
453/*
454 * helper function to allocate a block for a given tree
455 * returns the tree buffer or NULL.
456 */
e20d96d6 457struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
e089f05c 458 struct btrfs_root *root)
fec577fb 459{
e2fa7227 460 struct btrfs_key ins;
fec577fb 461 int ret;
e20d96d6 462 struct buffer_head *buf;
fec577fb 463
e089f05c 464 ret = alloc_extent(trans, root, 1, 0, (unsigned long)-1,
e20d96d6 465 btrfs_header_parentid(btrfs_buffer_header(root->node)), &ins);
fec577fb
CM
466 if (ret) {
467 BUG();
468 return NULL;
469 }
037e6390 470 buf = find_tree_block(root, ins.objectid);
df2ce34c 471 set_buffer_uptodate(buf);
fec577fb
CM
472 return buf;
473}
a28ec197 474
9aca1d51
CM
475/*
476 * helper function for drop_snapshot, this walks down the tree dropping ref
477 * counts as it goes.
478 */
e089f05c
CM
479static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
480 *root, struct btrfs_path *path, int *level)
20524f02 481{
e20d96d6
CM
482 struct buffer_head *next;
483 struct buffer_head *cur;
20524f02
CM
484 u64 blocknr;
485 int ret;
486 u32 refs;
487
e20d96d6 488 ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr,
e089f05c 489 &refs);
20524f02
CM
490 BUG_ON(ret);
491 if (refs > 1)
492 goto out;
9aca1d51
CM
493 /*
494 * walk down to the last node level and free all the leaves
495 */
20524f02
CM
496 while(*level > 0) {
497 cur = path->nodes[*level];
7518a238 498 if (path->slots[*level] >=
e20d96d6 499 btrfs_header_nritems(btrfs_buffer_header(cur)))
20524f02 500 break;
e20d96d6
CM
501 blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
502 path->slots[*level]);
e089f05c 503 ret = lookup_block_ref(trans, root, blocknr, &refs);
20524f02
CM
504 if (refs != 1 || *level == 1) {
505 path->slots[*level]++;
e089f05c 506 ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
20524f02
CM
507 BUG_ON(ret);
508 continue;
509 }
510 BUG_ON(ret);
511 next = read_tree_block(root, blocknr);
83e15a28 512 if (path->nodes[*level-1])
234b63a0 513 btrfs_block_release(root, path->nodes[*level-1]);
20524f02 514 path->nodes[*level-1] = next;
e20d96d6 515 *level = btrfs_header_level(btrfs_buffer_header(next));
20524f02
CM
516 path->slots[*level] = 0;
517 }
518out:
e20d96d6
CM
519 ret = btrfs_free_extent(trans, root, path->nodes[*level]->b_blocknr,
520 1, 1);
234b63a0 521 btrfs_block_release(root, path->nodes[*level]);
20524f02
CM
522 path->nodes[*level] = NULL;
523 *level += 1;
524 BUG_ON(ret);
525 return 0;
526}
527
9aca1d51
CM
528/*
529 * helper for dropping snapshots. This walks back up the tree in the path
530 * to find the first node higher up where we haven't yet gone through
531 * all the slots
532 */
e089f05c
CM
533static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
534 *root, struct btrfs_path *path, int *level)
20524f02
CM
535{
536 int i;
537 int slot;
538 int ret;
234b63a0 539 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
20524f02 540 slot = path->slots[i];
e20d96d6
CM
541 if (slot < btrfs_header_nritems(
542 btrfs_buffer_header(path->nodes[i])) - 1) {
20524f02
CM
543 path->slots[i]++;
544 *level = i;
545 return 0;
546 } else {
e089f05c 547 ret = btrfs_free_extent(trans, root,
e20d96d6 548 path->nodes[*level]->b_blocknr,
e089f05c 549 1, 1);
234b63a0 550 btrfs_block_release(root, path->nodes[*level]);
83e15a28 551 path->nodes[*level] = NULL;
20524f02
CM
552 *level = i + 1;
553 BUG_ON(ret);
554 }
555 }
556 return 1;
557}
558
9aca1d51
CM
559/*
560 * drop the reference count on the tree rooted at 'snap'. This traverses
561 * the tree freeing any blocks that have a ref count of zero after being
562 * decremented.
563 */
e089f05c 564int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
e20d96d6 565 *root, struct buffer_head *snap)
20524f02 566{
3768f368 567 int ret = 0;
9aca1d51 568 int wret;
20524f02 569 int level;
234b63a0 570 struct btrfs_path path;
20524f02
CM
571 int i;
572 int orig_level;
573
234b63a0 574 btrfs_init_path(&path);
20524f02 575
e20d96d6 576 level = btrfs_header_level(btrfs_buffer_header(snap));
20524f02
CM
577 orig_level = level;
578 path.nodes[level] = snap;
579 path.slots[level] = 0;
580 while(1) {
e089f05c 581 wret = walk_down_tree(trans, root, &path, &level);
9aca1d51 582 if (wret > 0)
20524f02 583 break;
9aca1d51
CM
584 if (wret < 0)
585 ret = wret;
586
e089f05c 587 wret = walk_up_tree(trans, root, &path, &level);
9aca1d51 588 if (wret > 0)
20524f02 589 break;
9aca1d51
CM
590 if (wret < 0)
591 ret = wret;
20524f02 592 }
83e15a28
CM
593 for (i = 0; i <= orig_level; i++) {
594 if (path.nodes[i]) {
234b63a0 595 btrfs_block_release(root, path.nodes[i]);
83e15a28 596 }
20524f02 597 }
9aca1d51 598 return ret;
20524f02 599}