diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-09 16:28:12 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | f188591e987e21b6f7f8864c66a02858b95b530e (patch) | |
tree | 996f04b7c8d1e8a626b123e7a2a217992d705c60 /fs/btrfs/volumes.c | |
parent | 22c599485b1fdd95e4476a4752596a6cf6c6629a (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.c | 39 |
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 | ||
791 | int 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 | |||
791 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | 813 | int 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 | ||
941 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | 970 | int 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; |