aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
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
parentdee26a9f7aab7ffe1193cd1415b23a69426acc9f (diff)
Btrfs: reference counts on data extents
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/TODO3
-rw-r--r--fs/btrfs/ctree.h9
-rw-r--r--fs/btrfs/extent-tree.c87
-rw-r--r--fs/btrfs/inode-map.c1
-rw-r--r--fs/btrfs/super.c6
5 files changed, 82 insertions, 24 deletions
diff --git a/fs/btrfs/TODO b/fs/btrfs/TODO
index 2ca301b289a6..7aec75e9a37e 100644
--- a/fs/btrfs/TODO
+++ b/fs/btrfs/TODO
@@ -8,7 +8,10 @@
8* Add block mapping tree (simple dm layer) 8* Add block mapping tree (simple dm layer)
9* Add simple tree locking (semaphore per tree) 9* Add simple tree locking (semaphore per tree)
10* Make allocator smarter 10* Make allocator smarter
11* make level a field in header
12* add a block group to struct inode
11* Make directory hashing work on 32 bit 13* Make directory hashing work on 32 bit
14* Make sure nobh stuff is working properly for cows
12* Do actual block accounting 15* Do actual block accounting
13* Check compat and incompat flags on the inode 16* Check compat and incompat flags on the inode
14* Add virtual filesystems, mountable snapshots 17* Add virtual filesystems, mountable snapshots
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 7b7120d3ab42..1a98952e0faf 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -9,10 +9,11 @@ struct btrfs_transaction;
9 9
10#define BTRFS_MAGIC "_BtRfS_M" 10#define BTRFS_MAGIC "_BtRfS_M"
11 11
12#define BTRFS_ROOT_TREE_OBJECTID 1 12#define BTRFS_ROOT_TREE_OBJECTID 1ULL
13#define BTRFS_EXTENT_TREE_OBJECTID 2 13#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
14#define BTRFS_INODE_MAP_OBJECTID 3 14#define BTRFS_INODE_MAP_OBJECTID 3ULL
15#define BTRFS_FS_TREE_OBJECTID 4 15#define BTRFS_FS_TREE_OBJECTID 4ULL
16#define BTRFS_FIRST_FREE_OBJECTID 5ULL
16 17
17/* 18/*
18 * we can actually store much bigger names, but lets not confuse the rest 19 * we can actually store much bigger names, but lets not confuse the rest
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;
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index ad2d375b830d..1b2c5e043508 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -25,6 +25,7 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
25 if (fs_root->fs_info->last_inode_alloc_dirid == dirid) 25 if (fs_root->fs_info->last_inode_alloc_dirid == dirid)
26 search_start = fs_root->fs_info->last_inode_alloc; 26 search_start = fs_root->fs_info->last_inode_alloc;
27 27
28 search_start = max(search_start, BTRFS_FIRST_FREE_OBJECTID);
28 search_key.objectid = search_start; 29 search_key.objectid = search_start;
29 search_key.flags = 0; 30 search_key.flags = 0;
30 btrfs_set_key_type(&search_key, BTRFS_INODE_MAP_ITEM_KEY); 31 btrfs_set_key_type(&search_key, BTRFS_INODE_MAP_ITEM_KEY);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 2c2883f2856d..487da5a213c0 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -700,7 +700,7 @@ out:
700static int btrfs_prepare_write(struct file *file, struct page *page, 700static int btrfs_prepare_write(struct file *file, struct page *page,
701 unsigned from, unsigned to) 701 unsigned from, unsigned to)
702{ 702{
703 return block_prepare_write(page, from, to, btrfs_get_block); 703 return nobh_prepare_write(page, from, to, btrfs_get_block);
704} 704}
705 705
706static void btrfs_write_super(struct super_block *sb) 706static void btrfs_write_super(struct super_block *sb)
@@ -721,7 +721,7 @@ static int btrfs_readpages(struct file *file, struct address_space *mapping,
721 721
722static int btrfs_writepage(struct page *page, struct writeback_control *wbc) 722static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
723{ 723{
724 return block_write_full_page(page, btrfs_get_block, wbc); 724 return nobh_writepage(page, btrfs_get_block, wbc);
725} 725}
726 726
727static int btrfs_get_sb(struct file_system_type *fs_type, 727static int btrfs_get_sb(struct file_system_type *fs_type,
@@ -768,7 +768,7 @@ static struct address_space_operations btrfs_aops = {
768 .writepage = btrfs_writepage, 768 .writepage = btrfs_writepage,
769 .sync_page = block_sync_page, 769 .sync_page = block_sync_page,
770 .prepare_write = btrfs_prepare_write, 770 .prepare_write = btrfs_prepare_write,
771 .commit_write = generic_commit_write, 771 .commit_write = nobh_commit_write,
772}; 772};
773 773
774static struct inode_operations btrfs_file_inode_operations = { 774static struct inode_operations btrfs_file_inode_operations = {