summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c130
1 files changed, 70 insertions, 60 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f1685a2b45c..f8e2943101a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2880,7 +2880,7 @@ static int find_live_mirror(struct map_lookup *map, int first, int num,
static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 logical, u64 *length,
- struct btrfs_multi_bio **multi_ret,
+ struct btrfs_bio **bbio_ret,
int mirror_num)
{
struct extent_map *em;
@@ -2898,18 +2898,18 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int i;
int num_stripes;
int max_errors = 0;
- struct btrfs_multi_bio *multi = NULL;
+ struct btrfs_bio *bbio = NULL;
- if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD)))
+ if (bbio_ret && !(rw & (REQ_WRITE | REQ_DISCARD)))
stripes_allocated = 1;
again:
- if (multi_ret) {
- multi = kzalloc(btrfs_multi_bio_size(stripes_allocated),
+ if (bbio_ret) {
+ bbio = kzalloc(btrfs_bio_size(stripes_allocated),
GFP_NOFS);
- if (!multi)
+ if (!bbio)
return -ENOMEM;
- atomic_set(&multi->error, 0);
+ atomic_set(&bbio->error, 0);
}
read_lock(&em_tree->lock);
@@ -2930,7 +2930,7 @@ again:
if (mirror_num > map->num_stripes)
mirror_num = 0;
- /* if our multi bio struct is too small, back off and try again */
+ /* if our btrfs_bio struct is too small, back off and try again */
if (rw & REQ_WRITE) {
if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_DUP)) {
@@ -2949,11 +2949,11 @@ again:
stripes_required = map->num_stripes;
}
}
- if (multi_ret && (rw & (REQ_WRITE | REQ_DISCARD)) &&
+ if (bbio_ret && (rw & (REQ_WRITE | REQ_DISCARD)) &&
stripes_allocated < stripes_required) {
stripes_allocated = map->num_stripes;
free_extent_map(em);
- kfree(multi);
+ kfree(bbio);
goto again;
}
stripe_nr = offset;
@@ -2982,7 +2982,7 @@ again:
*length = em->len - offset;
}
- if (!multi_ret)
+ if (!bbio_ret)
goto out;
num_stripes = 1;
@@ -3007,13 +3007,17 @@ again:
stripe_index = find_live_mirror(map, 0,
map->num_stripes,
current->pid % map->num_stripes);
+ mirror_num = stripe_index + 1;
}
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
- if (rw & (REQ_WRITE | REQ_DISCARD))
+ if (rw & (REQ_WRITE | REQ_DISCARD)) {
num_stripes = map->num_stripes;
- else if (mirror_num)
+ } else if (mirror_num) {
stripe_index = mirror_num - 1;
+ } else {
+ mirror_num = 1;
+ }
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
int factor = map->num_stripes / map->sub_stripes;
@@ -3033,6 +3037,7 @@ again:
stripe_index = find_live_mirror(map, stripe_index,
map->sub_stripes, stripe_index +
current->pid % map->sub_stripes);
+ mirror_num = stripe_index + 1;
}
} else {
/*
@@ -3041,15 +3046,16 @@ again:
* stripe_index is the number of our device in the stripe array
*/
stripe_index = do_div(stripe_nr, map->num_stripes);
+ mirror_num = stripe_index + 1;
}
BUG_ON(stripe_index >= map->num_stripes);
if (rw & REQ_DISCARD) {
for (i = 0; i < num_stripes; i++) {
- multi->stripes[i].physical =
+ bbio->stripes[i].physical =
map->stripes[stripe_index].physical +
stripe_offset + stripe_nr * map->stripe_len;
- multi->stripes[i].dev = map->stripes[stripe_index].dev;
+ bbio->stripes[i].dev = map->stripes[stripe_index].dev;
if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
u64 stripes;
@@ -3070,16 +3076,16 @@ again:
}
stripes = stripe_nr_end - 1 - j;
do_div(stripes, map->num_stripes);
- multi->stripes[i].length = map->stripe_len *
+ bbio->stripes[i].length = map->stripe_len *
(stripes - stripe_nr + 1);
if (i == 0) {
- multi->stripes[i].length -=
+ bbio->stripes[i].length -=
stripe_offset;
stripe_offset = 0;
}
if (stripe_index == last_stripe)
- multi->stripes[i].length -=
+ bbio->stripes[i].length -=
stripe_end_offset;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
u64 stripes;
@@ -3104,11 +3110,11 @@ again:
}
stripes = stripe_nr_end - 1 - j;
do_div(stripes, factor);
- multi->stripes[i].length = map->stripe_len *
+ bbio->stripes[i].length = map->stripe_len *
(stripes - stripe_nr + 1);
if (i < map->sub_stripes) {
- multi->stripes[i].length -=
+ bbio->stripes[i].length -=
stripe_offset;
if (i == map->sub_stripes - 1)
stripe_offset = 0;
@@ -3116,11 +3122,11 @@ again:
if (stripe_index >= last_stripe &&
stripe_index <= (last_stripe +
map->sub_stripes - 1)) {
- multi->stripes[i].length -=
+ bbio->stripes[i].length -=
stripe_end_offset;
}
} else
- multi->stripes[i].length = *length;
+ bbio->stripes[i].length = *length;
stripe_index++;
if (stripe_index == map->num_stripes) {
@@ -3131,19 +3137,20 @@ again:
}
} else {
for (i = 0; i < num_stripes; i++) {
- multi->stripes[i].physical =
+ bbio->stripes[i].physical =
map->stripes[stripe_index].physical +
stripe_offset +
stripe_nr * map->stripe_len;
- multi->stripes[i].dev =
+ bbio->stripes[i].dev =
map->stripes[stripe_index].dev;
stripe_index++;
}
}
- if (multi_ret) {
- *multi_ret = multi;
- multi->num_stripes = num_stripes;
- multi->max_errors = max_errors;
+ if (bbio_ret) {
+ *bbio_ret = bbio;
+ bbio->num_stripes = num_stripes;
+ bbio->max_errors = max_errors;
+ bbio->mirror_num = mirror_num;
}
out:
free_extent_map(em);
@@ -3152,9 +3159,9 @@ out:
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 logical, u64 *length,
- struct btrfs_multi_bio **multi_ret, int mirror_num)
+ struct btrfs_bio **bbio_ret, int mirror_num)
{
- return __btrfs_map_block(map_tree, rw, logical, length, multi_ret,
+ return __btrfs_map_block(map_tree, rw, logical, length, bbio_ret,
mirror_num);
}
@@ -3223,28 +3230,30 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
return 0;
}
-static void end_bio_multi_stripe(struct bio *bio, int err)
+static void btrfs_end_bio(struct bio *bio, int err)
{
- struct btrfs_multi_bio *multi = bio->bi_private;
+ struct btrfs_bio *bbio = bio->bi_private;
int is_orig_bio = 0;
if (err)
- atomic_inc(&multi->error);
+ atomic_inc(&bbio->error);
- if (bio == multi->orig_bio)
+ if (bio == bbio->orig_bio)
is_orig_bio = 1;
- if (atomic_dec_and_test(&multi->stripes_pending)) {
+ if (atomic_dec_and_test(&bbio->stripes_pending)) {
if (!is_orig_bio) {
bio_put(bio);
- bio = multi->orig_bio;
+ bio = bbio->orig_bio;
}
- bio->bi_private = multi->private;
- bio->bi_end_io = multi->end_io;
+ bio->bi_private = bbio->private;
+ bio->bi_end_io = bbio->end_io;
+ bio->bi_bdev = (struct block_device *)
+ (unsigned long)bbio->mirror_num;
/* only send an error to the higher layers if it is
* beyond the tolerance of the multi-bio
*/
- if (atomic_read(&multi->error) > multi->max_errors) {
+ if (atomic_read(&bbio->error) > bbio->max_errors) {
err = -EIO;
} else if (err) {
/*
@@ -3254,7 +3263,7 @@ static void end_bio_multi_stripe(struct bio *bio, int err)
set_bit(BIO_UPTODATE, &bio->bi_flags);
err = 0;
}
- kfree(multi);
+ kfree(bbio);
bio_endio(bio, err);
} else if (!is_orig_bio) {
@@ -3334,20 +3343,20 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
u64 logical = (u64)bio->bi_sector << 9;
u64 length = 0;
u64 map_length;
- struct btrfs_multi_bio *multi = NULL;
int ret;
int dev_nr = 0;
int total_devs = 1;
+ struct btrfs_bio *bbio = NULL;
length = bio->bi_size;
map_tree = &root->fs_info->mapping_tree;
map_length = length;
- ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi,
+ ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio,
mirror_num);
BUG_ON(ret);
- total_devs = multi->num_stripes;
+ total_devs = bbio->num_stripes;
if (map_length < length) {
printk(KERN_CRIT "mapping failed logical %llu bio len %llu "
"len %llu\n", (unsigned long long)logical,
@@ -3355,25 +3364,28 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
(unsigned long long)map_length);
BUG();
}
- multi->end_io = first_bio->bi_end_io;
- multi->private = first_bio->bi_private;
- multi->orig_bio = first_bio;
- atomic_set(&multi->stripes_pending, multi->num_stripes);
+
+ bbio->orig_bio = first_bio;
+ bbio->private = first_bio->bi_private;
+ bbio->end_io = first_bio->bi_end_io;
+ atomic_set(&bbio->stripes_pending, bbio->num_stripes);
while (dev_nr < total_devs) {
- if (total_devs > 1) {
- if (dev_nr < total_devs - 1) {
- bio = bio_clone(first_bio, GFP_NOFS);
- BUG_ON(!bio);
- } else {
- bio = first_bio;
- }
- bio->bi_private = multi;
- bio->bi_end_io = end_bio_multi_stripe;
+ if (dev_nr < total_devs - 1) {
+ bio = bio_clone(first_bio, GFP_NOFS);
+ BUG_ON(!bio);
+ } else {
+ bio = first_bio;
}
- bio->bi_sector = multi->stripes[dev_nr].physical >> 9;
- dev = multi->stripes[dev_nr].dev;
+ bio->bi_private = bbio;
+ bio->bi_end_io = btrfs_end_bio;
+ bio->bi_sector = bbio->stripes[dev_nr].physical >> 9;
+ dev = bbio->stripes[dev_nr].dev;
if (dev && dev->bdev && (rw != WRITE || dev->writeable)) {
+ pr_debug("btrfs_map_bio: rw %d, secor=%llu, dev=%lu "
+ "(%s id %llu), size=%u\n", rw,
+ (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev,
+ dev->name, dev->devid, bio->bi_size);
bio->bi_bdev = dev->bdev;
if (async_submit)
schedule_bio(root, dev, rw, bio);
@@ -3386,8 +3398,6 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
}
dev_nr++;
}
- if (total_devs == 1)
- kfree(multi);
return 0;
}