diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:15:53 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | db94535db75e67fab12ccbb7f5ee548e33fed891 (patch) | |
tree | 1ad7dfc82b003294a94ee87d7329b24b902b369f /fs/btrfs/disk-io.c | |
parent | 1a5bc167f6707542b79a55452075525620ed43f5 (diff) |
Btrfs: Allow tree blocks larger than the page size
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 92 |
1 files changed, 58 insertions, 34 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2b86a1d779b7..fad9298c6962 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "disk-io.h" | 28 | #include "disk-io.h" |
29 | #include "transaction.h" | 29 | #include "transaction.h" |
30 | #include "btrfs_inode.h" | 30 | #include "btrfs_inode.h" |
31 | #include "print-tree.h" | ||
31 | 32 | ||
32 | #if 0 | 33 | #if 0 |
33 | static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) | 34 | static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) |
@@ -43,26 +44,25 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) | |||
43 | #endif | 44 | #endif |
44 | 45 | ||
45 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | 46 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, |
46 | u64 blocknr) | 47 | u64 bytenr, u32 blocksize) |
47 | { | 48 | { |
48 | struct inode *btree_inode = root->fs_info->btree_inode; | 49 | struct inode *btree_inode = root->fs_info->btree_inode; |
49 | struct extent_buffer *eb; | 50 | struct extent_buffer *eb; |
50 | eb = find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | 51 | eb = find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, |
51 | blocknr * root->sectorsize, | 52 | bytenr, blocksize, GFP_NOFS); |
52 | root->sectorsize, GFP_NOFS); | ||
53 | if (eb) | 53 | if (eb) |
54 | eb->alloc_addr = (unsigned long)__builtin_return_address(0); | 54 | eb->alloc_addr = (unsigned long)__builtin_return_address(0); |
55 | return eb; | 55 | return eb; |
56 | } | 56 | } |
57 | 57 | ||
58 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, | 58 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, |
59 | u64 blocknr) | 59 | u64 bytenr, u32 blocksize) |
60 | { | 60 | { |
61 | struct inode *btree_inode = root->fs_info->btree_inode; | 61 | struct inode *btree_inode = root->fs_info->btree_inode; |
62 | struct extent_buffer *eb; | 62 | struct extent_buffer *eb; |
63 | |||
63 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | 64 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, |
64 | blocknr * root->sectorsize, | 65 | bytenr, blocksize, GFP_NOFS); |
65 | root->sectorsize, GFP_NOFS); | ||
66 | eb->alloc_addr = (unsigned long)__builtin_return_address(0); | 66 | eb->alloc_addr = (unsigned long)__builtin_return_address(0); |
67 | return eb; | 67 | return eb; |
68 | } | 68 | } |
@@ -208,13 +208,13 @@ static struct address_space_operations btree_aops = { | |||
208 | .sync_page = block_sync_page, | 208 | .sync_page = block_sync_page, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | int readahead_tree_block(struct btrfs_root *root, u64 blocknr) | 211 | int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) |
212 | { | 212 | { |
213 | struct extent_buffer *buf = NULL; | 213 | struct extent_buffer *buf = NULL; |
214 | struct inode *btree_inode = root->fs_info->btree_inode; | 214 | struct inode *btree_inode = root->fs_info->btree_inode; |
215 | int ret = 0; | 215 | int ret = 0; |
216 | 216 | ||
217 | buf = btrfs_find_create_tree_block(root, blocknr); | 217 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); |
218 | if (!buf) | 218 | if (!buf) |
219 | return 0; | 219 | return 0; |
220 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, | 220 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
@@ -223,12 +223,13 @@ int readahead_tree_block(struct btrfs_root *root, u64 blocknr) | |||
223 | return ret; | 223 | return ret; |
224 | } | 224 | } |
225 | 225 | ||
226 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) | 226 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, |
227 | u32 blocksize) | ||
227 | { | 228 | { |
228 | struct extent_buffer *buf = NULL; | 229 | struct extent_buffer *buf = NULL; |
229 | struct inode *btree_inode = root->fs_info->btree_inode; | 230 | struct inode *btree_inode = root->fs_info->btree_inode; |
230 | 231 | ||
231 | buf = btrfs_find_create_tree_block(root, blocknr); | 232 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); |
232 | if (!buf) | 233 | if (!buf) |
233 | return NULL; | 234 | return NULL; |
234 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, | 235 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
@@ -261,7 +262,7 @@ int set_tree_block_dirty(struct btrfs_root *root, struct extent_buffer *buf) | |||
261 | return 0; | 262 | return 0; |
262 | } | 263 | } |
263 | 264 | ||
264 | static int __setup_root(int blocksize, | 265 | static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, |
265 | struct btrfs_root *root, | 266 | struct btrfs_root *root, |
266 | struct btrfs_fs_info *fs_info, | 267 | struct btrfs_fs_info *fs_info, |
267 | u64 objectid) | 268 | u64 objectid) |
@@ -269,9 +270,9 @@ static int __setup_root(int blocksize, | |||
269 | root->node = NULL; | 270 | root->node = NULL; |
270 | root->inode = NULL; | 271 | root->inode = NULL; |
271 | root->commit_root = NULL; | 272 | root->commit_root = NULL; |
272 | root->sectorsize = blocksize; | 273 | root->sectorsize = sectorsize; |
273 | root->nodesize = blocksize; | 274 | root->nodesize = nodesize; |
274 | root->leafsize = blocksize; | 275 | root->leafsize = leafsize; |
275 | root->ref_cows = 0; | 276 | root->ref_cows = 0; |
276 | root->fs_info = fs_info; | 277 | root->fs_info = fs_info; |
277 | root->objectid = objectid; | 278 | root->objectid = objectid; |
@@ -291,21 +292,23 @@ static int __setup_root(int blocksize, | |||
291 | return 0; | 292 | return 0; |
292 | } | 293 | } |
293 | 294 | ||
294 | static int find_and_setup_root(int blocksize, | 295 | static int find_and_setup_root(struct btrfs_root *tree_root, |
295 | struct btrfs_root *tree_root, | ||
296 | struct btrfs_fs_info *fs_info, | 296 | struct btrfs_fs_info *fs_info, |
297 | u64 objectid, | 297 | u64 objectid, |
298 | struct btrfs_root *root) | 298 | struct btrfs_root *root) |
299 | { | 299 | { |
300 | int ret; | 300 | int ret; |
301 | u32 blocksize; | ||
301 | 302 | ||
302 | __setup_root(blocksize, root, fs_info, objectid); | 303 | __setup_root(tree_root->nodesize, tree_root->leafsize, |
304 | tree_root->sectorsize, root, fs_info, objectid); | ||
303 | ret = btrfs_find_last_root(tree_root, objectid, | 305 | ret = btrfs_find_last_root(tree_root, objectid, |
304 | &root->root_item, &root->root_key); | 306 | &root->root_item, &root->root_key); |
305 | BUG_ON(ret); | 307 | BUG_ON(ret); |
306 | 308 | ||
307 | root->node = read_tree_block(root, | 309 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); |
308 | btrfs_root_blocknr(&root->root_item)); | 310 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
311 | blocksize); | ||
309 | BUG_ON(!root->node); | 312 | BUG_ON(!root->node); |
310 | return 0; | 313 | return 0; |
311 | } | 314 | } |
@@ -318,14 +321,14 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | |||
318 | struct btrfs_path *path; | 321 | struct btrfs_path *path; |
319 | struct extent_buffer *l; | 322 | struct extent_buffer *l; |
320 | u64 highest_inode; | 323 | u64 highest_inode; |
324 | u32 blocksize; | ||
321 | int ret = 0; | 325 | int ret = 0; |
322 | 326 | ||
323 | root = kzalloc(sizeof(*root), GFP_NOFS); | 327 | root = kzalloc(sizeof(*root), GFP_NOFS); |
324 | if (!root) | 328 | if (!root) |
325 | return ERR_PTR(-ENOMEM); | 329 | return ERR_PTR(-ENOMEM); |
326 | if (location->offset == (u64)-1) { | 330 | if (location->offset == (u64)-1) { |
327 | ret = find_and_setup_root(fs_info->sb->s_blocksize, | 331 | ret = find_and_setup_root(tree_root, fs_info, |
328 | fs_info->tree_root, fs_info, | ||
329 | location->objectid, root); | 332 | location->objectid, root); |
330 | if (ret) { | 333 | if (ret) { |
331 | kfree(root); | 334 | kfree(root); |
@@ -334,7 +337,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | |||
334 | goto insert; | 337 | goto insert; |
335 | } | 338 | } |
336 | 339 | ||
337 | __setup_root(fs_info->sb->s_blocksize, root, fs_info, | 340 | __setup_root(tree_root->nodesize, tree_root->leafsize, |
341 | tree_root->sectorsize, root, fs_info, | ||
338 | location->objectid); | 342 | location->objectid); |
339 | 343 | ||
340 | path = btrfs_alloc_path(); | 344 | path = btrfs_alloc_path(); |
@@ -357,8 +361,9 @@ out: | |||
357 | kfree(root); | 361 | kfree(root); |
358 | return ERR_PTR(ret); | 362 | return ERR_PTR(ret); |
359 | } | 363 | } |
360 | root->node = read_tree_block(root, | 364 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); |
361 | btrfs_root_blocknr(&root->root_item)); | 365 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
366 | blocksize); | ||
362 | BUG_ON(!root->node); | 367 | BUG_ON(!root->node); |
363 | insert: | 368 | insert: |
364 | root->ref_cows = 1; | 369 | root->ref_cows = 1; |
@@ -418,6 +423,10 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
418 | 423 | ||
419 | struct btrfs_root *open_ctree(struct super_block *sb) | 424 | struct btrfs_root *open_ctree(struct super_block *sb) |
420 | { | 425 | { |
426 | u32 sectorsize; | ||
427 | u32 nodesize; | ||
428 | u32 leafsize; | ||
429 | u32 blocksize; | ||
421 | struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), | 430 | struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), |
422 | GFP_NOFS); | 431 | GFP_NOFS); |
423 | struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), | 432 | struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), |
@@ -474,12 +483,12 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
474 | mutex_init(&fs_info->trans_mutex); | 483 | mutex_init(&fs_info->trans_mutex); |
475 | mutex_init(&fs_info->fs_mutex); | 484 | mutex_init(&fs_info->fs_mutex); |
476 | 485 | ||
477 | __setup_root(sb->s_blocksize, tree_root, | 486 | __setup_root(512, 512, 512, tree_root, |
478 | fs_info, BTRFS_ROOT_TREE_OBJECTID); | 487 | fs_info, BTRFS_ROOT_TREE_OBJECTID); |
479 | 488 | ||
480 | fs_info->sb_buffer = read_tree_block(tree_root, | 489 | fs_info->sb_buffer = read_tree_block(tree_root, |
481 | BTRFS_SUPER_INFO_OFFSET / | 490 | BTRFS_SUPER_INFO_OFFSET, |
482 | sb->s_blocksize); | 491 | 512); |
483 | 492 | ||
484 | if (!fs_info->sb_buffer) | 493 | if (!fs_info->sb_buffer) |
485 | goto fail_iput; | 494 | goto fail_iput; |
@@ -494,9 +503,15 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
494 | if (!btrfs_super_root(disk_super)) | 503 | if (!btrfs_super_root(disk_super)) |
495 | goto fail_sb_buffer; | 504 | goto fail_sb_buffer; |
496 | 505 | ||
506 | nodesize = btrfs_super_nodesize(disk_super); | ||
507 | leafsize = btrfs_super_leafsize(disk_super); | ||
508 | sectorsize = btrfs_super_sectorsize(disk_super); | ||
509 | tree_root->nodesize = nodesize; | ||
510 | tree_root->leafsize = leafsize; | ||
511 | tree_root->sectorsize = sectorsize; | ||
512 | |||
497 | i_size_write(fs_info->btree_inode, | 513 | i_size_write(fs_info->btree_inode, |
498 | btrfs_super_total_blocks(disk_super) << | 514 | btrfs_super_total_bytes(disk_super)); |
499 | fs_info->btree_inode->i_blkbits); | ||
500 | 515 | ||
501 | 516 | ||
502 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, | 517 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, |
@@ -504,13 +519,22 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
504 | printk("btrfs: valid FS not found on %s\n", sb->s_id); | 519 | printk("btrfs: valid FS not found on %s\n", sb->s_id); |
505 | goto fail_sb_buffer; | 520 | goto fail_sb_buffer; |
506 | } | 521 | } |
522 | blocksize = btrfs_level_size(tree_root, | ||
523 | btrfs_super_root_level(disk_super)); | ||
507 | tree_root->node = read_tree_block(tree_root, | 524 | tree_root->node = read_tree_block(tree_root, |
508 | btrfs_super_root(disk_super)); | 525 | btrfs_super_root(disk_super), |
526 | blocksize); | ||
509 | if (!tree_root->node) | 527 | if (!tree_root->node) |
510 | goto fail_sb_buffer; | 528 | goto fail_sb_buffer; |
511 | 529 | ||
530 | #if 0 | ||
531 | btrfs_print_leaf(tree_root, tree_root->node); | ||
532 | err = -EIO; | ||
533 | goto fail_tree_root; | ||
534 | #endif | ||
512 | mutex_lock(&fs_info->fs_mutex); | 535 | mutex_lock(&fs_info->fs_mutex); |
513 | ret = find_and_setup_root(sb->s_blocksize, tree_root, fs_info, | 536 | |
537 | ret = find_and_setup_root(tree_root, fs_info, | ||
514 | BTRFS_EXTENT_TREE_OBJECTID, extent_root); | 538 | BTRFS_EXTENT_TREE_OBJECTID, extent_root); |
515 | if (ret) { | 539 | if (ret) { |
516 | mutex_unlock(&fs_info->fs_mutex); | 540 | mutex_unlock(&fs_info->fs_mutex); |
@@ -611,11 +635,11 @@ int close_ctree(struct btrfs_root *root) | |||
611 | free_extent_buffer(fs_info->tree_root->node); | 635 | free_extent_buffer(fs_info->tree_root->node); |
612 | 636 | ||
613 | free_extent_buffer(fs_info->sb_buffer); | 637 | free_extent_buffer(fs_info->sb_buffer); |
614 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | ||
615 | iput(fs_info->btree_inode); | ||
616 | 638 | ||
617 | btrfs_free_block_groups(root->fs_info); | 639 | btrfs_free_block_groups(root->fs_info); |
618 | del_fs_roots(fs_info); | 640 | del_fs_roots(fs_info); |
641 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | ||
642 | iput(fs_info->btree_inode); | ||
619 | kfree(fs_info->extent_root); | 643 | kfree(fs_info->extent_root); |
620 | kfree(fs_info->tree_root); | 644 | kfree(fs_info->tree_root); |
621 | return 0; | 645 | return 0; |
@@ -642,7 +666,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) | |||
642 | 666 | ||
643 | if (transid != root->fs_info->generation) { | 667 | if (transid != root->fs_info->generation) { |
644 | printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", | 668 | printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", |
645 | (unsigned long long)extent_buffer_blocknr(buf), | 669 | (unsigned long long)buf->start, |
646 | transid, root->fs_info->generation); | 670 | transid, root->fs_info->generation); |
647 | WARN_ON(1); | 671 | WARN_ON(1); |
648 | } | 672 | } |