]> git.karo-electronics.de Git - mv-sheeva.git/blob - fs/btrfs/extent-tree.c
Btrfs: fix extent owner/type setting on extent tree blocks
[mv-sheeva.git] / fs / btrfs / extent-tree.c
1 #include <linux/module.h>
2 #include "ctree.h"
3 #include "disk-io.h"
4 #include "print-tree.h"
5 #include "transaction.h"
6
7 static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
8                             *orig_root, u64 num_blocks, u64 search_start, u64
9                             search_end, struct btrfs_key *ins);
10 static int finish_current_insert(struct btrfs_trans_handle *trans, struct
11                                  btrfs_root *extent_root);
12 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
13                                btrfs_root *extent_root);
14
15 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
16                                 struct btrfs_root *root,
17                                 u64 blocknr, u64 num_blocks)
18 {
19         struct btrfs_path *path;
20         int ret;
21         struct btrfs_key key;
22         struct btrfs_leaf *l;
23         struct btrfs_extent_item *item;
24         struct btrfs_key ins;
25         u32 refs;
26
27         find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
28                          &ins);
29         path = btrfs_alloc_path();
30         BUG_ON(!path);
31         btrfs_init_path(path);
32         key.objectid = blocknr;
33         key.flags = 0;
34         btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
35         key.offset = num_blocks;
36         ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
37                                 0, 1);
38         if (ret != 0) {
39 printk("can't find block %Lu %Lu\n", blocknr, num_blocks);
40                 BUG();
41         }
42         BUG_ON(ret != 0);
43         l = btrfs_buffer_leaf(path->nodes[0]);
44         item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
45         refs = btrfs_extent_refs(item);
46         btrfs_set_extent_refs(item, refs + 1);
47         btrfs_mark_buffer_dirty(path->nodes[0]);
48
49         btrfs_release_path(root->fs_info->extent_root, path);
50         btrfs_free_path(path);
51         finish_current_insert(trans, root->fs_info->extent_root);
52         del_pending_extents(trans, root->fs_info->extent_root);
53         return 0;
54 }
55
56 static int lookup_extent_ref(struct btrfs_trans_handle *trans,
57                              struct btrfs_root *root, u64 blocknr,
58                              u64 num_blocks, u32 *refs)
59 {
60         struct btrfs_path *path;
61         int ret;
62         struct btrfs_key key;
63         struct btrfs_leaf *l;
64         struct btrfs_extent_item *item;
65
66         path = btrfs_alloc_path();
67         btrfs_init_path(path);
68         key.objectid = blocknr;
69         key.offset = num_blocks;
70         key.flags = 0;
71         btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
72         ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
73                                 0, 0);
74         if (ret != 0)
75                 BUG();
76         l = btrfs_buffer_leaf(path->nodes[0]);
77         item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
78         *refs = btrfs_extent_refs(item);
79         btrfs_release_path(root->fs_info->extent_root, path);
80         btrfs_free_path(path);
81         return 0;
82 }
83
84 int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
85                        struct btrfs_root *root)
86 {
87         return btrfs_inc_extent_ref(trans, root, bh_blocknr(root->node), 1);
88 }
89
90 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
91                   struct buffer_head *buf)
92 {
93         u64 blocknr;
94         struct btrfs_node *buf_node;
95         struct btrfs_leaf *buf_leaf;
96         struct btrfs_disk_key *key;
97         struct btrfs_file_extent_item *fi;
98         int i;
99         int leaf;
100         int ret;
101
102         if (!root->ref_cows)
103                 return 0;
104         buf_node = btrfs_buffer_node(buf);
105         leaf = btrfs_is_leaf(buf_node);
106         buf_leaf = btrfs_buffer_leaf(buf);
107         for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
108                 if (leaf) {
109                         key = &buf_leaf->items[i].key;
110                         if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
111                                 continue;
112                         fi = btrfs_item_ptr(buf_leaf, i,
113                                             struct btrfs_file_extent_item);
114                         if (btrfs_file_extent_type(fi) ==
115                             BTRFS_FILE_EXTENT_INLINE)
116                                 continue;
117                         ret = btrfs_inc_extent_ref(trans, root,
118                                     btrfs_file_extent_disk_blocknr(fi),
119                                     btrfs_file_extent_disk_num_blocks(fi));
120                         BUG_ON(ret);
121                 } else {
122                         blocknr = btrfs_node_blockptr(buf_node, i);
123                         ret = btrfs_inc_extent_ref(trans, root, blocknr, 1);
124                         BUG_ON(ret);
125                 }
126         }
127         return 0;
128 }
129
130 int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
131                                btrfs_root *root)
132 {
133         unsigned long gang[8];
134         u64 first = 0;
135         int ret;
136         int i;
137         struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
138
139         while(1) {
140                 ret = find_first_radix_bit(pinned_radix, gang,
141                                            ARRAY_SIZE(gang));
142                 if (!ret)
143                         break;
144                 if (!first)
145                         first = gang[0];
146                 for (i = 0; i < ret; i++) {
147                         clear_radix_bit(pinned_radix, gang[i]);
148                 }
149         }
150         if (root->fs_info->last_insert.objectid > first)
151                 root->fs_info->last_insert.objectid = first;
152         root->fs_info->last_insert.offset = 0;
153         return 0;
154 }
155
156 static int finish_current_insert(struct btrfs_trans_handle *trans, struct
157                                  btrfs_root *extent_root)
158 {
159         struct btrfs_key ins;
160         struct btrfs_extent_item extent_item;
161         int i;
162         int ret;
163         u64 super_blocks_used;
164         struct btrfs_fs_info *info = extent_root->fs_info;
165
166         btrfs_set_extent_refs(&extent_item, 1);
167         ins.offset = 1;
168         ins.flags = 0;
169         btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
170         btrfs_set_extent_type(&extent_item, BTRFS_EXTENT_TREE);
171         btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
172
173         for (i = 0; i < extent_root->fs_info->current_insert.flags; i++) {
174                 ins.objectid = extent_root->fs_info->current_insert.objectid +
175                                 i;
176                 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
177                 btrfs_set_super_blocks_used(info->disk_super,
178                                             super_blocks_used + 1);
179                 ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
180                                         sizeof(extent_item));
181                 BUG_ON(ret);
182         }
183         extent_root->fs_info->current_insert.offset = 0;
184         return 0;
185 }
186
187 static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
188 {
189         int err;
190         struct btrfs_header *header;
191         struct buffer_head *bh;
192
193         if (!pending) {
194                 bh = btrfs_find_tree_block(root, blocknr);
195                 if (bh) {
196                         if (buffer_uptodate(bh)) {
197                                 u64 transid =
198                                     root->fs_info->running_transaction->transid;
199                                 header = btrfs_buffer_header(bh);
200                                 if (btrfs_header_generation(header) ==
201                                     transid) {
202                                         btrfs_block_release(root, bh);
203                                         return 0;
204                                 }
205                         }
206                         btrfs_block_release(root, bh);
207                 }
208                 err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
209         } else {
210                 err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
211         }
212         BUG_ON(err);
213         return 0;
214 }
215
216 /*
217  * remove an extent from the root, returns 0 on success
218  */
219 static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
220                          *root, u64 blocknr, u64 num_blocks, int pin)
221 {
222         struct btrfs_path *path;
223         struct btrfs_key key;
224         struct btrfs_fs_info *info = root->fs_info;
225         struct btrfs_root *extent_root = info->extent_root;
226         int ret;
227         struct btrfs_extent_item *ei;
228         struct btrfs_key ins;
229         u32 refs;
230
231         key.objectid = blocknr;
232         key.flags = 0;
233         btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
234         key.offset = num_blocks;
235
236         find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
237         path = btrfs_alloc_path();
238         BUG_ON(!path);
239         btrfs_init_path(path);
240
241         ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
242         if (ret) {
243                 printk("failed to find %Lu\n", key.objectid);
244                 btrfs_print_tree(extent_root, extent_root->node);
245                 printk("failed to find %Lu\n", key.objectid);
246                 BUG();
247         }
248         ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
249                             struct btrfs_extent_item);
250         BUG_ON(ei->refs == 0);
251         refs = btrfs_extent_refs(ei) - 1;
252         btrfs_set_extent_refs(ei, refs);
253         btrfs_mark_buffer_dirty(path->nodes[0]);
254         if (refs == 0) {
255                 u64 super_blocks_used;
256
257                 if (pin) {
258                         ret = pin_down_block(root, blocknr, 0);
259                         BUG_ON(ret);
260                 }
261
262                 super_blocks_used = btrfs_super_blocks_used(info->disk_super);
263                 btrfs_set_super_blocks_used(info->disk_super,
264                                             super_blocks_used - num_blocks);
265                 ret = btrfs_del_item(trans, extent_root, path);
266                 if (ret)
267                         BUG();
268         }
269         btrfs_release_path(extent_root, path);
270         btrfs_free_path(path);
271         finish_current_insert(trans, extent_root);
272         return ret;
273 }
274
275 /*
276  * find all the blocks marked as pending in the radix tree and remove
277  * them from the extent map
278  */
279 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
280                                btrfs_root *extent_root)
281 {
282         int ret;
283         int wret;
284         int err = 0;
285         unsigned long gang[4];
286         int i;
287         struct radix_tree_root *pending_radix;
288         struct radix_tree_root *pinned_radix;
289
290         pending_radix = &extent_root->fs_info->pending_del_radix;
291         pinned_radix = &extent_root->fs_info->pinned_radix;
292
293         while(1) {
294                 ret = find_first_radix_bit(pending_radix, gang,
295                                            ARRAY_SIZE(gang));
296                 if (!ret)
297                         break;
298                 for (i = 0; i < ret; i++) {
299                         wret = set_radix_bit(pinned_radix, gang[i]);
300                         BUG_ON(wret);
301                         wret = clear_radix_bit(pending_radix, gang[i]);
302                         BUG_ON(wret);
303                         wret = __free_extent(trans, extent_root,
304                                              gang[i], 1, 0);
305                         if (wret)
306                                 err = wret;
307                 }
308         }
309         return err;
310 }
311
312 /*
313  * remove an extent from the root, returns 0 on success
314  */
315 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
316                       *root, u64 blocknr, u64 num_blocks, int pin)
317 {
318         struct btrfs_root *extent_root = root->fs_info->extent_root;
319         int pending_ret;
320         int ret;
321
322         if (root == extent_root) {
323                 pin_down_block(root, blocknr, 1);
324                 return 0;
325         }
326         ret = __free_extent(trans, root, blocknr, num_blocks, pin);
327         pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
328         return ret ? ret : pending_ret;
329 }
330
331 /*
332  * walks the btree of allocated extents and find a hole of a given size.
333  * The key ins is changed to record the hole:
334  * ins->objectid == block start
335  * ins->flags = BTRFS_EXTENT_ITEM_KEY
336  * ins->offset == number of blocks
337  * Any available blocks before search_start are skipped.
338  */
339 static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
340                             *orig_root, u64 num_blocks, u64 search_start, u64
341                             search_end, struct btrfs_key *ins)
342 {
343         struct btrfs_path *path;
344         struct btrfs_key key;
345         int ret;
346         u64 hole_size = 0;
347         int slot = 0;
348         u64 last_block = 0;
349         u64 test_block;
350         int start_found;
351         struct btrfs_leaf *l;
352         struct btrfs_root * root = orig_root->fs_info->extent_root;
353         int total_needed = num_blocks;
354         int level;
355
356         path = btrfs_alloc_path();
357         ins->flags = 0;
358         btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
359
360         level = btrfs_header_level(btrfs_buffer_header(root->node));
361         total_needed += (level + 2) * 3;
362         if (root->fs_info->last_insert.objectid == 0 && search_end == (u64)-1) {
363                 struct btrfs_disk_key *last_key;
364                 btrfs_init_path(path);
365                 ins->objectid = (u64)-1;
366                 ins->offset = (u64)-1;
367                 ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
368                 if (ret < 0)
369                         goto error;
370                 BUG_ON(ret == 0);
371                 if (path->slots[0] > 0)
372                         path->slots[0]--;
373                 l = btrfs_buffer_leaf(path->nodes[0]);
374                 last_key = &l->items[path->slots[0]].key;
375                 search_start = btrfs_disk_key_objectid(last_key);
376         }
377         if (root->fs_info->last_insert.objectid > search_start)
378                 search_start = root->fs_info->last_insert.objectid;
379
380 check_failed:
381         btrfs_init_path(path);
382         ins->objectid = search_start;
383         ins->offset = 0;
384         start_found = 0;
385         ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
386         if (ret < 0)
387                 goto error;
388
389         if (path->slots[0] > 0)
390                 path->slots[0]--;
391
392         while (1) {
393                 l = btrfs_buffer_leaf(path->nodes[0]);
394                 slot = path->slots[0];
395                 if (slot >= btrfs_header_nritems(&l->header)) {
396                         ret = btrfs_next_leaf(root, path);
397                         if (ret == 0)
398                                 continue;
399                         if (ret < 0)
400                                 goto error;
401                         if (!start_found) {
402                                 ins->objectid = search_start;
403                                 ins->offset = (u64)-1;
404                                 start_found = 1;
405                                 goto check_pending;
406                         }
407                         ins->objectid = last_block > search_start ?
408                                         last_block : search_start;
409                         ins->offset = (u64)-1;
410                         goto check_pending;
411                 }
412                 btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
413                 if (key.objectid >= search_start) {
414                         if (start_found) {
415                                 if (last_block < search_start)
416                                         last_block = search_start;
417                                 hole_size = key.objectid - last_block;
418                                 if (hole_size > total_needed) {
419                                         ins->objectid = last_block;
420                                         ins->offset = hole_size;
421                                         goto check_pending;
422                                 }
423                         }
424                 }
425                 start_found = 1;
426                 last_block = key.objectid + key.offset;
427                 path->slots[0]++;
428         }
429         // FIXME -ENOSPC
430 check_pending:
431         /* we have to make sure we didn't find an extent that has already
432          * been allocated by the map tree or the original allocation
433          */
434         btrfs_release_path(root, path);
435         BUG_ON(ins->objectid < search_start);
436         for (test_block = ins->objectid;
437              test_block < ins->objectid + total_needed; test_block++) {
438                 if (test_radix_bit(&root->fs_info->pinned_radix,
439                                       test_block)) {
440                         search_start = test_block + 1;
441                         goto check_failed;
442                 }
443         }
444         BUG_ON(root->fs_info->current_insert.offset);
445         root->fs_info->current_insert.offset = total_needed - num_blocks;
446         root->fs_info->current_insert.objectid = ins->objectid + num_blocks;
447         root->fs_info->current_insert.flags = 0;
448         root->fs_info->last_insert.objectid = ins->objectid;
449         ins->offset = num_blocks;
450         btrfs_free_path(path);
451         return 0;
452 error:
453         btrfs_release_path(root, path);
454         btrfs_free_path(path);
455         return ret;
456 }
457
458 /*
459  * finds a free extent and does all the dirty work required for allocation
460  * returns the key for the extent through ins, and a tree buffer for
461  * the first block of the extent through buf.
462  *
463  * returns 0 if everything worked, non-zero otherwise.
464  */
465 int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
466                        struct btrfs_root *root, u64 owner,
467                        u8 type, u64 num_blocks, u64 search_start,
468                        u64 search_end, struct btrfs_key *ins)
469 {
470         int ret;
471         int pending_ret;
472         u64 super_blocks_used;
473         struct btrfs_fs_info *info = root->fs_info;
474         struct btrfs_root *extent_root = info->extent_root;
475         struct btrfs_extent_item extent_item;
476
477         btrfs_set_extent_refs(&extent_item, 1);
478         btrfs_set_extent_owner(&extent_item, owner);
479         btrfs_set_extent_type(&extent_item, type);
480
481         if (root == extent_root) {
482                 BUG_ON(extent_root->fs_info->current_insert.offset == 0);
483                 BUG_ON(num_blocks != 1);
484                 BUG_ON(extent_root->fs_info->current_insert.flags ==
485                        extent_root->fs_info->current_insert.offset);
486                 ins->offset = 1;
487                 ins->objectid = extent_root->fs_info->current_insert.objectid +
488                                 extent_root->fs_info->current_insert.flags++;
489                 return 0;
490         }
491         ret = find_free_extent(trans, root, num_blocks, search_start,
492                                search_end, ins);
493         if (ret)
494                 return ret;
495
496         super_blocks_used = btrfs_super_blocks_used(info->disk_super);
497         btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
498                                     num_blocks);
499         ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
500                                 sizeof(extent_item));
501
502         finish_current_insert(trans, extent_root);
503         pending_ret = del_pending_extents(trans, extent_root);
504         if (ret)
505                 return ret;
506         if (pending_ret)
507                 return pending_ret;
508         return 0;
509 }
510
511 /*
512  * helper function to allocate a block for a given tree
513  * returns the tree buffer or NULL.
514  */
515 struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
516                                            struct btrfs_root *root)
517 {
518         struct btrfs_key ins;
519         int ret;
520         struct buffer_head *buf;
521
522         ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
523                                  BTRFS_EXTENT_TREE,
524                                  1, 0, (unsigned long)-1, &ins);
525         if (ret) {
526                 BUG();
527                 return NULL;
528         }
529         buf = btrfs_find_create_tree_block(root, ins.objectid);
530         set_buffer_uptodate(buf);
531         return buf;
532 }
533
534 static int drop_leaf_ref(struct btrfs_trans_handle *trans,
535                          struct btrfs_root *root, struct buffer_head *cur)
536 {
537         struct btrfs_disk_key *key;
538         struct btrfs_leaf *leaf;
539         struct btrfs_file_extent_item *fi;
540         int i;
541         int nritems;
542         int ret;
543
544         BUG_ON(!btrfs_is_leaf(btrfs_buffer_node(cur)));
545         leaf = btrfs_buffer_leaf(cur);
546         nritems = btrfs_header_nritems(&leaf->header);
547         for (i = 0; i < nritems; i++) {
548                 key = &leaf->items[i].key;
549                 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
550                         continue;
551                 fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
552                 if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE)
553                         continue;
554                 /*
555                  * FIXME make sure to insert a trans record that
556                  * repeats the snapshot del on crash
557                  */
558                 ret = btrfs_free_extent(trans, root,
559                                         btrfs_file_extent_disk_blocknr(fi),
560                                         btrfs_file_extent_disk_num_blocks(fi),
561                                         0);
562                 BUG_ON(ret);
563         }
564         return 0;
565 }
566
567 /*
568  * helper function for drop_snapshot, this walks down the tree dropping ref
569  * counts as it goes.
570  */
571 static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
572                           *root, struct btrfs_path *path, int *level)
573 {
574         struct buffer_head *next;
575         struct buffer_head *cur;
576         u64 blocknr;
577         int ret;
578         u32 refs;
579
580         WARN_ON(*level < 0);
581         WARN_ON(*level >= BTRFS_MAX_LEVEL);
582         ret = lookup_extent_ref(trans, root, bh_blocknr(path->nodes[*level]),
583                                1, &refs);
584         BUG_ON(ret);
585         if (refs > 1)
586                 goto out;
587         /*
588          * walk down to the last node level and free all the leaves
589          */
590         while(*level >= 0) {
591                 WARN_ON(*level < 0);
592                 WARN_ON(*level >= BTRFS_MAX_LEVEL);
593                 cur = path->nodes[*level];
594                 if (btrfs_header_level(btrfs_buffer_header(cur)) != *level)
595                         WARN_ON(1);
596                 if (path->slots[*level] >=
597                     btrfs_header_nritems(btrfs_buffer_header(cur)))
598                         break;
599                 if (*level == 0) {
600                         ret = drop_leaf_ref(trans, root, cur);
601                         BUG_ON(ret);
602                         break;
603                 }
604                 blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
605                                               path->slots[*level]);
606                 ret = lookup_extent_ref(trans, root, blocknr, 1, &refs);
607                 BUG_ON(ret);
608                 if (refs != 1) {
609                         path->slots[*level]++;
610                         ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
611                         BUG_ON(ret);
612                         continue;
613                 }
614                 next = read_tree_block(root, blocknr);
615                 WARN_ON(*level <= 0);
616                 if (path->nodes[*level-1])
617                         btrfs_block_release(root, path->nodes[*level-1]);
618                 path->nodes[*level-1] = next;
619                 *level = btrfs_header_level(btrfs_buffer_header(next));
620                 path->slots[*level] = 0;
621         }
622 out:
623         WARN_ON(*level < 0);
624         WARN_ON(*level >= BTRFS_MAX_LEVEL);
625         ret = btrfs_free_extent(trans, root,
626                                 bh_blocknr(path->nodes[*level]), 1, 1);
627         btrfs_block_release(root, path->nodes[*level]);
628         path->nodes[*level] = NULL;
629         *level += 1;
630         BUG_ON(ret);
631         return 0;
632 }
633
634 /*
635  * helper for dropping snapshots.  This walks back up the tree in the path
636  * to find the first node higher up where we haven't yet gone through
637  * all the slots
638  */
639 static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
640                         *root, struct btrfs_path *path, int *level)
641 {
642         int i;
643         int slot;
644         int ret;
645         for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
646                 slot = path->slots[i];
647                 if (slot < btrfs_header_nritems(
648                     btrfs_buffer_header(path->nodes[i])) - 1) {
649                         path->slots[i]++;
650                         *level = i;
651                         return 0;
652                 } else {
653                         ret = btrfs_free_extent(trans, root,
654                                                 bh_blocknr(path->nodes[*level]),
655                                                 1, 1);
656                         BUG_ON(ret);
657                         btrfs_block_release(root, path->nodes[*level]);
658                         path->nodes[*level] = NULL;
659                         *level = i + 1;
660                 }
661         }
662         return 1;
663 }
664
665 /*
666  * drop the reference count on the tree rooted at 'snap'.  This traverses
667  * the tree freeing any blocks that have a ref count of zero after being
668  * decremented.
669  */
670 int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
671                         *root, struct buffer_head *snap)
672 {
673         int ret = 0;
674         int wret;
675         int level;
676         struct btrfs_path *path;
677         int i;
678         int orig_level;
679
680         path = btrfs_alloc_path();
681         BUG_ON(!path);
682         btrfs_init_path(path);
683
684         level = btrfs_header_level(btrfs_buffer_header(snap));
685         orig_level = level;
686         path->nodes[level] = snap;
687         path->slots[level] = 0;
688         while(1) {
689                 wret = walk_down_tree(trans, root, path, &level);
690                 if (wret > 0)
691                         break;
692                 if (wret < 0)
693                         ret = wret;
694
695                 wret = walk_up_tree(trans, root, path, &level);
696                 if (wret > 0)
697                         break;
698                 if (wret < 0)
699                         ret = wret;
700         }
701         for (i = 0; i <= orig_level; i++) {
702                 if (path->nodes[i]) {
703                         btrfs_block_release(root, path->nodes[i]);
704                 }
705         }
706         btrfs_free_path(path);
707         return ret;
708 }