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=/file of=/dev/null bs=1M count=1024
Signed-off-by: Miao Xie
---
Changelog v1 -> v2:
- fix 64bit division problem on i386 machine
---
fs/btrfs/extent_io.c| 31 +++
fs/btrfs/extent_io.h| 2 ++
fs/btrfs/file-item.c| 45 ++---
fs/btrfs/ordered-data.c | 28 +---
fs/btrfs/ordered-data.h | 3 ++-
5 files changed, 78 insertions(+), 31 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index cdee391..fc4d3bc 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1777,6 +1777,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 258c921..59819f0 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 c4628a2..484017a 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -177,7 +177,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;
@@ -186,7 +187,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;
@@ -214,10 +216,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 ||
@@ -230,10 +233,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) {
s