Add raid10 support
authorChris Mason <chris.mason@oracle.com>
Wed, 16 Apr 2008 15:14:21 +0000 (11:14 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Wed, 16 Apr 2008 15:14:21 +0000 (11:14 -0400)
ctree.h
mkfs.c
volumes.c

diff --git a/ctree.h b/ctree.h
index fb0a600..b72ed81 100644 (file)
--- a/ctree.h
+++ b/ctree.h
@@ -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);
 
diff --git a/mkfs.c b/mkfs.c
index 741edc6..2b74309 100644 (file)
--- a/mkfs.c
+++ b/mkfs.c
@@ -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 {
index 9ecfdb8..ce8b706 100644 (file)
--- 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 =