Commit cea9e445 authored by Chris Mason's avatar Chris Mason

Change btrfs_map_block to return a structure with mappings for all stripes

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent d18a2c44
...@@ -2025,8 +2025,10 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2025,8 +2025,10 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
root->root_key.objectid, root->root_key.objectid,
root_gen, disk_key.objectid, 0, root_gen, disk_key.objectid, 0,
l->start, 0); l->start, 0);
if (IS_ERR(right)) if (IS_ERR(right)) {
BUG_ON(1);
return PTR_ERR(right); return PTR_ERR(right);
}
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_bytenr(right, right->start); btrfs_set_header_bytenr(right, right->start);
......
...@@ -301,12 +301,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, ...@@ -301,12 +301,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
{ {
struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
struct btrfs_mapping_tree *map_tree; struct btrfs_mapping_tree *map_tree;
struct btrfs_device *dev;
u64 logical = bio->bi_sector << 9; u64 logical = bio->bi_sector << 9;
u64 physical;
u64 length = 0; u64 length = 0;
u64 map_length; u64 map_length;
int total_devs;
struct bio_vec *bvec; struct bio_vec *bvec;
int i; int i;
int ret; int ret;
...@@ -316,8 +313,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, ...@@ -316,8 +313,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
} }
map_tree = &root->fs_info->mapping_tree; map_tree = &root->fs_info->mapping_tree;
map_length = length; map_length = length;
ret = btrfs_map_block(map_tree, READ, 0, logical, &physical, ret = btrfs_map_block(map_tree, READ, logical,
&map_length, &dev, &total_devs); &map_length, NULL);
if (map_length < length + size) { if (map_length < length + size) {
return 1; return 1;
} }
......
...@@ -26,18 +26,6 @@ ...@@ -26,18 +26,6 @@
#include "print-tree.h" #include "print-tree.h"
#include "volumes.h" #include "volumes.h"
struct stripe {
struct btrfs_device *dev;
u64 physical;
};
struct multi_bio {
atomic_t stripes;
bio_end_io_t *end_io;
void *private;
int error;
};
struct map_lookup { struct map_lookup {
u64 type; u64 type;
int io_align; int io_align;
...@@ -45,11 +33,11 @@ struct map_lookup { ...@@ -45,11 +33,11 @@ struct map_lookup {
int stripe_len; int stripe_len;
int sector_size; int sector_size;
int num_stripes; int num_stripes;
struct stripe stripes[]; struct btrfs_bio_stripe stripes[];
}; };
#define map_lookup_size(n) (sizeof(struct map_lookup) + \ #define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct stripe) * (n))) (sizeof(struct btrfs_bio_stripe) * (n)))
static DEFINE_MUTEX(uuid_mutex); static DEFINE_MUTEX(uuid_mutex);
static LIST_HEAD(fs_uuids); static LIST_HEAD(fs_uuids);
...@@ -801,8 +789,8 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) ...@@ -801,8 +789,8 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
} }
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int dev_nr, u64 logical, u64 *phys, u64 *length, u64 logical, u64 *length,
struct btrfs_device **dev, int *total_devs) struct btrfs_multi_bio **multi_ret)
{ {
struct extent_map *em; struct extent_map *em;
struct map_lookup *map; struct map_lookup *map;
...@@ -810,8 +798,21 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -810,8 +798,21 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 offset; u64 offset;
u64 stripe_offset; u64 stripe_offset;
u64 stripe_nr; u64 stripe_nr;
int stripes_allocated = 8;
int stripe_index; int stripe_index;
int i;
struct btrfs_multi_bio *multi = NULL;
if (multi_ret && !(rw & (1 << BIO_RW))) {
stripes_allocated = 1;
}
again:
if (multi_ret) {
multi = kzalloc(btrfs_multi_bio_size(stripes_allocated),
GFP_NOFS);
if (!multi)
return -ENOMEM;
}
spin_lock(&em_tree->lock); spin_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, logical, *length); 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,6 +822,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
map = (struct map_lookup *)em->bdev; map = (struct map_lookup *)em->bdev;
offset = logical - em->start; offset = logical - em->start;
/* if our multi bio struct is too small, back off and try again */
if (multi_ret && (rw & (1 << BIO_RW)) &&
stripes_allocated < map->num_stripes &&
((map->type & BTRFS_BLOCK_GROUP_RAID1) ||
(map->type & BTRFS_BLOCK_GROUP_DUP))) {
stripes_allocated = map->num_stripes;
spin_unlock(&em_tree->lock);
free_extent_map(em);
kfree(multi);
goto again;
}
stripe_nr = offset; stripe_nr = offset;
/* /*
* stripe_nr counts the total number of stripes we have to stride * 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,10 +846,22 @@ 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 is the offset of this block in its stripe*/
stripe_offset = offset - stripe_offset; 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, em->len - offset,
map->stripe_len - stripe_offset);
} else {
*length = em->len - offset;
}
if (!multi_ret)
goto out;
multi->num_stripes = 1;
stripe_index = 0;
if (map->type & BTRFS_BLOCK_GROUP_RAID1) { if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
stripe_index = dev_nr;
if (rw & (1 << BIO_RW)) if (rw & (1 << BIO_RW))
*total_devs = map->num_stripes; multi->num_stripes = map->num_stripes;
else { else {
int i; int i;
u64 least = (u64)-1; u64 least = (u64)-1;
...@@ -852,16 +876,10 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -852,16 +876,10 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
} }
spin_unlock(&cur->io_lock); spin_unlock(&cur->io_lock);
} }
*total_devs = 1;
} }
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) { } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
if (rw == WRITE) { if (rw & (1 << BIO_RW))
*total_devs = map->num_stripes; multi->num_stripes = map->num_stripes;
stripe_index = dev_nr;
} else {
stripe_index = 0;
*total_devs = 1;
}
} else { } else {
/* /*
* after this do_div call, stripe_nr is the number of stripes * 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,18 +889,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
stripe_index = do_div(stripe_nr, map->num_stripes); stripe_index = do_div(stripe_nr, map->num_stripes);
} }
BUG_ON(stripe_index >= map->num_stripes); BUG_ON(stripe_index >= map->num_stripes);
*phys = map->stripes[stripe_index].physical + stripe_offset + BUG_ON(stripe_index != 0 && multi->num_stripes > 1);
stripe_nr * map->stripe_len;
for (i = 0; i < multi->num_stripes; i++) {
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | multi->stripes[i].physical =
BTRFS_BLOCK_GROUP_DUP)) { map->stripes[stripe_index].physical + stripe_offset +
/* we limit the length of each bio to what fits in a stripe */ stripe_nr * map->stripe_len;
*length = min_t(u64, em->len - offset, multi->stripes[i].dev = map->stripes[stripe_index].dev;
map->stripe_len - stripe_offset); stripe_index++;
} else {
*length = em->len - offset;
} }
*dev = map->stripes[stripe_index].dev; *multi_ret = multi;
out:
free_extent_map(em); free_extent_map(em);
spin_unlock(&em_tree->lock); spin_unlock(&em_tree->lock);
return 0; return 0;
...@@ -895,7 +912,7 @@ static int end_bio_multi_stripe(struct bio *bio, ...@@ -895,7 +912,7 @@ static int end_bio_multi_stripe(struct bio *bio,
unsigned int bytes_done, int err) unsigned int bytes_done, int err)
#endif #endif
{ {
struct multi_bio *multi = bio->bi_private; struct btrfs_multi_bio *multi = bio->bi_private;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
if (bio->bi_size) if (bio->bi_size)
...@@ -904,7 +921,7 @@ static int end_bio_multi_stripe(struct bio *bio, ...@@ -904,7 +921,7 @@ static int end_bio_multi_stripe(struct bio *bio,
if (err) if (err)
multi->error = err; multi->error = err;
if (atomic_dec_and_test(&multi->stripes)) { if (atomic_dec_and_test(&multi->stripes_pending)) {
bio->bi_private = multi->private; bio->bi_private = multi->private;
bio->bi_end_io = multi->end_io; bio->bi_end_io = multi->end_io;
...@@ -927,11 +944,10 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) ...@@ -927,11 +944,10 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
struct btrfs_device *dev; struct btrfs_device *dev;
struct bio *first_bio = bio; struct bio *first_bio = bio;
u64 logical = bio->bi_sector << 9; u64 logical = bio->bi_sector << 9;
u64 physical;
u64 length = 0; u64 length = 0;
u64 map_length; u64 map_length;
struct bio_vec *bvec; struct bio_vec *bvec;
struct multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
int i; int i;
int ret; int ret;
int dev_nr = 0; int dev_nr = 0;
...@@ -943,26 +959,22 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) ...@@ -943,26 +959,22 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
map_tree = &root->fs_info->mapping_tree; map_tree = &root->fs_info->mapping_tree;
map_length = length; map_length = length;
ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi);
BUG_ON(ret);
total_devs = multi->num_stripes;
if (map_length < length) {
printk("mapping failed logical %Lu bio len %Lu "
"len %Lu\n", logical, length, map_length);
BUG();
}
multi->end_io = first_bio->bi_end_io;
multi->private = first_bio->bi_private;
atomic_set(&multi->stripes_pending, multi->num_stripes);
while(dev_nr < total_devs) { while(dev_nr < total_devs) {
ret = btrfs_map_block(map_tree, rw, dev_nr, logical,
&physical, &map_length, &dev,
&total_devs);
if (map_length < length) {
printk("mapping failed logical %Lu bio len %Lu physical %Lu "
"len %Lu\n", logical, length, physical, map_length);
BUG();
}
BUG_ON(map_length < length);
if (total_devs > 1) { if (total_devs > 1) {
if (!multi) {
multi = kmalloc(sizeof(*multi), GFP_NOFS);
atomic_set(&multi->stripes, 1);
multi->end_io = bio->bi_end_io;
multi->private = first_bio->bi_private;
multi->error = 0;
} else {
atomic_inc(&multi->stripes);
}
if (dev_nr < total_devs - 1) { if (dev_nr < total_devs - 1) {
bio = bio_clone(first_bio, GFP_NOFS); bio = bio_clone(first_bio, GFP_NOFS);
BUG_ON(!bio); BUG_ON(!bio);
...@@ -972,7 +984,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) ...@@ -972,7 +984,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
bio->bi_private = multi; bio->bi_private = multi;
bio->bi_end_io = end_bio_multi_stripe; bio->bi_end_io = end_bio_multi_stripe;
} }
bio->bi_sector = physical >> 9; bio->bi_sector = multi->stripes[dev_nr].physical >> 9;
dev = multi->stripes[dev_nr].dev;
bio->bi_bdev = dev->bdev; bio->bi_bdev = dev->bdev;
spin_lock(&dev->io_lock); spin_lock(&dev->io_lock);
dev->total_ios++; dev->total_ios++;
...@@ -980,6 +993,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) ...@@ -980,6 +993,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
submit_bio(rw, bio); submit_bio(rw, bio);
dev_nr++; dev_nr++;
} }
if (total_devs == 1)
kfree(multi);
return 0; return 0;
} }
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#ifndef __BTRFS_VOLUMES_ #ifndef __BTRFS_VOLUMES_
#define __BTRFS_VOLUMES_ #define __BTRFS_VOLUMES_
#include <linux/bio.h>
struct btrfs_device { struct btrfs_device {
struct list_head dev_list; struct list_head dev_list;
struct btrfs_root *dev_root; struct btrfs_root *dev_root;
...@@ -69,12 +71,29 @@ struct btrfs_fs_devices { ...@@ -69,12 +71,29 @@ struct btrfs_fs_devices {
struct list_head list; struct list_head list;
}; };
struct btrfs_bio_stripe {
struct btrfs_device *dev;
u64 physical;
};
struct btrfs_multi_bio {
atomic_t stripes_pending;
bio_end_io_t *end_io;
void *private;
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, int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, struct btrfs_device *device,
u64 owner, u64 num_bytes, u64 *start); u64 owner, u64 num_bytes, u64 *start);
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int stripe_nr, int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 logical, u64 *phys, u64 *length, u64 logical, u64 *length,
struct btrfs_device **dev, int *total_stripes); struct btrfs_multi_bio **multi_ret);
int btrfs_read_sys_array(struct btrfs_root *root); int btrfs_read_sys_array(struct btrfs_root *root);
int btrfs_read_chunk_tree(struct btrfs_root *root); int btrfs_read_chunk_tree(struct btrfs_root *root);
int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment