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