aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-09 16:28:12 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commitf188591e987e21b6f7f8864c66a02858b95b530e (patch)
tree996f04b7c8d1e8a626b123e7a2a217992d705c60 /fs/btrfs/volumes.c
parent22c599485b1fdd95e4476a4752596a6cf6c6629a (diff)
Btrfs: Retry metadata reads in the face of checksum failures
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 008d3640e8c2..3b927f698320 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -788,9 +788,31 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
788 } 788 }
789} 789}
790 790
791int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
792{
793 struct extent_map *em;
794 struct map_lookup *map;
795 struct extent_map_tree *em_tree = &map_tree->map_tree;
796 int ret;
797
798 spin_lock(&em_tree->lock);
799 em = lookup_extent_mapping(em_tree, logical, len);
800 BUG_ON(!em);
801
802 BUG_ON(em->start > logical || em->start + em->len < logical);
803 map = (struct map_lookup *)em->bdev;
804 if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
805 ret = map->num_stripes;
806 else
807 ret = 1;
808 free_extent_map(em);
809 spin_unlock(&em_tree->lock);
810 return ret;
811}
812
791int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, 813int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
792 u64 logical, u64 *length, 814 u64 logical, u64 *length,
793 struct btrfs_multi_bio **multi_ret) 815 struct btrfs_multi_bio **multi_ret, int mirror_num)
794{ 816{
795 struct extent_map *em; 817 struct extent_map *em;
796 struct map_lookup *map; 818 struct map_lookup *map;
@@ -822,6 +844,9 @@ again:
822 map = (struct map_lookup *)em->bdev; 844 map = (struct map_lookup *)em->bdev;
823 offset = logical - em->start; 845 offset = logical - em->start;
824 846
847 if (mirror_num > map->num_stripes)
848 mirror_num = 0;
849
825 /* if our multi bio struct is too small, back off and try again */ 850 /* if our multi bio struct is too small, back off and try again */
826 if (multi_ret && (rw & (1 << BIO_RW)) && 851 if (multi_ret && (rw & (1 << BIO_RW)) &&
827 stripes_allocated < map->num_stripes && 852 stripes_allocated < map->num_stripes &&
@@ -862,7 +887,9 @@ again:
862 if (map->type & BTRFS_BLOCK_GROUP_RAID1) { 887 if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
863 if (rw & (1 << BIO_RW)) 888 if (rw & (1 << BIO_RW))
864 multi->num_stripes = map->num_stripes; 889 multi->num_stripes = map->num_stripes;
865 else { 890 else if (mirror_num) {
891 stripe_index = mirror_num - 1;
892 } else {
866 int i; 893 int i;
867 u64 least = (u64)-1; 894 u64 least = (u64)-1;
868 struct btrfs_device *cur; 895 struct btrfs_device *cur;
@@ -880,6 +907,8 @@ again:
880 } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { 907 } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
881 if (rw & (1 << BIO_RW)) 908 if (rw & (1 << BIO_RW))
882 multi->num_stripes = map->num_stripes; 909 multi->num_stripes = map->num_stripes;
910 else if (mirror_num)
911 stripe_index = mirror_num - 1;
883 } else { 912 } else {
884 /* 913 /*
885 * after this do_div call, stripe_nr is the number of stripes 914 * after this do_div call, stripe_nr is the number of stripes
@@ -938,7 +967,8 @@ static int end_bio_multi_stripe(struct bio *bio,
938#endif 967#endif
939} 968}
940 969
941int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) 970int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
971 int mirror_num)
942{ 972{
943 struct btrfs_mapping_tree *map_tree; 973 struct btrfs_mapping_tree *map_tree;
944 struct btrfs_device *dev; 974 struct btrfs_device *dev;
@@ -960,7 +990,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
960 map_tree = &root->fs_info->mapping_tree; 990 map_tree = &root->fs_info->mapping_tree;
961 map_length = length; 991 map_length = length;
962 992
963 ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi); 993 ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi,
994 mirror_num);
964 BUG_ON(ret); 995 BUG_ON(ret);
965 996
966 total_devs = multi->num_stripes; 997 total_devs = multi->num_stripes;