There are a few places in btrfs where knowledge of the various
parameters of a replication type is needed. Factor this out into a
single function which can supply all the relevant information.

Signed-off-by: Hugo Mills <h...@carfax.org.uk>
---
 fs/btrfs/super.c   |   16 ++---
 fs/btrfs/volumes.c |  155 +++++++++++++++++++++++++---------------------------
 fs/btrfs/volumes.h |   17 ++++++
 3 files changed, 98 insertions(+), 90 deletions(-)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 0bb4ebb..2ea4e01 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -965,12 +965,12 @@ static int btrfs_calc_avail_data_space(struct btrfs_root 
*root, u64 *free_bytes)
        struct btrfs_device_info *devices_info;
        struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
        struct btrfs_device *device;
+       struct btrfs_replication_info repl_info;
        u64 skip_space;
        u64 type;
        u64 avail_space;
        u64 used_space;
        u64 min_stripe_size;
-       int min_stripes = 1;
        int i = 0, nr_devices;
        int ret;
 
@@ -984,12 +984,7 @@ static int btrfs_calc_avail_data_space(struct btrfs_root 
*root, u64 *free_bytes)
 
        /* calc min stripe number for data space alloction */
        type = btrfs_get_alloc_profile(root, 1);
-       if (type & BTRFS_BLOCK_GROUP_RAID0)
-               min_stripes = 2;
-       else if (type & BTRFS_BLOCK_GROUP_RAID1)
-               min_stripes = 2;
-       else if (type & BTRFS_BLOCK_GROUP_RAID10)
-               min_stripes = 4;
+       btrfs_get_replication_info(&repl_info, type);
 
        if (type & BTRFS_BLOCK_GROUP_DUP)
                min_stripe_size = 2 * BTRFS_STRIPE_LEN;
@@ -1057,14 +1052,15 @@ static int btrfs_calc_avail_data_space(struct 
btrfs_root *root, u64 *free_bytes)
 
        i = nr_devices - 1;
        avail_space = 0;
-       while (nr_devices >= min_stripes) {
+       while (nr_devices >= repl_info.devs_min) {
                if (devices_info[i].max_avail >= min_stripe_size) {
                        int j;
                        u64 alloc_size;
 
-                       avail_space += devices_info[i].max_avail * min_stripes;
+                       avail_space += devices_info[i].max_avail
+                               * repl_info.devs_min;
                        alloc_size = devices_info[i].max_avail;
-                       for (j = i + 1 - min_stripes; j <= i; j++)
+                       for (j = i + 1 - repl_info.devs_min; j <= i; j++)
                                devices_info[j].max_avail -= alloc_size;
                }
                i--;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 828aa34..fb11550 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -117,6 +117,52 @@ static void requeue_list(struct btrfs_pending_bios 
*pending_bios,
                pending_bios->tail = tail;
 }
 
+void btrfs_get_replication_info(struct btrfs_replication_info *info,
+                                                               u64 type)
+{
+       info->sub_stripes = 1;
+       info->dev_stripes = 1;
+       info->devs_increment = 1;
+       info->num_copies = 1;
+       info->devs_max = 0;     /* 0 == as many as possible */
+       info->devs_min = 1;
+
+       if (type & BTRFS_BLOCK_GROUP_DUP) {
+               info->dev_stripes = 2;
+               info->num_copies = 2;
+               info->devs_max = 1;
+       } else if (type & BTRFS_BLOCK_GROUP_RAID0) {
+               info->devs_min = 2;
+       } else if (type & BTRFS_BLOCK_GROUP_RAID1) {
+               info->devs_increment = 2;
+               info->num_copies = 2;
+               info->devs_max = 2;
+               info->devs_min = 2;
+       } else if (type & BTRFS_BLOCK_GROUP_RAID10) {
+               info->sub_stripes = 2;
+               info->devs_increment = 2;
+               info->num_copies = 2;
+               info->devs_min = 4;
+       }
+
+       if (type & BTRFS_BLOCK_GROUP_DATA) {
+               info->max_stripe_size = 1024 * 1024 * 1024;
+               info->min_stripe_size = 64 * 1024 * 1024;
+               info->max_chunk_size = 10 * info->max_stripe_size;
+       } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
+               info->max_stripe_size = 256 * 1024 * 1024;
+               info->min_stripe_size = 32 * 1024 * 1024;
+               info->max_chunk_size = info->max_stripe_size;
+       } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
+               info->max_stripe_size = 8 * 1024 * 1024;
+               info->min_stripe_size = 1 * 1024 * 1024;
+               info->max_chunk_size = 2 * info->max_stripe_size;
+       } else {
+               printk(KERN_ERR "Block group is of an unknown usage type: not 
data, metadata or system.\n");
+               BUG_ON(1);
+       }
+}
+
 /*
  * we try to collect pending bios for a device so we don't get a large
  * number of procs sending bios down to the same device.  This greatly
@@ -1216,6 +1262,7 @@ int btrfs_rm_device(struct btrfs_root *root, char 
*device_path)
        struct block_device *bdev;
        struct buffer_head *bh = NULL;
        struct btrfs_super_block *disk_super;
+       struct btrfs_replication_info repl_info;
        struct btrfs_fs_devices *cur_devices;
        u64 all_avail;
        u64 devid;
@@ -1231,18 +1278,16 @@ int btrfs_rm_device(struct btrfs_root *root, char 
*device_path)
                root->fs_info->avail_system_alloc_bits |
                root->fs_info->avail_metadata_alloc_bits;
 
-       if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) &&
-           root->fs_info->fs_devices->num_devices <= 4) {
-               printk(KERN_ERR "btrfs: unable to go below four devices "
-                      "on raid10\n");
-               ret = -EINVAL;
-               goto out;
-       }
+       btrfs_get_replication_info(&repl_info, all_avail);
 
-       if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) &&
-           root->fs_info->fs_devices->num_devices <= 2) {
-               printk(KERN_ERR "btrfs: unable to go below two "
-                      "devices on raid1\n");
+       if (root->fs_info->fs_devices->num_devices <= repl_info.devs_min) {
+               if (all_avail & BTRFS_BLOCK_GROUP_RAID10) {
+                       printk(KERN_ERR "btrfs: unable to go below four "
+                                  "devices on raid10\n");
+               } else if (all_avail & BTRFS_BLOCK_GROUP_RAID1) {
+                       printk(KERN_ERR "btrfs: unable to go below two "
+                                  "devices on raid1\n");
+               }
                ret = -EINVAL;
                goto out;
        }
@@ -2446,16 +2491,10 @@ static int __btrfs_alloc_chunk(struct 
btrfs_trans_handle *trans,
        struct extent_map_tree *em_tree;
        struct extent_map *em;
        struct btrfs_device_info *devices_info = NULL;
+       struct btrfs_replication_info repl_info;
        u64 total_avail;
        int num_stripes;        /* total number of stripes to allocate */
-       int sub_stripes;        /* sub_stripes info for map */
-       int dev_stripes;        /* stripes per dev */
-       int devs_max;           /* max devs to use */
-       int devs_min;           /* min devs needed */
-       int devs_increment;     /* ndevs has to be a multiple of this */
-       int ncopies;            /* how many copies to data has */
        int ret;
-       u64 max_stripe_size;
        u64 max_chunk_size;
        u64 stripe_size;
        u64 num_bytes;
@@ -2472,56 +2511,11 @@ static int __btrfs_alloc_chunk(struct 
btrfs_trans_handle *trans,
        if (list_empty(&fs_devices->alloc_list))
                return -ENOSPC;
 
-       sub_stripes = 1;
-       dev_stripes = 1;
-       devs_increment = 1;
-       ncopies = 1;
-       devs_max = 0;   /* 0 == as many as possible */
-       devs_min = 1;
-
-       /*
-        * define the properties of each RAID type.
-        * FIXME: move this to a global table and use it in all RAID
-        * calculation code
-        */
-       if (type & (BTRFS_BLOCK_GROUP_DUP)) {
-               dev_stripes = 2;
-               ncopies = 2;
-               devs_max = 1;
-       } else if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
-               devs_min = 2;
-       } else if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
-               devs_increment = 2;
-               ncopies = 2;
-               devs_max = 2;
-               devs_min = 2;
-       } else if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
-               sub_stripes = 2;
-               devs_increment = 2;
-               ncopies = 2;
-               devs_min = 4;
-       } else {
-               devs_max = 1;
-       }
-
-       if (type & BTRFS_BLOCK_GROUP_DATA) {
-               max_stripe_size = 1024 * 1024 * 1024;
-               max_chunk_size = 10 * max_stripe_size;
-       } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
-               max_stripe_size = 256 * 1024 * 1024;
-               max_chunk_size = max_stripe_size;
-       } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
-               max_stripe_size = 8 * 1024 * 1024;
-               max_chunk_size = 2 * max_stripe_size;
-       } else {
-               printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n",
-                      type);
-               BUG_ON(1);
-       }
+       btrfs_get_replication_info(&repl_info, type);
 
        /* we don't want a chunk larger than 10% of writeable space */
        max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
-                            max_chunk_size);
+                            repl_info.max_chunk_size);
 
        devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
                               GFP_NOFS);
@@ -2563,15 +2557,15 @@ static int __btrfs_alloc_chunk(struct 
btrfs_trans_handle *trans,
                 */
 
                ret = find_free_dev_extent(trans, device,
-                                          max_stripe_size * dev_stripes,
+                                          repl_info.max_stripe_size * 
repl_info.dev_stripes,
                                           &dev_offset, &max_avail);
                if (ret && ret != -ENOSPC)
                        goto error;
 
                if (ret == 0)
-                       max_avail = max_stripe_size * dev_stripes;
+                       max_avail = repl_info.max_stripe_size * 
repl_info.dev_stripes;
 
-               if (max_avail < BTRFS_STRIPE_LEN * dev_stripes)
+               if (max_avail < BTRFS_STRIPE_LEN * repl_info.dev_stripes)
                        continue;
 
                devices_info[ndevs].dev_offset = dev_offset;
@@ -2588,28 +2582,29 @@ static int __btrfs_alloc_chunk(struct 
btrfs_trans_handle *trans,
             btrfs_cmp_device_info, NULL);
 
        /* round down to number of usable stripes */
-       ndevs -= ndevs % devs_increment;
+       ndevs -= ndevs % repl_info.devs_increment;
 
-       if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
+       if (ndevs < repl_info.devs_increment * repl_info.sub_stripes
+               || ndevs < repl_info.devs_min) {
                ret = -ENOSPC;
                goto error;
        }
 
-       if (devs_max && ndevs > devs_max)
-               ndevs = devs_max;
+       if (repl_info.devs_max && ndevs > repl_info.devs_max)
+               ndevs = repl_info.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.
         */
        stripe_size = devices_info[ndevs-1].max_avail;
-       num_stripes = ndevs * dev_stripes;
+       num_stripes = ndevs * repl_info.dev_stripes;
 
-       if (stripe_size * num_stripes > max_chunk_size * ncopies) {
-               stripe_size = max_chunk_size * ncopies;
+       if (stripe_size * num_stripes > max_chunk_size * repl_info.num_copies) {
+               stripe_size = max_chunk_size * repl_info.num_copies;
                do_div(stripe_size, num_stripes);
        }
 
-       do_div(stripe_size, dev_stripes);
+       do_div(stripe_size, repl_info.dev_stripes);
        do_div(stripe_size, BTRFS_STRIPE_LEN);
        stripe_size *= BTRFS_STRIPE_LEN;
 
@@ -2621,8 +2616,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle 
*trans,
        map->num_stripes = num_stripes;
 
        for (i = 0; i < ndevs; ++i) {
-               for (j = 0; j < dev_stripes; ++j) {
-                       int s = i * dev_stripes + j;
+               for (j = 0; j < repl_info.dev_stripes; ++j) {
+                       int s = i * repl_info.dev_stripes + j;
                        map->stripes[s].dev = devices_info[i].dev;
                        map->stripes[s].physical = devices_info[i].dev_offset +
                                                   j * stripe_size;
@@ -2633,10 +2628,10 @@ static int __btrfs_alloc_chunk(struct 
btrfs_trans_handle *trans,
        map->io_align = BTRFS_STRIPE_LEN;
        map->io_width = BTRFS_STRIPE_LEN;
        map->type = type;
-       map->sub_stripes = sub_stripes;
+       map->sub_stripes = repl_info.sub_stripes;
 
        *map_ret = map;
-       num_bytes = stripe_size * (num_stripes / ncopies);
+       num_bytes = stripe_size * (num_stripes / repl_info.num_copies);
 
        *stripe_size_out = stripe_size;
        *num_bytes_out = num_bytes;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 08ec502..4fe9580 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -164,6 +164,22 @@ struct map_lookup {
        struct btrfs_bio_stripe stripes[];
 };
 
+/*
+ * Information about a the parameters of a replication strategy (RAID
+ * level)
+ */
+struct btrfs_replication_info {
+       u32 sub_stripes;
+       u32 dev_stripes;
+       u32 devs_increment;
+       u32 num_copies;
+       u32 devs_max;
+       u32 devs_min;
+       u64 max_stripe_size;
+       u64 min_stripe_size;
+       u64 max_chunk_size;
+};
+
 #define map_lookup_size(n) (sizeof(struct map_lookup) + \
                            (sizeof(struct btrfs_bio_stripe) * (n)))
 
@@ -217,4 +233,5 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 
chunk_offset);
 int find_free_dev_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_device *device, u64 num_bytes,
                         u64 *start, u64 *max_avail);
+void btrfs_get_replication_info(struct btrfs_replication_info *info, u64 type);
 #endif
-- 
1.7.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to