diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-03-24 15:01:56 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:00 -0400 |
commit | 0b86a832a1f38abec695864ec2eaedc9d2383f1b (patch) | |
tree | 8ec0db0b55f77eb6a23fe7db3c1064d298db55c1 /fs/btrfs/disk-io.c | |
parent | 7f93bf8d27653726e3721c01fefc523487ecf2af (diff) |
Btrfs: Add support for multiple devices per filesystem
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 | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 88e21bdbc478..8e37fa120cc8 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 "volumes.h" | ||
31 | #include "print-tree.h" | 32 | #include "print-tree.h" |
32 | 33 | ||
33 | #if 0 | 34 | #if 0 |
@@ -234,6 +235,19 @@ static int btree_writepage_io_hook(struct page *page, u64 start, u64 end) | |||
234 | return 0; | 235 | return 0; |
235 | } | 236 | } |
236 | 237 | ||
238 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | ||
239 | { | ||
240 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
241 | u64 offset; | ||
242 | offset = bio->bi_sector << 9; | ||
243 | if (offset == BTRFS_SUPER_INFO_OFFSET) { | ||
244 | bio->bi_bdev = root->fs_info->sb->s_bdev; | ||
245 | submit_bio(rw, bio); | ||
246 | return 0; | ||
247 | } | ||
248 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio); | ||
249 | } | ||
250 | |||
237 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 251 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
238 | { | 252 | { |
239 | struct extent_io_tree *tree; | 253 | struct extent_io_tree *tree; |
@@ -345,6 +359,23 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) | |||
345 | return ret; | 359 | return ret; |
346 | } | 360 | } |
347 | 361 | ||
362 | static int close_all_devices(struct btrfs_fs_info *fs_info) | ||
363 | { | ||
364 | struct list_head *list; | ||
365 | struct list_head *next; | ||
366 | struct btrfs_device *device; | ||
367 | |||
368 | list = &fs_info->devices; | ||
369 | while(!list_empty(list)) { | ||
370 | next = list->next; | ||
371 | list_del(next); | ||
372 | device = list_entry(next, struct btrfs_device, dev_list); | ||
373 | kfree(device->name); | ||
374 | kfree(device); | ||
375 | } | ||
376 | return 0; | ||
377 | } | ||
378 | |||
348 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | 379 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, |
349 | u32 blocksize) | 380 | u32 blocksize) |
350 | { | 381 | { |
@@ -420,6 +451,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
420 | root->leafsize = leafsize; | 451 | root->leafsize = leafsize; |
421 | root->stripesize = stripesize; | 452 | root->stripesize = stripesize; |
422 | root->ref_cows = 0; | 453 | root->ref_cows = 0; |
454 | root->track_dirty = 0; | ||
455 | |||
423 | root->fs_info = fs_info; | 456 | root->fs_info = fs_info; |
424 | root->objectid = objectid; | 457 | root->objectid = objectid; |
425 | root->last_trans = 0; | 458 | root->last_trans = 0; |
@@ -427,6 +460,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
427 | root->last_inode_alloc = 0; | 460 | root->last_inode_alloc = 0; |
428 | root->name = NULL; | 461 | root->name = NULL; |
429 | root->in_sysfs = 0; | 462 | root->in_sysfs = 0; |
463 | |||
464 | INIT_LIST_HEAD(&root->dirty_list); | ||
430 | memset(&root->root_key, 0, sizeof(root->root_key)); | 465 | memset(&root->root_key, 0, sizeof(root->root_key)); |
431 | memset(&root->root_item, 0, sizeof(root->root_item)); | 466 | memset(&root->root_item, 0, sizeof(root->root_item)); |
432 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); | 467 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); |
@@ -634,6 +669,10 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
634 | GFP_NOFS); | 669 | GFP_NOFS); |
635 | struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info), | 670 | struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info), |
636 | GFP_NOFS); | 671 | GFP_NOFS); |
672 | struct btrfs_root *chunk_root = kmalloc(sizeof(struct btrfs_root), | ||
673 | GFP_NOFS); | ||
674 | struct btrfs_root *dev_root = kmalloc(sizeof(struct btrfs_root), | ||
675 | GFP_NOFS); | ||
637 | int ret; | 676 | int ret; |
638 | int err = -EIO; | 677 | int err = -EIO; |
639 | struct btrfs_super_block *disk_super; | 678 | struct btrfs_super_block *disk_super; |
@@ -657,6 +696,12 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
657 | fs_info->last_trans_committed = 0; | 696 | fs_info->last_trans_committed = 0; |
658 | fs_info->tree_root = tree_root; | 697 | fs_info->tree_root = tree_root; |
659 | fs_info->extent_root = extent_root; | 698 | fs_info->extent_root = extent_root; |
699 | fs_info->chunk_root = chunk_root; | ||
700 | fs_info->dev_root = dev_root; | ||
701 | INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); | ||
702 | INIT_LIST_HEAD(&fs_info->devices); | ||
703 | btrfs_mapping_init(&fs_info->mapping_tree); | ||
704 | fs_info->last_device = &fs_info->devices; | ||
660 | fs_info->sb = sb; | 705 | fs_info->sb = sb; |
661 | fs_info->throttles = 0; | 706 | fs_info->throttles = 0; |
662 | fs_info->mount_opt = 0; | 707 | fs_info->mount_opt = 0; |
@@ -714,12 +759,12 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
714 | goto fail_iput; | 759 | goto fail_iput; |
715 | } | 760 | } |
716 | #endif | 761 | #endif |
717 | __setup_root(512, 512, 512, 512, tree_root, | 762 | __setup_root(4096, 4096, 4096, 4096, tree_root, |
718 | fs_info, BTRFS_ROOT_TREE_OBJECTID); | 763 | fs_info, BTRFS_ROOT_TREE_OBJECTID); |
719 | 764 | ||
720 | fs_info->sb_buffer = read_tree_block(tree_root, | 765 | fs_info->sb_buffer = read_tree_block(tree_root, |
721 | BTRFS_SUPER_INFO_OFFSET, | 766 | BTRFS_SUPER_INFO_OFFSET, |
722 | 512); | 767 | 4096); |
723 | 768 | ||
724 | if (!fs_info->sb_buffer) | 769 | if (!fs_info->sb_buffer) |
725 | goto fail_iput; | 770 | goto fail_iput; |
@@ -730,6 +775,7 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
730 | read_extent_buffer(fs_info->sb_buffer, fs_info->fsid, | 775 | read_extent_buffer(fs_info->sb_buffer, fs_info->fsid, |
731 | (unsigned long)btrfs_super_fsid(fs_info->sb_buffer), | 776 | (unsigned long)btrfs_super_fsid(fs_info->sb_buffer), |
732 | BTRFS_FSID_SIZE); | 777 | BTRFS_FSID_SIZE); |
778 | |||
733 | disk_super = &fs_info->super_copy; | 779 | disk_super = &fs_info->super_copy; |
734 | if (!btrfs_super_root(disk_super)) | 780 | if (!btrfs_super_root(disk_super)) |
735 | goto fail_sb_buffer; | 781 | goto fail_sb_buffer; |
@@ -753,23 +799,47 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
753 | goto fail_sb_buffer; | 799 | goto fail_sb_buffer; |
754 | } | 800 | } |
755 | 801 | ||
802 | mutex_lock(&fs_info->fs_mutex); | ||
803 | ret = btrfs_read_sys_array(tree_root); | ||
804 | BUG_ON(ret); | ||
805 | |||
806 | blocksize = btrfs_level_size(tree_root, | ||
807 | btrfs_super_chunk_root_level(disk_super)); | ||
808 | |||
809 | __setup_root(nodesize, leafsize, sectorsize, stripesize, | ||
810 | chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID); | ||
811 | |||
812 | chunk_root->node = read_tree_block(chunk_root, | ||
813 | btrfs_super_chunk_root(disk_super), | ||
814 | blocksize); | ||
815 | BUG_ON(!chunk_root->node); | ||
816 | |||
817 | ret = btrfs_read_chunk_tree(chunk_root); | ||
818 | BUG_ON(ret); | ||
819 | |||
756 | blocksize = btrfs_level_size(tree_root, | 820 | blocksize = btrfs_level_size(tree_root, |
757 | btrfs_super_root_level(disk_super)); | 821 | btrfs_super_root_level(disk_super)); |
758 | 822 | ||
823 | |||
759 | tree_root->node = read_tree_block(tree_root, | 824 | tree_root->node = read_tree_block(tree_root, |
760 | btrfs_super_root(disk_super), | 825 | btrfs_super_root(disk_super), |
761 | blocksize); | 826 | blocksize); |
762 | if (!tree_root->node) | 827 | if (!tree_root->node) |
763 | goto fail_sb_buffer; | 828 | goto fail_sb_buffer; |
764 | 829 | ||
765 | mutex_lock(&fs_info->fs_mutex); | ||
766 | 830 | ||
767 | ret = find_and_setup_root(tree_root, fs_info, | 831 | ret = find_and_setup_root(tree_root, fs_info, |
768 | BTRFS_EXTENT_TREE_OBJECTID, extent_root); | 832 | BTRFS_EXTENT_TREE_OBJECTID, extent_root); |
769 | if (ret) { | 833 | if (ret) |
770 | mutex_unlock(&fs_info->fs_mutex); | ||
771 | goto fail_tree_root; | 834 | goto fail_tree_root; |
772 | } | 835 | extent_root->track_dirty = 1; |
836 | |||
837 | ret = find_and_setup_root(tree_root, fs_info, | ||
838 | BTRFS_DEV_TREE_OBJECTID, dev_root); | ||
839 | dev_root->track_dirty = 1; | ||
840 | |||
841 | if (ret) | ||
842 | goto fail_extent_root; | ||
773 | 843 | ||
774 | btrfs_read_block_groups(extent_root); | 844 | btrfs_read_block_groups(extent_root); |
775 | 845 | ||
@@ -777,7 +847,10 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
777 | mutex_unlock(&fs_info->fs_mutex); | 847 | mutex_unlock(&fs_info->fs_mutex); |
778 | return tree_root; | 848 | return tree_root; |
779 | 849 | ||
850 | fail_extent_root: | ||
851 | free_extent_buffer(extent_root->node); | ||
780 | fail_tree_root: | 852 | fail_tree_root: |
853 | mutex_unlock(&fs_info->fs_mutex); | ||
781 | free_extent_buffer(tree_root->node); | 854 | free_extent_buffer(tree_root->node); |
782 | fail_sb_buffer: | 855 | fail_sb_buffer: |
783 | free_extent_buffer(fs_info->sb_buffer); | 856 | free_extent_buffer(fs_info->sb_buffer); |
@@ -874,6 +947,12 @@ int close_ctree(struct btrfs_root *root) | |||
874 | if (fs_info->tree_root->node) | 947 | if (fs_info->tree_root->node) |
875 | free_extent_buffer(fs_info->tree_root->node); | 948 | free_extent_buffer(fs_info->tree_root->node); |
876 | 949 | ||
950 | if (root->fs_info->chunk_root->node); | ||
951 | free_extent_buffer(root->fs_info->chunk_root->node); | ||
952 | |||
953 | if (root->fs_info->dev_root->node); | ||
954 | free_extent_buffer(root->fs_info->dev_root->node); | ||
955 | |||
877 | free_extent_buffer(fs_info->sb_buffer); | 956 | free_extent_buffer(fs_info->sb_buffer); |
878 | 957 | ||
879 | btrfs_free_block_groups(root->fs_info); | 958 | btrfs_free_block_groups(root->fs_info); |
@@ -901,8 +980,13 @@ int close_ctree(struct btrfs_root *root) | |||
901 | kfree(hasher); | 980 | kfree(hasher); |
902 | } | 981 | } |
903 | #endif | 982 | #endif |
983 | close_all_devices(fs_info); | ||
984 | btrfs_mapping_tree_free(&fs_info->mapping_tree); | ||
985 | |||
904 | kfree(fs_info->extent_root); | 986 | kfree(fs_info->extent_root); |
905 | kfree(fs_info->tree_root); | 987 | kfree(fs_info->tree_root); |
988 | kfree(fs_info->chunk_root); | ||
989 | kfree(fs_info->dev_root); | ||
906 | return 0; | 990 | return 0; |
907 | } | 991 | } |
908 | 992 | ||
@@ -1016,4 +1100,5 @@ int btrfs_read_buffer(struct extent_buffer *buf) | |||
1016 | 1100 | ||
1017 | static struct extent_io_ops btree_extent_io_ops = { | 1101 | static struct extent_io_ops btree_extent_io_ops = { |
1018 | .writepage_io_hook = btree_writepage_io_hook, | 1102 | .writepage_io_hook = btree_writepage_io_hook, |
1103 | .submit_bio_hook = btree_submit_bio_hook, | ||
1019 | }; | 1104 | }; |