static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
 {
-       return (cache->flags & bits);
+       return (cache->flags & bits) == bits;
 }
 
 static int noinline find_search_start(struct btrfs_root *root,
 
 }
 
+static int update_space_info(struct btrfs_fs_info *info, u64 flags,
+                            u64 total_bytes, u64 bytes_used,
+                            struct btrfs_space_info **space_info)
+{
+       struct btrfs_space_info *found;
+
+       found = __find_space_info(info, flags);
+       if (found) {
+               found->total_bytes += total_bytes;
+               found->bytes_used += bytes_used;
+               WARN_ON(found->total_bytes < found->bytes_used);
+               *space_info = found;
+               return 0;
+       }
+       found = kmalloc(sizeof(*found), GFP_NOFS);
+       if (!found)
+               return -ENOMEM;
+
+       list_add(&found->list, &info->space_info);
+       found->flags = flags;
+       found->total_bytes = total_bytes;
+       found->bytes_used = bytes_used;
+       found->bytes_pinned = 0;
+       found->full = 0;
+       *space_info = found;
+       return 0;
+}
+
+
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
                          u64 flags)
        int ret;
 
        space_info = __find_space_info(extent_root->fs_info, flags);
+       if (!space_info) {
+               ret = update_space_info(extent_root->fs_info, flags,
+                                       0, 0, &space_info);
+               BUG_ON(ret);
+       }
        BUG_ON(!space_info);
 
        if (space_info->full)
                     extent_root->fs_info->chunk_root->root_key.objectid,
                     start, num_bytes);
        BUG_ON(ret);
+
+       if (flags & BTRFS_BLOCK_GROUP_RAID0) {
+               if (flags & BTRFS_BLOCK_GROUP_DATA) {
+                       extent_root->fs_info->extra_data_alloc_bits =
+                               BTRFS_BLOCK_GROUP_RAID0;
+               }
+               if (flags & BTRFS_BLOCK_GROUP_METADATA) {
+                       extent_root->fs_info->extra_alloc_bits =
+                               BTRFS_BLOCK_GROUP_RAID0;
+               }
+       }
        return 0;
 }
 
        struct btrfs_extent_ref *ref;
        struct btrfs_path *path;
        struct btrfs_key keys[2];
+       int extra_chunk_alloc_bits = 0;
 
        if (data) {
-               data = BTRFS_BLOCK_GROUP_DATA;
+               data = BTRFS_BLOCK_GROUP_DATA | info->extra_data_alloc_bits;
        } else if (root == root->fs_info->chunk_root) {
                data = BTRFS_BLOCK_GROUP_SYSTEM;
        } else {
-               data = BTRFS_BLOCK_GROUP_METADATA;
+               data = BTRFS_BLOCK_GROUP_METADATA | info->extra_alloc_bits;
        }
+       if (btrfs_super_num_devices(&info->super_copy) > 1 &&
+           !(data & BTRFS_BLOCK_GROUP_SYSTEM))
+               extra_chunk_alloc_bits = BTRFS_BLOCK_GROUP_RAID0;
 
        if (root->ref_cows) {
-               if (data != BTRFS_BLOCK_GROUP_METADATA) {
+               if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
                        ret = do_chunk_alloc(trans, root->fs_info->extent_root,
                                             2 * 1024 * 1024,
-                                            BTRFS_BLOCK_GROUP_METADATA);
+                                            BTRFS_BLOCK_GROUP_METADATA |
+                                            info->extra_alloc_bits |
+                                            extra_chunk_alloc_bits);
                        BUG_ON(ret);
                }
                ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                                    num_bytes + 2 * 1024 * 1024, data);
+                                    num_bytes + 2 * 1024 * 1024, data |
+                                    extra_chunk_alloc_bits);
                BUG_ON(ret);
        }
 
        return ret;
 }
 
-static int update_space_info(struct btrfs_fs_info *info, u64 flags,
-                            u64 total_bytes, u64 bytes_used,
-                            struct btrfs_space_info **space_info)
-{
-       struct btrfs_space_info *found;
-
-       found = __find_space_info(info, flags);
-       if (found) {
-               found->total_bytes += total_bytes;
-               found->bytes_used += bytes_used;
-               WARN_ON(found->total_bytes < found->bytes_used);
-               *space_info = found;
-               return 0;
-       }
-       found = kmalloc(sizeof(*found), GFP_NOFS);
-       if (!found)
-               return -ENOMEM;
-
-       list_add(&found->list, &info->space_info);
-       found->flags = flags;
-       found->total_bytes = total_bytes;
-       found->bytes_used = bytes_used;
-       found->bytes_pinned = 0;
-       found->full = 0;
-       *space_info = found;
-       return 0;
-}
-
 int btrfs_read_block_groups(struct btrfs_root *root)
 {
        struct btrfs_path *path;
                } else if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) {
                        bit = BLOCK_GROUP_METADATA;
                }
+               if (cache->flags & BTRFS_BLOCK_GROUP_RAID0) {
+                       if (cache->flags & BTRFS_BLOCK_GROUP_DATA) {
+                               info->extra_data_alloc_bits =
+                                       BTRFS_BLOCK_GROUP_RAID0;
+                       }
+                       if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) {
+                               info->extra_alloc_bits =
+                                       BTRFS_BLOCK_GROUP_RAID0;
+                       }
+               }
 
                ret = update_space_info(info, cache->flags, found_key.offset,
                                        btrfs_block_group_used(&cache->item),
 
 #include <linux/sched.h>
 #include <linux/bio.h>
 #include <linux/buffer_head.h>
+#include <asm/div64.h>
 #include "ctree.h"
 #include "extent_map.h"
 #include "disk-io.h"
 #include "print-tree.h"
 #include "volumes.h"
 
-struct map_lookup {
+struct stripe {
        struct btrfs_device *dev;
        u64 physical;
 };
+
+struct map_lookup {
+       u64 type;
+       int io_align;
+       int io_width;
+       int stripe_len;
+       int sector_size;
+       int num_stripes;
+       struct stripe stripes[];
+};
+
+#define map_lookup_size(n) (sizeof(struct map_lookup) + \
+                           (sizeof(struct stripe) * (n)))
+
 static DEFINE_MUTEX(uuid_mutex);
 static LIST_HEAD(fs_uuids);
 
                      u64 *num_bytes, u64 type)
 {
        u64 dev_offset;
+       struct btrfs_fs_info *info = extent_root->fs_info;
        struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root;
        struct btrfs_stripe *stripes;
        struct btrfs_device *device = NULL;
        int looped = 0;
        int ret;
        int index;
+       int stripe_len = 64 * 1024;
        struct btrfs_key key;
 
        if (list_empty(dev_list))
                return -ENOSPC;
+
+       if (type & BTRFS_BLOCK_GROUP_RAID0)
+               num_stripes = btrfs_super_num_devices(&info->super_copy);
+       if (type & BTRFS_BLOCK_GROUP_DATA)
+               stripe_len = 64 * 1024;
+       if (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM))
+               stripe_len = 32 * 1024;
 again:
        INIT_LIST_HEAD(&private_devs);
        cur = dev_list->next;
        if (!chunk)
                return -ENOMEM;
 
+       map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
+       if (!map) {
+               kfree(chunk);
+               return -ENOMEM;
+       }
+
        stripes = &chunk->stripe;
 
-       *num_bytes = calc_size;
+       *num_bytes = calc_size * num_stripes;
        index = 0;
        while(index < num_stripes) {
                BUG_ON(list_empty(&private_devs));
                ret = btrfs_update_device(trans, device);
                BUG_ON(ret);
 
+               map->stripes[index].dev = device;
+               map->stripes[index].physical = dev_offset;
                btrfs_set_stack_stripe_devid(stripes + index, device->devid);
                btrfs_set_stack_stripe_offset(stripes + index, dev_offset);
                physical = dev_offset;
        key.offset = *num_bytes;
        key.type = BTRFS_CHUNK_ITEM_KEY;
        btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid);
-       btrfs_set_stack_chunk_stripe_len(chunk, 64 * 1024);
+       btrfs_set_stack_chunk_stripe_len(chunk, stripe_len);
        btrfs_set_stack_chunk_type(chunk, type);
        btrfs_set_stack_chunk_num_stripes(chunk, num_stripes);
-       btrfs_set_stack_chunk_io_align(chunk, extent_root->sectorsize);
-       btrfs_set_stack_chunk_io_width(chunk, extent_root->sectorsize);
+       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);
+       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;
 
        ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
                                btrfs_chunk_item_size(num_stripes));
        em = alloc_extent_map(GFP_NOFS);
        if (!em)
                return -ENOMEM;
-       map = kmalloc(sizeof(*map), GFP_NOFS);
-       if (!map) {
-               free_extent_map(em);
-               return -ENOMEM;
-       }
-
        em->bdev = (struct block_device *)map;
        em->start = key.objectid;
        em->len = key.offset;
        em->block_start = 0;
 
-       map->physical = physical;
-       map->dev = device;
-
-       if (!map->dev) {
-               kfree(map);
-               free_extent_map(em);
-               return -EIO;
-       }
        kfree(chunk);
 
        em_tree = &extent_root->fs_info->mapping_tree.map_tree;
        struct map_lookup *map;
        struct extent_map_tree *em_tree = &map_tree->map_tree;
        u64 offset;
+       u64 stripe_offset;
+       u64 stripe_nr;
+       int stripe_index;
 
 
        spin_lock(&em_tree->lock);
        BUG_ON(em->start > logical || em->start + em->len < logical);
        map = (struct map_lookup *)em->bdev;
        offset = logical - em->start;
-       *phys = map->physical + offset;
-       *length = em->len - offset;
-       *dev = map->dev;
+
+       stripe_nr = offset;
+       /*
+        * stripe_nr counts the total number of stripes we have to stride
+        * to get to this block
+        */
+       do_div(stripe_nr, map->stripe_len);
+
+       stripe_offset = stripe_nr * map->stripe_len;
+       BUG_ON(offset < stripe_offset);
+
+       /* stripe_offset is the offset of this block in its stripe*/
+       stripe_offset = offset - stripe_offset;
+
+       /*
+        * after this do_div call, stripe_nr is the number of stripes
+        * on this device we have to walk to find the data, and
+        * stripe_index is the number of our device in the stripe array
+        */
+       stripe_index = do_div(stripe_nr, map->num_stripes);
+
+       BUG_ON(stripe_index >= map->num_stripes);
+
+       *phys = map->stripes[stripe_index].physical + stripe_offset +
+               stripe_nr * map->stripe_len;
+
+       if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
+               /* we limit the length of each bio to what fits in a stripe */
+               *length = min_t(u64, em->len - offset,
+                             map->stripe_len - stripe_offset);
+       } else {
+               *length = em->len - offset;
+       }
+       *dev = map->stripes[stripe_index].dev;
        free_extent_map(em);
        spin_unlock(&em_tree->lock);
        return 0;
        u64 logical;
        u64 length;
        u64 devid;
+       int num_stripes;
        int ret;
+       int i;
 
        logical = key->objectid;
        length = key->offset;
        em = alloc_extent_map(GFP_NOFS);
        if (!em)
                return -ENOMEM;
-       map = kmalloc(sizeof(*map), GFP_NOFS);
+       num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+       map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
        if (!map) {
                free_extent_map(em);
                return -ENOMEM;
        em->len = length;
        em->block_start = 0;
 
-       map->physical = btrfs_stripe_offset_nr(leaf, chunk, 0);
-       devid = btrfs_stripe_devid_nr(leaf, chunk, 0);
-       map->dev = btrfs_find_device(root, devid);
-       if (!map->dev) {
-               kfree(map);
-               free_extent_map(em);
-               return -EIO;
+       map->num_stripes = num_stripes;
+       map->io_width = btrfs_chunk_io_width(leaf, chunk);
+       map->io_align = btrfs_chunk_io_align(leaf, chunk);
+       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);
+       for (i = 0; i < num_stripes; i++) {
+               map->stripes[i].physical =
+                       btrfs_stripe_offset_nr(leaf, chunk, i);
+               devid = btrfs_stripe_devid_nr(leaf, chunk, i);
+               map->stripes[i].dev = btrfs_find_device(root, devid);
+               if (!map->stripes[i].dev) {
+                       kfree(map);
+                       free_extent_map(em);
+                       return -EIO;
+               }
        }
 
        spin_lock(&map_tree->map_tree.lock);