diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-11 15:53:25 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-11 15:53:25 -0400 |
commit | 7eccb903a817e890c947ba4bc90c6a9af9b4219a (patch) | |
tree | 0e8553fb8f1dfd701d4e8eacd618ec72a8ec8720 /fs | |
parent | 0bd93ba022f5c1ddb4e5b722b02f3c4a4a8865ad (diff) |
Btrfs: create a logical->phsyical block number mapping scheme
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 38 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 140 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 8 | ||||
-rw-r--r-- | fs/btrfs/super.c | 6 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 8 |
7 files changed, 134 insertions, 68 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index f31ac843bf2e..e2fc6f0d0243 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -66,21 +66,21 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
66 | if (buf->b_size != root->blocksize || cow->b_size != root->blocksize) | 66 | if (buf->b_size != root->blocksize || cow->b_size != root->blocksize) |
67 | WARN_ON(1); | 67 | WARN_ON(1); |
68 | memcpy(cow_node, btrfs_buffer_node(buf), root->blocksize); | 68 | memcpy(cow_node, btrfs_buffer_node(buf), root->blocksize); |
69 | btrfs_set_header_blocknr(&cow_node->header, cow->b_blocknr); | 69 | btrfs_set_header_blocknr(&cow_node->header, bh_blocknr(cow)); |
70 | btrfs_set_header_generation(&cow_node->header, trans->transid); | 70 | btrfs_set_header_generation(&cow_node->header, trans->transid); |
71 | btrfs_inc_ref(trans, root, buf); | 71 | btrfs_inc_ref(trans, root, buf); |
72 | if (buf == root->node) { | 72 | if (buf == root->node) { |
73 | root->node = cow; | 73 | root->node = cow; |
74 | get_bh(cow); | 74 | get_bh(cow); |
75 | if (buf != root->commit_root) { | 75 | if (buf != root->commit_root) { |
76 | btrfs_free_extent(trans, root, buf->b_blocknr, 1, 1); | 76 | btrfs_free_extent(trans, root, bh_blocknr(buf), 1, 1); |
77 | } | 77 | } |
78 | btrfs_block_release(root, buf); | 78 | btrfs_block_release(root, buf); |
79 | } else { | 79 | } else { |
80 | btrfs_set_node_blockptr(btrfs_buffer_node(parent), parent_slot, | 80 | btrfs_set_node_blockptr(btrfs_buffer_node(parent), parent_slot, |
81 | cow->b_blocknr); | 81 | bh_blocknr(cow)); |
82 | btrfs_mark_buffer_dirty(parent); | 82 | btrfs_mark_buffer_dirty(parent); |
83 | btrfs_free_extent(trans, root, buf->b_blocknr, 1, 1); | 83 | btrfs_free_extent(trans, root, bh_blocknr(buf), 1, 1); |
84 | } | 84 | } |
85 | btrfs_block_release(root, buf); | 85 | btrfs_block_release(root, buf); |
86 | mark_buffer_dirty(cow); | 86 | mark_buffer_dirty(cow); |
@@ -312,7 +312,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
312 | */ | 312 | */ |
313 | if (!parent_buf) { | 313 | if (!parent_buf) { |
314 | struct buffer_head *child; | 314 | struct buffer_head *child; |
315 | u64 blocknr = mid_buf->b_blocknr; | 315 | u64 blocknr = bh_blocknr(mid_buf); |
316 | 316 | ||
317 | if (btrfs_header_nritems(&mid->header) != 1) | 317 | if (btrfs_header_nritems(&mid->header) != 1) |
318 | return 0; | 318 | return 0; |
@@ -361,7 +361,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
361 | if (wret < 0) | 361 | if (wret < 0) |
362 | ret = wret; | 362 | ret = wret; |
363 | if (btrfs_header_nritems(&right->header) == 0) { | 363 | if (btrfs_header_nritems(&right->header) == 0) { |
364 | u64 blocknr = right_buf->b_blocknr; | 364 | u64 blocknr = bh_blocknr(right_buf); |
365 | clean_tree_block(trans, root, right_buf); | 365 | clean_tree_block(trans, root, right_buf); |
366 | wait_on_buffer(right_buf); | 366 | wait_on_buffer(right_buf); |
367 | btrfs_block_release(root, right_buf); | 367 | btrfs_block_release(root, right_buf); |
@@ -400,7 +400,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root | |||
400 | } | 400 | } |
401 | if (btrfs_header_nritems(&mid->header) == 0) { | 401 | if (btrfs_header_nritems(&mid->header) == 0) { |
402 | /* we've managed to empty the middle node, drop it */ | 402 | /* we've managed to empty the middle node, drop it */ |
403 | u64 blocknr = mid_buf->b_blocknr; | 403 | u64 blocknr = bh_blocknr(mid_buf); |
404 | clean_tree_block(trans, root, mid_buf); | 404 | clean_tree_block(trans, root, mid_buf); |
405 | wait_on_buffer(mid_buf); | 405 | wait_on_buffer(mid_buf); |
406 | btrfs_block_release(root, mid_buf); | 406 | btrfs_block_release(root, mid_buf); |
@@ -686,7 +686,7 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
686 | memset(c, 0, root->blocksize); | 686 | memset(c, 0, root->blocksize); |
687 | btrfs_set_header_nritems(&c->header, 1); | 687 | btrfs_set_header_nritems(&c->header, 1); |
688 | btrfs_set_header_level(&c->header, level); | 688 | btrfs_set_header_level(&c->header, level); |
689 | btrfs_set_header_blocknr(&c->header, t->b_blocknr); | 689 | btrfs_set_header_blocknr(&c->header, bh_blocknr(t)); |
690 | btrfs_set_header_generation(&c->header, trans->transid); | 690 | btrfs_set_header_generation(&c->header, trans->transid); |
691 | lower = btrfs_buffer_node(path->nodes[level-1]); | 691 | lower = btrfs_buffer_node(path->nodes[level-1]); |
692 | memcpy(c->header.fsid, root->fs_info->disk_super->fsid, | 692 | memcpy(c->header.fsid, root->fs_info->disk_super->fsid, |
@@ -697,7 +697,7 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
697 | lower_key = &lower->ptrs[0].key; | 697 | lower_key = &lower->ptrs[0].key; |
698 | btrfs_memcpy(root, c, &c->ptrs[0].key, lower_key, | 698 | btrfs_memcpy(root, c, &c->ptrs[0].key, lower_key, |
699 | sizeof(struct btrfs_disk_key)); | 699 | sizeof(struct btrfs_disk_key)); |
700 | btrfs_set_node_blockptr(c, 0, path->nodes[level - 1]->b_blocknr); | 700 | btrfs_set_node_blockptr(c, 0, bh_blocknr(path->nodes[level - 1])); |
701 | 701 | ||
702 | btrfs_mark_buffer_dirty(t); | 702 | btrfs_mark_buffer_dirty(t); |
703 | 703 | ||
@@ -780,7 +780,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | |||
780 | split = btrfs_buffer_node(split_buffer); | 780 | split = btrfs_buffer_node(split_buffer); |
781 | btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header)); | 781 | btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header)); |
782 | btrfs_set_header_level(&split->header, btrfs_header_level(&c->header)); | 782 | btrfs_set_header_level(&split->header, btrfs_header_level(&c->header)); |
783 | btrfs_set_header_blocknr(&split->header, split_buffer->b_blocknr); | 783 | btrfs_set_header_blocknr(&split->header, bh_blocknr(split_buffer)); |
784 | btrfs_set_header_generation(&split->header, trans->transid); | 784 | btrfs_set_header_generation(&split->header, trans->transid); |
785 | memcpy(split->header.fsid, root->fs_info->disk_super->fsid, | 785 | memcpy(split->header.fsid, root->fs_info->disk_super->fsid, |
786 | sizeof(split->header.fsid)); | 786 | sizeof(split->header.fsid)); |
@@ -794,7 +794,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | |||
794 | btrfs_mark_buffer_dirty(t); | 794 | btrfs_mark_buffer_dirty(t); |
795 | btrfs_mark_buffer_dirty(split_buffer); | 795 | btrfs_mark_buffer_dirty(split_buffer); |
796 | wret = insert_ptr(trans, root, path, &split->ptrs[0].key, | 796 | wret = insert_ptr(trans, root, path, &split->ptrs[0].key, |
797 | split_buffer->b_blocknr, path->slots[level + 1] + 1, | 797 | bh_blocknr(split_buffer), path->slots[level + 1] + 1, |
798 | level + 1); | 798 | level + 1); |
799 | if (wret) | 799 | if (wret) |
800 | ret = wret; | 800 | ret = wret; |
@@ -1138,7 +1138,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1138 | BUG_ON(!right_buffer); | 1138 | BUG_ON(!right_buffer); |
1139 | right = btrfs_buffer_leaf(right_buffer); | 1139 | right = btrfs_buffer_leaf(right_buffer); |
1140 | memset(&right->header, 0, sizeof(right->header)); | 1140 | memset(&right->header, 0, sizeof(right->header)); |
1141 | btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr); | 1141 | btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); |
1142 | btrfs_set_header_generation(&right->header, trans->transid); | 1142 | btrfs_set_header_generation(&right->header, trans->transid); |
1143 | btrfs_set_header_level(&right->header, 0); | 1143 | btrfs_set_header_level(&right->header, 0); |
1144 | memcpy(right->header.fsid, root->fs_info->disk_super->fsid, | 1144 | memcpy(right->header.fsid, root->fs_info->disk_super->fsid, |
@@ -1152,7 +1152,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1152 | btrfs_set_header_nritems(&right->header, 0); | 1152 | btrfs_set_header_nritems(&right->header, 0); |
1153 | wret = insert_ptr(trans, root, path, | 1153 | wret = insert_ptr(trans, root, path, |
1154 | &disk_key, | 1154 | &disk_key, |
1155 | right_buffer->b_blocknr, | 1155 | bh_blocknr(right_buffer), |
1156 | path->slots[1] + 1, 1); | 1156 | path->slots[1] + 1, 1); |
1157 | if (wret) | 1157 | if (wret) |
1158 | ret = wret; | 1158 | ret = wret; |
@@ -1173,7 +1173,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1173 | btrfs_set_header_nritems(&right->header, 0); | 1173 | btrfs_set_header_nritems(&right->header, 0); |
1174 | wret = insert_ptr(trans, root, path, | 1174 | wret = insert_ptr(trans, root, path, |
1175 | &disk_key, | 1175 | &disk_key, |
1176 | right_buffer->b_blocknr, | 1176 | bh_blocknr(right_buffer), |
1177 | path->slots[1] - 1, 1); | 1177 | path->slots[1] - 1, 1); |
1178 | if (wret) | 1178 | if (wret) |
1179 | ret = wret; | 1179 | ret = wret; |
@@ -1207,7 +1207,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1207 | btrfs_set_header_nritems(&l->header, mid); | 1207 | btrfs_set_header_nritems(&l->header, mid); |
1208 | ret = 0; | 1208 | ret = 0; |
1209 | wret = insert_ptr(trans, root, path, &right->items[0].key, | 1209 | wret = insert_ptr(trans, root, path, &right->items[0].key, |
1210 | right_buffer->b_blocknr, path->slots[1] + 1, 1); | 1210 | bh_blocknr(right_buffer), path->slots[1] + 1, 1); |
1211 | if (wret) | 1211 | if (wret) |
1212 | ret = wret; | 1212 | ret = wret; |
1213 | btrfs_mark_buffer_dirty(right_buffer); | 1213 | btrfs_mark_buffer_dirty(right_buffer); |
@@ -1228,7 +1228,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1228 | BUG_ON(!right_buffer); | 1228 | BUG_ON(!right_buffer); |
1229 | right = btrfs_buffer_leaf(right_buffer); | 1229 | right = btrfs_buffer_leaf(right_buffer); |
1230 | memset(&right->header, 0, sizeof(right->header)); | 1230 | memset(&right->header, 0, sizeof(right->header)); |
1231 | btrfs_set_header_blocknr(&right->header, right_buffer->b_blocknr); | 1231 | btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); |
1232 | btrfs_set_header_generation(&right->header, trans->transid); | 1232 | btrfs_set_header_generation(&right->header, trans->transid); |
1233 | btrfs_set_header_level(&right->header, 0); | 1233 | btrfs_set_header_level(&right->header, 0); |
1234 | memcpy(right->header.fsid, root->fs_info->disk_super->fsid, | 1234 | memcpy(right->header.fsid, root->fs_info->disk_super->fsid, |
@@ -1237,7 +1237,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1237 | btrfs_set_header_nritems(&right->header, 0); | 1237 | btrfs_set_header_nritems(&right->header, 0); |
1238 | wret = insert_ptr(trans, root, path, | 1238 | wret = insert_ptr(trans, root, path, |
1239 | &disk_key, | 1239 | &disk_key, |
1240 | right_buffer->b_blocknr, | 1240 | bh_blocknr(right_buffer), |
1241 | path->slots[1], 1); | 1241 | path->slots[1], 1); |
1242 | if (wret) | 1242 | if (wret) |
1243 | ret = wret; | 1243 | ret = wret; |
@@ -1456,7 +1456,7 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
1456 | if (wret) | 1456 | if (wret) |
1457 | ret = wret; | 1457 | ret = wret; |
1458 | wret = btrfs_free_extent(trans, root, | 1458 | wret = btrfs_free_extent(trans, root, |
1459 | leaf_buf->b_blocknr, 1, 1); | 1459 | bh_blocknr(leaf_buf), 1, 1); |
1460 | if (wret) | 1460 | if (wret) |
1461 | ret = wret; | 1461 | ret = wret; |
1462 | } | 1462 | } |
@@ -1487,7 +1487,7 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
1487 | ret = wret; | 1487 | ret = wret; |
1488 | } | 1488 | } |
1489 | if (btrfs_header_nritems(&leaf->header) == 0) { | 1489 | if (btrfs_header_nritems(&leaf->header) == 0) { |
1490 | u64 blocknr = leaf_buf->b_blocknr; | 1490 | u64 blocknr = bh_blocknr(leaf_buf); |
1491 | clean_tree_block(trans, root, leaf_buf); | 1491 | clean_tree_block(trans, root, leaf_buf); |
1492 | wait_on_buffer(leaf_buf); | 1492 | wait_on_buffer(leaf_buf); |
1493 | wret = del_ptr(trans, root, path, 1, slot); | 1493 | wret = del_ptr(trans, root, path, 1, slot); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 01310de2bf4a..454eb88611bb 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -242,6 +242,7 @@ struct btrfs_fs_info { | |||
242 | struct radix_tree_root fs_roots_radix; | 242 | struct radix_tree_root fs_roots_radix; |
243 | struct radix_tree_root pending_del_radix; | 243 | struct radix_tree_root pending_del_radix; |
244 | struct radix_tree_root pinned_radix; | 244 | struct radix_tree_root pinned_radix; |
245 | struct radix_tree_root dev_radix; | ||
245 | u64 generation; | 246 | u64 generation; |
246 | struct btrfs_transaction *running_transaction; | 247 | struct btrfs_transaction *running_transaction; |
247 | struct btrfs_super_block *disk_super; | 248 | struct btrfs_super_block *disk_super; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e09233262af6..c872a7e67abd 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -10,10 +10,30 @@ | |||
10 | #include "transaction.h" | 10 | #include "transaction.h" |
11 | #include "btrfs_inode.h" | 11 | #include "btrfs_inode.h" |
12 | 12 | ||
13 | struct dev_lookup { | ||
14 | u64 block_start; | ||
15 | u64 num_blocks; | ||
16 | struct block_device *bdev; | ||
17 | }; | ||
18 | |||
19 | u64 bh_blocknr(struct buffer_head *bh) | ||
20 | { | ||
21 | int blkbits = bh->b_page->mapping->host->i_blkbits; | ||
22 | u64 blocknr = bh->b_page->index << (PAGE_CACHE_SHIFT - blkbits); | ||
23 | unsigned long offset; | ||
24 | |||
25 | if (PageHighMem(bh->b_page)) | ||
26 | offset = (unsigned long)bh->b_data; | ||
27 | else | ||
28 | offset = bh->b_data - (char *)page_address(bh->b_page); | ||
29 | blocknr += offset >> (PAGE_CACHE_SHIFT - blkbits); | ||
30 | return blocknr; | ||
31 | } | ||
32 | |||
13 | static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) | 33 | static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) |
14 | { | 34 | { |
15 | struct btrfs_node *node = btrfs_buffer_node(buf); | 35 | struct btrfs_node *node = btrfs_buffer_node(buf); |
16 | if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) { | 36 | if (bh_blocknr(buf) != btrfs_header_blocknr(&node->header)) { |
17 | BUG(); | 37 | BUG(); |
18 | } | 38 | } |
19 | return 0; | 39 | return 0; |
@@ -40,7 +60,7 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr) | |||
40 | head = page_buffers(page); | 60 | head = page_buffers(page); |
41 | bh = head; | 61 | bh = head; |
42 | do { | 62 | do { |
43 | if (buffer_mapped(bh) && bh->b_blocknr == blocknr) { | 63 | if (buffer_mapped(bh) && bh_blocknr(bh) == blocknr) { |
44 | ret = bh; | 64 | ret = bh; |
45 | get_bh(bh); | 65 | get_bh(bh); |
46 | goto out_unlock; | 66 | goto out_unlock; |
@@ -56,6 +76,33 @@ out_unlock: | |||
56 | return ret; | 76 | return ret; |
57 | } | 77 | } |
58 | 78 | ||
79 | static int map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh, | ||
80 | u64 logical) | ||
81 | { | ||
82 | struct dev_lookup *lookup[2]; | ||
83 | char b[BDEVNAME_SIZE]; | ||
84 | |||
85 | int ret; | ||
86 | |||
87 | root = root->fs_info->dev_root; | ||
88 | ret = radix_tree_gang_lookup(&root->fs_info->dev_radix, | ||
89 | (void **)lookup, | ||
90 | (unsigned long)logical, | ||
91 | ARRAY_SIZE(lookup)); | ||
92 | if (ret == 0 || lookup[0]->block_start > logical || | ||
93 | lookup[0]->block_start + lookup[0]->num_blocks <= logical) { | ||
94 | ret = -ENOENT; | ||
95 | goto out; | ||
96 | } | ||
97 | bh->b_bdev = lookup[0]->bdev; | ||
98 | bh->b_blocknr = logical - lookup[0]->block_start; | ||
99 | printk("logical mapping %Lu to %lu bdev %s\n", logical, bh->b_blocknr, bdevname(bh->b_bdev, b)); | ||
100 | set_buffer_mapped(bh); | ||
101 | ret = 0; | ||
102 | out: | ||
103 | return ret; | ||
104 | } | ||
105 | |||
59 | struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, | 106 | struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, |
60 | u64 blocknr) | 107 | u64 blocknr) |
61 | { | 108 | { |
@@ -66,6 +113,7 @@ struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, | |||
66 | struct buffer_head *bh; | 113 | struct buffer_head *bh; |
67 | struct buffer_head *head; | 114 | struct buffer_head *head; |
68 | struct buffer_head *ret = NULL; | 115 | struct buffer_head *ret = NULL; |
116 | int err; | ||
69 | u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits); | 117 | u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits); |
70 | 118 | ||
71 | page = grab_cache_page(mapping, index); | 119 | page = grab_cache_page(mapping, index); |
@@ -78,11 +126,10 @@ struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, | |||
78 | bh = head; | 126 | bh = head; |
79 | do { | 127 | do { |
80 | if (!buffer_mapped(bh)) { | 128 | if (!buffer_mapped(bh)) { |
81 | bh->b_bdev = root->fs_info->sb->s_bdev; | 129 | err = map_bh_to_logical(root, bh, first_block); |
82 | bh->b_blocknr = first_block; | 130 | BUG_ON(err); |
83 | set_buffer_mapped(bh); | ||
84 | } | 131 | } |
85 | if (bh->b_blocknr == blocknr) { | 132 | if (bh_blocknr(bh) == blocknr) { |
86 | ret = bh; | 133 | ret = bh; |
87 | get_bh(bh); | 134 | get_bh(bh); |
88 | goto out_unlock; | 135 | goto out_unlock; |
@@ -98,38 +145,13 @@ out_unlock: | |||
98 | return ret; | 145 | return ret; |
99 | } | 146 | } |
100 | 147 | ||
101 | static sector_t max_block(struct block_device *bdev) | ||
102 | { | ||
103 | sector_t retval = ~((sector_t)0); | ||
104 | loff_t sz = i_size_read(bdev->bd_inode); | ||
105 | |||
106 | if (sz) { | ||
107 | unsigned int size = block_size(bdev); | ||
108 | unsigned int sizebits = blksize_bits(size); | ||
109 | retval = (sz >> sizebits); | ||
110 | } | ||
111 | return retval; | ||
112 | } | ||
113 | |||
114 | static int btree_get_block(struct inode *inode, sector_t iblock, | 148 | static int btree_get_block(struct inode *inode, sector_t iblock, |
115 | struct buffer_head *bh, int create) | 149 | struct buffer_head *bh, int create) |
116 | { | 150 | { |
117 | if (iblock >= max_block(inode->i_sb->s_bdev)) { | 151 | int err; |
118 | if (create) | 152 | struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root; |
119 | return -EIO; | 153 | err = map_bh_to_logical(root, bh, iblock); |
120 | 154 | return err; | |
121 | /* | ||
122 | * for reads, we're just trying to fill a partial page. | ||
123 | * return a hole, they will have to call get_block again | ||
124 | * before they can fill it, and they will get -EIO at that | ||
125 | * time | ||
126 | */ | ||
127 | return 0; | ||
128 | } | ||
129 | bh->b_bdev = inode->i_sb->s_bdev; | ||
130 | bh->b_blocknr = iblock; | ||
131 | set_buffer_mapped(bh); | ||
132 | return 0; | ||
133 | } | 155 | } |
134 | 156 | ||
135 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | 157 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, |
@@ -164,8 +186,8 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, | |||
164 | return ret; | 186 | return ret; |
165 | if (verify) { | 187 | if (verify) { |
166 | if (memcmp(bh->b_data, result, BTRFS_CSUM_SIZE)) { | 188 | if (memcmp(bh->b_data, result, BTRFS_CSUM_SIZE)) { |
167 | printk("checksum verify failed on %lu\n", | 189 | printk("checksum verify failed on %Lu\n", |
168 | bh->b_blocknr); | 190 | bh_blocknr(bh)); |
169 | return 1; | 191 | return 1; |
170 | } | 192 | } |
171 | } else { | 193 | } else { |
@@ -386,10 +408,12 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
386 | GFP_NOFS); | 408 | GFP_NOFS); |
387 | int ret; | 409 | int ret; |
388 | struct btrfs_super_block *disk_super; | 410 | struct btrfs_super_block *disk_super; |
411 | struct dev_lookup *dev_lookup; | ||
389 | 412 | ||
390 | init_bit_radix(&fs_info->pinned_radix); | 413 | init_bit_radix(&fs_info->pinned_radix); |
391 | init_bit_radix(&fs_info->pending_del_radix); | 414 | init_bit_radix(&fs_info->pending_del_radix); |
392 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); | 415 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); |
416 | INIT_RADIX_TREE(&fs_info->dev_radix, GFP_NOFS); | ||
393 | sb_set_blocksize(sb, 4096); | 417 | sb_set_blocksize(sb, 4096); |
394 | fs_info->running_transaction = NULL; | 418 | fs_info->running_transaction = NULL; |
395 | fs_info->tree_root = tree_root; | 419 | fs_info->tree_root = tree_root; |
@@ -422,6 +446,13 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
422 | 446 | ||
423 | __setup_root(sb->s_blocksize, tree_root, | 447 | __setup_root(sb->s_blocksize, tree_root, |
424 | fs_info, BTRFS_ROOT_TREE_OBJECTID); | 448 | fs_info, BTRFS_ROOT_TREE_OBJECTID); |
449 | |||
450 | dev_lookup = kmalloc(sizeof(*dev_lookup), GFP_NOFS); | ||
451 | dev_lookup->block_start = 0; | ||
452 | dev_lookup->num_blocks = (u32)-2; | ||
453 | dev_lookup->bdev = sb->s_bdev; | ||
454 | ret = radix_tree_insert(&fs_info->dev_radix, (u32)-2, dev_lookup); | ||
455 | BUG_ON(ret); | ||
425 | fs_info->sb_buffer = read_tree_block(tree_root, | 456 | fs_info->sb_buffer = read_tree_block(tree_root, |
426 | BTRFS_SUPER_INFO_OFFSET / | 457 | BTRFS_SUPER_INFO_OFFSET / |
427 | sb->s_blocksize); | 458 | sb->s_blocksize); |
@@ -432,6 +463,14 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
432 | if (!btrfs_super_root(disk_super)) | 463 | if (!btrfs_super_root(disk_super)) |
433 | return NULL; | 464 | return NULL; |
434 | 465 | ||
466 | radix_tree_delete(&fs_info->dev_radix, (u32)-2); | ||
467 | dev_lookup->block_start = btrfs_super_device_block_start(disk_super); | ||
468 | dev_lookup->num_blocks = btrfs_super_device_num_blocks(disk_super); | ||
469 | ret = radix_tree_insert(&fs_info->dev_radix, | ||
470 | dev_lookup->block_start + | ||
471 | dev_lookup->num_blocks, dev_lookup); | ||
472 | BUG_ON(ret); | ||
473 | |||
435 | fs_info->disk_super = disk_super; | 474 | fs_info->disk_super = disk_super; |
436 | dev_root->node = read_tree_block(tree_root, | 475 | dev_root->node = read_tree_block(tree_root, |
437 | btrfs_super_device_root(disk_super)); | 476 | btrfs_super_device_root(disk_super)); |
@@ -459,7 +498,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | |||
459 | struct buffer_head *bh = root->fs_info->sb_buffer; | 498 | struct buffer_head *bh = root->fs_info->sb_buffer; |
460 | 499 | ||
461 | btrfs_set_super_root(root->fs_info->disk_super, | 500 | btrfs_set_super_root(root->fs_info->disk_super, |
462 | root->fs_info->tree_root->node->b_blocknr); | 501 | bh_blocknr(root->fs_info->tree_root->node)); |
463 | lock_buffer(bh); | 502 | lock_buffer(bh); |
464 | WARN_ON(atomic_read(&bh->b_count) < 1); | 503 | WARN_ON(atomic_read(&bh->b_count) < 1); |
465 | clear_buffer_dirty(bh); | 504 | clear_buffer_dirty(bh); |
@@ -506,6 +545,29 @@ int del_fs_roots(struct btrfs_fs_info *fs_info) | |||
506 | } | 545 | } |
507 | return 0; | 546 | return 0; |
508 | } | 547 | } |
548 | static int free_dev_radix(struct btrfs_fs_info *fs_info) | ||
549 | { | ||
550 | struct dev_lookup *lookup[8]; | ||
551 | struct block_device *super_bdev = fs_info->sb->s_bdev; | ||
552 | int ret; | ||
553 | int i; | ||
554 | while(1) { | ||
555 | ret = radix_tree_gang_lookup(&fs_info->dev_radix, | ||
556 | (void **)lookup, 0, | ||
557 | ARRAY_SIZE(lookup)); | ||
558 | if (!ret) | ||
559 | break; | ||
560 | for (i = 0; i < ret; i++) { | ||
561 | if (lookup[i]->bdev != super_bdev) | ||
562 | close_bdev_excl(lookup[i]->bdev); | ||
563 | radix_tree_delete(&fs_info->dev_radix, | ||
564 | lookup[i]->block_start + | ||
565 | lookup[i]->num_blocks); | ||
566 | kfree(lookup[i]); | ||
567 | } | ||
568 | } | ||
569 | return 0; | ||
570 | } | ||
509 | 571 | ||
510 | int close_ctree(struct btrfs_root *root) | 572 | int close_ctree(struct btrfs_root *root) |
511 | { | 573 | { |
@@ -537,6 +599,8 @@ int close_ctree(struct btrfs_root *root) | |||
537 | crypto_free_hash(fs_info->hash_tfm); | 599 | crypto_free_hash(fs_info->hash_tfm); |
538 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | 600 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); |
539 | iput(fs_info->btree_inode); | 601 | iput(fs_info->btree_inode); |
602 | |||
603 | free_dev_radix(fs_info); | ||
540 | del_fs_roots(fs_info); | 604 | del_fs_roots(fs_info); |
541 | kfree(fs_info->extent_root); | 605 | kfree(fs_info->extent_root); |
542 | kfree(fs_info->tree_root); | 606 | kfree(fs_info->tree_root); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 0ef6e6f714af..46cc5dc9d572 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -41,4 +41,5 @@ int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | |||
41 | char *result); | 41 | char *result); |
42 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 42 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, |
43 | struct btrfs_key *location); | 43 | struct btrfs_key *location); |
44 | u64 bh_blocknr(struct buffer_head *bh); | ||
44 | #endif | 45 | #endif |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index be9630df506c..d560831c10a7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -80,7 +80,7 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root | |||
80 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, | 80 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, |
81 | struct btrfs_root *root) | 81 | struct btrfs_root *root) |
82 | { | 82 | { |
83 | return inc_block_ref(trans, root, root->node->b_blocknr, 1); | 83 | return inc_block_ref(trans, root, bh_blocknr(root->node), 1); |
84 | } | 84 | } |
85 | 85 | ||
86 | int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 86 | int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
@@ -563,7 +563,7 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root | |||
563 | 563 | ||
564 | WARN_ON(*level < 0); | 564 | WARN_ON(*level < 0); |
565 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 565 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
566 | ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr, | 566 | ret = lookup_block_ref(trans, root, bh_blocknr(path->nodes[*level]), |
567 | 1, &refs); | 567 | 1, &refs); |
568 | BUG_ON(ret); | 568 | BUG_ON(ret); |
569 | if (refs > 1) | 569 | if (refs > 1) |
@@ -607,7 +607,7 @@ out: | |||
607 | WARN_ON(*level < 0); | 607 | WARN_ON(*level < 0); |
608 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 608 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
609 | ret = btrfs_free_extent(trans, root, | 609 | ret = btrfs_free_extent(trans, root, |
610 | path->nodes[*level]->b_blocknr, 1, 1); | 610 | bh_blocknr(path->nodes[*level]), 1, 1); |
611 | btrfs_block_release(root, path->nodes[*level]); | 611 | btrfs_block_release(root, path->nodes[*level]); |
612 | path->nodes[*level] = NULL; | 612 | path->nodes[*level] = NULL; |
613 | *level += 1; | 613 | *level += 1; |
@@ -635,7 +635,7 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root | |||
635 | return 0; | 635 | return 0; |
636 | } else { | 636 | } else { |
637 | ret = btrfs_free_extent(trans, root, | 637 | ret = btrfs_free_extent(trans, root, |
638 | path->nodes[*level]->b_blocknr, | 638 | bh_blocknr(path->nodes[*level]), |
639 | 1, 1); | 639 | 1, 1); |
640 | BUG_ON(ret); | 640 | BUG_ON(ret); |
641 | btrfs_block_release(root, path->nodes[*level]); | 641 | btrfs_block_release(root, path->nodes[*level]); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2972aaa9eb7e..4ff0cc1efb13 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -1700,7 +1700,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
1700 | leaf = btrfs_buffer_leaf(subvol); | 1700 | leaf = btrfs_buffer_leaf(subvol); |
1701 | btrfs_set_header_nritems(&leaf->header, 0); | 1701 | btrfs_set_header_nritems(&leaf->header, 0); |
1702 | btrfs_set_header_level(&leaf->header, 0); | 1702 | btrfs_set_header_level(&leaf->header, 0); |
1703 | btrfs_set_header_blocknr(&leaf->header, subvol->b_blocknr); | 1703 | btrfs_set_header_blocknr(&leaf->header, bh_blocknr(subvol)); |
1704 | btrfs_set_header_generation(&leaf->header, trans->transid); | 1704 | btrfs_set_header_generation(&leaf->header, trans->transid); |
1705 | memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, | 1705 | memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, |
1706 | sizeof(leaf->header.fsid)); | 1706 | sizeof(leaf->header.fsid)); |
@@ -1713,7 +1713,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
1713 | btrfs_set_inode_nblocks(inode_item, 1); | 1713 | btrfs_set_inode_nblocks(inode_item, 1); |
1714 | btrfs_set_inode_mode(inode_item, S_IFDIR | 0755); | 1714 | btrfs_set_inode_mode(inode_item, S_IFDIR | 0755); |
1715 | 1715 | ||
1716 | btrfs_set_root_blocknr(&root_item, subvol->b_blocknr); | 1716 | btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol)); |
1717 | btrfs_set_root_refs(&root_item, 1); | 1717 | btrfs_set_root_refs(&root_item, 1); |
1718 | 1718 | ||
1719 | mark_buffer_dirty(subvol); | 1719 | mark_buffer_dirty(subvol); |
@@ -1803,7 +1803,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
1803 | key.offset = 1; | 1803 | key.offset = 1; |
1804 | key.flags = 0; | 1804 | key.flags = 0; |
1805 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 1805 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
1806 | btrfs_set_root_blocknr(&new_root_item, root->node->b_blocknr); | 1806 | btrfs_set_root_blocknr(&new_root_item, bh_blocknr(root->node)); |
1807 | 1807 | ||
1808 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | 1808 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, |
1809 | &new_root_item); | 1809 | &new_root_item); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index e15a072407bf..3a15943ea8ed 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -119,10 +119,10 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |||
119 | 119 | ||
120 | while(1) { | 120 | while(1) { |
121 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | 121 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); |
122 | if (old_extent_block == extent_root->node->b_blocknr) | 122 | if (old_extent_block == bh_blocknr(extent_root->node)) |
123 | break; | 123 | break; |
124 | btrfs_set_root_blocknr(&extent_root->root_item, | 124 | btrfs_set_root_blocknr(&extent_root->root_item, |
125 | extent_root->node->b_blocknr); | 125 | bh_blocknr(extent_root->node)); |
126 | ret = btrfs_update_root(trans, tree_root, | 126 | ret = btrfs_update_root(trans, tree_root, |
127 | &extent_root->root_key, | 127 | &extent_root->root_key, |
128 | &extent_root->root_item); | 128 | &extent_root->root_item); |
@@ -176,7 +176,7 @@ int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
176 | (unsigned long)root->root_key.objectid, | 176 | (unsigned long)root->root_key.objectid, |
177 | BTRFS_ROOT_TRANS_TAG); | 177 | BTRFS_ROOT_TRANS_TAG); |
178 | if (root->commit_root == root->node) { | 178 | if (root->commit_root == root->node) { |
179 | WARN_ON(root->node->b_blocknr != | 179 | WARN_ON(bh_blocknr(root->node) != |
180 | btrfs_root_blocknr(&root->root_item)); | 180 | btrfs_root_blocknr(&root->root_item)); |
181 | brelse(root->commit_root); | 181 | brelse(root->commit_root); |
182 | root->commit_root = NULL; | 182 | root->commit_root = NULL; |
@@ -191,7 +191,7 @@ int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
191 | dirty->root = root; | 191 | dirty->root = root; |
192 | root->root_key.offset = root->fs_info->generation; | 192 | root->root_key.offset = root->fs_info->generation; |
193 | btrfs_set_root_blocknr(&root->root_item, | 193 | btrfs_set_root_blocknr(&root->root_item, |
194 | root->node->b_blocknr); | 194 | bh_blocknr(root->node)); |
195 | err = btrfs_insert_root(trans, root->fs_info->tree_root, | 195 | err = btrfs_insert_root(trans, root->fs_info->tree_root, |
196 | &root->root_key, | 196 | &root->root_key, |
197 | &root->root_item); | 197 | &root->root_item); |