Change btrfs_map_block to return a structure with mappings for all stripes
authorChris Mason <chris.mason@oracle.com>
Wed, 9 Apr 2008 20:28:12 +0000 (16:28 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Wed, 9 Apr 2008 20:28:12 +0000 (16:28 -0400)
ctree.c
disk-io.c
volumes.c
volumes.h

diff --git a/ctree.c b/ctree.c
index 051cab5..9f90462 100644 (file)
--- a/ctree.c
+++ b/ctree.c
@@ -1928,8 +1928,10 @@ again:
                                         root->root_key.objectid,
                                         root_gen, disk_key.objectid, 0,
                                         l->start, 0);
-       if (IS_ERR(right))
+       if (IS_ERR(right)) {
+               BUG_ON(1);
                return PTR_ERR(right);
+       }
 
        memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_bytenr(right, right->start);
index ccc2f35..d49f2ce 100644 (file)
--- a/disk-io.c
+++ b/disk-io.c
@@ -97,11 +97,10 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
 int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
 {
        int ret;
-       int total_devs = 1;
        int dev_nr;
        struct extent_buffer *eb;
-       u64 physical;
        u64 length;
+       struct btrfs_multi_bio *multi = NULL;
        struct btrfs_device *device;
 
        eb = btrfs_find_tree_block(root, bytenr, blocksize);
@@ -111,13 +110,15 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
        }
 
        dev_nr = 0;
-       ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, dev_nr,
-                             bytenr, &physical, &length, &device,
-                             &total_devs);
+       length = blocksize;
+       ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
+                             bytenr, &length, &multi);
        BUG_ON(ret);
+       device = multi->stripes[0].dev;
        device->total_ios++;
        blocksize = min(blocksize, (u32)(64 * 1024));
-       readahead(device->fd, physical, blocksize);
+       readahead(device->fd, multi->stripes[0].physical, blocksize);
+       kfree(multi);
        return 0;
 }
 
@@ -125,11 +126,10 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
                                     u32 blocksize)
 {
        int ret;
-       int total_devs = 1;
        int dev_nr;
        struct extent_buffer *eb;
-       u64 physical;
        u64 length;
+       struct btrfs_multi_bio *multi = NULL;
        struct btrfs_device *device;
 
        eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
@@ -140,19 +140,21 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
                return eb;
 
        dev_nr = 0;
-       ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, dev_nr,
-                             eb->start, &physical, &length, &device,
-                             &total_devs);
+       length = blocksize;
+       ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
+                             eb->start, &length, &multi);
        BUG_ON(ret);
+       device = multi->stripes[0].dev;
        eb->fd = device->fd;
        device->total_ios++;
-       eb->dev_bytenr = physical;
+       eb->dev_bytenr = multi->stripes[0].physical;
        ret = read_extent_from_disk(eb);
        if (ret) {
                free_extent_buffer(eb);
                return NULL;
        }
        btrfs_set_buffer_uptodate(eb);
+       kfree(multi);
        return eb;
 }
 
@@ -160,11 +162,9 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                     struct extent_buffer *eb)
 {
        int ret;
-       int total_devs = 1;
        int dev_nr;
-       u64 physical;
        u64 length;
-       struct btrfs_device *device;
+       struct btrfs_multi_bio *multi = NULL;
 
        if (check_tree_block(root, eb))
                BUG();
@@ -175,18 +175,19 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        csum_tree_block(root, eb, 0);
 
        dev_nr = 0;
-       while(dev_nr < total_devs) {
-               ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE,
-                                     dev_nr, eb->start, &physical, &length,
-                                     &device, &total_devs);
+       length = eb->len;
+       ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE,
+                             eb->start, &length, &multi);
+       while(dev_nr < multi->num_stripes) {
                BUG_ON(ret);
-               eb->fd = device->fd;
-               eb->dev_bytenr = physical;
+               eb->fd = multi->stripes[dev_nr].dev->fd;
+               eb->dev_bytenr = multi->stripes[dev_nr].physical;
+               multi->stripes[dev_nr].dev->total_ios++;
                dev_nr++;
-               device->total_ios++;
                ret = write_extent_to_disk(eb);
                BUG_ON(ret);
        }
+       kfree(multi);
        return 0;
 }
 
index c86202d..ef2f59c 100644 (file)
--- a/volumes.c
+++ b/volumes.c
@@ -43,11 +43,11 @@ struct map_lookup {
        int stripe_len;
        int sector_size;
        int num_stripes;
-       struct stripe stripes[];
+       struct btrfs_bio_stripe stripes[];
 };
 
 #define map_lookup_size(n) (sizeof(struct map_lookup) + \
-                           (sizeof(struct stripe) * (n)))
+                           (sizeof(struct btrfs_bio_stripe) * (n)))
 
 static LIST_HEAD(fs_uuids);
 
@@ -733,15 +733,29 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
 }
 
 int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
-                   int dev_nr, u64 logical, u64 *phys, u64 *length,
-                   struct btrfs_device **dev, int *total_devs)
+                   u64 logical, u64 *length,
+                   struct btrfs_multi_bio **multi_ret)
 {
        struct cache_extent *ce;
        struct map_lookup *map;
        u64 offset;
        u64 stripe_offset;
        u64 stripe_nr;
+       int stripes_allocated = 8;
        int stripe_index;
+       int i;
+       struct btrfs_multi_bio *multi = NULL;
+
+       if (multi_ret && rw == READ) {
+               stripes_allocated = 1;
+       }
+again:
+       if (multi_ret) {
+               multi = kzalloc(btrfs_multi_bio_size(stripes_allocated),
+                               GFP_NOFS);
+               if (!multi)
+                       return -ENOMEM;
+       }
 
        ce = find_first_cache_extent(&map_tree->cache_tree, logical);
        BUG_ON(!ce);
@@ -749,6 +763,15 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        map = container_of(ce, struct map_lookup, ce);
        offset = logical - ce->start;
 
+       /* 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))) {
+               stripes_allocated = map->num_stripes;
+               kfree(multi);
+               goto again;
+       }
        stripe_nr = offset;
        /*
         * stripe_nr counts the total number of stripes we have to stride
@@ -762,22 +785,28 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        /* stripe_offset is the offset of this block in its stripe*/
        stripe_offset = offset - stripe_offset;
 
+       if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
+                        BTRFS_BLOCK_GROUP_DUP)) {
+               /* we limit the length of each bio to what fits in a stripe */
+               *length = min_t(u64, ce->size - offset,
+                             map->stripe_len - stripe_offset);
+       } else {
+               *length = ce->size - offset;
+       }
+
+       if (!multi_ret)
+               goto out;
+
+       multi->num_stripes = 1;
+       stripe_index = 0;
        if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
-               stripe_index = dev_nr;
                if (rw == WRITE)
-                       *total_devs = map->num_stripes;
-               else {
+                       multi->num_stripes = map->num_stripes;
+               else
                        stripe_index = stripe_nr % map->num_stripes;
-                       *total_devs = 1;
-               }
        } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
-               if (rw == WRITE) {
-                       *total_devs = map->num_stripes;
-                       stripe_index = dev_nr;
-               } else {
-                       stripe_index = 0;
-                       *total_devs = 1;
-               }
+               if (rw == WRITE)
+                       multi->num_stripes = map->num_stripes;
        } else {
                /*
                 * after this do_div call, stripe_nr is the number of stripes
@@ -788,18 +817,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                stripe_nr = 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 | BTRFS_BLOCK_GROUP_RAID1 |
-                        BTRFS_BLOCK_GROUP_DUP)) {
-               /* we limit the length of each bio to what fits in a stripe */
-               *length = min_t(u64, ce->size - offset,
-                             map->stripe_len - stripe_offset);
-       } else {
-               *length = ce->size - offset;
+       BUG_ON(stripe_index != 0 && multi->num_stripes > 1);
+       for (i = 0; i < multi->num_stripes; i++) {
+               multi->stripes[i].physical =
+                       map->stripes[stripe_index].physical + stripe_offset +
+                       stripe_nr * map->stripe_len;
+               multi->stripes[i].dev = map->stripes[stripe_index].dev;
+               stripe_index++;
        }
-       *dev = map->stripes[stripe_index].dev;
+       *multi_ret = multi;
+out:
        return 0;
 }
 
index a51cfe5..9928c1f 100644 (file)
--- a/volumes.h
+++ b/volumes.h
@@ -66,12 +66,26 @@ struct btrfs_fs_devices {
        struct list_head list;
 };
 
+struct btrfs_bio_stripe {
+       struct btrfs_device *dev;
+       u64 physical;
+};
+
+struct btrfs_multi_bio {
+       int error;
+       int num_stripes;
+       struct btrfs_bio_stripe stripes[];
+};
+
+#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
+                           (sizeof(struct btrfs_bio_stripe) * (n)))
+
 int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
                           struct btrfs_device *device,
                           u64 owner, u64 num_bytes, u64 *start);
-int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int stripe_nr,
-                   u64 logical, u64 *phys, u64 *length,
-                   struct btrfs_device **dev, int *total_stripes);
+int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+                   u64 logical, u64 *length,
+                   struct btrfs_multi_bio **multi_ret);
 int btrfs_read_sys_array(struct btrfs_root *root);
 int btrfs_read_chunk_tree(struct btrfs_root *root);
 int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,