Commit fce3bb9a authored by Li Dongyang's avatar Li Dongyang Committed by root

Btrfs: make btrfs_map_block() return entire free extent for each device of RAID0/1/10/DUP

btrfs_map_block() will only return a single stripe length, but we want the
full extent be mapped to each disk when we are trimming the extent,
so we add length to btrfs_bio_stripe and fill it if we are mapping for REQ_DISCARD.
Signed-off-by: default avatarLi Dongyang <lidongyang@novell.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent b4d00d56
...@@ -2956,7 +2956,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2956,7 +2956,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
struct extent_map_tree *em_tree = &map_tree->map_tree; struct extent_map_tree *em_tree = &map_tree->map_tree;
u64 offset; u64 offset;
u64 stripe_offset; u64 stripe_offset;
u64 stripe_end_offset;
u64 stripe_nr; u64 stripe_nr;
u64 stripe_nr_orig;
u64 stripe_nr_end;
int stripes_allocated = 8; int stripes_allocated = 8;
int stripes_required = 1; int stripes_required = 1;
int stripe_index; int stripe_index;
...@@ -2965,7 +2968,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2965,7 +2968,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int max_errors = 0; int max_errors = 0;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
if (multi_ret && !(rw & REQ_WRITE)) if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD)))
stripes_allocated = 1; stripes_allocated = 1;
again: again:
if (multi_ret) { if (multi_ret) {
...@@ -3011,7 +3014,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3011,7 +3014,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
max_errors = 1; max_errors = 1;
} }
} }
if (multi_ret && (rw & REQ_WRITE) && if (rw & REQ_DISCARD) {
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_DUP |
BTRFS_BLOCK_GROUP_RAID10)) {
stripes_required = map->num_stripes;
}
}
if (multi_ret && (rw & (REQ_WRITE | REQ_DISCARD)) &&
stripes_allocated < stripes_required) { stripes_allocated < stripes_required) {
stripes_allocated = map->num_stripes; stripes_allocated = map->num_stripes;
free_extent_map(em); free_extent_map(em);
...@@ -3031,7 +3042,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3031,7 +3042,10 @@ static 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 | if (rw & REQ_DISCARD)
*length = min_t(u64, em->len - offset, *length);
else if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP)) { BTRFS_BLOCK_GROUP_DUP)) {
/* we limit the length of each bio to what fits in a stripe */ /* we limit the length of each bio to what fits in a stripe */
...@@ -3046,8 +3060,19 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3046,8 +3060,19 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
num_stripes = 1; num_stripes = 1;
stripe_index = 0; stripe_index = 0;
if (map->type & BTRFS_BLOCK_GROUP_RAID1) { stripe_nr_orig = stripe_nr;
if (unplug_page || (rw & REQ_WRITE)) stripe_nr_end = (offset + *length + map->stripe_len - 1) &
(~(map->stripe_len - 1));
do_div(stripe_nr_end, map->stripe_len);
stripe_end_offset = stripe_nr_end * map->stripe_len -
(offset + *length);
if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
if (rw & REQ_DISCARD)
num_stripes = min_t(u64, map->num_stripes,
stripe_nr_end - stripe_nr_orig);
stripe_index = do_div(stripe_nr, map->num_stripes);
} else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
if (unplug_page || (rw & (REQ_WRITE | REQ_DISCARD)))
num_stripes = map->num_stripes; num_stripes = map->num_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
...@@ -3058,7 +3083,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3058,7 +3083,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
} }
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) { } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
if (rw & REQ_WRITE) if (rw & (REQ_WRITE | REQ_DISCARD))
num_stripes = map->num_stripes; num_stripes = map->num_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
...@@ -3071,6 +3096,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3071,6 +3096,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
if (unplug_page || (rw & REQ_WRITE)) if (unplug_page || (rw & REQ_WRITE))
num_stripes = map->sub_stripes; num_stripes = map->sub_stripes;
else if (rw & REQ_DISCARD)
num_stripes = min_t(u64, map->sub_stripes *
(stripe_nr_end - stripe_nr_orig),
map->num_stripes);
else if (mirror_num) else if (mirror_num)
stripe_index += mirror_num - 1; stripe_index += mirror_num - 1;
else { else {
...@@ -3088,6 +3117,78 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3088,6 +3117,78 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
} }
BUG_ON(stripe_index >= map->num_stripes); BUG_ON(stripe_index >= map->num_stripes);
if (rw & REQ_DISCARD) {
for (i = 0; i < 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;
if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
u64 stripes;
int last_stripe = (stripe_nr_end - 1) %
map->num_stripes;
int j;
for (j = 0; j < map->num_stripes; j++) {
if ((stripe_nr_end - 1 - j) %
map->num_stripes == stripe_index)
break;
}
stripes = stripe_nr_end - 1 - j;
do_div(stripes, map->num_stripes);
multi->stripes[i].length = map->stripe_len *
(stripes - stripe_nr + 1);
if (i == 0) {
multi->stripes[i].length -=
stripe_offset;
stripe_offset = 0;
}
if (stripe_index == last_stripe)
multi->stripes[i].length -=
stripe_end_offset;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
u64 stripes;
int j;
int factor = map->num_stripes /
map->sub_stripes;
int last_stripe = (stripe_nr_end - 1) % factor;
last_stripe *= map->sub_stripes;
for (j = 0; j < factor; j++) {
if ((stripe_nr_end - 1 - j) % factor ==
stripe_index / map->sub_stripes)
break;
}
stripes = stripe_nr_end - 1 - j;
do_div(stripes, factor);
multi->stripes[i].length = map->stripe_len *
(stripes - stripe_nr + 1);
if (i < map->sub_stripes) {
multi->stripes[i].length -=
stripe_offset;
if (i == map->sub_stripes - 1)
stripe_offset = 0;
}
if (stripe_index >= last_stripe &&
stripe_index <= (last_stripe +
map->sub_stripes - 1)) {
multi->stripes[i].length -=
stripe_end_offset;
}
} else
multi->stripes[i].length = *length;
stripe_index++;
if (stripe_index == map->num_stripes) {
/* This could only happen for RAID0/10 */
stripe_index = 0;
stripe_nr++;
}
}
} else {
for (i = 0; i < num_stripes; i++) { for (i = 0; i < num_stripes; i++) {
if (unplug_page) { if (unplug_page) {
struct btrfs_device *device; struct btrfs_device *device;
...@@ -3095,18 +3196,23 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3095,18 +3196,23 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
device = map->stripes[stripe_index].dev; device = map->stripes[stripe_index].dev;
if (device->bdev) { if (device->bdev) {
bdi = blk_get_backing_dev_info(device->bdev); bdi = blk_get_backing_dev_info(device->
bdev);
if (bdi->unplug_io_fn) if (bdi->unplug_io_fn)
bdi->unplug_io_fn(bdi, unplug_page); bdi->unplug_io_fn(bdi,
unplug_page);
} }
} else { } else {
multi->stripes[i].physical = multi->stripes[i].physical =
map->stripes[stripe_index].physical + map->stripes[stripe_index].physical +
stripe_offset + stripe_nr * map->stripe_len; stripe_offset +
multi->stripes[i].dev = map->stripes[stripe_index].dev; stripe_nr * map->stripe_len;
multi->stripes[i].dev =
map->stripes[stripe_index].dev;
} }
stripe_index++; stripe_index++;
} }
}
if (multi_ret) { if (multi_ret) {
*multi_ret = multi; *multi_ret = multi;
multi->num_stripes = num_stripes; multi->num_stripes = num_stripes;
......
...@@ -126,6 +126,7 @@ struct btrfs_fs_devices { ...@@ -126,6 +126,7 @@ struct btrfs_fs_devices {
struct btrfs_bio_stripe { struct btrfs_bio_stripe {
struct btrfs_device *dev; struct btrfs_device *dev;
u64 physical; u64 physical;
u64 length; /* only used for discard mappings */
}; };
struct btrfs_multi_bio { struct btrfs_multi_bio {
......
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