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 | cea9e4452ebaf18dd0951e90dc84d82a5dee40b2 (patch) | |
tree | 94f6a3c4fa25ebdff1f46d8b41ab58ee92723609 /fs/btrfs/volumes.c | |
parent | d18a2c447524751137a12cc8ccaf9d1e0b7fa1b3 (diff) |
Change btrfs_map_block to return a structure with mappings for all stripes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 135 |
1 files changed, 75 insertions, 60 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index b9294e3c05f0..008d3640e8c2 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -26,18 +26,6 @@ | |||
26 | #include "print-tree.h" | 26 | #include "print-tree.h" |
27 | #include "volumes.h" | 27 | #include "volumes.h" |
28 | 28 | ||
29 | struct stripe { | ||
30 | struct btrfs_device *dev; | ||
31 | u64 physical; | ||
32 | }; | ||
33 | |||
34 | struct multi_bio { | ||
35 | atomic_t stripes; | ||
36 | bio_end_io_t *end_io; | ||
37 | void *private; | ||
38 | int error; | ||
39 | }; | ||
40 | |||
41 | struct map_lookup { | 29 | struct map_lookup { |
42 | u64 type; | 30 | u64 type; |
43 | int io_align; | 31 | int io_align; |
@@ -45,11 +33,11 @@ struct map_lookup { | |||
45 | int stripe_len; | 33 | int stripe_len; |
46 | int sector_size; | 34 | int sector_size; |
47 | int num_stripes; | 35 | int num_stripes; |
48 | struct stripe stripes[]; | 36 | struct btrfs_bio_stripe stripes[]; |
49 | }; | 37 | }; |
50 | 38 | ||
51 | #define map_lookup_size(n) (sizeof(struct map_lookup) + \ | 39 | #define map_lookup_size(n) (sizeof(struct map_lookup) + \ |
52 | (sizeof(struct stripe) * (n))) | 40 | (sizeof(struct btrfs_bio_stripe) * (n))) |
53 | 41 | ||
54 | static DEFINE_MUTEX(uuid_mutex); | 42 | static DEFINE_MUTEX(uuid_mutex); |
55 | static LIST_HEAD(fs_uuids); | 43 | static LIST_HEAD(fs_uuids); |
@@ -801,8 +789,8 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) | |||
801 | } | 789 | } |
802 | 790 | ||
803 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | 791 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, |
804 | int dev_nr, u64 logical, u64 *phys, u64 *length, | 792 | u64 logical, u64 *length, |
805 | struct btrfs_device **dev, int *total_devs) | 793 | struct btrfs_multi_bio **multi_ret) |
806 | { | 794 | { |
807 | struct extent_map *em; | 795 | struct extent_map *em; |
808 | struct map_lookup *map; | 796 | struct map_lookup *map; |
@@ -810,8 +798,21 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
810 | u64 offset; | 798 | u64 offset; |
811 | u64 stripe_offset; | 799 | u64 stripe_offset; |
812 | u64 stripe_nr; | 800 | u64 stripe_nr; |
801 | int stripes_allocated = 8; | ||
813 | int stripe_index; | 802 | int stripe_index; |
803 | int i; | ||
804 | struct btrfs_multi_bio *multi = NULL; | ||
814 | 805 | ||
806 | if (multi_ret && !(rw & (1 << BIO_RW))) { | ||
807 | stripes_allocated = 1; | ||
808 | } | ||
809 | again: | ||
810 | if (multi_ret) { | ||
811 | multi = kzalloc(btrfs_multi_bio_size(stripes_allocated), | ||
812 | GFP_NOFS); | ||
813 | if (!multi) | ||
814 | return -ENOMEM; | ||
815 | } | ||
815 | 816 | ||
816 | spin_lock(&em_tree->lock); | 817 | spin_lock(&em_tree->lock); |
817 | em = lookup_extent_mapping(em_tree, logical, *length); | 818 | em = lookup_extent_mapping(em_tree, logical, *length); |
@@ -821,6 +822,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
821 | map = (struct map_lookup *)em->bdev; | 822 | map = (struct map_lookup *)em->bdev; |
822 | offset = logical - em->start; | 823 | offset = logical - em->start; |
823 | 824 | ||
825 | /* if our multi bio struct is too small, back off and try again */ | ||
826 | if (multi_ret && (rw & (1 << BIO_RW)) && | ||
827 | stripes_allocated < map->num_stripes && | ||
828 | ((map->type & BTRFS_BLOCK_GROUP_RAID1) || | ||
829 | (map->type & BTRFS_BLOCK_GROUP_DUP))) { | ||
830 | stripes_allocated = map->num_stripes; | ||
831 | spin_unlock(&em_tree->lock); | ||
832 | free_extent_map(em); | ||
833 | kfree(multi); | ||
834 | goto again; | ||
835 | } | ||
824 | stripe_nr = offset; | 836 | stripe_nr = offset; |
825 | /* | 837 | /* |
826 | * stripe_nr counts the total number of stripes we have to stride | 838 | * stripe_nr counts the total number of stripes we have to stride |
@@ -834,10 +846,22 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
834 | /* stripe_offset is the offset of this block in its stripe*/ | 846 | /* stripe_offset is the offset of this block in its stripe*/ |
835 | stripe_offset = offset - stripe_offset; | 847 | stripe_offset = offset - stripe_offset; |
836 | 848 | ||
849 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | | ||
850 | BTRFS_BLOCK_GROUP_DUP)) { | ||
851 | /* we limit the length of each bio to what fits in a stripe */ | ||
852 | *length = min_t(u64, em->len - offset, | ||
853 | map->stripe_len - stripe_offset); | ||
854 | } else { | ||
855 | *length = em->len - offset; | ||
856 | } | ||
857 | if (!multi_ret) | ||
858 | goto out; | ||
859 | |||
860 | multi->num_stripes = 1; | ||
861 | stripe_index = 0; | ||
837 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | 862 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { |
838 | stripe_index = dev_nr; | ||
839 | if (rw & (1 << BIO_RW)) | 863 | if (rw & (1 << BIO_RW)) |
840 | *total_devs = map->num_stripes; | 864 | multi->num_stripes = map->num_stripes; |
841 | else { | 865 | else { |
842 | int i; | 866 | int i; |
843 | u64 least = (u64)-1; | 867 | u64 least = (u64)-1; |
@@ -852,16 +876,10 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
852 | } | 876 | } |
853 | spin_unlock(&cur->io_lock); | 877 | spin_unlock(&cur->io_lock); |
854 | } | 878 | } |
855 | *total_devs = 1; | ||
856 | } | 879 | } |
857 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { | 880 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { |
858 | if (rw == WRITE) { | 881 | if (rw & (1 << BIO_RW)) |
859 | *total_devs = map->num_stripes; | 882 | multi->num_stripes = map->num_stripes; |
860 | stripe_index = dev_nr; | ||
861 | } else { | ||
862 | stripe_index = 0; | ||
863 | *total_devs = 1; | ||
864 | } | ||
865 | } else { | 883 | } else { |
866 | /* | 884 | /* |
867 | * after this do_div call, stripe_nr is the number of stripes | 885 | * after this do_div call, stripe_nr is the number of stripes |
@@ -871,18 +889,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
871 | stripe_index = do_div(stripe_nr, map->num_stripes); | 889 | stripe_index = do_div(stripe_nr, map->num_stripes); |
872 | } | 890 | } |
873 | BUG_ON(stripe_index >= map->num_stripes); | 891 | BUG_ON(stripe_index >= map->num_stripes); |
874 | *phys = map->stripes[stripe_index].physical + stripe_offset + | 892 | BUG_ON(stripe_index != 0 && multi->num_stripes > 1); |
875 | stripe_nr * map->stripe_len; | 893 | |
876 | 894 | for (i = 0; i < multi->num_stripes; i++) { | |
877 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | | 895 | multi->stripes[i].physical = |
878 | BTRFS_BLOCK_GROUP_DUP)) { | 896 | map->stripes[stripe_index].physical + stripe_offset + |
879 | /* we limit the length of each bio to what fits in a stripe */ | 897 | stripe_nr * map->stripe_len; |
880 | *length = min_t(u64, em->len - offset, | 898 | multi->stripes[i].dev = map->stripes[stripe_index].dev; |
881 | map->stripe_len - stripe_offset); | 899 | stripe_index++; |
882 | } else { | ||
883 | *length = em->len - offset; | ||
884 | } | 900 | } |
885 | *dev = map->stripes[stripe_index].dev; | 901 | *multi_ret = multi; |
902 | out: | ||
886 | free_extent_map(em); | 903 | free_extent_map(em); |
887 | spin_unlock(&em_tree->lock); | 904 | spin_unlock(&em_tree->lock); |
888 | return 0; | 905 | return 0; |
@@ -895,7 +912,7 @@ static int end_bio_multi_stripe(struct bio *bio, | |||
895 | unsigned int bytes_done, int err) | 912 | unsigned int bytes_done, int err) |
896 | #endif | 913 | #endif |
897 | { | 914 | { |
898 | struct multi_bio *multi = bio->bi_private; | 915 | struct btrfs_multi_bio *multi = bio->bi_private; |
899 | 916 | ||
900 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) | 917 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) |
901 | if (bio->bi_size) | 918 | if (bio->bi_size) |
@@ -904,7 +921,7 @@ static int end_bio_multi_stripe(struct bio *bio, | |||
904 | if (err) | 921 | if (err) |
905 | multi->error = err; | 922 | multi->error = err; |
906 | 923 | ||
907 | if (atomic_dec_and_test(&multi->stripes)) { | 924 | if (atomic_dec_and_test(&multi->stripes_pending)) { |
908 | bio->bi_private = multi->private; | 925 | bio->bi_private = multi->private; |
909 | bio->bi_end_io = multi->end_io; | 926 | bio->bi_end_io = multi->end_io; |
910 | 927 | ||
@@ -927,11 +944,10 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | |||
927 | struct btrfs_device *dev; | 944 | struct btrfs_device *dev; |
928 | struct bio *first_bio = bio; | 945 | struct bio *first_bio = bio; |
929 | u64 logical = bio->bi_sector << 9; | 946 | u64 logical = bio->bi_sector << 9; |
930 | u64 physical; | ||
931 | u64 length = 0; | 947 | u64 length = 0; |
932 | u64 map_length; | 948 | u64 map_length; |
933 | struct bio_vec *bvec; | 949 | struct bio_vec *bvec; |
934 | struct multi_bio *multi = NULL; | 950 | struct btrfs_multi_bio *multi = NULL; |
935 | int i; | 951 | int i; |
936 | int ret; | 952 | int ret; |
937 | int dev_nr = 0; | 953 | int dev_nr = 0; |
@@ -943,26 +959,22 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | |||
943 | 959 | ||
944 | map_tree = &root->fs_info->mapping_tree; | 960 | map_tree = &root->fs_info->mapping_tree; |
945 | map_length = length; | 961 | map_length = length; |
962 | |||
963 | ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi); | ||
964 | BUG_ON(ret); | ||
965 | |||
966 | total_devs = multi->num_stripes; | ||
967 | if (map_length < length) { | ||
968 | printk("mapping failed logical %Lu bio len %Lu " | ||
969 | "len %Lu\n", logical, length, map_length); | ||
970 | BUG(); | ||
971 | } | ||
972 | multi->end_io = first_bio->bi_end_io; | ||
973 | multi->private = first_bio->bi_private; | ||
974 | atomic_set(&multi->stripes_pending, multi->num_stripes); | ||
975 | |||
946 | while(dev_nr < total_devs) { | 976 | while(dev_nr < total_devs) { |
947 | ret = btrfs_map_block(map_tree, rw, dev_nr, logical, | ||
948 | &physical, &map_length, &dev, | ||
949 | &total_devs); | ||
950 | if (map_length < length) { | ||
951 | printk("mapping failed logical %Lu bio len %Lu physical %Lu " | ||
952 | "len %Lu\n", logical, length, physical, map_length); | ||
953 | BUG(); | ||
954 | } | ||
955 | BUG_ON(map_length < length); | ||
956 | if (total_devs > 1) { | 977 | if (total_devs > 1) { |
957 | if (!multi) { | ||
958 | multi = kmalloc(sizeof(*multi), GFP_NOFS); | ||
959 | atomic_set(&multi->stripes, 1); | ||
960 | multi->end_io = bio->bi_end_io; | ||
961 | multi->private = first_bio->bi_private; | ||
962 | multi->error = 0; | ||
963 | } else { | ||
964 | atomic_inc(&multi->stripes); | ||
965 | } | ||
966 | if (dev_nr < total_devs - 1) { | 978 | if (dev_nr < total_devs - 1) { |
967 | bio = bio_clone(first_bio, GFP_NOFS); | 979 | bio = bio_clone(first_bio, GFP_NOFS); |
968 | BUG_ON(!bio); | 980 | BUG_ON(!bio); |
@@ -972,7 +984,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | |||
972 | bio->bi_private = multi; | 984 | bio->bi_private = multi; |
973 | bio->bi_end_io = end_bio_multi_stripe; | 985 | bio->bi_end_io = end_bio_multi_stripe; |
974 | } | 986 | } |
975 | bio->bi_sector = physical >> 9; | 987 | bio->bi_sector = multi->stripes[dev_nr].physical >> 9; |
988 | dev = multi->stripes[dev_nr].dev; | ||
976 | bio->bi_bdev = dev->bdev; | 989 | bio->bi_bdev = dev->bdev; |
977 | spin_lock(&dev->io_lock); | 990 | spin_lock(&dev->io_lock); |
978 | dev->total_ios++; | 991 | dev->total_ios++; |
@@ -980,6 +993,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | |||
980 | submit_bio(rw, bio); | 993 | submit_bio(rw, bio); |
981 | dev_nr++; | 994 | dev_nr++; |
982 | } | 995 | } |
996 | if (total_devs == 1) | ||
997 | kfree(multi); | ||
983 | return 0; | 998 | return 0; |
984 | } | 999 | } |
985 | 1000 | ||