btrfs: factor out decide_stripe_size()
authorNaohiro Aota <naohiro.aota@wdc.com>
Tue, 25 Feb 2020 03:56:13 +0000 (12:56 +0900)
committerDavid Sterba <dsterba@suse.com>
Mon, 23 Mar 2020 16:01:49 +0000 (17:01 +0100)
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>
fs/btrfs/volumes.c

index 84c12ff..6309a73 100644 (file)
@@ -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();