summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ctree.c4
-rw-r--r--disk-io.c45
-rw-r--r--volumes.c80
-rw-r--r--volumes.h20
4 files changed, 97 insertions, 52 deletions
diff --git a/ctree.c b/ctree.c
index 051cab59..9f904620 100644
--- a/ctree.c
+++ b/ctree.c
@@ -1928,8 +1928,10 @@ again:
root->root_key.objectid,
root_gen, disk_key.objectid, 0,
l->start, 0);
- if (IS_ERR(right))
+ if (IS_ERR(right)) {
+ BUG_ON(1);
return PTR_ERR(right);
+ }
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_bytenr(right, right->start);
diff --git a/disk-io.c b/disk-io.c
index ccc2f35d..d49f2cea 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -97,11 +97,10 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
{
int ret;
- int total_devs = 1;
int dev_nr;
struct extent_buffer *eb;
- u64 physical;
u64 length;
+ struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
eb = btrfs_find_tree_block(root, bytenr, blocksize);
@@ -111,13 +110,15 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
}
dev_nr = 0;
- ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, dev_nr,
- bytenr, &physical, &length, &device,
- &total_devs);
+ length = blocksize;
+ ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
+ bytenr, &length, &multi);
BUG_ON(ret);
+ device = multi->stripes[0].dev;
device->total_ios++;
blocksize = min(blocksize, (u32)(64 * 1024));
- readahead(device->fd, physical, blocksize);
+ readahead(device->fd, multi->stripes[0].physical, blocksize);
+ kfree(multi);
return 0;
}
@@ -125,11 +126,10 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize)
{
int ret;
- int total_devs = 1;
int dev_nr;
struct extent_buffer *eb;
- u64 physical;
u64 length;
+ struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
@@ -140,19 +140,21 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
return eb;
dev_nr = 0;
- ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, dev_nr,
- eb->start, &physical, &length, &device,
- &total_devs);
+ length = blocksize;
+ ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
+ eb->start, &length, &multi);
BUG_ON(ret);
+ device = multi->stripes[0].dev;
eb->fd = device->fd;
device->total_ios++;
- eb->dev_bytenr = physical;
+ eb->dev_bytenr = multi->stripes[0].physical;
ret = read_extent_from_disk(eb);
if (ret) {
free_extent_buffer(eb);
return NULL;
}
btrfs_set_buffer_uptodate(eb);
+ kfree(multi);
return eb;
}
@@ -160,11 +162,9 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *eb)
{
int ret;
- int total_devs = 1;
int dev_nr;
- u64 physical;
u64 length;
- struct btrfs_device *device;
+ struct btrfs_multi_bio *multi = NULL;
if (check_tree_block(root, eb))
BUG();
@@ -175,18 +175,19 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
csum_tree_block(root, eb, 0);
dev_nr = 0;
- while(dev_nr < total_devs) {
- ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE,
- dev_nr, eb->start, &physical, &length,
- &device, &total_devs);
+ length = eb->len;
+ ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE,
+ eb->start, &length, &multi);
+ while(dev_nr < multi->num_stripes) {
BUG_ON(ret);
- eb->fd = device->fd;
- eb->dev_bytenr = physical;
+ eb->fd = multi->stripes[dev_nr].dev->fd;
+ eb->dev_bytenr = multi->stripes[dev_nr].physical;
+ multi->stripes[dev_nr].dev->total_ios++;
dev_nr++;
- device->total_ios++;
ret = write_extent_to_disk(eb);
BUG_ON(ret);
}
+ kfree(multi);
return 0;
}
diff --git a/volumes.c b/volumes.c
index c86202de..ef2f59ca 100644
--- a/volumes.c
+++ b/volumes.c
@@ -43,11 +43,11 @@ struct map_lookup {
int stripe_len;
int sector_size;
int num_stripes;
- struct stripe stripes[];
+ struct btrfs_bio_stripe stripes[];
};
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
- (sizeof(struct stripe) * (n)))
+ (sizeof(struct btrfs_bio_stripe) * (n)))
static LIST_HEAD(fs_uuids);
@@ -733,15 +733,29 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
}
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
- int dev_nr, u64 logical, u64 *phys, u64 *length,
- struct btrfs_device **dev, int *total_devs)
+ u64 logical, u64 *length,
+ struct btrfs_multi_bio **multi_ret)
{
struct cache_extent *ce;
struct map_lookup *map;
u64 offset;
u64 stripe_offset;
u64 stripe_nr;
+ int stripes_allocated = 8;
int stripe_index;
+ int i;
+ struct btrfs_multi_bio *multi = NULL;
+
+ if (multi_ret && rw == READ) {
+ stripes_allocated = 1;
+ }
+again:
+ if (multi_ret) {
+ multi = kzalloc(btrfs_multi_bio_size(stripes_allocated),
+ GFP_NOFS);
+ if (!multi)
+ return -ENOMEM;
+ }
ce = find_first_cache_extent(&map_tree->cache_tree, logical);
BUG_ON(!ce);
@@ -749,6 +763,15 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
map = container_of(ce, struct map_lookup, ce);
offset = logical - ce->start;
+ /* if our multi bio struct is too small, back off and try again */
+ if (multi_ret && (rw == WRITE) &&
+ stripes_allocated < map->num_stripes &&
+ ((map->type & BTRFS_BLOCK_GROUP_RAID1) ||
+ (map->type & BTRFS_BLOCK_GROUP_DUP))) {
+ stripes_allocated = map->num_stripes;
+ kfree(multi);
+ goto again;
+ }
stripe_nr = offset;
/*
* stripe_nr counts the total number of stripes we have to stride
@@ -762,22 +785,28 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
/* stripe_offset is the offset of this block in its stripe*/
stripe_offset = offset - stripe_offset;
+ if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_DUP)) {
+ /* we limit the length of each bio to what fits in a stripe */
+ *length = min_t(u64, ce->size - offset,
+ map->stripe_len - stripe_offset);
+ } else {
+ *length = ce->size - offset;
+ }
+
+ if (!multi_ret)
+ goto out;
+
+ multi->num_stripes = 1;
+ stripe_index = 0;
if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
- stripe_index = dev_nr;
if (rw == WRITE)
- *total_devs = map->num_stripes;
- else {
+ multi->num_stripes = map->num_stripes;
+ else
stripe_index = stripe_nr % map->num_stripes;
- *total_devs = 1;
- }
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
- if (rw == WRITE) {
- *total_devs = map->num_stripes;
- stripe_index = dev_nr;
- } else {
- stripe_index = 0;
- *total_devs = 1;
- }
+ if (rw == WRITE)
+ multi->num_stripes = map->num_stripes;
} else {
/*
* after this do_div call, stripe_nr is the number of stripes
@@ -788,18 +817,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
stripe_nr = stripe_nr / map->num_stripes;
}
BUG_ON(stripe_index >= map->num_stripes);
- *phys = map->stripes[stripe_index].physical + stripe_offset +
- stripe_nr * map->stripe_len;
- if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
- BTRFS_BLOCK_GROUP_DUP)) {
- /* we limit the length of each bio to what fits in a stripe */
- *length = min_t(u64, ce->size - offset,
- map->stripe_len - stripe_offset);
- } else {
- *length = ce->size - offset;
+ BUG_ON(stripe_index != 0 && multi->num_stripes > 1);
+ for (i = 0; i < multi->num_stripes; i++) {
+ multi->stripes[i].physical =
+ map->stripes[stripe_index].physical + stripe_offset +
+ stripe_nr * map->stripe_len;
+ multi->stripes[i].dev = map->stripes[stripe_index].dev;
+ stripe_index++;
}
- *dev = map->stripes[stripe_index].dev;
+ *multi_ret = multi;
+out:
return 0;
}
diff --git a/volumes.h b/volumes.h
index a51cfe54..9928c1f9 100644
--- a/volumes.h
+++ b/volumes.h
@@ -66,12 +66,26 @@ struct btrfs_fs_devices {
struct list_head list;
};
+struct btrfs_bio_stripe {
+ struct btrfs_device *dev;
+ u64 physical;
+};
+
+struct btrfs_multi_bio {
+ int error;
+ int num_stripes;
+ struct btrfs_bio_stripe stripes[];
+};
+
+#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
+ (sizeof(struct btrfs_bio_stripe) * (n)))
+
int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
u64 owner, u64 num_bytes, u64 *start);
-int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int stripe_nr,
- u64 logical, u64 *phys, u64 *length,
- struct btrfs_device **dev, int *total_stripes);
+int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+ u64 logical, u64 *length,
+ struct btrfs_multi_bio **multi_ret);
int btrfs_read_sys_array(struct btrfs_root *root);
int btrfs_read_chunk_tree(struct btrfs_root *root);
int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,