Change btrfs_map_block to return a structure with mappings for all stripes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
d18a2c4475
commit
cea9e4452e
|
@ -2025,8 +2025,10 @@ again:
|
||||||
root->root_key.objectid,
|
root->root_key.objectid,
|
||||||
root_gen, disk_key.objectid, 0,
|
root_gen, disk_key.objectid, 0,
|
||||||
l->start, 0);
|
l->start, 0);
|
||||||
if (IS_ERR(right))
|
if (IS_ERR(right)) {
|
||||||
|
BUG_ON(1);
|
||||||
return PTR_ERR(right);
|
return PTR_ERR(right);
|
||||||
|
}
|
||||||
|
|
||||||
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
|
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
|
||||||
btrfs_set_header_bytenr(right, right->start);
|
btrfs_set_header_bytenr(right, right->start);
|
||||||
|
|
|
@ -301,12 +301,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
|
||||||
{
|
{
|
||||||
struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
|
struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
|
||||||
struct btrfs_mapping_tree *map_tree;
|
struct btrfs_mapping_tree *map_tree;
|
||||||
struct btrfs_device *dev;
|
|
||||||
u64 logical = bio->bi_sector << 9;
|
u64 logical = bio->bi_sector << 9;
|
||||||
u64 physical;
|
|
||||||
u64 length = 0;
|
u64 length = 0;
|
||||||
u64 map_length;
|
u64 map_length;
|
||||||
int total_devs;
|
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -316,8 +313,9 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
|
||||||
}
|
}
|
||||||
map_tree = &root->fs_info->mapping_tree;
|
map_tree = &root->fs_info->mapping_tree;
|
||||||
map_length = length;
|
map_length = length;
|
||||||
ret = btrfs_map_block(map_tree, READ, 0, logical, &physical,
|
ret = btrfs_map_block(map_tree, READ, logical,
|
||||||
&map_length, &dev, &total_devs);
|
&map_length, NULL);
|
||||||
|
|
||||||
if (map_length < length + size) {
|
if (map_length < length + size) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,18 +26,6 @@
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
|
|
||||||
struct stripe {
|
|
||||||
struct btrfs_device *dev;
|
|
||||||
u64 physical;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct multi_bio {
|
|
||||||
atomic_t stripes;
|
|
||||||
bio_end_io_t *end_io;
|
|
||||||
void *private;
|
|
||||||
int error;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct map_lookup {
|
struct map_lookup {
|
||||||
u64 type;
|
u64 type;
|
||||||
int io_align;
|
int io_align;
|
||||||
|
@ -45,11 +33,11 @@ struct map_lookup {
|
||||||
int stripe_len;
|
int stripe_len;
|
||||||
int sector_size;
|
int sector_size;
|
||||||
int num_stripes;
|
int num_stripes;
|
||||||
struct stripe stripes[];
|
struct btrfs_bio_stripe stripes[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
|
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
|
||||||
(sizeof(struct stripe) * (n)))
|
(sizeof(struct btrfs_bio_stripe) * (n)))
|
||||||
|
|
||||||
static DEFINE_MUTEX(uuid_mutex);
|
static DEFINE_MUTEX(uuid_mutex);
|
||||||
static LIST_HEAD(fs_uuids);
|
static LIST_HEAD(fs_uuids);
|
||||||
|
@ -801,8 +789,8 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
||||||
int dev_nr, u64 logical, u64 *phys, u64 *length,
|
u64 logical, u64 *length,
|
||||||
struct btrfs_device **dev, int *total_devs)
|
struct btrfs_multi_bio **multi_ret)
|
||||||
{
|
{
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
struct map_lookup *map;
|
struct map_lookup *map;
|
||||||
|
@ -810,8 +798,21 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 stripe_offset;
|
u64 stripe_offset;
|
||||||
u64 stripe_nr;
|
u64 stripe_nr;
|
||||||
|
int stripes_allocated = 8;
|
||||||
int stripe_index;
|
int stripe_index;
|
||||||
|
int i;
|
||||||
|
struct btrfs_multi_bio *multi = NULL;
|
||||||
|
|
||||||
|
if (multi_ret && !(rw & (1 << BIO_RW))) {
|
||||||
|
stripes_allocated = 1;
|
||||||
|
}
|
||||||
|
again:
|
||||||
|
if (multi_ret) {
|
||||||
|
multi = kzalloc(btrfs_multi_bio_size(stripes_allocated),
|
||||||
|
GFP_NOFS);
|
||||||
|
if (!multi)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
spin_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, logical, *length);
|
em = lookup_extent_mapping(em_tree, logical, *length);
|
||||||
|
@ -821,6 +822,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
||||||
map = (struct map_lookup *)em->bdev;
|
map = (struct map_lookup *)em->bdev;
|
||||||
offset = logical - em->start;
|
offset = logical - em->start;
|
||||||
|
|
||||||
|
/* 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))) {
|
||||||
|
stripes_allocated = map->num_stripes;
|
||||||
|
spin_unlock(&em_tree->lock);
|
||||||
|
free_extent_map(em);
|
||||||
|
kfree(multi);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
stripe_nr = offset;
|
stripe_nr = offset;
|
||||||
/*
|
/*
|
||||||
* stripe_nr counts the total number of stripes we have to stride
|
* stripe_nr counts the total number of stripes we have to stride
|
||||||
|
@ -834,10 +846,22 @@ 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 is the offset of this block in its stripe*/
|
||||||
stripe_offset = offset - stripe_offset;
|
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, em->len - offset,
|
||||||
|
map->stripe_len - stripe_offset);
|
||||||
|
} else {
|
||||||
|
*length = em->len - offset;
|
||||||
|
}
|
||||||
|
if (!multi_ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
multi->num_stripes = 1;
|
||||||
|
stripe_index = 0;
|
||||||
if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
|
if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
|
||||||
stripe_index = dev_nr;
|
|
||||||
if (rw & (1 << BIO_RW))
|
if (rw & (1 << BIO_RW))
|
||||||
*total_devs = map->num_stripes;
|
multi->num_stripes = map->num_stripes;
|
||||||
else {
|
else {
|
||||||
int i;
|
int i;
|
||||||
u64 least = (u64)-1;
|
u64 least = (u64)-1;
|
||||||
|
@ -852,16 +876,10 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
||||||
}
|
}
|
||||||
spin_unlock(&cur->io_lock);
|
spin_unlock(&cur->io_lock);
|
||||||
}
|
}
|
||||||
*total_devs = 1;
|
|
||||||
}
|
}
|
||||||
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
|
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
|
||||||
if (rw == WRITE) {
|
if (rw & (1 << BIO_RW))
|
||||||
*total_devs = map->num_stripes;
|
multi->num_stripes = map->num_stripes;
|
||||||
stripe_index = dev_nr;
|
|
||||||
} else {
|
|
||||||
stripe_index = 0;
|
|
||||||
*total_devs = 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* after this do_div call, stripe_nr is the number of stripes
|
* after this do_div call, stripe_nr is the number of stripes
|
||||||
|
@ -871,18 +889,17 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
||||||
stripe_index = do_div(stripe_nr, map->num_stripes);
|
stripe_index = do_div(stripe_nr, map->num_stripes);
|
||||||
}
|
}
|
||||||
BUG_ON(stripe_index >= map->num_stripes);
|
BUG_ON(stripe_index >= map->num_stripes);
|
||||||
*phys = map->stripes[stripe_index].physical + stripe_offset +
|
BUG_ON(stripe_index != 0 && multi->num_stripes > 1);
|
||||||
stripe_nr * map->stripe_len;
|
|
||||||
|
|
||||||
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
|
for (i = 0; i < multi->num_stripes; i++) {
|
||||||
BTRFS_BLOCK_GROUP_DUP)) {
|
multi->stripes[i].physical =
|
||||||
/* we limit the length of each bio to what fits in a stripe */
|
map->stripes[stripe_index].physical + stripe_offset +
|
||||||
*length = min_t(u64, em->len - offset,
|
stripe_nr * map->stripe_len;
|
||||||
map->stripe_len - stripe_offset);
|
multi->stripes[i].dev = map->stripes[stripe_index].dev;
|
||||||
} else {
|
stripe_index++;
|
||||||
*length = em->len - offset;
|
|
||||||
}
|
}
|
||||||
*dev = map->stripes[stripe_index].dev;
|
*multi_ret = multi;
|
||||||
|
out:
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
spin_unlock(&em_tree->lock);
|
spin_unlock(&em_tree->lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -895,7 +912,7 @@ static int end_bio_multi_stripe(struct bio *bio,
|
||||||
unsigned int bytes_done, int err)
|
unsigned int bytes_done, int err)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct multi_bio *multi = bio->bi_private;
|
struct btrfs_multi_bio *multi = bio->bi_private;
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
|
||||||
if (bio->bi_size)
|
if (bio->bi_size)
|
||||||
|
@ -904,7 +921,7 @@ static int end_bio_multi_stripe(struct bio *bio,
|
||||||
if (err)
|
if (err)
|
||||||
multi->error = err;
|
multi->error = err;
|
||||||
|
|
||||||
if (atomic_dec_and_test(&multi->stripes)) {
|
if (atomic_dec_and_test(&multi->stripes_pending)) {
|
||||||
bio->bi_private = multi->private;
|
bio->bi_private = multi->private;
|
||||||
bio->bi_end_io = multi->end_io;
|
bio->bi_end_io = multi->end_io;
|
||||||
|
|
||||||
|
@ -927,11 +944,10 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
|
||||||
struct btrfs_device *dev;
|
struct btrfs_device *dev;
|
||||||
struct bio *first_bio = bio;
|
struct bio *first_bio = bio;
|
||||||
u64 logical = bio->bi_sector << 9;
|
u64 logical = bio->bi_sector << 9;
|
||||||
u64 physical;
|
|
||||||
u64 length = 0;
|
u64 length = 0;
|
||||||
u64 map_length;
|
u64 map_length;
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
struct multi_bio *multi = NULL;
|
struct btrfs_multi_bio *multi = NULL;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
int dev_nr = 0;
|
int dev_nr = 0;
|
||||||
|
@ -943,26 +959,22 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
|
||||||
|
|
||||||
map_tree = &root->fs_info->mapping_tree;
|
map_tree = &root->fs_info->mapping_tree;
|
||||||
map_length = length;
|
map_length = length;
|
||||||
|
|
||||||
|
ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi);
|
||||||
|
BUG_ON(ret);
|
||||||
|
|
||||||
|
total_devs = multi->num_stripes;
|
||||||
|
if (map_length < length) {
|
||||||
|
printk("mapping failed logical %Lu bio len %Lu "
|
||||||
|
"len %Lu\n", logical, length, map_length);
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
multi->end_io = first_bio->bi_end_io;
|
||||||
|
multi->private = first_bio->bi_private;
|
||||||
|
atomic_set(&multi->stripes_pending, multi->num_stripes);
|
||||||
|
|
||||||
while(dev_nr < total_devs) {
|
while(dev_nr < total_devs) {
|
||||||
ret = btrfs_map_block(map_tree, rw, dev_nr, logical,
|
|
||||||
&physical, &map_length, &dev,
|
|
||||||
&total_devs);
|
|
||||||
if (map_length < length) {
|
|
||||||
printk("mapping failed logical %Lu bio len %Lu physical %Lu "
|
|
||||||
"len %Lu\n", logical, length, physical, map_length);
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
BUG_ON(map_length < length);
|
|
||||||
if (total_devs > 1) {
|
if (total_devs > 1) {
|
||||||
if (!multi) {
|
|
||||||
multi = kmalloc(sizeof(*multi), GFP_NOFS);
|
|
||||||
atomic_set(&multi->stripes, 1);
|
|
||||||
multi->end_io = bio->bi_end_io;
|
|
||||||
multi->private = first_bio->bi_private;
|
|
||||||
multi->error = 0;
|
|
||||||
} else {
|
|
||||||
atomic_inc(&multi->stripes);
|
|
||||||
}
|
|
||||||
if (dev_nr < total_devs - 1) {
|
if (dev_nr < total_devs - 1) {
|
||||||
bio = bio_clone(first_bio, GFP_NOFS);
|
bio = bio_clone(first_bio, GFP_NOFS);
|
||||||
BUG_ON(!bio);
|
BUG_ON(!bio);
|
||||||
|
@ -972,7 +984,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
|
||||||
bio->bi_private = multi;
|
bio->bi_private = multi;
|
||||||
bio->bi_end_io = end_bio_multi_stripe;
|
bio->bi_end_io = end_bio_multi_stripe;
|
||||||
}
|
}
|
||||||
bio->bi_sector = physical >> 9;
|
bio->bi_sector = multi->stripes[dev_nr].physical >> 9;
|
||||||
|
dev = multi->stripes[dev_nr].dev;
|
||||||
bio->bi_bdev = dev->bdev;
|
bio->bi_bdev = dev->bdev;
|
||||||
spin_lock(&dev->io_lock);
|
spin_lock(&dev->io_lock);
|
||||||
dev->total_ios++;
|
dev->total_ios++;
|
||||||
|
@ -980,6 +993,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
|
||||||
submit_bio(rw, bio);
|
submit_bio(rw, bio);
|
||||||
dev_nr++;
|
dev_nr++;
|
||||||
}
|
}
|
||||||
|
if (total_devs == 1)
|
||||||
|
kfree(multi);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef __BTRFS_VOLUMES_
|
#ifndef __BTRFS_VOLUMES_
|
||||||
#define __BTRFS_VOLUMES_
|
#define __BTRFS_VOLUMES_
|
||||||
|
|
||||||
|
#include <linux/bio.h>
|
||||||
|
|
||||||
struct btrfs_device {
|
struct btrfs_device {
|
||||||
struct list_head dev_list;
|
struct list_head dev_list;
|
||||||
struct btrfs_root *dev_root;
|
struct btrfs_root *dev_root;
|
||||||
|
@ -69,12 +71,29 @@ struct btrfs_fs_devices {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct btrfs_bio_stripe {
|
||||||
|
struct btrfs_device *dev;
|
||||||
|
u64 physical;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct btrfs_multi_bio {
|
||||||
|
atomic_t stripes_pending;
|
||||||
|
bio_end_io_t *end_io;
|
||||||
|
void *private;
|
||||||
|
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,
|
int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_device *device,
|
struct btrfs_device *device,
|
||||||
u64 owner, u64 num_bytes, u64 *start);
|
u64 owner, u64 num_bytes, u64 *start);
|
||||||
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int stripe_nr,
|
int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
|
||||||
u64 logical, u64 *phys, u64 *length,
|
u64 logical, u64 *length,
|
||||||
struct btrfs_device **dev, int *total_stripes);
|
struct btrfs_multi_bio **multi_ret);
|
||||||
int btrfs_read_sys_array(struct btrfs_root *root);
|
int btrfs_read_sys_array(struct btrfs_root *root);
|
||||||
int btrfs_read_chunk_tree(struct btrfs_root *root);
|
int btrfs_read_chunk_tree(struct btrfs_root *root);
|
||||||
int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||||
|
|
Loading…
Reference in a new issue