|
@@ -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,
|
|
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 @@ again:
|
|
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,12 +3042,15 @@ again:
|
|
/* 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_RAID10 |
|
|
|
|
- BTRFS_BLOCK_GROUP_DUP)) {
|
|
|
|
|
|
+ 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_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 */
|
|
*length = min_t(u64, em->len - offset,
|
|
*length = min_t(u64, em->len - offset,
|
|
- map->stripe_len - stripe_offset);
|
|
|
|
|
|
+ map->stripe_len - stripe_offset);
|
|
} else {
|
|
} else {
|
|
*length = em->len - offset;
|
|
*length = em->len - offset;
|
|
}
|
|
}
|
|
@@ -3046,8 +3060,19 @@ again:
|
|
|
|
|
|
num_stripes = 1;
|
|
num_stripes = 1;
|
|
stripe_index = 0;
|
|
stripe_index = 0;
|
|
- if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
|
|
|
|
- if (unplug_page || (rw & REQ_WRITE))
|
|
|
|
|
|
+ stripe_nr_orig = stripe_nr;
|
|
|
|
+ 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 @@ again:
|
|
}
|
|
}
|
|
|
|
|
|
} 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 @@ again:
|
|
|
|
|
|
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,24 +3117,101 @@ again:
|
|
}
|
|
}
|
|
BUG_ON(stripe_index >= map->num_stripes);
|
|
BUG_ON(stripe_index >= map->num_stripes);
|
|
|
|
|
|
- for (i = 0; i < num_stripes; i++) {
|
|
|
|
- if (unplug_page) {
|
|
|
|
- struct btrfs_device *device;
|
|
|
|
- struct backing_dev_info *bdi;
|
|
|
|
-
|
|
|
|
- device = map->stripes[stripe_index].dev;
|
|
|
|
- if (device->bdev) {
|
|
|
|
- bdi = blk_get_backing_dev_info(device->bdev);
|
|
|
|
- if (bdi->unplug_io_fn)
|
|
|
|
- bdi->unplug_io_fn(bdi, unplug_page);
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
|
|
+ if (rw & REQ_DISCARD) {
|
|
|
|
+ for (i = 0; i < num_stripes; i++) {
|
|
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 + stripe_nr * map->stripe_len;
|
|
multi->stripes[i].dev = map->stripes[stripe_index].dev;
|
|
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++) {
|
|
|
|
+ if (unplug_page) {
|
|
|
|
+ struct btrfs_device *device;
|
|
|
|
+ struct backing_dev_info *bdi;
|
|
|
|
+
|
|
|
|
+ device = map->stripes[stripe_index].dev;
|
|
|
|
+ if (device->bdev) {
|
|
|
|
+ bdi = blk_get_backing_dev_info(device->
|
|
|
|
+ bdev);
|
|
|
|
+ if (bdi->unplug_io_fn)
|
|
|
|
+ bdi->unplug_io_fn(bdi,
|
|
|
|
+ unplug_page);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ 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++;
|
|
}
|
|
}
|
|
- stripe_index++;
|
|
|
|
}
|
|
}
|
|
if (multi_ret) {
|
|
if (multi_ret) {
|
|
*multi_ret = multi;
|
|
*multi_ret = multi;
|