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 <hugo@xxxxxxxxxxxxx>
---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html