diff options
-rw-r--r-- | fs/btrfs/disk-io.c | 26 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 6 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 79 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 2 |
4 files changed, 75 insertions, 38 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c829612c797e..7f5aca35494d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -913,18 +913,22 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) | |||
913 | 913 | ||
914 | void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) | 914 | void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) |
915 | { | 915 | { |
916 | struct list_head *cur; | 916 | struct inode *inode = page->mapping->host; |
917 | struct btrfs_device *device; | 917 | struct extent_map_tree *em_tree; |
918 | struct btrfs_fs_info *info; | 918 | struct extent_map *em; |
919 | u64 offset = page_offset(page); | ||
919 | 920 | ||
920 | info = (struct btrfs_fs_info *)bdi->unplug_io_data; | 921 | em_tree = &BTRFS_I(inode)->extent_tree; |
921 | list_for_each(cur, &info->fs_devices->devices) { | 922 | spin_lock(&em_tree->lock); |
922 | device = list_entry(cur, struct btrfs_device, dev_list); | 923 | em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE); |
923 | bdi = blk_get_backing_dev_info(device->bdev); | 924 | spin_unlock(&em_tree->lock); |
924 | if (bdi->unplug_io_fn) { | 925 | if (!em) |
925 | bdi->unplug_io_fn(bdi, page); | 926 | return; |
926 | } | 927 | |
927 | } | 928 | offset = offset - em->start; |
929 | btrfs_unplug_page(&BTRFS_I(inode)->root->fs_info->mapping_tree, | ||
930 | em->block_start + offset, page); | ||
931 | free_extent_map(em); | ||
928 | } | 932 | } |
929 | 933 | ||
930 | static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) | 934 | static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5b1514e58de4..e875c7c8a647 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -313,13 +313,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | |||
313 | u64 logical = bio->bi_sector << 9; | 313 | u64 logical = bio->bi_sector << 9; |
314 | u64 length = 0; | 314 | u64 length = 0; |
315 | u64 map_length; | 315 | u64 map_length; |
316 | struct bio_vec *bvec; | ||
317 | int i; | ||
318 | int ret; | 316 | int ret; |
319 | 317 | ||
320 | bio_for_each_segment(bvec, bio, i) { | 318 | length = bio->bi_size; |
321 | length += bvec->bv_len; | ||
322 | } | ||
323 | map_tree = &root->fs_info->mapping_tree; | 319 | map_tree = &root->fs_info->mapping_tree; |
324 | map_length = length; | 320 | map_length = length; |
325 | ret = btrfs_map_block(map_tree, READ, logical, | 321 | ret = btrfs_map_block(map_tree, READ, logical, |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4fc92cf813d8..460240706505 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/bio.h> | 19 | #include <linux/bio.h> |
20 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
21 | #include <linux/blkdev.h> | ||
21 | #include <asm/div64.h> | 22 | #include <asm/div64.h> |
22 | #include "ctree.h" | 23 | #include "ctree.h" |
23 | #include "extent_map.h" | 24 | #include "extent_map.h" |
@@ -930,9 +931,10 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) | |||
930 | return ret; | 931 | return ret; |
931 | } | 932 | } |
932 | 933 | ||
933 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | 934 | static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, |
934 | u64 logical, u64 *length, | 935 | u64 logical, u64 *length, |
935 | struct btrfs_multi_bio **multi_ret, int mirror_num) | 936 | struct btrfs_multi_bio **multi_ret, |
937 | int mirror_num, struct page *unplug_page) | ||
936 | { | 938 | { |
937 | struct extent_map *em; | 939 | struct extent_map *em; |
938 | struct map_lookup *map; | 940 | struct map_lookup *map; |
@@ -944,6 +946,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
944 | int stripes_required = 1; | 946 | int stripes_required = 1; |
945 | int stripe_index; | 947 | int stripe_index; |
946 | int i; | 948 | int i; |
949 | int num_stripes; | ||
947 | struct btrfs_multi_bio *multi = NULL; | 950 | struct btrfs_multi_bio *multi = NULL; |
948 | 951 | ||
949 | if (multi_ret && !(rw & (1 << BIO_RW))) { | 952 | if (multi_ret && !(rw & (1 << BIO_RW))) { |
@@ -960,10 +963,14 @@ again: | |||
960 | spin_lock(&em_tree->lock); | 963 | spin_lock(&em_tree->lock); |
961 | em = lookup_extent_mapping(em_tree, logical, *length); | 964 | em = lookup_extent_mapping(em_tree, logical, *length); |
962 | spin_unlock(&em_tree->lock); | 965 | spin_unlock(&em_tree->lock); |
966 | |||
967 | if (!em && unplug_page) | ||
968 | return 0; | ||
969 | |||
963 | if (!em) { | 970 | if (!em) { |
964 | printk("unable to find logical %Lu\n", logical); | 971 | printk("unable to find logical %Lu\n", logical); |
972 | BUG(); | ||
965 | } | 973 | } |
966 | BUG_ON(!em); | ||
967 | 974 | ||
968 | BUG_ON(em->start > logical || em->start + em->len < logical); | 975 | BUG_ON(em->start > logical || em->start + em->len < logical); |
969 | map = (struct map_lookup *)em->bdev; | 976 | map = (struct map_lookup *)em->bdev; |
@@ -1010,14 +1017,15 @@ again: | |||
1010 | } else { | 1017 | } else { |
1011 | *length = em->len - offset; | 1018 | *length = em->len - offset; |
1012 | } | 1019 | } |
1013 | if (!multi_ret) | 1020 | |
1021 | if (!multi_ret && !unplug_page) | ||
1014 | goto out; | 1022 | goto out; |
1015 | 1023 | ||
1016 | multi->num_stripes = 1; | 1024 | num_stripes = 1; |
1017 | stripe_index = 0; | 1025 | stripe_index = 0; |
1018 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | 1026 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { |
1019 | if (rw & (1 << BIO_RW)) | 1027 | if (unplug_page || (rw & (1 << BIO_RW))) |
1020 | multi->num_stripes = map->num_stripes; | 1028 | num_stripes = map->num_stripes; |
1021 | else if (mirror_num) { | 1029 | else if (mirror_num) { |
1022 | stripe_index = mirror_num - 1; | 1030 | stripe_index = mirror_num - 1; |
1023 | } else { | 1031 | } else { |
@@ -1037,7 +1045,7 @@ again: | |||
1037 | } | 1045 | } |
1038 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { | 1046 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { |
1039 | if (rw & (1 << BIO_RW)) | 1047 | if (rw & (1 << BIO_RW)) |
1040 | multi->num_stripes = map->num_stripes; | 1048 | num_stripes = map->num_stripes; |
1041 | else if (mirror_num) | 1049 | else if (mirror_num) |
1042 | stripe_index = mirror_num - 1; | 1050 | stripe_index = mirror_num - 1; |
1043 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { | 1051 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { |
@@ -1047,8 +1055,8 @@ again: | |||
1047 | stripe_index = do_div(stripe_nr, factor); | 1055 | stripe_index = do_div(stripe_nr, factor); |
1048 | stripe_index *= map->sub_stripes; | 1056 | stripe_index *= map->sub_stripes; |
1049 | 1057 | ||
1050 | if (rw & (1 << BIO_RW)) | 1058 | if (unplug_page || (rw & (1 << BIO_RW))) |
1051 | multi->num_stripes = map->sub_stripes; | 1059 | num_stripes = map->sub_stripes; |
1052 | else if (mirror_num) | 1060 | else if (mirror_num) |
1053 | stripe_index += mirror_num - 1; | 1061 | stripe_index += mirror_num - 1; |
1054 | else | 1062 | else |
@@ -1063,19 +1071,50 @@ again: | |||
1063 | } | 1071 | } |
1064 | BUG_ON(stripe_index >= map->num_stripes); | 1072 | BUG_ON(stripe_index >= map->num_stripes); |
1065 | 1073 | ||
1066 | for (i = 0; i < multi->num_stripes; i++) { | 1074 | for (i = 0; i < num_stripes; i++) { |
1067 | multi->stripes[i].physical = | 1075 | if (unplug_page) { |
1068 | map->stripes[stripe_index].physical + stripe_offset + | 1076 | struct btrfs_device *device; |
1069 | stripe_nr * map->stripe_len; | 1077 | struct backing_dev_info *bdi; |
1070 | multi->stripes[i].dev = map->stripes[stripe_index].dev; | 1078 | |
1079 | device = map->stripes[stripe_index].dev; | ||
1080 | bdi = blk_get_backing_dev_info(device->bdev); | ||
1081 | if (bdi->unplug_io_fn) { | ||
1082 | bdi->unplug_io_fn(bdi, unplug_page); | ||
1083 | } | ||
1084 | } else { | ||
1085 | multi->stripes[i].physical = | ||
1086 | map->stripes[stripe_index].physical + | ||
1087 | stripe_offset + stripe_nr * map->stripe_len; | ||
1088 | multi->stripes[i].dev = map->stripes[stripe_index].dev; | ||
1089 | } | ||
1071 | stripe_index++; | 1090 | stripe_index++; |
1072 | } | 1091 | } |
1073 | *multi_ret = multi; | 1092 | if (multi_ret) { |
1093 | *multi_ret = multi; | ||
1094 | multi->num_stripes = num_stripes; | ||
1095 | } | ||
1074 | out: | 1096 | out: |
1075 | free_extent_map(em); | 1097 | free_extent_map(em); |
1076 | return 0; | 1098 | return 0; |
1077 | } | 1099 | } |
1078 | 1100 | ||
1101 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | ||
1102 | u64 logical, u64 *length, | ||
1103 | struct btrfs_multi_bio **multi_ret, int mirror_num) | ||
1104 | { | ||
1105 | return __btrfs_map_block(map_tree, rw, logical, length, multi_ret, | ||
1106 | mirror_num, NULL); | ||
1107 | } | ||
1108 | |||
1109 | int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, | ||
1110 | u64 logical, struct page *page) | ||
1111 | { | ||
1112 | u64 length = PAGE_CACHE_SIZE; | ||
1113 | return __btrfs_map_block(map_tree, READ, logical, &length, | ||
1114 | NULL, 0, page); | ||
1115 | } | ||
1116 | |||
1117 | |||
1079 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) | 1118 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) |
1080 | static void end_bio_multi_stripe(struct bio *bio, int err) | 1119 | static void end_bio_multi_stripe(struct bio *bio, int err) |
1081 | #else | 1120 | #else |
@@ -1122,16 +1161,12 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, | |||
1122 | u64 logical = bio->bi_sector << 9; | 1161 | u64 logical = bio->bi_sector << 9; |
1123 | u64 length = 0; | 1162 | u64 length = 0; |
1124 | u64 map_length; | 1163 | u64 map_length; |
1125 | struct bio_vec *bvec; | ||
1126 | struct btrfs_multi_bio *multi = NULL; | 1164 | struct btrfs_multi_bio *multi = NULL; |
1127 | int i; | ||
1128 | int ret; | 1165 | int ret; |
1129 | int dev_nr = 0; | 1166 | int dev_nr = 0; |
1130 | int total_devs = 1; | 1167 | int total_devs = 1; |
1131 | 1168 | ||
1132 | bio_for_each_segment(bvec, bio, i) { | 1169 | length = bio->bi_size; |
1133 | length += bvec->bv_len; | ||
1134 | } | ||
1135 | 1170 | ||
1136 | map_tree = &root->fs_info->mapping_tree; | 1171 | map_tree = &root->fs_info->mapping_tree; |
1137 | map_length = length; | 1172 | map_length = length; |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index f9cae3072171..dfe7e8a9507c 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -119,4 +119,6 @@ int btrfs_add_device(struct btrfs_trans_handle *trans, | |||
119 | struct btrfs_device *device); | 119 | struct btrfs_device *device); |
120 | int btrfs_cleanup_fs_uuids(void); | 120 | int btrfs_cleanup_fs_uuids(void); |
121 | int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); | 121 | int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); |
122 | int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, | ||
123 | u64 logical, struct page *page); | ||
122 | #endif | 124 | #endif |