diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-27 06:33:00 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-27 06:33:00 -0400 |
commit | 6407bf6d7c449cbfb0a39d985194e265eda3baf4 (patch) | |
tree | 29b7226d36b1fbbe2a6bed134ddc3f8d98853bb2 | |
parent | dee26a9f7aab7ffe1193cd1415b23a69426acc9f (diff) |
Btrfs: reference counts on data extents
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/TODO | 3 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 9 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 87 | ||||
-rw-r--r-- | fs/btrfs/inode-map.c | 1 | ||||
-rw-r--r-- | fs/btrfs/super.c | 6 |
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 | ||
15 | static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root | 15 | static 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 | ||
50 | static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root | 50 | static 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 | ||
489 | static 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 | } |
515 | out: | 568 | out: |
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: | |||
700 | static int btrfs_prepare_write(struct file *file, struct page *page, | 700 | static 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 | ||
706 | static void btrfs_write_super(struct super_block *sb) | 706 | static 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 | ||
722 | static int btrfs_writepage(struct page *page, struct writeback_control *wbc) | 722 | static 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 | ||
727 | static int btrfs_get_sb(struct file_system_type *fs_type, | 727 | static 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 | ||
774 | static struct inode_operations btrfs_file_inode_operations = { | 774 | static struct inode_operations btrfs_file_inode_operations = { |