aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-27 06:33:00 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-27 06:33:00 -0400
commit6407bf6d7c449cbfb0a39d985194e265eda3baf4 (patch)
tree29b7226d36b1fbbe2a6bed134ddc3f8d98853bb2 /fs/btrfs/extent-tree.c
parentdee26a9f7aab7ffe1193cd1415b23a69426acc9f (diff)
Btrfs: reference counts on data extents
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c87
1 files changed, 70 insertions, 17 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 82f6e9eed1d0..4d4fc48c0a31 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -13,7 +13,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
13 btrfs_root *extent_root); 13 btrfs_root *extent_root);
14 14
15static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root 15static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
16 *root, u64 blocknr) 16 *root, u64 blocknr, u64 num_blocks)
17{ 17{
18 struct btrfs_path path; 18 struct btrfs_path path;
19 int ret; 19 int ret;
@@ -29,7 +29,7 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
29 key.objectid = blocknr; 29 key.objectid = blocknr;
30 key.flags = 0; 30 key.flags = 0;
31 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); 31 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
32 key.offset = 1; 32 key.offset = num_blocks;
33 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path, 33 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
34 0, 1); 34 0, 1);
35 if (ret != 0) 35 if (ret != 0)
@@ -48,7 +48,7 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
48} 48}
49 49
50static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root 50static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
51 *root, u64 blocknr, u32 *refs) 51 *root, u64 blocknr, u64 num_blocks, u32 *refs)
52{ 52{
53 struct btrfs_path path; 53 struct btrfs_path path;
54 int ret; 54 int ret;
@@ -57,7 +57,7 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
57 struct btrfs_extent_item *item; 57 struct btrfs_extent_item *item;
58 btrfs_init_path(&path); 58 btrfs_init_path(&path);
59 key.objectid = blocknr; 59 key.objectid = blocknr;
60 key.offset = 1; 60 key.offset = num_blocks;
61 key.flags = 0; 61 key.flags = 0;
62 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); 62 btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
63 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path, 63 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
@@ -76,17 +76,34 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
76{ 76{
77 u64 blocknr; 77 u64 blocknr;
78 struct btrfs_node *buf_node; 78 struct btrfs_node *buf_node;
79 struct btrfs_leaf *buf_leaf;
80 struct btrfs_disk_key *key;
81 struct btrfs_file_extent_item *fi;
79 int i; 82 int i;
83 int leaf;
84 int ret;
80 85
81 if (!root->ref_cows) 86 if (!root->ref_cows)
82 return 0; 87 return 0;
83 buf_node = btrfs_buffer_node(buf); 88 buf_node = btrfs_buffer_node(buf);
84 if (btrfs_is_leaf(buf_node)) 89 leaf = btrfs_is_leaf(buf_node);
85 return 0; 90 buf_leaf = btrfs_buffer_leaf(buf);
86
87 for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) { 91 for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
88 blocknr = btrfs_node_blockptr(buf_node, i); 92 if (leaf) {
89 inc_block_ref(trans, root, blocknr); 93 key = &buf_leaf->items[i].key;
94 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
95 continue;
96 fi = btrfs_item_ptr(buf_leaf, i,
97 struct btrfs_file_extent_item);
98 ret = inc_block_ref(trans, root,
99 btrfs_file_extent_disk_blocknr(fi),
100 btrfs_file_extent_disk_num_blocks(fi));
101 BUG_ON(ret);
102 } else {
103 blocknr = btrfs_node_blockptr(buf_node, i);
104 ret = inc_block_ref(trans, root, blocknr, 1);
105 BUG_ON(ret);
106 }
90 } 107 }
91 return 0; 108 return 0;
92} 109}
@@ -469,6 +486,37 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
469 return buf; 486 return buf;
470} 487}
471 488
489static int drop_leaf_ref(struct btrfs_trans_handle *trans,
490 struct btrfs_root *root, struct buffer_head *cur)
491{
492 struct btrfs_disk_key *key;
493 struct btrfs_leaf *leaf;
494 struct btrfs_file_extent_item *fi;
495 int i;
496 int nritems;
497 int ret;
498
499 BUG_ON(!btrfs_is_leaf(btrfs_buffer_node(cur)));
500 leaf = btrfs_buffer_leaf(cur);
501 nritems = btrfs_header_nritems(&leaf->header);
502 for (i = 0; i < nritems; i++) {
503 key = &leaf->items[i].key;
504 if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
505 continue;
506 fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
507 /*
508 * FIXME make sure to insert a trans record that
509 * repeats the snapshot del on crash
510 */
511 ret = btrfs_free_extent(trans, root,
512 btrfs_file_extent_disk_blocknr(fi),
513 btrfs_file_extent_disk_num_blocks(fi),
514 0);
515 BUG_ON(ret);
516 }
517 return 0;
518}
519
472/* 520/*
473 * helper function for drop_snapshot, this walks down the tree dropping ref 521 * helper function for drop_snapshot, this walks down the tree dropping ref
474 * counts as it goes. 522 * counts as it goes.
@@ -483,28 +531,33 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
483 u32 refs; 531 u32 refs;
484 532
485 ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr, 533 ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr,
486 &refs); 534 1, &refs);
487 BUG_ON(ret); 535 BUG_ON(ret);
488 if (refs > 1) 536 if (refs > 1)
489 goto out; 537 goto out;
490 /* 538 /*
491 * walk down to the last node level and free all the leaves 539 * walk down to the last node level and free all the leaves
492 */ 540 */
493 while(*level > 0) { 541 while(*level >= 0) {
494 cur = path->nodes[*level]; 542 cur = path->nodes[*level];
495 if (path->slots[*level] >= 543 if (path->slots[*level] >=
496 btrfs_header_nritems(btrfs_buffer_header(cur))) 544 btrfs_header_nritems(btrfs_buffer_header(cur)))
497 break; 545 break;
546 if (*level == 0) {
547 ret = drop_leaf_ref(trans, root, cur);
548 BUG_ON(ret);
549 break;
550 }
498 blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur), 551 blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur),
499 path->slots[*level]); 552 path->slots[*level]);
500 ret = lookup_block_ref(trans, root, blocknr, &refs); 553 ret = lookup_block_ref(trans, root, blocknr, 1, &refs);
501 if (refs != 1 || *level == 1) { 554 BUG_ON(ret);
555 if (refs != 1) {
502 path->slots[*level]++; 556 path->slots[*level]++;
503 ret = btrfs_free_extent(trans, root, blocknr, 1, 1); 557 ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
504 BUG_ON(ret); 558 BUG_ON(ret);
505 continue; 559 continue;
506 } 560 }
507 BUG_ON(ret);
508 next = read_tree_block(root, blocknr); 561 next = read_tree_block(root, blocknr);
509 if (path->nodes[*level-1]) 562 if (path->nodes[*level-1])
510 btrfs_block_release(root, path->nodes[*level-1]); 563 btrfs_block_release(root, path->nodes[*level-1]);
@@ -513,8 +566,8 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
513 path->slots[*level] = 0; 566 path->slots[*level] = 0;
514 } 567 }
515out: 568out:
516 ret = btrfs_free_extent(trans, root, path->nodes[*level]->b_blocknr, 569 ret = btrfs_free_extent(trans, root,
517 1, 1); 570 path->nodes[*level]->b_blocknr, 1, 1);
518 btrfs_block_release(root, path->nodes[*level]); 571 btrfs_block_release(root, path->nodes[*level]);
519 path->nodes[*level] = NULL; 572 path->nodes[*level] = NULL;
520 *level += 1; 573 *level += 1;
@@ -544,10 +597,10 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
544 ret = btrfs_free_extent(trans, root, 597 ret = btrfs_free_extent(trans, root,
545 path->nodes[*level]->b_blocknr, 598 path->nodes[*level]->b_blocknr,
546 1, 1); 599 1, 1);
600 BUG_ON(ret);
547 btrfs_block_release(root, path->nodes[*level]); 601 btrfs_block_release(root, path->nodes[*level]);
548 path->nodes[*level] = NULL; 602 path->nodes[*level] = NULL;
549 *level = i + 1; 603 *level = i + 1;
550 BUG_ON(ret);
551 } 604 }
552 } 605 }
553 return 1; 606 return 1;