On Thu, Mar 28, 2013 at 04:10:41PM +0800, Miao Xie wrote:
> It is very likely that there are several blocks in bio, it is very
> inefficient if we get their csums one by one. This patch improves
> this problem by getting the csums in batch.
>
> According to the result of the following test, the execute time of
> __btrfs_lookup_bio_sums() is down by ~28%(300us -> 217us).
>
> # dd if=<mnt>/file of=/dev/null bs=1M count=1024
Looks good to me.
Reviewed-by: Liu Bo <bo.li.liu@xxxxxxxxxx>
>
> Signed-off-by: Miao Xie <miaox@xxxxxxxxxxxxxx>
> ---
> fs/btrfs/extent_io.c | 31 +++++++++++++++++++++++++++++++
> fs/btrfs/extent_io.h | 2 ++
> fs/btrfs/file-item.c | 45 ++++++++++++++++++++++++++-------------------
> fs/btrfs/ordered-data.c | 24 ++++++++++++++----------
> fs/btrfs/ordered-data.h | 3 ++-
> 5 files changed, 75 insertions(+), 30 deletions(-)
>
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index f173c5a..3da8da5 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -1744,6 +1744,37 @@ out:
> return ret;
> }
>
> +void cache_csums(struct extent_io_tree *tree, u64 start, u32 csums[],
> + int count, int sectorsize)
> +{
> + struct rb_node *node;
> + struct extent_state *state, *next;
> +
> + spin_lock(&tree->lock);
> + /*
> + * this search will find all the extents that end after
> + * our range starts.
> + */
> + node = tree_search(tree, start);
> + BUG_ON(!node);
> +
> + state = rb_entry(node, struct extent_state, rb_node);
> + BUG_ON(state->start != start);
> +
> + while (count) {
> + BUG_ON(state->end + 1 - state->start != sectorsize);
> +
> + state->private = *csums++;
> + count--;
> + next = next_state(state);
> +
> + BUG_ON(count && (!next || next->start != state->end + 1));
> +
> + state = next;
> + }
> + spin_unlock(&tree->lock);
> +}
> +
> int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
> {
> struct rb_node *node;
> diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
> index 6068a19..b95fb6a 100644
> --- a/fs/btrfs/extent_io.h
> +++ b/fs/btrfs/extent_io.h
> @@ -261,6 +261,8 @@ int extent_readpages(struct extent_io_tree *tree,
> int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
> __u64 start, __u64 len, get_extent_t *get_extent);
> int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
> +void cache_csums(struct extent_io_tree *tree, u64 start, u32 csums[],
> + int count, int sectorsize);
> int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
> void set_page_extent_mapped(struct page *page);
>
> diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
> index b7e529d..3e2f080 100644
> --- a/fs/btrfs/file-item.c
> +++ b/fs/btrfs/file-item.c
> @@ -175,7 +175,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
> struct inode *inode, struct bio *bio,
> u64 logical_offset, u32 *dst, int dio)
> {
> - u32 sum;
> + u32 sum[16];
> + int len;
> struct bio_vec *bvec = bio->bi_io_vec;
> int bio_index = 0;
> u64 offset = 0;
> @@ -184,7 +185,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
> u64 disk_bytenr;
> u32 diff;
> u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
> - int ret;
> + int count;
> + int index;
> struct btrfs_path *path;
> struct btrfs_csum_item *item = NULL;
> struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
> @@ -212,10 +214,11 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
> if (dio)
> offset = logical_offset;
> while (bio_index < bio->bi_vcnt) {
> + len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index);
> if (!dio)
> offset = page_offset(bvec->bv_page) + bvec->bv_offset;
> - ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum);
> - if (ret == 0)
> + count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum, len);
> + if (count)
> goto found;
>
> if (!item || disk_bytenr < item_start_offset ||
> @@ -228,10 +231,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
> item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
> path, disk_bytenr, 0);
> if (IS_ERR(item)) {
> - ret = PTR_ERR(item);
> - if (ret == -ENOENT || ret == -EFBIG)
> - ret = 0;
> - sum = 0;
> + count = 1;
> + sum[0] = 0;
> if (BTRFS_I(inode)->root->root_key.objectid ==
> BTRFS_DATA_RELOC_TREE_OBJECTID) {
> set_extent_bits(io_tree, offset,
> @@ -267,19 +268,25 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
> diff = disk_bytenr - item_start_offset;
> diff = diff / root->sectorsize;
> diff = diff * csum_size;
> -
> - read_extent_buffer(path->nodes[0], &sum,
> + count = min_t(int, len, (item_last_offset - disk_bytenr) /
> + root->sectorsize);
> + read_extent_buffer(path->nodes[0], sum,
> ((unsigned long)item) + diff,
> - csum_size);
> + csum_size * count);
> found:
> - if (dst)
> - *dst++ = sum;
> - else
> - set_state_private(io_tree, offset, sum);
> - disk_bytenr += bvec->bv_len;
> - offset += bvec->bv_len;
> - bio_index++;
> - bvec++;
> + if (dst) {
> + for (index = 0; index < count; index++)
> + *dst++ = sum[index];
> + } else {
> + cache_csums(io_tree, offset, sum, count,
> + root->sectorsize);
> + }
> + while (count--) {
> + disk_bytenr += bvec->bv_len;
> + offset += bvec->bv_len;
> + bio_index++;
> + bvec++;
> + }
> }
> btrfs_free_path(path);
> return 0;
> diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
> index dc08d77..2b959b6 100644
> --- a/fs/btrfs/ordered-data.c
> +++ b/fs/btrfs/ordered-data.c
> @@ -984,7 +984,7 @@ out:
> * be reclaimed before their checksum is actually put into the btree
> */
> int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
> - u32 *sum)
> + u32 *sum, int len)
> {
> struct btrfs_ordered_sum *ordered_sum;
> struct btrfs_sector_sum *sector_sums;
> @@ -993,22 +993,26 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
> unsigned long num_sectors;
> unsigned long i;
> u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
> - int ret = 1;
> + int index = 0;
>
> ordered = btrfs_lookup_ordered_extent(inode, offset);
> if (!ordered)
> - return 1;
> + return 0;
>
> spin_lock_irq(&tree->lock);
> list_for_each_entry_reverse(ordered_sum, &ordered->list, list) {
> - if (disk_bytenr >= ordered_sum->bytenr) {
> + if (disk_bytenr >= ordered_sum->bytenr &&
> + disk_bytenr < ordered_sum->bytenr + ordered_sum->len) {
> + i = (disk_bytenr - ordered_sum->bytenr) / sectorsize;
> + sector_sums = ordered_sum->sums + i;
> num_sectors = ordered_sum->len / sectorsize;
> - sector_sums = ordered_sum->sums;
> - for (i = 0; i < num_sectors; i++) {
> + for (; i < num_sectors; i++) {
> if (sector_sums[i].bytenr == disk_bytenr) {
> - *sum = sector_sums[i].sum;
> - ret = 0;
> - goto out;
> + sum[index] = sector_sums[i].sum;
> + index++;
> + if (index == len)
> + goto out;
> + disk_bytenr += sectorsize;
> }
> }
> }
> @@ -1016,7 +1020,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
> out:
> spin_unlock_irq(&tree->lock);
> btrfs_put_ordered_extent(ordered);
> - return ret;
> + return index;
> }
>
>
> diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
> index 8eadfe4..58b0e3b 100644
> --- a/fs/btrfs/ordered-data.h
> +++ b/fs/btrfs/ordered-data.h
> @@ -196,7 +196,8 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
> u64 len);
> int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
> struct btrfs_ordered_extent *ordered);
> -int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
> +int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
> + u32 *sum, int len);
> int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
> struct btrfs_root *root, int wait);
> void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
> --
> 1.8.0.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html