Commit 321aecc6 authored by Chris Mason's avatar Chris Mason

Btrfs: Add RAID10 support

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent e17cade2
...@@ -197,6 +197,9 @@ struct btrfs_chunk { ...@@ -197,6 +197,9 @@ struct btrfs_chunk {
* item in the btree * item in the btree
*/ */
__le16 num_stripes; __le16 num_stripes;
/* sub stripes only matter for raid10 */
__le16 sub_stripes;
struct btrfs_stripe stripe; struct btrfs_stripe stripe;
/* additional stripes go here */ /* additional stripes go here */
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
...@@ -444,6 +447,7 @@ struct btrfs_csum_item { ...@@ -444,6 +447,7 @@ struct btrfs_csum_item {
#define BTRFS_BLOCK_GROUP_RAID0 (1 << 3) #define BTRFS_BLOCK_GROUP_RAID0 (1 << 3)
#define BTRFS_BLOCK_GROUP_RAID1 (1 << 4) #define BTRFS_BLOCK_GROUP_RAID1 (1 << 4)
#define BTRFS_BLOCK_GROUP_DUP (1 << 5) #define BTRFS_BLOCK_GROUP_DUP (1 << 5)
#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6)
struct btrfs_block_group_item { struct btrfs_block_group_item {
...@@ -757,6 +761,7 @@ BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32); ...@@ -757,6 +761,7 @@ BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32);
BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32); BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);
BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64); BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);
BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16); BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);
BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16);
BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64); BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);
BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64); BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);
...@@ -778,6 +783,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk, ...@@ -778,6 +783,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk,
BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64); BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);
BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk, BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,
num_stripes, 16); num_stripes, 16);
BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk,
sub_stripes, 16);
BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64); BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);
BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64); BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);
......
...@@ -1042,6 +1042,7 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) ...@@ -1042,6 +1042,7 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
{ {
u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 | u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP); BTRFS_BLOCK_GROUP_DUP);
if (extra_flags) { if (extra_flags) {
if (flags & BTRFS_BLOCK_GROUP_DATA) if (flags & BTRFS_BLOCK_GROUP_DATA)
......
...@@ -33,6 +33,7 @@ struct map_lookup { ...@@ -33,6 +33,7 @@ struct map_lookup {
int stripe_len; int stripe_len;
int sector_size; int sector_size;
int num_stripes; int num_stripes;
int sub_stripes;
struct btrfs_bio_stripe stripes[]; struct btrfs_bio_stripe stripes[];
}; };
...@@ -641,6 +642,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ...@@ -641,6 +642,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
u64 avail; u64 avail;
u64 max_avail = 0; u64 max_avail = 0;
int num_stripes = 1; int num_stripes = 1;
int sub_stripes = 0;
int looped = 0; int looped = 0;
int ret; int ret;
int index; int index;
...@@ -658,6 +660,13 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ...@@ -658,6 +660,13 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
num_stripes = min_t(u64, 2, num_stripes = min_t(u64, 2,
btrfs_super_num_devices(&info->super_copy)); 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: again:
INIT_LIST_HEAD(&private_devs); INIT_LIST_HEAD(&private_devs);
cur = dev_list->next; cur = dev_list->next;
...@@ -714,6 +723,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ...@@ -714,6 +723,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
*num_bytes = calc_size; *num_bytes = calc_size;
else if (type & BTRFS_BLOCK_GROUP_RAID10)
*num_bytes = calc_size * num_stripes / sub_stripes;
else else
*num_bytes = calc_size * num_stripes; *num_bytes = calc_size * num_stripes;
...@@ -760,12 +771,14 @@ printk("alloc chunk start %Lu size %Lu from dev %Lu type %Lu\n", key.offset, cal ...@@ -760,12 +771,14 @@ printk("alloc chunk start %Lu size %Lu from dev %Lu type %Lu\n", key.offset, cal
btrfs_set_stack_chunk_io_align(chunk, stripe_len); btrfs_set_stack_chunk_io_align(chunk, stripe_len);
btrfs_set_stack_chunk_io_width(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_sector_size(chunk, extent_root->sectorsize);
btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes);
map->sector_size = extent_root->sectorsize; map->sector_size = extent_root->sectorsize;
map->stripe_len = stripe_len; map->stripe_len = stripe_len;
map->io_align = stripe_len; map->io_align = stripe_len;
map->io_width = stripe_len; map->io_width = stripe_len;
map->type = type; map->type = type;
map->num_stripes = num_stripes; map->num_stripes = num_stripes;
map->sub_stripes = sub_stripes;
ret = btrfs_insert_item(trans, chunk_root, &key, chunk, ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
btrfs_chunk_item_size(num_stripes)); btrfs_chunk_item_size(num_stripes));
...@@ -832,6 +845,8 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) ...@@ -832,6 +845,8 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
map = (struct map_lookup *)em->bdev; map = (struct map_lookup *)em->bdev;
if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
ret = map->num_stripes; ret = map->num_stripes;
else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
ret = map->sub_stripes;
else else
ret = 1; ret = 1;
free_extent_map(em); free_extent_map(em);
...@@ -849,6 +864,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -849,6 +864,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
u64 stripe_offset; u64 stripe_offset;
u64 stripe_nr; u64 stripe_nr;
int stripes_allocated = 8; int stripes_allocated = 8;
int stripes_required = 1;
int stripe_index; int stripe_index;
int i; int i;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
...@@ -877,10 +893,16 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -877,10 +893,16 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
mirror_num = 0; mirror_num = 0;
/* if our multi bio struct is too small, back off and try again */ /* if our multi bio struct is too small, back off and try again */
if (multi_ret && (rw & (1 << BIO_RW)) && if (rw & (1 << BIO_RW)) {
stripes_allocated < map->num_stripes && if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
((map->type & BTRFS_BLOCK_GROUP_RAID1) || BTRFS_BLOCK_GROUP_DUP)) {
(map->type & BTRFS_BLOCK_GROUP_DUP))) { stripes_required = map->num_stripes;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
stripes_required = map->sub_stripes;
}
}
if (multi_ret && rw == WRITE &&
stripes_allocated < stripes_required) {
stripes_allocated = map->num_stripes; stripes_allocated = map->num_stripes;
free_extent_map(em); free_extent_map(em);
kfree(multi); kfree(multi);
...@@ -900,6 +922,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -900,6 +922,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
stripe_offset = offset - stripe_offset; stripe_offset = offset - stripe_offset;
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP)) { BTRFS_BLOCK_GROUP_DUP)) {
/* we limit the length of each bio to what fits in a stripe */ /* we limit the length of each bio to what fits in a stripe */
*length = min_t(u64, em->len - offset, *length = min_t(u64, em->len - offset,
...@@ -937,6 +960,19 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -937,6 +960,19 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
multi->num_stripes = map->num_stripes; multi->num_stripes = map->num_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
int factor = map->num_stripes / map->sub_stripes;
int orig_stripe_nr = stripe_nr;
stripe_index = do_div(stripe_nr, factor);
stripe_index *= map->sub_stripes;
if (rw & (1 << BIO_RW))
multi->num_stripes = map->sub_stripes;
else if (mirror_num)
stripe_index += mirror_num - 1;
else
stripe_index += orig_stripe_nr % map->sub_stripes;
} else { } else {
/* /*
* after this do_div call, stripe_nr is the number of stripes * after this do_div call, stripe_nr is the number of stripes
...@@ -946,7 +982,6 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -946,7 +982,6 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
stripe_index = do_div(stripe_nr, map->num_stripes); stripe_index = do_div(stripe_nr, map->num_stripes);
} }
BUG_ON(stripe_index >= map->num_stripes); BUG_ON(stripe_index >= map->num_stripes);
BUG_ON(stripe_index != 0 && multi->num_stripes > 1);
for (i = 0; i < multi->num_stripes; i++) { for (i = 0; i < multi->num_stripes; i++) {
multi->stripes[i].physical = multi->stripes[i].physical =
...@@ -1120,6 +1155,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, ...@@ -1120,6 +1155,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
map->sector_size = btrfs_chunk_sector_size(leaf, chunk); map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
map->type = btrfs_chunk_type(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++) { for (i = 0; i < num_stripes; i++) {
map->stripes[i].physical = map->stripes[i].physical =
btrfs_stripe_offset_nr(leaf, chunk, i); btrfs_stripe_offset_nr(leaf, chunk, i);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment