diff options
-rw-r--r-- | ctree.h | 7 | ||||
-rw-r--r-- | mkfs.c | 7 | ||||
-rw-r--r-- | volumes.c | 49 |
3 files changed, 58 insertions, 5 deletions
@@ -186,6 +186,9 @@ struct btrfs_chunk { * item in the btree */ __le16 num_stripes; + + /* sub stripes only matter for raid10 */ + __le16 sub_stripes; struct btrfs_stripe stripe; /* additional stripes go here */ } __attribute__ ((__packed__)); @@ -432,6 +435,7 @@ struct btrfs_csum_item { #define BTRFS_BLOCK_GROUP_RAID0 (1 << 3) #define BTRFS_BLOCK_GROUP_RAID1 (1 << 4) #define BTRFS_BLOCK_GROUP_DUP (1 << 5) +#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6) struct btrfs_block_group_item { __le64 used; @@ -705,6 +709,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_type, struct btrfs_chunk, type, 64); 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_offset, struct btrfs_stripe, offset, 64); @@ -726,6 +731,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_num_stripes, struct btrfs_chunk, 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_offset, struct btrfs_stripe, offset, 64); @@ -203,7 +203,10 @@ static int create_raid_groups(struct btrfs_trans_handle *trans, if (num_devices == 1) allowed = BTRFS_BLOCK_GROUP_DUP; - else + else if (num_devices >= 4) { + allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID10; + } else allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1; if (allowed & metadata_profile) { @@ -246,6 +249,8 @@ static u64 parse_profile(char *s) return BTRFS_BLOCK_GROUP_RAID0; } else if (strcmp(s, "raid1") == 0) { return BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP; + } else if (strcmp(s, "raid10") == 0) { + return BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP; } else if (strcmp(s, "single") == 0) { return 0; } else { @@ -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 = |