summaryrefslogtreecommitdiff
path: root/volumes.c
diff options
context:
space:
mode:
Diffstat (limited to 'volumes.c')
-rw-r--r--volumes.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/volumes.c b/volumes.c
index 9ecfdb82..ce8b706d 100644
--- a/volumes.c
+++ b/volumes.c
@@ -43,6 +43,7 @@ struct map_lookup {
int stripe_len;
int sector_size;
int num_stripes;
+ int sub_stripes;
struct btrfs_bio_stripe stripes[];
};
@@ -594,6 +595,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
u64 avail;
u64 max_avail = 0;
int num_stripes = 1;
+ int sub_stripes = 0;
int looped = 0;
int ret;
int index;
@@ -605,6 +607,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
}
if (type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP)) {
if (type & BTRFS_BLOCK_GROUP_SYSTEM)
calc_size = 128 * 1024 * 1024;
@@ -619,6 +622,13 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
num_stripes = 2;
if (type & (BTRFS_BLOCK_GROUP_RAID0))
num_stripes = btrfs_super_num_devices(&info->super_copy);
+ if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
+ num_stripes = btrfs_super_num_devices(&info->super_copy);
+ if (num_stripes < 4)
+ return -ENOSPC;
+ num_stripes &= ~(u32)1;
+ sub_stripes = 2;
+ }
again:
INIT_LIST_HEAD(&private_devs);
cur = dev_list->next;
@@ -674,6 +684,8 @@ again:
if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
*num_bytes = calc_size;
+ else if (type & BTRFS_BLOCK_GROUP_RAID10)
+ *num_bytes = calc_size * num_stripes / sub_stripes;
else
*num_bytes = calc_size * num_stripes;
@@ -723,12 +735,14 @@ printk("\talloc chunk size %llu from dev %llu phys %llu\n",
btrfs_set_stack_chunk_io_align(chunk, stripe_len);
btrfs_set_stack_chunk_io_width(chunk, stripe_len);
btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize);
+ btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes);
map->sector_size = extent_root->sectorsize;
map->stripe_len = stripe_len;
map->io_align = stripe_len;
map->io_width = stripe_len;
map->type = type;
map->num_stripes = num_stripes;
+ map->sub_stripes = sub_stripes;
ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
btrfs_chunk_item_size(num_stripes));
@@ -773,6 +787,8 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
offset = logical - ce->start;
if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
ret = map->num_stripes;
+ else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
+ ret = map->sub_stripes;
else
ret = 1;
return ret;
@@ -788,6 +804,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 stripe_offset;
u64 stripe_nr;
int stripes_allocated = 8;
+ int stripes_required = 1;
int stripe_index;
int i;
struct btrfs_multi_bio *multi = NULL;
@@ -809,11 +826,17 @@ again:
map = container_of(ce, struct map_lookup, ce);
offset = logical - ce->start;
+ if (rw == WRITE) {
+ if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_DUP)) {
+ stripes_required = map->num_stripes;
+ } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
+ stripes_required = map->sub_stripes;
+ }
+ }
/* if our multi bio struct is too small, back off and try again */
- if (multi_ret && (rw == WRITE) &&
- stripes_allocated < map->num_stripes &&
- ((map->type & BTRFS_BLOCK_GROUP_RAID1) ||
- (map->type & BTRFS_BLOCK_GROUP_DUP))) {
+ if (multi_ret && rw == WRITE &&
+ stripes_allocated < stripes_required) {
stripes_allocated = map->num_stripes;
kfree(multi);
goto again;
@@ -832,6 +855,7 @@ again:
stripe_offset = offset - stripe_offset;
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP)) {
/* we limit the length of each bio to what fits in a stripe */
*length = min_t(u64, ce->size - offset,
@@ -852,6 +876,20 @@ again:
stripe_index = mirror_num - 1;
else
stripe_index = stripe_nr % map->num_stripes;
+ } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
+ int factor = map->num_stripes / map->sub_stripes;
+
+ stripe_index = stripe_nr % factor;
+ stripe_index *= map->sub_stripes;
+
+ if (rw == WRITE)
+ multi->num_stripes = map->sub_stripes;
+ else if (mirror_num)
+ stripe_index += mirror_num - 1;
+ else
+ stripe_index = stripe_nr % map->sub_stripes;
+
+ stripe_nr = stripe_nr / factor;
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
if (rw == WRITE)
multi->num_stripes = map->num_stripes;
@@ -895,6 +933,7 @@ int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
u64 logical = BTRFS_SUPER_INFO_OFFSET;
u64 length = BTRFS_SUPER_INFO_SIZE;
int num_stripes = 0;
+ int sub_stripes = 0;
int ret;
int i;
struct list_head *cur;
@@ -909,6 +948,7 @@ int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
map->ce.start = logical;
map->ce.size = length;
map->num_stripes = num_stripes;
+ map->sub_stripes = sub_stripes;
map->io_width = length;
map->io_align = length;
map->sector_size = length;
@@ -983,6 +1023,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
map->type = btrfs_chunk_type(leaf, chunk);
+ map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
for (i = 0; i < num_stripes; i++) {
map->stripes[i].physical =