* 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__));
 #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 {
 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);
 
 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);
 
 
        int stripe_len;
        int sector_size;
        int num_stripes;
+       int sub_stripes;
        struct btrfs_bio_stripe stripes[];
 };
 
        u64 avail;
        u64 max_avail = 0;
        int num_stripes = 1;
+       int sub_stripes = 0;
        int looped = 0;
        int ret;
        int index;
                num_stripes = min_t(u64, 2,
                                  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;
 
        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;
 
        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));
        map = (struct map_lookup *)em->bdev;
        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;
        free_extent_map(em);
        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;
                mirror_num = 0;
 
        /* if our multi bio struct is too small, back off and try again */
-       if (multi_ret && (rw & (1 << BIO_RW)) &&
-           stripes_allocated < map->num_stripes &&
-           ((map->type & BTRFS_BLOCK_GROUP_RAID1) ||
-            (map->type & BTRFS_BLOCK_GROUP_DUP))) {
+       if (rw & (1 << BIO_RW)) {
+               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 (multi_ret && rw == WRITE &&
+           stripes_allocated < stripes_required) {
                stripes_allocated = map->num_stripes;
                free_extent_map(em);
                kfree(multi);
        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, em->len - offset,
                        multi->num_stripes = map->num_stripes;
                else if (mirror_num)
                        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 {
                /*
                 * after this do_div call, stripe_nr is the number of stripes
                stripe_index = do_div(stripe_nr, 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++) {
                multi->stripes[i].physical =
        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 =
                        btrfs_stripe_offset_nr(leaf, chunk, i);