Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+128 −22
Original line number Diff line number Diff line
@@ -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;
	u64 offset;
	u64 stripe_offset;
	u64 stripe_end_offset;
	u64 stripe_nr;
	u64 stripe_nr_orig;
	u64 stripe_nr_end;
	int stripes_allocated = 8;
	int stripes_required = 1;
	int stripe_index;
@@ -2965,7 +2968,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
	int max_errors = 0;
	struct btrfs_multi_bio *multi = NULL;

	if (multi_ret && !(rw & REQ_WRITE))
	if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD)))
		stripes_allocated = 1;
again:
	if (multi_ret) {
@@ -3011,7 +3014,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
			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 = map->num_stripes;
		free_extent_map(em);
@@ -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 = 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_DUP)) {
		/* 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,

	num_stripes = 1;
	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;
		else if (mirror_num)
			stripe_index = mirror_num - 1;
@@ -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) {
		if (rw & REQ_WRITE)
		if (rw & (REQ_WRITE | REQ_DISCARD))
			num_stripes = map->num_stripes;
		else if (mirror_num)
			stripe_index = mirror_num - 1;
@@ -3071,6 +3096,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,

		if (unplug_page || (rw & REQ_WRITE))
			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)
			stripe_index += mirror_num - 1;
		else {
@@ -3088,6 +3117,78 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
	}
	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++) {
			if (unplug_page) {
				struct btrfs_device *device;
@@ -3095,18 +3196,23 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,

				device = map->stripes[stripe_index].dev;
				if (device->bdev) {
				bdi = blk_get_backing_dev_info(device->bdev);
					bdi = blk_get_backing_dev_info(device->
								       bdev);
					if (bdi->unplug_io_fn)
					bdi->unplug_io_fn(bdi, unplug_page);
						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_offset +
					stripe_nr * map->stripe_len;
				multi->stripes[i].dev =
					map->stripes[stripe_index].dev;
			}
			stripe_index++;
		}
	}
	if (multi_ret) {
		*multi_ret = multi;
		multi->num_stripes = num_stripes;
+1 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ struct btrfs_fs_devices {
struct btrfs_bio_stripe {
	struct btrfs_device *dev;
	u64 physical;
	u64 length; /* only used for discard mappings */
};

struct btrfs_multi_bio {