diff options
author | Naohiro Aota <naohiro.aota@wdc.com> | 2020-02-25 06:56:13 +0300 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2020-03-23 19:01:49 +0300 |
commit | 5badf512ecd0530fbb517c999fccacf6a9d87dc1 (patch) | |
tree | 75ad369e9c035a73f97abf0a7ad99982e51a0079 /fs/btrfs | |
parent | 560156cb25fcb423969543d8bc93fe95eedc6b4c (diff) | |
download | linux-5badf512ecd0530fbb517c999fccacf6a9d87dc1.tar.xz |
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: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/volumes.c | 136 |
1 files changed, 78 insertions, 58 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 84c12ff94eb7..6309a73d100a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -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(); |