diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-16 10:49:51 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | 321aecc65671ae8136bd2ca6879b56f0221f8ac8 (patch) | |
tree | 9e397c5a6b4750703e60d70c0b588c463aaf376c /fs/btrfs/volumes.c | |
parent | e17cade25ff8074101d653557a78df09c16ca276 (diff) |
Btrfs: Add RAID10 support
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 23ebd95b25e0..e6417a573d44 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -33,6 +33,7 @@ struct map_lookup { | |||
33 | int stripe_len; | 33 | int stripe_len; |
34 | int sector_size; | 34 | int sector_size; |
35 | int num_stripes; | 35 | int num_stripes; |
36 | int sub_stripes; | ||
36 | struct btrfs_bio_stripe stripes[]; | 37 | struct btrfs_bio_stripe stripes[]; |
37 | }; | 38 | }; |
38 | 39 | ||
@@ -641,6 +642,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
641 | u64 avail; | 642 | u64 avail; |
642 | u64 max_avail = 0; | 643 | u64 max_avail = 0; |
643 | int num_stripes = 1; | 644 | int num_stripes = 1; |
645 | int sub_stripes = 0; | ||
644 | int looped = 0; | 646 | int looped = 0; |
645 | int ret; | 647 | int ret; |
646 | int index; | 648 | int index; |
@@ -658,6 +660,13 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
658 | num_stripes = min_t(u64, 2, | 660 | num_stripes = min_t(u64, 2, |
659 | btrfs_super_num_devices(&info->super_copy)); | 661 | btrfs_super_num_devices(&info->super_copy)); |
660 | } | 662 | } |
663 | if (type & (BTRFS_BLOCK_GROUP_RAID10)) { | ||
664 | num_stripes = btrfs_super_num_devices(&info->super_copy); | ||
665 | if (num_stripes < 4) | ||
666 | return -ENOSPC; | ||
667 | num_stripes &= ~(u32)1; | ||
668 | sub_stripes = 2; | ||
669 | } | ||
661 | again: | 670 | again: |
662 | INIT_LIST_HEAD(&private_devs); | 671 | INIT_LIST_HEAD(&private_devs); |
663 | cur = dev_list->next; | 672 | cur = dev_list->next; |
@@ -714,6 +723,8 @@ again: | |||
714 | 723 | ||
715 | if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) | 724 | if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) |
716 | *num_bytes = calc_size; | 725 | *num_bytes = calc_size; |
726 | else if (type & BTRFS_BLOCK_GROUP_RAID10) | ||
727 | *num_bytes = calc_size * num_stripes / sub_stripes; | ||
717 | else | 728 | else |
718 | *num_bytes = calc_size * num_stripes; | 729 | *num_bytes = calc_size * num_stripes; |
719 | 730 | ||
@@ -760,12 +771,14 @@ printk("alloc chunk start %Lu size %Lu from dev %Lu type %Lu\n", key.offset, cal | |||
760 | btrfs_set_stack_chunk_io_align(chunk, stripe_len); | 771 | btrfs_set_stack_chunk_io_align(chunk, stripe_len); |
761 | btrfs_set_stack_chunk_io_width(chunk, stripe_len); | 772 | btrfs_set_stack_chunk_io_width(chunk, stripe_len); |
762 | btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); | 773 | btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); |
774 | btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes); | ||
763 | map->sector_size = extent_root->sectorsize; | 775 | map->sector_size = extent_root->sectorsize; |
764 | map->stripe_len = stripe_len; | 776 | map->stripe_len = stripe_len; |
765 | map->io_align = stripe_len; | 777 | map->io_align = stripe_len; |
766 | map->io_width = stripe_len; | 778 | map->io_width = stripe_len; |
767 | map->type = type; | 779 | map->type = type; |
768 | map->num_stripes = num_stripes; | 780 | map->num_stripes = num_stripes; |
781 | map->sub_stripes = sub_stripes; | ||
769 | 782 | ||
770 | ret = btrfs_insert_item(trans, chunk_root, &key, chunk, | 783 | ret = btrfs_insert_item(trans, chunk_root, &key, chunk, |
771 | btrfs_chunk_item_size(num_stripes)); | 784 | btrfs_chunk_item_size(num_stripes)); |
@@ -832,6 +845,8 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) | |||
832 | map = (struct map_lookup *)em->bdev; | 845 | map = (struct map_lookup *)em->bdev; |
833 | if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) | 846 | if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) |
834 | ret = map->num_stripes; | 847 | ret = map->num_stripes; |
848 | else if (map->type & BTRFS_BLOCK_GROUP_RAID10) | ||
849 | ret = map->sub_stripes; | ||
835 | else | 850 | else |
836 | ret = 1; | 851 | ret = 1; |
837 | free_extent_map(em); | 852 | free_extent_map(em); |
@@ -849,6 +864,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
849 | u64 stripe_offset; | 864 | u64 stripe_offset; |
850 | u64 stripe_nr; | 865 | u64 stripe_nr; |
851 | int stripes_allocated = 8; | 866 | int stripes_allocated = 8; |
867 | int stripes_required = 1; | ||
852 | int stripe_index; | 868 | int stripe_index; |
853 | int i; | 869 | int i; |
854 | struct btrfs_multi_bio *multi = NULL; | 870 | struct btrfs_multi_bio *multi = NULL; |
@@ -877,10 +893,16 @@ again: | |||
877 | mirror_num = 0; | 893 | mirror_num = 0; |
878 | 894 | ||
879 | /* if our multi bio struct is too small, back off and try again */ | 895 | /* if our multi bio struct is too small, back off and try again */ |
880 | if (multi_ret && (rw & (1 << BIO_RW)) && | 896 | if (rw & (1 << BIO_RW)) { |
881 | stripes_allocated < map->num_stripes && | 897 | if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | |
882 | ((map->type & BTRFS_BLOCK_GROUP_RAID1) || | 898 | BTRFS_BLOCK_GROUP_DUP)) { |
883 | (map->type & BTRFS_BLOCK_GROUP_DUP))) { | 899 | stripes_required = map->num_stripes; |
900 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { | ||
901 | stripes_required = map->sub_stripes; | ||
902 | } | ||
903 | } | ||
904 | if (multi_ret && rw == WRITE && | ||
905 | stripes_allocated < stripes_required) { | ||
884 | stripes_allocated = map->num_stripes; | 906 | stripes_allocated = map->num_stripes; |
885 | free_extent_map(em); | 907 | free_extent_map(em); |
886 | kfree(multi); | 908 | kfree(multi); |
@@ -900,6 +922,7 @@ again: | |||
900 | stripe_offset = offset - stripe_offset; | 922 | stripe_offset = offset - stripe_offset; |
901 | 923 | ||
902 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | | 924 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | |
925 | BTRFS_BLOCK_GROUP_RAID10 | | ||
903 | BTRFS_BLOCK_GROUP_DUP)) { | 926 | BTRFS_BLOCK_GROUP_DUP)) { |
904 | /* we limit the length of each bio to what fits in a stripe */ | 927 | /* we limit the length of each bio to what fits in a stripe */ |
905 | *length = min_t(u64, em->len - offset, | 928 | *length = min_t(u64, em->len - offset, |
@@ -937,6 +960,19 @@ again: | |||
937 | multi->num_stripes = map->num_stripes; | 960 | multi->num_stripes = map->num_stripes; |
938 | else if (mirror_num) | 961 | else if (mirror_num) |
939 | stripe_index = mirror_num - 1; | 962 | stripe_index = mirror_num - 1; |
963 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { | ||
964 | int factor = map->num_stripes / map->sub_stripes; | ||
965 | int orig_stripe_nr = stripe_nr; | ||
966 | |||
967 | stripe_index = do_div(stripe_nr, factor); | ||
968 | stripe_index *= map->sub_stripes; | ||
969 | |||
970 | if (rw & (1 << BIO_RW)) | ||
971 | multi->num_stripes = map->sub_stripes; | ||
972 | else if (mirror_num) | ||
973 | stripe_index += mirror_num - 1; | ||
974 | else | ||
975 | stripe_index += orig_stripe_nr % map->sub_stripes; | ||
940 | } else { | 976 | } else { |
941 | /* | 977 | /* |
942 | * after this do_div call, stripe_nr is the number of stripes | 978 | * after this do_div call, stripe_nr is the number of stripes |
@@ -946,7 +982,6 @@ again: | |||
946 | stripe_index = do_div(stripe_nr, map->num_stripes); | 982 | stripe_index = do_div(stripe_nr, map->num_stripes); |
947 | } | 983 | } |
948 | BUG_ON(stripe_index >= map->num_stripes); | 984 | BUG_ON(stripe_index >= map->num_stripes); |
949 | BUG_ON(stripe_index != 0 && multi->num_stripes > 1); | ||
950 | 985 | ||
951 | for (i = 0; i < multi->num_stripes; i++) { | 986 | for (i = 0; i < multi->num_stripes; i++) { |
952 | multi->stripes[i].physical = | 987 | multi->stripes[i].physical = |
@@ -1120,6 +1155,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
1120 | map->sector_size = btrfs_chunk_sector_size(leaf, chunk); | 1155 | map->sector_size = btrfs_chunk_sector_size(leaf, chunk); |
1121 | map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); | 1156 | map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); |
1122 | map->type = btrfs_chunk_type(leaf, chunk); | 1157 | map->type = btrfs_chunk_type(leaf, chunk); |
1158 | map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); | ||
1123 | for (i = 0; i < num_stripes; i++) { | 1159 | for (i = 0; i < num_stripes; i++) { |
1124 | map->stripes[i].physical = | 1160 | map->stripes[i].physical = |
1125 | btrfs_stripe_offset_nr(leaf, chunk, i); | 1161 | btrfs_stripe_offset_nr(leaf, chunk, i); |