aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c26
-rw-r--r--fs/btrfs/inode.c6
-rw-r--r--fs/btrfs/volumes.c79
-rw-r--r--fs/btrfs/volumes.h2
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
914void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) 914void 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
930static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) 934static 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
933int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, 934static 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 }
1074out: 1096out:
1075 free_extent_map(em); 1097 free_extent_map(em);
1076 return 0; 1098 return 0;
1077} 1099}
1078 1100
1101int 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
1109int 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)
1080static void end_bio_multi_stripe(struct bio *bio, int err) 1119static 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);
120int btrfs_cleanup_fs_uuids(void); 120int btrfs_cleanup_fs_uuids(void);
121int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); 121int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
122int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
123 u64 logical, struct page *page);
122#endif 124#endif