Commit 5badf512 authored by Naohiro Aota's avatar Naohiro Aota Committed by David Sterba
Browse files

btrfs: factor out decide_stripe_size()



Factor out decide_stripe_size() from __btrfs_alloc_chunk(). This
function calculates the actual stripe size to allocate.
decide_stripe_size() handles the common case to round down the 'ndevs'
to 'devs_increment' and check the upper and lower limitation of 'ndevs'.
decide_stripe_size_regular() decides the size of a stripe and the size
of a chunk. The policy is to maximize the number of stripes.

This commit has no functional changes.

Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarNaohiro Aota <naohiro.aota@wdc.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 560156cb
Loading
Loading
Loading
Loading
+78 −58
Original line number Diff line number Diff line
@@ -4943,6 +4943,82 @@ static int gather_device_info(struct btrfs_fs_devices *fs_devices,
	return 0;
}

static int decide_stripe_size_regular(struct alloc_chunk_ctl *ctl,
				      struct btrfs_device_info *devices_info)
{
	/* Number of stripes that count for block group size */
	int data_stripes;

	/*
	 * The primary goal is to maximize the number of stripes, so use as
	 * many devices as possible, even if the stripes are not maximum sized.
	 *
	 * The DUP profile stores more than one stripe per device, the
	 * max_avail is the total size so we have to adjust.
	 */
	ctl->stripe_size = div_u64(devices_info[ctl->ndevs - 1].max_avail,
				   ctl->dev_stripes);
	ctl->num_stripes = ctl->ndevs * ctl->dev_stripes;

	/* This will have to be fixed for RAID1 and RAID10 over more drives */
	data_stripes = (ctl->num_stripes - ctl->nparity) / ctl->ncopies;

	/*
	 * Use the number of data stripes to figure out how big this chunk is
	 * really going to be in terms of logical address space, and compare
	 * that answer with the max chunk size. If it's higher, we try to
	 * reduce stripe_size.
	 */
	if (ctl->stripe_size * data_stripes > ctl->max_chunk_size) {
		/*
		 * Reduce stripe_size, round it up to a 16MB boundary again and
		 * then use it, unless it ends up being even bigger than the
		 * previous value we had already.
		 */
		ctl->stripe_size = min(round_up(div_u64(ctl->max_chunk_size,
							data_stripes), SZ_16M),
				       ctl->stripe_size);
	}

	/* Align to BTRFS_STRIPE_LEN */
	ctl->stripe_size = round_down(ctl->stripe_size, BTRFS_STRIPE_LEN);
	ctl->chunk_size = ctl->stripe_size * data_stripes;

	return 0;
}

static int decide_stripe_size(struct btrfs_fs_devices *fs_devices,
			      struct alloc_chunk_ctl *ctl,
			      struct btrfs_device_info *devices_info)
{
	struct btrfs_fs_info *info = fs_devices->fs_info;

	/*
	 * Round down to number of usable stripes, devs_increment can be any
	 * number so we can't use round_down() that requires power of 2, while
	 * rounddown is safe.
	 */
	ctl->ndevs = rounddown(ctl->ndevs, ctl->devs_increment);

	if (ctl->ndevs < ctl->devs_min) {
		if (btrfs_test_opt(info, ENOSPC_DEBUG)) {
			btrfs_debug(info,
	"%s: not enough devices with free space: have=%d minimum required=%d",
				    __func__, ctl->ndevs, ctl->devs_min);
		}
		return -ENOSPC;
	}

	ctl->ndevs = min(ctl->ndevs, ctl->devs_max);

	switch (fs_devices->chunk_alloc_policy) {
	case BTRFS_CHUNK_ALLOC_REGULAR:
		return decide_stripe_size_regular(ctl, devices_info);
	default:
		BUG();
	}
}

static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
			       u64 start, u64 type)
{
@@ -4953,8 +5029,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
	struct extent_map *em;
	struct btrfs_device_info *devices_info = NULL;
	struct alloc_chunk_ctl ctl;
	/* Number of stripes that count for block group size */
	int data_stripes;
	int ret;
	int i;
	int j;
@@ -4989,61 +5063,9 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
	if (ret < 0)
		goto error;

	/*
	 * Round down to number of usable stripes, devs_increment can be any
	 * number so we can't use round_down()
	 */
	ctl.ndevs -= ctl.ndevs % ctl.devs_increment;

	if (ctl.ndevs < ctl.devs_min) {
		ret = -ENOSPC;
		if (btrfs_test_opt(info, ENOSPC_DEBUG)) {
			btrfs_debug(info,
	"%s: not enough devices with free space: have=%d minimum required=%d",
				    __func__, ctl.ndevs, ctl.devs_min);
		}
	ret = decide_stripe_size(fs_devices, &ctl, devices_info);
	if (ret < 0)
		goto error;
	}

	ctl.ndevs = min(ctl.ndevs, ctl.devs_max);

	/*
	 * The primary goal is to maximize the number of stripes, so use as
	 * many devices as possible, even if the stripes are not maximum sized.
	 *
	 * The DUP profile stores more than one stripe per device, the
	 * max_avail is the total size so we have to adjust.
	 */
	ctl.stripe_size = div_u64(devices_info[ctl.ndevs - 1].max_avail,
				   ctl.dev_stripes);
	ctl.num_stripes = ctl.ndevs * ctl.dev_stripes;

	/*
	 * this will have to be fixed for RAID1 and RAID10 over
	 * more drives
	 */
	data_stripes = (ctl.num_stripes - ctl.nparity) / ctl.ncopies;

	/*
	 * Use the number of data stripes to figure out how big this chunk
	 * is really going to be in terms of logical address space,
	 * and compare that answer with the max chunk size. If it's higher,
	 * we try to reduce stripe_size.
	 */
	if (ctl.stripe_size * data_stripes > ctl.max_chunk_size) {
		/*
		 * Reduce stripe_size, round it up to a 16MB boundary again and
		 * then use it, unless it ends up being even bigger than the
		 * previous value we had already.
		 */
		ctl.stripe_size =
			min(round_up(div_u64(ctl.max_chunk_size, data_stripes),
				     SZ_16M),
			    ctl.stripe_size);
	}

	/* align to BTRFS_STRIPE_LEN */
	ctl.stripe_size = round_down(ctl.stripe_size, BTRFS_STRIPE_LEN);

	map = kmalloc(map_lookup_size(ctl.num_stripes), GFP_NOFS);
	if (!map) {
@@ -5067,8 +5089,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
	map->type = type;
	map->sub_stripes = ctl.sub_stripes;

	ctl.chunk_size = ctl.stripe_size * data_stripes;

	trace_btrfs_chunk_alloc(info, map, start, ctl.chunk_size);

	em = alloc_extent_map();